Страница 32 из 72
Re: Таймеры/счётчики в AVR
Добавлено: Пт дек 04, 2015 17:57:03
xcoma
Использую МК ATmega168PA, по даташиту сложновато пока для меня все настройки сделать, посмотрите пожалуйста может быть фъюзы не так установлены:

Re: Таймеры/счётчики в AVR
Добавлено: Пт дек 04, 2015 20:24:39
xcoma
Всем спасибо, разобрался, заработало
Re: Таймеры/счётчики в AVR
Добавлено: Пн дек 07, 2015 12:06:02
sphincs
Добрый день!
table[state][0] - 16-битное число (unsigned short). правильно ли я записываю его в выход счетчика?
Код: Выделить всё
OCR1BH = table[state][0] >> 8;
OCR1BL = (0x00FF & table[state][0]);
равносильны ли в данном случае такие записи?
и
т.е. что происходит при попытке записать 16-битное число в 8-битный регистр? пишется только какой-то из разрядов (старший/младший)?
Re: Таймеры/счётчики в AVR
Добавлено: Пн дек 07, 2015 12:49:20
ddimochka
При попытке записать 16 битное число в 8-битный регистр происходит запись МЛАДШИХ восьми разрядов.
Re: Таймеры/счётчики в AVR
Добавлено: Пн дек 07, 2015 13:09:16
sphincs
значит можно просто без маски 0x00ff записывать, спасибо.
еще вот этот момент немного не понятен с первой страницы
Gudd-Head писал(а):Предделитель (прескалер) считает постоянно, поэтому используя в качестве тактов СК/8, СК/64, СК/256 или СК/1024 перед запуском таймера хорошо бы его сбрасывать (ресетить) для получения точных временных интервалов. Однако, таймер/счётчик0 и таймер/счётчик1 используют один и тот же предделитель, так что сбрасывать надо осторожно чтобы не сбить работу другого таймера.
мне для выполнения задачи на меге8 для т/с0 нужен предделитель 1024 (выставляю в TCCR0), а для т/с1 - 8 (соответственно в TCCR1B). что значит "сбрасывать предделитель"?
Re: Таймеры/счётчики в AVR
Добавлено: Вт дек 08, 2015 20:39:32
ddimochka
Я не очень понял откуда вы приводите эти строчки. Лично мое понимание выражения "обресетить таймер" это - обнулить его счетный регистр TCNTx. Я еще не разу не сталкивался с проблемами влияния одного таймера на работу другого. Смело играйтесь с регистрами обоих таймеров. Если выскочит какая-нибудь бага, то не сочтите за труд, сообщите об этом общественности

Re: Таймеры/счётчики в AVR
Добавлено: Вт дек 08, 2015 22:11:23
sphincs
Это цитата с самой первой страницы этой темы. Беглое гугление говорит, что это связано с регистром SFIOR как-то.
Re: Таймеры/счётчики в AVR
Добавлено: Вт дек 08, 2015 23:50:40
lcleo
sphincs,Предделитель - двоичный счетчик,который считает тактовые импульсы ядра,при достижении счета значения N(это число задает коэф. деления частоты) меняет состояние своего выхода на противоположное(было 0, стало 1 и наоборот). Сигнал с выхода этого предделителя считает таймер микроконтроллера.И этот предделитель работает постоянно, независимо от состояния таймера.При включении таймера мы не знаем в каком положении находиться прескалер - он может быть в начале счета очередного интервала, в середине, в конце, т.е. мы не знаем сколько времени займет первый "тик" таймера.Поэтому и написано про сброс прескалера перед запуском таймера.Для сброса есть соответсвующий бит соответсвующего регистра.На одном прескалере могут сидеть несколько таймеров - следовательно сброс предделителя повлияет и на них.
P.S.Если мега8, то сброс предделителя - установка бита PSR10 регистра SFIOR это для прескалера, от которого работают Т0 и Т1
Re: Таймеры/счётчики в AVR
Добавлено: Сб фев 13, 2016 23:55:06
SIM31
А как сделать синхронную генерацию PWM на 2х таймерах? Просто, если даже настройки таймеров одинаковые, может образоваться сдвиг по фазе. Периодически приравнивать таймер2 к таймер1 ?
Re: Таймеры/счётчики в AVR
Добавлено: Вс фев 14, 2016 06:23:07
akl
Поскольку таймеры циклические и всегда у них есть состояние 0, логично синхронизировать их работу обнулением, включая очистку предделителей.
Re: Таймеры/счётчики в AVR
Добавлено: Вс фев 21, 2016 23:56:10
igorek1999
Здравствуйте. Только начинаю осваивать мк, собственно проблема: при установке значения 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
Добавлено: Пн фев 22, 2016 00:49:26
akl
В прерывании задержки делать не надо. Обработчик прерывания для этого камня записывается оператором
Код: Выделить всё
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; // счетный регистр;
Re: Таймеры/счётчики в AVR
Добавлено: Пн фев 22, 2016 01:24:23
igorek1999
В общем, работает если проверять через протеус (там схема с светодиодами). Но когда нажимаю несколько раз "step into (f11)" в студии, то все равно (желтая строка) не как не переходит на вектор.

Правда, я удалил делитель на 64, что бы быстрее изменять значение в TCNT0
Оказывается мой код тоже "как бы" работает, но та же проблема.
Re: Таймеры/счётчики в AVR
Добавлено: Пн фев 22, 2016 19:52:44
c2n
в прерывании смысла комманды запрещать/разрешать прерывания нет. Тоесть иногда есть, но если мы ждем какого либо либо другого прерывания...
код должен выглядеть примерено так:
Действия_В_СлучаеПрерывании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
Добавлено: Ср мар 16, 2016 09:48:08
artemik32
Всем, привет! У меня вопрос такой: у таймера Т1 есть режим СТС - сброс по совпадению OCR1A и есть 2 прерывания по совпадению числа А и В, а сброса по совпадению ОСR1B нет? У меня получается, что при совпадении с числом В прерывание наступает, но счетчик не сбрасывается и продолжает тикать до тех пор пока не сравняется с числом А, и тогда TCNT1 - обнуляется. Это так и должно быть?
Спойлер
Код: Выделить всё
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
Добавлено: Ср мар 16, 2016 10:18:18
akl
artemik32 писал(а):Это так и должно быть?
Да.
artemik32 писал(а):Поэтому мне пришлось регистру OCR1A присвоить такое же значение что и OCR1B, чтобы при прерывании по совпадению числа В - счетчик обнулялся.
Прерывание OC1A имеет более высокий приоритет, поэтому, при прочих равных, срабатывает именно оно. Прерывание OC1B будет обработано позже.
Re: Таймеры/счётчики в AVR
Добавлено: Ср мар 16, 2016 12:37:44
artemik32
Я хочу чтобы прерывания по совпадению каналов А и В работали независимо, т.е. сначала разрешил прерывание по каналу А - произошло сравнение с OCR1A, обнулился TCNT1, выполнился обработчик TIMER1 COMPA, далее запретил прерывание по каналу А, разрешил прерывание по каналу В - сравнение с OCR1B, обнулился TCNT1, выполнился обработчик TIMER1 COMPB. Или так нельзя? У меня почему то по достижении OCR1B - происходит прерывание, выполняется обработчик, но TCNT1 не обнуляется, продолжает считать дальше пока не дойдет до OCR1A, поскольку OCR1A больше, чем OCR1B и тогда обнуляется. Почему так? Прерывание же TIMER1 COMPA выключено!!!
И еще у меня вопрос: почему как только я разрешаю глобальные прерывания, сразу срабатывает прерывание и уходит в обработчик? Он ещё не "дотикал" до OCR1A!?
Re: Таймеры/счётчики в AVR
Добавлено: Ср мар 16, 2016 12:49:49
akl
artemik32 писал(а):Или так нельзя? У меня почему то по достижении OCR1B - происходит прерывание, выполняется обработчик, но TCNT1 не обнуляется, продолжает считать дальше пока не дойдет до OCR1A, поскольку OCR1A больше, чем OCR1B и тогда обнуляется. Почему так? Прерывание же TIMER1 COMPA выключено!!!
У канала сравнения OC1B нет режима CTC. Как я понял при запрете прерывания OC1A режим CTC остается. Поэтому таймер обнуляется.
artemik32 писал(а):почему как только я разрешаю глобальные прерывания, сразу срабатывает прерывание и уходит в обработчик? Он ещё не "дотикал" до OCR1A!?
Не соблюдена последовательность установки режима работы таймера. Сначала устанавливаются точки сравнения, затем разрешаются локальные прерывания и чистятся флаги, запускается счет и только затем идет глобальное разрешение.
Re: Таймеры/счётчики в AVR
Добавлено: Ср мар 16, 2016 13:51:08
artemik32
Не соблюдена последовательность установки режима работы таймера.
Вроде с этим все нормально:
Код: Выделить всё
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. Что не правильно?
Re: Таймеры/счётчики в AVR
Добавлено: Ср мар 16, 2016 16:04:49
COKPOWEHEU
А говорите "нормально"...
akl писал(а):Сначала устанавливаются точки сравнения, затем разрешаются локальные прерывания и чистятся флаги, запускается счет и только затем идет глобальное разрешение.
Где у вас очистка TIFR?
Ах да, автоконфигураторы не нужны. Проще написать инициализацию самому, чем приводить в читаемый вид продукт жизнедеятельности конфигуратора.