Таймеры/счётчики в AVR
Re: Таймеры/счётчики в AVR
Всем спасибо, разобрался, заработало
- sphincs
- Нашел транзистор. Понюхал.
- Сообщения: 174
- Зарегистрирован: Вт сен 11, 2012 09:13:52
- Откуда: Брест, Беларусь
- Контактная информация:
Re: Таймеры/счётчики в AVR
Добрый день!
table[state][0] - 16-битное число (unsigned short). правильно ли я записываю его в выход счетчика?
равносильны ли в данном случае такие записи?
и
т.е. что происходит при попытке записать 16-битное число в 8-битный регистр? пишется только какой-то из разрядов (старший/младший)?
table[state][0] - 16-битное число (unsigned short). правильно ли я записываю его в выход счетчика?
Код: Выделить всё
OCR1BH = table[state][0] >> 8;
OCR1BL = (0x00FF & table[state][0]);
равносильны ли в данном случае такие записи?
Код: Выделить всё
OCR1BL = (0x00FF & table[state][0]);и
Код: Выделить всё
OCR1BL = table[state][0];т.е. что происходит при попытке записать 16-битное число в 8-битный регистр? пишется только какой-то из разрядов (старший/младший)?
Re: Таймеры/счётчики в AVR
При попытке записать 16 битное число в 8-битный регистр происходит запись МЛАДШИХ восьми разрядов.
- sphincs
- Нашел транзистор. Понюхал.
- Сообщения: 174
- Зарегистрирован: Вт сен 11, 2012 09:13:52
- Откуда: Брест, Беларусь
- Контактная информация:
Re: Таймеры/счётчики в AVR
значит можно просто без маски 0x00ff записывать, спасибо.
еще вот этот момент немного не понятен с первой страницы
мне для выполнения задачи на меге8 для т/с0 нужен предделитель 1024 (выставляю в TCCR0), а для т/с1 - 8 (соответственно в TCCR1B). что значит "сбрасывать предделитель"?
еще вот этот момент немного не понятен с первой страницы
Gudd-Head писал(а):Предделитель (прескалер) считает постоянно, поэтому используя в качестве тактов СК/8, СК/64, СК/256 или СК/1024 перед запуском таймера хорошо бы его сбрасывать (ресетить) для получения точных временных интервалов. Однако, таймер/счётчик0 и таймер/счётчик1 используют один и тот же предделитель, так что сбрасывать надо осторожно чтобы не сбить работу другого таймера.
мне для выполнения задачи на меге8 для т/с0 нужен предделитель 1024 (выставляю в TCCR0), а для т/с1 - 8 (соответственно в TCCR1B). что значит "сбрасывать предделитель"?
Re: Таймеры/счётчики в AVR
Я не очень понял откуда вы приводите эти строчки. Лично мое понимание выражения "обресетить таймер" это - обнулить его счетный регистр TCNTx. Я еще не разу не сталкивался с проблемами влияния одного таймера на работу другого. Смело играйтесь с регистрами обоих таймеров. Если выскочит какая-нибудь бага, то не сочтите за труд, сообщите об этом общественности 
- sphincs
- Нашел транзистор. Понюхал.
- Сообщения: 174
- Зарегистрирован: Вт сен 11, 2012 09:13:52
- Откуда: Брест, Беларусь
- Контактная информация:
Re: Таймеры/счётчики в AVR
Это цитата с самой первой страницы этой темы. Беглое гугление говорит, что это связано с регистром SFIOR как-то.
Re: Таймеры/счётчики в AVR
sphincs,Предделитель - двоичный счетчик,который считает тактовые импульсы ядра,при достижении счета значения N(это число задает коэф. деления частоты) меняет состояние своего выхода на противоположное(было 0, стало 1 и наоборот). Сигнал с выхода этого предделителя считает таймер микроконтроллера.И этот предделитель работает постоянно, независимо от состояния таймера.При включении таймера мы не знаем в каком положении находиться прескалер - он может быть в начале счета очередного интервала, в середине, в конце, т.е. мы не знаем сколько времени займет первый "тик" таймера.Поэтому и написано про сброс прескалера перед запуском таймера.Для сброса есть соответсвующий бит соответсвующего регистра.На одном прескалере могут сидеть несколько таймеров - следовательно сброс предделителя повлияет и на них.
P.S.Если мега8, то сброс предделителя - установка бита PSR10 регистра SFIOR это для прескалера, от которого работают Т0 и Т1
P.S.Если мега8, то сброс предделителя - установка бита PSR10 регистра SFIOR это для прескалера, от которого работают Т0 и Т1
- SIM31
- Это не хвост, это антенна
- Сообщения: 1363
- Зарегистрирован: Чт апр 04, 2013 22:22:57
- Откуда: Белгород, РФ
Re: Таймеры/счётчики в AVR
А как сделать синхронную генерацию PWM на 2х таймерах? Просто, если даже настройки таймеров одинаковые, может образоваться сдвиг по фазе. Периодически приравнивать таймер2 к таймер1 ?
Re: Таймеры/счётчики в AVR
Поскольку таймеры циклические и всегда у них есть состояние 0, логично синхронизировать их работу обнулением, включая очистку предделителей.
- igorek1999
- Нашел транзистор. Понюхал.
- Сообщения: 179
- Зарегистрирован: Чт май 26, 2011 10:32:58
- Откуда: украина,харьков
Re: Таймеры/счётчики в AVR
Здравствуйте. Только начинаю осваивать мк, собственно проблема: при установке значения 2 в регистре OCR0A не идет переход на вектор прерывания. Что не так? мк - атмега328.
Код: Выделить всё
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
void timer () // инициалияция таймера 0;
{
TCCR0A = 0b00000010; // режим подсчета импульсов (сброс при совпадении);
TCCR0B = 0b00000001; // установка режима тактирования - тактовый генератор CLK;
TIMSK0 = 0b00000010; // разрешение прерывания при совпадении с А ;
OCR0A = 2; // счетный регистр;
}
ISR( TIMER0_COMPA_vect){ //вектор перехода;
asm("cli");
PORTB = 0b11111111;
_delay_ms(1000);
PORTB = 0b00000000;
asm("sei");
}
void preset(){ //инициализация портов;
DDRB = 0xff;
PORTB = 0x00;
DDRC = 0xff;
PORTC = 0x00;
}
short zyfra[] =// не используется;
{
0b00111111, //0
0b00000110, //1
0b01011011, //2
0b01001111, //3
0b01100110, //4
0b01101101, //5
0b01111101, //6
0b00000111, //7
0b01111111, //8
0b01101111 //9
};
int main(void)
{
preset();
timer();
asm("sei");
while(1)
{
asm("nop");
}
}игорь
Re: Таймеры/счётчики в AVR
В прерывании задержки делать не надо. Обработчик прерывания для этого камня записывается оператором
Переключатель вывода на порт B длительностью 1000мкс
Код: Выделить всё
ISR( TIMER0_COMPA_vect){ //вектор перехода;
PINB = 0b00000000;Переключатель вывода на порт B длительностью 1000мкс
Код: Выделить всё
OCR0A = 1000*F_CPU/64/1000000-1; // 1000мксек;
TCCR0A = 0b00000010; // режим подсчета импульсов (сброс при совпадении);
TCCR0B = 0b00000011; // установка режима тактирования - тактовый генератор CLK/64;
;TCCR0B = 0b00000001; // установка режима тактирования - тактовый генератор CLK;
TIMSK0 = 0b00000010; // разрешение прерывания при совпадении с А ;
;OCR0A = 2; // счетный регистр;- igorek1999
- Нашел транзистор. Понюхал.
- Сообщения: 179
- Зарегистрирован: Чт май 26, 2011 10:32:58
- Откуда: украина,харьков
Re: Таймеры/счётчики в AVR
В общем, работает если проверять через протеус (там схема с светодиодами). Но когда нажимаю несколько раз "step into (f11)" в студии, то все равно (желтая строка) не как не переходит на вектор.
Правда, я удалил делитель на 64, что бы быстрее изменять значение в TCNT0
Оказывается мой код тоже "как бы" работает, но та же проблема.
Оказывается мой код тоже "как бы" работает, но та же проблема.
игорь
- c2n
- Сверлит текстолит когтями
- Сообщения: 1193
- Зарегистрирован: Ср июл 25, 2012 21:40:09
- Откуда: Самара
- Контактная информация:
Re: Таймеры/счётчики в AVR
в прерывании смысла комманды запрещать/разрешать прерывания нет. Тоесть иногда есть, но если мы ждем какого либо либо другого прерывания...
код должен выглядеть примерено так:
Действия_В_СлучаеПрерывании1 //ISR(чего-то-там1)
{
Функция_запретаИразрешения_ЧЕГОТОТАМ1(0); // запретить это прерывание
...//что то делается...
...Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // разрешили прерывание 2. теперь система ждет ИЛИ это ИЛИ другое прерывание...
...
Функция_запретаИразрешения_ЧЕГОТОТАМ1(1); // разрешить это прерывание
};
Действия_В_СлучаеПрерывании2 //ISR(чего-то-там2)
{
...
// что то делается
Функция_запретаИразрешения_ЧЕГОТОТАМ2(0); // запретили прерывание 2, т.е. это прерывание.
...
};
Функция_настройки_переферии(Параметры...)
{
...
}
Функция_запретаИразрешения_ЧЕГОТОТАМ1(Можно)
{
if Можно == 1
{
РегистрЧегоТоТам1 |= (1<< ЧтоМожно1); //разрешить прерывания от устройства
}
else
{
РегистрЧегоТоТам1 &= ~(1<< ЧтоМожно1); //ЗАПРЕТИТЬ прерывания от устройства.
}
};
Функция_запретаИразрешения_ЧЕГОТОТАМ2(Можно)
{
...
// смотри Функция_запретаИразрешения_ЧЕГОТОТАМ1(Можно)
...
};
int main()
{
Функция_настройки_переферии(Параметры...); // настроили переферию
Функция_запретаИразрешения_ЧЕГОТОТАМ1(1); // разрешили прерывание 1.
Функция_запретаИразрешения_ЧЕГОТОТАМ2(0); // запретили прерывание 2.
SEI/CLI // и после всего этого - разрешаете прерывания!
while (1==1)
{
// TODO code... Это бесконечный цикл....
if (некое условие)
{ Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // разрешили прерывание 2. };
}
};
Иначе у вас получается что прерывание срабатывает раньше, чем его событие успевает отработать.
1. тоесть таймер считает ВНЕ зависимости от того сработало ли прерывание или нет. причем считает по каждому клоку кварца или встроенного RC. далее оно все уходит на предделители и все такое... но "первый" регистр таймера инкрементируется по каждому клоку кварца. (очень многие наступают на эти грабли)
2. при входе в процедуру прерывания - флаг "I" регистра SREG сбрасывается, флаг "Есть прерывание" - остается неизменным. При выходе из процедуры прерывания - {SREG возвращают назад, флаг прерывания - сбрасывают} - АВТОМАТИЧЕСКИ!!!
3. Если прерывание разрешено, но процедура не объявлена, то в 99.999% контроллер уйдет по комманде jump 0; что равносильно ребуту.
4. Если прерывания срабатывают во время работы кода прерывания, то флаг "есть прерывание" - выставляется. по возвращении в основное тело программы, все флаги будут обработаны в порядке очереди. Порядок очередеди задан "железно" и каждое прерывание имеет свой приоритет.
типичная логика повесить таймер к чертям...
1.включить 8бит таймер. Настроив ему {событие при совпадении, при совпадении счетчик обнуляется, предделитель 1/1}
2. в прерывании считать от 0 до 255 выводя это число в порт., разрешить прерывания SREG(I).
3. событие при совпадении счетчика происходит при счетчик = 3. (хотя и при 255 контроллер заколбасит).
код должен выглядеть примерено так:
Действия_В_СлучаеПрерывании1 //ISR(чего-то-там1)
{
Функция_запретаИразрешения_ЧЕГОТОТАМ1(0); // запретить это прерывание
...//что то делается...
...Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // разрешили прерывание 2. теперь система ждет ИЛИ это ИЛИ другое прерывание...
...
Функция_запретаИразрешения_ЧЕГОТОТАМ1(1); // разрешить это прерывание
};
Действия_В_СлучаеПрерывании2 //ISR(чего-то-там2)
{
...
// что то делается
Функция_запретаИразрешения_ЧЕГОТОТАМ2(0); // запретили прерывание 2, т.е. это прерывание.
...
};
Функция_настройки_переферии(Параметры...)
{
...
}
Функция_запретаИразрешения_ЧЕГОТОТАМ1(Можно)
{
if Можно == 1
{
РегистрЧегоТоТам1 |= (1<< ЧтоМожно1); //разрешить прерывания от устройства
}
else
{
РегистрЧегоТоТам1 &= ~(1<< ЧтоМожно1); //ЗАПРЕТИТЬ прерывания от устройства.
}
};
Функция_запретаИразрешения_ЧЕГОТОТАМ2(Можно)
{
...
// смотри Функция_запретаИразрешения_ЧЕГОТОТАМ1(Можно)
...
};
int main()
{
Функция_настройки_переферии(Параметры...); // настроили переферию
Функция_запретаИразрешения_ЧЕГОТОТАМ1(1); // разрешили прерывание 1.
Функция_запретаИразрешения_ЧЕГОТОТАМ2(0); // запретили прерывание 2.
SEI/CLI // и после всего этого - разрешаете прерывания!
while (1==1)
{
// TODO code... Это бесконечный цикл....
if (некое условие)
{ Функция_запретаИразрешения_ЧЕГОТОТАМ2(1); // разрешили прерывание 2. };
}
};
Иначе у вас получается что прерывание срабатывает раньше, чем его событие успевает отработать.
1. тоесть таймер считает ВНЕ зависимости от того сработало ли прерывание или нет. причем считает по каждому клоку кварца или встроенного RC. далее оно все уходит на предделители и все такое... но "первый" регистр таймера инкрементируется по каждому клоку кварца. (очень многие наступают на эти грабли)
2. при входе в процедуру прерывания - флаг "I" регистра SREG сбрасывается, флаг "Есть прерывание" - остается неизменным. При выходе из процедуры прерывания - {SREG возвращают назад, флаг прерывания - сбрасывают} - АВТОМАТИЧЕСКИ!!!
3. Если прерывание разрешено, но процедура не объявлена, то в 99.999% контроллер уйдет по комманде jump 0; что равносильно ребуту.
4. Если прерывания срабатывают во время работы кода прерывания, то флаг "есть прерывание" - выставляется. по возвращении в основное тело программы, все флаги будут обработаны в порядке очереди. Порядок очередеди задан "железно" и каждое прерывание имеет свой приоритет.
типичная логика повесить таймер к чертям...
1.включить 8бит таймер. Настроив ему {событие при совпадении, при совпадении счетчик обнуляется, предделитель 1/1}
2. в прерывании считать от 0 до 255 выводя это число в порт., разрешить прерывания SREG(I).
3. событие при совпадении счетчика происходит при счетчик = 3. (хотя и при 255 контроллер заколбасит).
Re: Таймеры/счётчики в AVR
Всем, привет! У меня вопрос такой: у таймера Т1 есть режим СТС - сброс по совпадению OCR1A и есть 2 прерывания по совпадению числа А и В, а сброса по совпадению ОСR1B нет? У меня получается, что при совпадении с числом В прерывание наступает, но счетчик не сбрасывается и продолжает тикать до тех пор пока не сравняется с числом А, и тогда TCNT1 - обнуляется. Это так и должно быть?
Поэтому мне пришлось регистру OCR1A присвоить такое же значение что и OCR1B, чтобы при прерывании по совпадению числа В - счетчик обнулялся.
Спойлер
Код: Выделить всё
unsigned char flag1; // флаг количества стартовых полубитов
unsigned char flag2=0; // флаг смены полубитов
unsigned char flag3=0; // флаг количества информационных полубитов
unsigned char j=0;
unsigned char knopki=0;
unsigned int kanal1;
unsigned int kanal2;
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
PORTD |= (1<<0);
flag1++;
}
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
if (flag2==0)
{
PORTD = kanal1 & 0b00000001; // маска, обнуляющая все биты кроме младшего, выводим биты начиная с младшего
}
else
{
PORTD = ~kanal1 & 0b00000001; // инвертирование
kanal1 = kanal1 >> 1; // сдвиг
//OCR1A=0x0F9A; // 3994
}
flag2 = ~flag2;
}
void main(void)
{
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
PORTA=0x00;
DDRA=0x00;
PORTB=0xFF;
DDRB=0x00;
PORTD=0x00;
DDRD=0x7F;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR1A=0x00;
TCCR1B=0x09; // 0000 1001
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x0F; // число сравнения для стартовых битов - 3998 = 1000 мкс
OCR1AL=0x9E; //
OCR1BH=0x00; //
OCR1BL=0x00; //
GIMSK=0x00;
MCUCR=0x00;
TIMSK=0x40; // 0100 0000 - разрешение прерывания по совпадению канала А
USICR=0x00;
UCSRB=0x00;
ACSR=0x80;
DIDR=0x00;
while (1)
{
PORTD = 0b00000000; // обнуляем сигнальную линию
kanal1 = 0;
kanal2 = 0;
DDRD = 0b11111111; // 1 - на выход; 0 - на вход
PORTD = 0b00110000; // подача 5 В на конденсаторы
delay_us(1000); // время зарядки конденсаторов
DDRD = 0b1001111; // 4,5 биты - на вход
PORTD = 0b00000000; // отключаем порт D
while (PIND & ((1<<5)|(1<<4)))
{
if ((PIND & (1<<4))>0)
{
kanal1++;
}
else
{
delay_us(5);
}
if ((PIND & (1<<5))>0)
{
kanal2++;
}
else
{
delay_us(5);
}
}
flag1=0;
TCNT1=0;
#asm("sei") // разрешаем все прерывания
while (flag1<5)
{
knopki = PINB; // считывание состояния кнопок в переменную
}
OCR1AH=0x06;
OCR1AL=0x40;
OCR1BH=0x06; // число сравнения для информационных битов - 1600 = 400 мкс
OCR1BL=0x40; //
TIMSK=0x20; // 0010 0000 - разрешение прерывания по совпадению канала B
while (flag3<16)
{
knopki = PINB; // считывание состояния кнопок в переменную
}
Поэтому мне пришлось регистру OCR1A присвоить такое же значение что и OCR1B, чтобы при прерывании по совпадению числа В - счетчик обнулялся.
Истина где-то рядом...
Re: Таймеры/счётчики в AVR
Да.artemik32 писал(а):Это так и должно быть?
Прерывание OC1A имеет более высокий приоритет, поэтому, при прочих равных, срабатывает именно оно. Прерывание OC1B будет обработано позже.artemik32 писал(а):Поэтому мне пришлось регистру OCR1A присвоить такое же значение что и OCR1B, чтобы при прерывании по совпадению числа В - счетчик обнулялся.
Re: Таймеры/счётчики в AVR
Я хочу чтобы прерывания по совпадению каналов А и В работали независимо, т.е. сначала разрешил прерывание по каналу А - произошло сравнение с OCR1A, обнулился TCNT1, выполнился обработчик TIMER1 COMPA, далее запретил прерывание по каналу А, разрешил прерывание по каналу В - сравнение с OCR1B, обнулился TCNT1, выполнился обработчик TIMER1 COMPB. Или так нельзя? У меня почему то по достижении OCR1B - происходит прерывание, выполняется обработчик, но TCNT1 не обнуляется, продолжает считать дальше пока не дойдет до OCR1A, поскольку OCR1A больше, чем OCR1B и тогда обнуляется. Почему так? Прерывание же TIMER1 COMPA выключено!!!
И еще у меня вопрос: почему как только я разрешаю глобальные прерывания, сразу срабатывает прерывание и уходит в обработчик? Он ещё не "дотикал" до OCR1A!?
И еще у меня вопрос: почему как только я разрешаю глобальные прерывания, сразу срабатывает прерывание и уходит в обработчик? Он ещё не "дотикал" до OCR1A!?
Истина где-то рядом...
Re: Таймеры/счётчики в AVR
У канала сравнения OC1B нет режима CTC. Как я понял при запрете прерывания OC1A режим CTC остается. Поэтому таймер обнуляется.artemik32 писал(а):Или так нельзя? У меня почему то по достижении OCR1B - происходит прерывание, выполняется обработчик, но TCNT1 не обнуляется, продолжает считать дальше пока не дойдет до OCR1A, поскольку OCR1A больше, чем OCR1B и тогда обнуляется. Почему так? Прерывание же TIMER1 COMPA выключено!!!
Не соблюдена последовательность установки режима работы таймера. Сначала устанавливаются точки сравнения, затем разрешаются локальные прерывания и чистятся флаги, запускается счет и только затем идет глобальное разрешение.artemik32 писал(а):почему как только я разрешаю глобальные прерывания, сразу срабатывает прерывание и уходит в обработчик? Он ещё не "дотикал" до OCR1A!?
Re: Таймеры/счётчики в AVR
Не соблюдена последовательность установки режима работы таймера.
Вроде с этим все нормально:
Код: Выделить всё
TCCR1A=0x00;
TCCR1B=0x09; // выбор предделителя и режима СТС - сброс по совпадению
...
OCR1AH=0x0F; // число сравнения
OCR1AL=0x9E;
...
TIMSK=0x40; // разрешение прерывания по совпадению канала А
...
TCNT1=0;
#asm("sei") // разрешаем глобальные прерывания
while (flag1<5)
{
knopki = PINB; // считывание состояния кнопок в переменную
}
...
Последовательность инициализации регистров TCCR1A, TCCR1B, OCR1A, TIMSK - определяет CodeVisionAVR автоматически, но непосредственно перед глобальными прерываниями я дополнительно обнуляю счетчик TCNT1. Что не правильно?
Истина где-то рядом...
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Таймеры/счётчики в AVR
А говорите "нормально"...
Ах да, автоконфигураторы не нужны. Проще написать инициализацию самому, чем приводить в читаемый вид продукт жизнедеятельности конфигуратора.
Где у вас очистка TIFR?akl писал(а):Сначала устанавливаются точки сравнения, затем разрешаются локальные прерывания и чистятся флаги, запускается счет и только затем идет глобальное разрешение.
Ах да, автоконфигураторы не нужны. Проще написать инициализацию самому, чем приводить в читаемый вид продукт жизнедеятельности конфигуратора.
Последний раз редактировалось COKPOWEHEU Чт мар 17, 2016 07:04:43, всего редактировалось 1 раз.