Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: TIMER1 в mega8
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Метценгерштейн
вот его определение

Код
        TCCR1A= (1<<COM1A0);
        TCCR1B= (0<<CS02)|(0<<CS01) |(1<<CS00)|(1<<WGM12); //CTC mode, no prescaled
        TIMSK = (1<<TOIE0)|(1<<OCIE1A);   //for counter 0 and counter 1 (1<<TICIE1)|
        OCR1AL= 150; //init OCR1AL for CTC mode
        OCR1AH= 0;

хочу, чтобы счетчик досчитывал до 150, прерывался, там я инк. переменную, дальше он обнуляется и снова считает до 150...

пробовал без
Код
TCCR1A= (1<<COM1A0);

та же фигня.

моя переменная, кот. должна инк. =0 постоянно

вроде как ничего в коде не упустил?
Палыч
Цитата(Метценгерштейн @ May 8 2010, 02:10) *
Вроде как ничего в коде не упустил?
Порядок записи байт в двухбайтный регистр
Метценгерштейн
т.е. поменять местами
Код
OCR1AL= 150; //init OCR1AL for CTC mode
OCR1AH= 0;

на
Код
OCR1AH= 0;
OCR1AL= 150; //init OCR1AL for CTC mode

?

это принципиально разве?

Код
TCCR1A= (1<<COM1A0);
TCCR1B= (0<<CS02)|(0<<CS01) |(1<<CS00)|(1<<WGM12); //CTC mode, no prescaled

тоже менял- результат тот же- не работатет
Палыч
Цитата(Метценгерштейн @ May 8 2010, 09:36) *
это принципиально разве?
В данном случае, может быть, и - не принципиально. Но порядок - должен быть. А то у Вас: таймер запускается до его окончательной настройки, да ещё и прерывания разрешаются; запись в двубайтный регистр - строго наоборот. DS невнимательно читаете. Надеюсь, прерывания разрешены в SREG? По какому вектору прерывания ловите?
Метценгерштейн
Код
char __low_level_init (void) {   //this function will starts after reset AVR


        UBRRL = ((OSC / 16 / RS232_BAUDRATE - 1) >> 0) & 0xFF;   //for mega8
        UCSRB = (1 << RXCIE) | (1<<RXEN) | (1<<TXEN);  //for UART for RX & TX, enable interrupts

        TCCR0 = (1<<CS02)|(0<<CS01) |(1<<CS00); //prescaler for counter 0
        
        
        TCCR1B= (0<<CS02)|(0<<CS01) |(1<<CS00)|(1<<WGM12); //CTC mode, no prescaled
        TCCR1A= (1<<COM1A0);
        TIMSK = (1<<TOIE0)|(1<<OCIE1A);   //for counter 0 and counter 1 (1<<TICIE1)|
        OCR1AH= 0;
        OCR1AL= koeff; //init OCR1AL for CTC mode
        

        PORTB = (0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0);            // all pins to 0
        DDRB =(1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);              // all pins to out

        PORTD = (0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0);            // all pins to 0
        DDRD =(0<<7)|(0<<6)|(0<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1<<0);              // pins 5,6,7 to in

        return 1;                 // after return initialise memory
}


#pragma vector = TIMER1_OVF_vect
__interrupt void overflow_timer1(void)
  {
    CntMC++;
    cpl(TST); //for each ms on 24 pin
  }



даташиту уже зачитал до дыр наверное )))
что за
Код
TCCR1A= (1<<COM1A0);


что этот рег. делает?
может по другому вектору надо ловить? по вектору сравнения какому- то?
Палыч
Цитата(Метценгерштейн @ May 8 2010, 10:45) *
TIMSK = (1<<TOIE0)|(1<<OCIE1A); //for counter 0 and counter 1 (1<<TICIE1)|
#pragma vector = TIMER1_OVF_vect
может по другому вектору надо ловить? по вектору сравнения какому- то?
Конечно, переполнение наступит при значении счетчика = MAX, а не при OCR1A (см.таблицу 39).

Цитата(Метценгерштейн @ May 8 2010, 10:45) *
даташиту уже зачитал до дыр наверное )))
что за TCCR1A= (1<<COM1A0);
что этот рег. делает?

Это - для выхода ОС1А
Метценгерштейн
в этой таблице говорится, что если я хочу режим СТС, с вершиной OCR1, мне надо включить бит WGM12.

итого, вектор прерывания должен быть другой?
Код
#pragma vector = TIMER1_OVF_vect


скажете какой? пока читаю даташиты

так а этот надо включать?
Код
что за TCCR1A= (1<<COM1A0);
Палыч
Цитата(Метценгерштейн @ May 8 2010, 11:20) *
в этой таблице говорится, что если я хочу режим СТС, с вершиной OCR1, мне надо включить бит WGM12.

В этой таблице есть графа "TOV1 Flag Set on", которая определяет условие установки флага переполнения (а, значит, и соответствующего прерывания). Из неё видно, что в этом режиме прерывание по переполнению - не подходит
Цитата(Метценгерштейн @ May 8 2010, 11:20) *
итого, вектор прерывания должен быть другой?
Код
#pragma vector = TIMER1_OVF_vect

скажете какой?

У этого таймера всего четыре прерывания. Одно из них - не подходит. Угадайте с трёх раз: какой вектор, если условие сброса счетчика - регистр OCR1А. По-моему, это очевидно...
Цитата(Метценгерштейн @ May 8 2010, 11:20) *
так а этот надо включать?
что за
Код
TCCR1A= (1<<COM1A0);
Вам - на ноге ОС1А сигнал таймера нужен? Если - нет, не трогайте настройки, относящиеся к этому сигналу
Метценгерштейн
"TOV1 Flag Set on"
одного не пойму, в таблице написано что это МАХ, а ТОР это OCR1A
тогда при чем здесь МАХ?

думаю мне надо прерывание
Код
#pragma vector = TIMER1_ COMPA_vect


но вот беда, ИАР ругается на такое объявление (((
Метценгерштейн
заработало все- почему- то копирование из даташита TIMER1_ COMPA_vect
вызывало ругань. скопировал из io.h
sigmaN
При использовании Си, чтобы не париться с порядком записи байтов в двухбайтовый регистр - можно просто объявить этот регистр как двухбайтовую переменную(указатель на адрес регистра) и присваивать туда сразу 16бит за один раз.
Метценгерштейн
можно на примере, напрмиер, для

UBRRL = ((OSC / 16 / RS232_BAUDRATE - 1) >> 0) & 0xFF; //for mega8
UBRRH
demiurg_spb
Цитата(sigmaN @ May 9 2010, 20:57) *
При использовании Си, чтобы не париться с порядком записи байтов в двухбайтовый регистр - можно просто объявить этот регистр как двухбайтовую переменную(указатель на адрес регистра) и присваивать туда сразу 16бит за один раз.
При условии что эти два байта идут подряд в памяти, что не гарантировано в 100% случаев (считай никогда если пишешь универсальный модуль)...

Цитата(Метценгерштейн @ May 18 2010, 18:25) *
можно на примере, напрмиер, для ... mega8

Для неё как раз нельзя, т.к:
Код
#define UBRRL    _SFR_IO8(0x09)
#define UBRRH    _SFR_IO8(0x20)

а вообще так:
Код
UBRR = 0xXXXX;
Метценгерштейн
это понятно, имел ввиду указатель на адрес. Тут не ясно как это применять.

UBRR = 0xXXXX; А что если я не хочу одним числом туда все писать? А хочу как у меня

TCCR1B= (0<<CS02)|(0<<CS01) |(1<<CS00)|(1<<WGM12); //CTC mode, no prescaled
TCCR1A= (1<<COM1A0);

вот так, например.
demiurg_spb
Цитата(Метценгерштейн @ May 18 2010, 21:20) *
это понятно, имел ввиду указатель на адрес. Тут не ясно как это применять.

Я же говорю, что с UBRR для mega8 это невозможно в принципе.
А так:
Код
#define BYTE_AT(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define WORD_AT(mem_addr) (*(volatile uint16_t *)(mem_addr))

#define MY_REG_L   BYTE_AT(0x50)
#define MY_REG_H   BYTE_AT(0x51)

#define MY_REG    WORD_AT(0x50)


Цитата
вот так, например.
Не понял вопроса...
Метценгерштейн
все, понял, что нельзя для меги так
demiurg_spb
Уффф.... :-)
Метценгерштейн
думаю, надо делать на прерываниях, например вот так

Код
#pragma vector = TIMER1_COMPA_vect
__interrupt void overflow_timer1(void)
  {
    CntMC++;
  }
здесь я ровно каждую миллисекунду увеличиваю переменную (так настроил счетчик)

а тут

void main(void) {
BOOL active = TRUE;
  for (;;) {

if (active) {
on (LED);
CntMC=0;
active =FALSE;
}

if (CntMC >=200) { //например, 20 мс
off (LED);
active =TRUE;
}
}



вроде как должно работать, и диод будет мигать, и прога не будет тормозиться, только может есть более элегантное решение?
А если надо две лампочки? т.е. в прерываниях не хотел бы ничего менять.
Метценгерштейн
к сожалению, модератор перенес тему сюда, а что я хотел спросить в ней- не указал, поэтому немного мысль потеряна осталась.

здесь мне интересно, как лучше в программе мигать светодиодом, и при этом не тормозить основную прогу. Т.е. можно было бы просто зажечь его, вставить noop, погасить. Интересует как это делает народ.
demiurg_spb
Цитата(Метценгерштейн @ May 22 2010, 11:55) *
здесь мне интересно, как лучше в программе мигать светодиодом, и при этом не тормозить основную прогу.

В прерываниях устанавливают флаги а в фоновой программе (основной бесконечный цикл) их анализируют и включают-выключают светодиод.
rezident
Цитата(Метценгерштейн @ May 22 2010, 13:55) *
Интересует как это делает народ.
Идея у вас правильная, но реализация не совсем корректная. Не нужно в main-е или любой другой функции сбрасывать "тиковую" переменную, которая инкрементируется (считает тики прерывания, выраженные в единицах времени) в прерывании. Достаточно иметь в функции свою статическую (для которой выделяется постоянная память) переменную временной отметки/засечки, значение которой в свою очередь сравнивать с "тиковой" переменной беззнаковым вычитанием. Естественно обе этих переменных должны быть беззнаковыми, а "тиковая" еще глобальной с квалификаторлм volatile. Если переделать ваш вариант, то будет примерно так

Код
#define LED_BLINK_PERIOD 200U

volatile unsigned int CntMC;

#pragma vector = TIMER1_COMPA_vect
__interrupt void overflow_timer1(void)
{
  CntMC++; // инкремент "тиковой" переменной
}

void main(void)
{ BOOL active = TRUE;
  static unsigned int timeStamp=CntMC;
  initTickTimer(); // инициализация таймера, выделенного под счет времени
  for (;;)
  { if (active)   // устанавливаем состояние LED в соответствии с состоянием переменной active
      on (LED);
    esle
      off (LED);
    if ((CntMC-timeStamp)>=LED_BLINK_PERIOD) // проверяем окончание выделенного инетервала времени
    { if (active)
        active=FALSE;
      else
        active=TRUE;
      timeStamp=CntMC; // синхронизируем текущее состояние переменной временной отметки
    }
  }
}

Достоинство такого способа в том, что у вас в системе будет только один источник времени - "тиковая" переменная. В то же время переменных для временных засечек вы можете сделать столько, сколько вам будет нужно по количеству процессов, требующих временных отсчетов. Только следует учитывать два нюанса.
1. максимальный измеряемый временной период определяется периодом переполнения "тиковой" переменной. Если нужен сравнительно большой период, то нужна 32-х битная или даже 64-х битная переменная. Из этого следует второй нюанс.
2. если разрядность "тиковой" переменной превышает нативную разрядность архитектуры, то следует специальными методами обеспечит атомарность доступа к "тиковой" переменной. Атомарность доступа предполагает, что при копирования значения переменной по частям ее значение не может (не должно) изменяться (в прерывании, где она инкрементируется)
sigmaN
по-моему это вечный спор: лучше ли делать таймер глобальным или локальным, как вы советуете ))

Лично мне тоже больше нравится локальный вариант. Однако не так давно спорил со мной один знакомый, что подчас интереснее создать некую тайм-машину в которой регистрируется задача со своим колл бэком и веред и с песней smile.gif)) Сошлись мы на том, что его вариант более масштабный и часто избыточный.
rezident
Цитата(sigmaN @ May 23 2010, 18:54) *
по-моему это вечный спор: лучше ли делать таймер глобальным или локальным, как вы советуете ))

Любое измерение по сути и смыслу относительно. Измерение это сравнение (с образцом, эталоном). К измерениям времени эта характеристика тоже относится. См. сами. 100 лет назад (начало отсчета - текущий год), 1812 год (начало отсчета - рождение Христа), 3 век до н.э. (начало отсчета - наша эра, т.е. опять же рождение Христа), 5731 год от С.М.З.Х (начало отсчета - С.М.З.Х - Сотворение Мира в Звёздном Храме, согласно Славяно-Арийским Ведам заключение мира между ариями и "воинами дракона" - китайцами т.с.) ну и т.д. Независимые эталоны для каждого из измерений применять можно, но только до тех пор, пока сами измерения будут независимыми. Как только независимость измерений пропадает, то и эталон требуется единый.
Например. Можно время измерять в тиках прерываний, а напряжение в единицах отсчетов АЦП, но только до тех пор, пока они используются внутри программы, исполняющейся на МК. Как только появляется какая-либо связь с "внешним миром", то оказывается, что время нужно в миллисекундах или секундах, а напряжение в миллиВольтах или Вольтах. laughing.gif
Метценгерштейн
Спасибо за развернутый ответ.
т.к. здесь использован макрос Ascold.h, то можно ещё лучше записать, чтобы лампочкой мигать с ровным меандром

void main(void)
static unsigned int timeStamp=CntMC;

for (;;)
{
if ((CntMC-timeStamp)>=LED_BLINK_PERIOD)
cpl (LED); //Ascold.h перевернуть состояние с 0 на 1 и наоборот
timeStamp=CntMC;
}


только не понятно, как поведет себя это дело, когда тиковая переменная приблизится к концу размера своего. Ведь наша локальная переменная будет ждать, что тиковая больше неё на 200, а тиковая дойдет до границы своего размера и обнулится и больше нашей уже никогда не станет. тут не ясный момент.

Где можно почитать про объявления переменный как простые, или как static или как volatile? Или вкратце скажите, чем они отличаются?

и как выделить мой код, чтобы он стал виден как у Вас код?
rezident
Цитата(Метценгерштейн @ May 24 2010, 13:20) *
Ведь наша локальная переменная будет ждать, что тиковая больше неё на 200, а тиковая дойдет до границы своего размера и обнулится и больше нашей уже никогда не станет.
Переменная обнулится, произойдет ее переполнение, а счет продолжится дальше. Потеряется старший разряд, но этот момент ни на что не повлияет, т.к. вычитание в сравнении беззнаковое!
Для наглядности пример.
Допустим CntMC и timeStamp 16-и битные переменные (макс. значение 65535 в десятичном виде или 0xFFFF в 16-иричном). Значение переменной timeStamp - 65530, CntMC - 210. Совершенно точно прошло более 200 тиков прерываний, а именно (65535-65530)+1+210=216. Беззнаковое вычитание 210-65530 даст точно такой же результат - 216. 216>200, поэтому условие в сравнении ((CntMC-timeStamp)>=200) будет истинно.
Поясню откуда числа.
65535-65530 это разница в значениях счетчика до момента его переполнения.
1 - это учитываем состояние нуль.
210 - текущее значение тиковой переменной, после переполнения.
Если сомневаетесь, то переведите числа в 16-тиричный вид и посчитайте сами на виндусовом калькуляторе в инженерном режиме, ограничив его разрядность 2-мя байтами .
Цитата(Метценгерштейн @ May 24 2010, 13:20) *
Где можно почитать про объявления переменный как простые, или как static или как volatile? Или вкратце скажите, чем они отличаются?
В "букваре" языка Си. Или в стандарте Си. Вот только volatile это квалификатор, а не тип переменной, определяющий область ее распределения и видимости.
Цитата(Метценгерштейн @ May 24 2010, 13:20) *
и как выделить мой код, чтобы он стал виден как у Вас код?
Используйте тэги [ code ] и [ codebox ] для оформления цитаты кода. Кнопочка в редакторе вставляет первый из них. Второй, к сожалению, только вручную, редактированием сообщения.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.