Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопросы новичка
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Anjey_N
Добрый вечер уважаемые знатоки! help.gif Написал первую программу в IAR 4.20/
У меня 2 вопроса:
1. Как разрешить глобальные прерывания?
2.Не работает команда PORTD=decode[Tens], хоть компилятор ошибок не выдаёт. Проверку производил в AVRStudio.
Программу прилагаю.

/*Программа выводит на индикатор числа с возрастанием
с 0 до 99 или с убыванием с 99 до 0 с частотой 1 сек
Если кнопка на выводе 0 порта С отжата - происходит счёт на увеличение,
если нажата - на уменьшение.
Среда IAR 4.20
Микроконтроллер AtMega 16
Кварц 16 МГц*/

#include <ioavr.h>

// Описание глобальных переменных
unsigned char n,c,flag,Ones,Tens;
char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
#define Bit(n) (1<<(n))

// Обработка прерываний по таймеру ТС0
#pragma vector=TIMER0_OVF_vect
__interrupt void FIRST (void)
{
PORTB=0x03; // выключаем индикатор
if (n){
PORTD=decode[Ones];
PORTB&=~Bit(0); // включаем 1 индикатор
}
else{
PORTD=decode[Tens];
PORTB&=~Bit(1); // включаем 2 индикатор
}
n=!n;
}

// Обработка прерываний по таймеру ТС1
#pragma vector=TIMER1_OVF_vect
__interrupt void SECOND (void)
{
TCNT1=0xC35A;
flag=1;
if ((PINC & Bit(0))!=0) c++; // увеличиваем, если кнопка отжата
else c--; // уменьшаем, если кнопка нажата
if (c==0x64) c=0x00;
if (c==0xFF) c=0x63;
}

// Преобразование 2-10 кода в 2-й
char CharToBCD(char c)
{
char high;
high=0;
while (c>=10){

high++;
c-=10;
}
return (high<<4)|c;
}

// Настройка регистров контроллера
void unit_avr (void)
{
//Порт А
PORTA=0x00;
DDRA=0xFF;
//Порт B
PORTB=0x03;
DDRB=0x03;
//Порт C
PORTC=0x01;
DDRC=0x00;
//Порт DD
PORTD=0xFF;
DDRD=0xFF;

// Настройка таймера ТС0
// Источник синхронизации: внутренний
// Частота на входе: 62,500 kHz
// Переполнение каждые 4 мс
TCCR0=0x03;
TCNT0=0x00;
OCR0=0x00;

// Настройка таймера ТС1
// Источник синхронизации: внутренний
// Частота на входе: 15,625 kHz
// Переполнение каждую секунду
TCCR1A=0x00;
TCCR1B=0x04;
TCNT1=0xC35A;
ICR1=0x00;
OCR1A=0x00;
OCR1B=0x00;

// Таймер 2 отключён
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// Внешние прерывания отключены
MCUCR=0x00;
MCUCSR=0x00;

// Разрешены прерывания по переполнению таймеров ТС0 и ТС1
TIMSK=0x05;

// Аналоговый компаратор отключён
ACSR=0x80;
SFIOR=0x00;
}

void main (void)
{
unit_avr();
// Разрешены глобальные прерывания
// __enable interrupt(); // здесь выдаёт ошибку
SREG|=Bit(7);

while (1){
while(flag){
// Place your code here
flag=0;
Tens=CharToBCD©;
PORTA=Tens;
Ones=Tens;
Ones=Ones&(0x0F);
Tens=Tens>>4;
}
}
}



Помогите разобраться!
prottoss
Цитата(Anjey_N @ Jan 22 2007, 01:43) *
Помогите разобраться!


чтобы использовать __enable_interrupt надо подключить intrinsics.h.

А вообще я разрешаю глобальные прерывания с помощью

Код
#define SEI() asm("sei")


команда PORTD=decode[Tens], не работает, возможно, из-за того что прерывания не разрешены
Anjey_N
Эта строчка "чтобы использовать __enable_interrupt надо подключить intrinsics.h." не сработала.
Помогло #define SEI() asm("sei")

Спасибо
А вот PORTD=decode[Tens] так и не работает
prottoss
Цитата(Anjey_N @ Jan 22 2007, 02:07) *
Эта строчка "чтобы использовать __enable_interrupt надо подключить intrinsics.h." не сработала.
Помогло #define SEI() asm("sei")

Спасибо
А вот PORTD=decode[Tens] так и не работает
Прерывания то хоть заработали?
junoSynthesizer
Цитата(Anjey_N @ Jan 21 2007, 21:07) *
А вот PORTD=decode[Tens] так и не работает


в чём выражается "не работает" ?
SasaVitebsk
__enable_interrupt(); // Разрешить прерывания
satellite-plus
Цитата(Anjey_N @ Jan 21 2007, 20:43) *
Помогите разобраться!


#pragma language=extended
#include <iom16.h>
#include <ina90.h>
#include <string.h>


__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};


_SEI(); // разрешение прерываний
_CLI(); // запрет прерываний
Anjey_N
junoSynthesizer Дата Сегодня, 01:47

(Anjey_N @ Jan 21 2007, 21:07)

А вот PORTD=decode[Tens] так и не работает



в чём выражается "не работает" ?


В PORTD должно выводится значение из массива decode[11] с порядковым номером, вычисленном для переменной Tens. Это не работает.



Прерывания работают как по команде __enable_interrupt(); при #include <intrinsics.h>, так и при _SEI();


Может посмотрите ещё раз код, может я где-то ошибаюсь?


#include <ioavr.h>
#include <intrinsics.h> // для команды __enable_interrupt
#pragma language=extended
#include <iom16.h>
#include <ina90.h>
#include <string.h>
// Описание глобальных переменных
unsigned char n,c,flag,Ones,Tens;
//char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
#define Bit(n) (1<<(n))
#define Key (PINC & Bit(0))

// Обработка прерываний по таймеру ТС0
#pragma vector=TIMER0_OVF_vect
__interrupt void FIRST (void)
{
PORTB=0x03; // выключаем индикатор
if (n){
PORTD=decode[Ones]; // не работает
PORTB&=~Bit(0); // включаем 1 индикатор
}
else{
PORTD=decode[Tens]; // не работает
PORTB&=~Bit(1); // включаем 2 индикатор
}
n=!n;
}

// Обработка прерываний по таймеру ТС1
#pragma vector=TIMER1_OVF_vect
__interrupt void SECOND (void)
{
TCNT1=0xC35A;
flag=1;
if (Key) c++; // увеличиваем, если кнопка отжата
else c--; // уменьшаем, если кнопка нажата
if (c==0x64) c=0x00;
if (c==0xFF) c=0x63;
}

// Преобразование 2-10 кода в 2-й
char CharToBCD(char c)
{
char high;
high=0;
while (c>=10){

high++;
c-=10;
}
return (high<<4)|c;
}

// Настройка регистров контроллера
void unit_avr (void)
{
//Порт А
PORTA=0x00;
DDRA=0xFF;
//Порт B
PORTB=0x03;
DDRB=0x03;
//Порт C
PORTC=0x01;
DDRC=0x00;
//Порт DD
PORTD=0xFF;
DDRD=0xFF;

// Настройка таймера ТС0
// Источник синхронизации: внутренний
// Частота на входе: 62,500 kHz
// Переполнение каждые 4 мс
TCCR0=0x03;
TCNT0=0x00;
OCR0=0x00;

// Настройка таймера ТС1
// Источник синхронизации: внутренний
// Частота на входе: 15,625 kHz
// Переполнение каждую секунду
TCCR1A=0x00;
TCCR1B=0x04;
TCNT1=0xC35A;
ICR1=0x00;
OCR1A=0x00;
OCR1B=0x00;

// Таймер 2 отключён
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// Внешние прерывания отключены
MCUCR=0x00;
MCUCSR=0x00;

// Разрешены прерывания по переполнению таймеров ТС0 и ТС1
TIMSK=0x05;

// Аналоговый компаратор отключён
ACSR=0x80;
SFIOR=0x00;
}

void main (void)
{
unit_avr();
// Разрешены глобальные прерывания
__enable_interrupt();
while (1){
while(flag){
// Place your code here
flag=0;
Tens=CharToBCD©;
PORTA=Tens;
Ones=Tens;
Ones=Ones&(0x0F);
Tens=Tens>>4;
}
}
}
prottoss
Цитата(Anjey_N @ Jan 22 2007, 15:31) *
...

PORTD=decode[Tens]; // не работает
PORTB&=~Bit(1); // включаем 2 индикатор

...
А что, строчка ниже подчеркнутой работает?
otrog
Цитата(Anjey_N @ Jan 22 2007, 11:31) *
#include <ioavr.h>
#include <intrinsics.h> // для команды __enable_interrupt
#pragma language=extended
#include <iom16.h>
#include <ina90.h>
#include <string.h>
// Описание глобальных переменных
unsigned char n,c,flag,Ones,Tens;
//char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
#define Bit(n) (1<<(n))
#define Key (PINC & Bit(0))

// Обработка прерываний по таймеру ТС0
#pragma vector=TIMER0_OVF_vect
__interrupt void FIRST (void)
{
PORTB=0x03; // выключаем индикатор
if (n){
PORTD=decode[Ones]; // не работает
PORTB&=~Bit(0); // включаем 1 индикатор
}
else{
PORTD=decode[Tens]; // не работает
PORTB&=~Bit(1); // включаем 2 индикатор
}
n=!n;
}

Похоже что компилятор заоптимизировал переменную n.
Попробуйте объявить ее так:
Код
volatile unsigned char n;
satellite-plus
Посмотри как это делается.
GDI
Цитата
n=!n;


здесь инверсию хотите сделать? Имхо надо n = ~n;
Сергей Борщ
Цитата(GDI @ Jan 22 2007, 11:13) *
Цитата
n=!n;

здесь инверсию хотите сделать? Имхо надо n = ~n;
Как раз в этом случае правильнее !n, ибо переменная по логике программы должна принимать два значения - "ноль" и "не ноль". И конструкция !n это обеспечивает. А вот если n в программе каким-то образом примет любое значение, отличное от 0 или 0xFF, то конструкция ~n всегда будет давать в результате "не ноль":
Код
if(n) {

} else {

}
Для Anjey_N:
Код
Tens=CharToBCD©;   // A
PORTA=Tens;
Ones=Tens;                // B
Ones=Ones&(0x0F);
Tens=Tens>>4;          // C
                                 // D
Некорректно написан кусок программы. Если прерывание FIRST возникнет в любом месте между A и D то Tens будет иметь значение выходящее за пределы массива decode. Также между B и C Ones имеет некорректное значение. Надо пользоваться временной переменной или запрещать прерывания:
Код
__disable_interrupt();
Tens=CharToBCD( с );
PORTA=Tens;
Ones=Tens;
Ones=Ones&(0x0F);
Tens=Tens>>4;
__enable_interrupt();

или

unsigned char Tmp = CharToBCD( c );
PORTA=Tmp;
Ones=Tmp & 0x0F;
Tens=Tmp >> 4;

Кстати, чтобы компилятор не ругался на __enable_interrupt(), __disable_interrupt() и т.п. достаточно включить <inavr.h>, intrinsic.h подключится из него автоматически.
Anjey_N
Цитата(prottoss @ Jan 22 2007, 12:38) *
Цитата(Anjey_N @ Jan 22 2007, 15:31) *


...

PORTD=decode[Tens]; // не работает
PORTB&=~Bit(1); // включаем 2 индикатор

...
А что, строчка ниже подчеркнутой работает?


Да, эта строчка работает
aesok
Переменные 'flag', 'c' - должны быть volatile

Анатолий.
prottoss
Цитата(Anjey_N @ Jan 22 2007, 16:51) *
Цитата(prottoss @ Jan 22 2007, 12:38) *

Цитата(Anjey_N @ Jan 22 2007, 15:31) *

...
PORTD=decode[Tens]; // не работает
PORTB&=~Bit(1); // включаем 2 индикатор
...
А что, строчка ниже подчеркнутой работает?
Да, эта строчка работает
Тогда читайте, что сказал выше Сергей Борщ

Цитата(Сергей Борщ @ Jan 22 2007, 16:48) *
Кстати, чтобы компилятор не ругался на __enable_interrupt(), __disable_interrupt() и т.п. достаточно включить <inavr.h>, intrinsic.h подключится из него автоматически.
smile.gif Привожу текст inavr.h (IAR 4.10B)

Код
/**************************************************************
**             - INAVR.H -
**
**     Intrinsics for iccAVR
**
**     Used with iccAVR.
**
**     Copyright IAR Systems 1999. All rights reserved.
**
**     File version: $Revision: 1.10 $
**
**************************************************************/

#include <intrinsics.h>
/* The intrinsics for iccAVR has been moved to intrinsics.h */
Усе
Anjey_N
Спасибо всем, кто мне помогал, особенно Сергею Борщу. Он оказался прав. Программа теперь работает
Сергей Борщ
Цитата(Anjey_N @ Jan 22 2007, 21:32) *
Он оказался прав. Программа теперь работает
На самом деле правы были все. Обратите внимание на замечания otrog и aesok по поводу volatile. Без этого вполне возможно что программа у вас сейчас работает, а при смене уровня оптимизации, версии компилятора или просто добавлении лишней команды вдруг перестанет. Причем компилятор будет совершенно не виноват. Поскольку вы только начинаете - лучше сразу приучить себя писать правильно, чтобы потом не наступать на эти очень распространенные грабли на ровном месте.

Успехов!
Anjey_N
Согласен, правы были все и всем за это спасибо.

Объясните, пожалуйста. как понимать слово volatile!
И чем отличаются строки
char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

и

__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

И с той и с этой программа работает!


И спасибо за пожелание успехов!
IgorKossak
Цитата(Anjey_N @ Jan 23 2007, 10:27) *
Объясните, пожалуйста. как понимать слово volatile!
И чем отличаются строки
char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
и
__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};
И с той и с этой программа работает!

volatile означает "изменчивый". Это слово даёт компилятору указание не оптимизировать обращения к переменной или обьекту.

Строки, приведённые Вами, отличаются местом их хранения. Первая хранится в ОЗУ (грузится туда из flash при старте), вторая хранится во flash памяти.
satellite-plus
Цитата(Anjey_N @ Jan 23 2007, 10:27) *
Согласен, правы были все и всем за это спасибо.

Объясните, пожалуйста. как понимать слово volatile!
И чем отличаются строки
char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

и

__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

И с той и с этой программа работает!


И спасибо за пожелание успехов!


char decode[10] - переменные в ОЗУ. Параметры прописываются во флэш и при старте переписываются в ОЗУ.

__flash char decode[10] - константы. Расположены во флэши.

volatile - указывает компилятору что переменная может изменится , например в прерывании. Т.е. он должен работать с ней по ее физичекому расположению и не создавать копию( например перегружая в регистр, хотя так и быстрее).
Anjey_N
Цитата(satellite-plus @ Jan 23 2007, 12:46) *
Цитата(Anjey_N @ Jan 23 2007, 10:27) *

Согласен, правы были все и всем за это спасибо.

Объясните, пожалуйста. как понимать слово volatile!
И чем отличаются строки
char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

и

__flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};

И с той и с этой программа работает!


И спасибо за пожелание успехов!


char decode[10] - переменные в ОЗУ. Параметры прописываются во флэш и при старте переписываются в ОЗУ.

__flash char decode[10] - константы. Расположены во флэши.

volatile - указывает компилятору что переменная может изменится , например в прерывании. Т.е. он должен работать с ней по ее физичекому расположению и не создавать копию( например перегружая в регистр, хотя так и быстрее).



Т.е. если записать __flash char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};, то экономим ОЗУ?
Тогда все константы, таблицы лучше размещать во flash? Например какую-нибудь таблицу перекодировки!
SpiritDance
Да.
GDI
Только лучше написать __flash const char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};, а то при оптимизации компилятор может скопировать массив в ОЗУ
Anjey_N
Ура! Жизнь налаживается! cheers.gif
Пора заводить словарик!
Сергей Борщ
Цитата(GDI @ Jan 23 2007, 11:38) *
Только лучше написать __flash const char decode[10]={0xC0,0xFC,0xA4,0xB0,0x99,0x92,0x02,0xF8,0x80,0x90};, а то при оптимизации компилятор может скопировать массив в ОЗУ
Это имеет еще одно скрытое преимущество - если вы захотите перенести код на другую платформу (например для отладки алгоритма на PC), где нет понятия флеш или ключевого слова __flash, вы просто добавите в начало исходника строчку #define __flash и переменная будет продолжать вести себя адекватно, т.е. константой, и компилятор сможет проконтролировать попытки записи в нее.

И сразу на будущее - наверняка придется таскать код между платформами (пример только что привел), сразу же наткнетесь на то, что int, ling, float, double, в общем практически все типы имеют различный размер. Например int у AVR, MSP430, win16 = 2 байта, а у ARM, win32 - 4 байта. И чтобы не попадать в зависимость от этой неоднозначности есть два пути -
1)подключаете стандартный файл <stdint.h> и везде в программе используете переопределенные в нем типы uint8_t, int8_t, uin16_t, int16_t и т.д. (по названию понятно что они означают)
2)пишете для каждой платформы свой файл в котором подбираете подходящий тип:
Код
typedef unsigned char  byte;
typedef signed char    sbyte;
typedef unsigned short word;
typedef unsigned long  dword;

typedef volatile byte  sfr_byte;
typedef volatile word  sfr_word;
SpiritDance
эээ...
long и float разный размер на разных платформах?
насчет long может и соглашусь, так как нигде не указана его длина, но float - 32 разряда.
Сергей Борщ
Цитата(SpiritDance @ Jan 23 2007, 13:17) *
эээ...
long и float разный размер на разных платформах?
насчет long может и соглашусь, так как нигде не указана его длина, но float - 32 разряда.

про long (никаких домыслов, только факты):
Цитата
http://en.wikipedia.org/wiki/64-bit

However, in many programming environments on 64-bit machines, "int" variables are still 32 bits wide, but "long"s and pointers are 64 bits wide. These are described as having an LP64 data model.
Про float подловили :-) Действительно:
Цитата
http://en.wikipedia.org/wiki/IEEE_754
IEEE 754 specifies four formats for representing floating-point values: single-precision (32-bit), double-precision (64-bit),
И файл называется <stdint.h>, т.е. только целые типы. Правда есть исключения, но тут уже ничего не поможет:
Цитата
http://gcc.gnu.org/ml/gcc-patches/2006-11/msg00475.html

MIPS32 rev 2 optionally supports 64bit floating unit. This patch allows the use of 64bit floats by passing the -mfp64 option when used along with a MIPS32R2 cpu (the 24k/34k family with float point all have 64bit floating point units).
SpiritDance
Да собственно и нужны то только целые, так как с плавающей запятой никаких размерозависимых операций обычно не производится кроме операций выделения памяти, но тут спасает оператор sizeof. smile.gif
А вот насчет stdint.h... дело в том что он введен в только в стандарт c99, и по этой причине отсутсвует во многих писюковых компиляторах, например в msvc. sad.gif Так что для пущей портируемости, когда не хочется править ни строчки в исходниках, проще пользоватся своими переопределеными целыми типами.

Ладно хватит умничать... smile.gif (это я себе)
SasaVitebsk
Цитата(Сергей Борщ @ Jan 23 2007, 14:40) *
1)подключаете стандартный файл <stdint.h> и везде в программе используете переопределенные в нем типы uint8_t, int8_t, uin16_t, int16_t и т.д. (по названию понятно что они означают)


Вау! Я прямо горд за себя. Пришёл к этому самостоятельно когда оценивал компиляторы. Файлик свиснул из GCC. Правда подправлял чего-то там, а то не шло на IAR.

smile.gif
Сергей Борщ
Цитата(SpiritDance @ Jan 23 2007, 16:25) *
А вот насчет stdint.h... дело в том что он введен в только в стандарт c99, и по этой причине отсутсвует во многих писюковых компиляторах, например в msvc. sad.gif Так что для пущей портируемости, когда не хочется править ни строчки в исходниках, проще пользоватся своими переопределеными целыми типами.
Об этом мы долго спорили с коллегой dxp в привате. Да, конечно можно пользоваться своим. Но тогда придется его создавать его и на тех платформах, где есть stdint.h. Я сторонник stdint.h. Если его в каком-то компиляторе нет - написать руками тот же свой файл, но обозвать его stdint.h. Зато там, где stdint.h есть - писать не придется ничего. Мелочь, а приятно smile.gif
P.S. А стандарту С99 уже 8 лет как-никак. А мы (и разработчики компиляторов, к сожалению) все на С89 оглядываемся, который уже "не девочка" glare.gif .
SpiritDance
Можно в этом файле для тех компиляторов в котрых есть stdint.h преопределить через этот файл свои типы. Ну это имеет смысл делать для того чтобы файл был все-таки в одном экземпляре на все проекты. Писать свой stdint можно конечно, но если работаешь не один, то придется включать его во все проекты + если проект портируется между pc и компилятором с поддержкой C99, то приходится следить за тем какой stdint используется. В конечном итоге поступать приходится так как диктуют внешние условия разработки и требования к проекту. smile.gif

Кстати и называется этот файл во многих случаях по-разному sad.gif в компилерах которые поддерживают, так сказать, C89 с расширениями, например
codewarrior HCS12 stdtypes.h
realview inttypes.h
Сергей Борщ
Цитата(SpiritDance @ Jan 24 2007, 11:22) *
В конечном итоге поступать приходится так как диктуют внешние условия разработки и требования к проекту. smile.gif
Ну я ведь не настаиваю (кажется wink.gif )

Цитата(SpiritDance @ Jan 24 2007, 11:22) *
Кстати и называется этот файл во многих случаях по-разному sad.gif
Не знал. Запомню.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.