Таймеры/счётчики в AVR
Кстати, цеплял к тиньке кварц 3.2768 МГц - тоже завышало порядка 0.1% независимо от конденсаторов. ЧЯДНТ?
Иногда мой питомец уходит в такую спячку, что разбудить его можно только щелчком по первой ноге...
- Реклама
Подскажите, пожалуйста, почему не срабатывает прерывание по совпадению таймера, точнее прерывание то есть, только оно попадает на другой вектор почему то. МК - ATmega164. Вроде все перепроверил, все настройки правильные, но в AVR Studio 6 и в Proteuse прерывание попадает на строку компаратора или АЦП в таблице векторов
Спойлер
Код: Выделить всё
.include "m164pdef.inc"
.def temp = r16 ; Буфер
.def Counter = r17 ; Переменная цикла
.equ deley_vkl_0 = 35
.cseg ; Выбор сегмента программного кода
;------------------------- Начало программного кода
.org 0 ; Установка текущего адреса на ноль
jmp RESET ; Переход на начало программы
reti ; jmp EXT_INT0 ; Внешнее прерывание 0
reti ; jmp INT1 ; Внешнее прерывание 1
reti ; jmp INT2
reti ; jmp PCINT0 ; PCINT0 Handler
reti ; jmp PCINT1 ; PCINT1 Handler
reti ; jmp PCINT2 ; PCINT2 Handler
reti ; jmp PCINT3
reti ; jmp WDT ; Watchdog Timer Handler
reti ; jmp TIMER2_COMPA ; Timer2 Compare A Handler
reti ; jmp TIMER2_COMPB ; Timer2 Compare B Handler
reti ; jmp TIMER2_OVF ; Timer2 Overflow Handler
reti ; jmp TIMER1_CAPT ; Timer1 Capture Handler
jmp TIMER1_COMPA ; Timer1 Compare A Handler
reti ; jmp TIMER1_COMPB ; Timer1 Compare B Handler
reti ; jmp TIMER1_OVF ; Timer1 Overflow Handler
reti ; jmp TIMER0_COMPA ; Timer0 Compare A Handler
reti ; jmp TIMER0_COMPB ; Timer0 Compare B Handler
reti ; jmp TIMER0_OVF ; Timer0 Overflow Handler
reti ; jmp SPI, STC ; SPI Transfer Complete Handler
reti ; jmp USART0, RX ; USART, RX Complete Handler
reti ; jmp USART0, UDRE ; USART, UDR Empty Handler
reti ; jmp USART0, TX ; USART, TX Complete Handler
reti ; jmp ANA_COMP
reti ; jmp ADC ; ADC Conversion Complete Handler
reti ; jmp EE_RDY ; EEPROM Ready Handler
reti ; jmp TWI ; 2-wire Serial Interface Handler
reti ; jmp SPM_RDY ; Store Program Memory Ready Handler
reti ; jmp USART1, RX
reti ; jmp USART1, UDRE
reti ; jmp USART1, TX
; ------------------------- Модуль инициализации --------------------------------------
RESET:
;-------------------------- Инициализация портов ВВ ---------------------------------
clr temp ; Записываем 0 в регистр temp
out PORTD, temp ; порт PD0-PD5: выход =0, PD6: вход =Z
ldi temp, 0x7B
out DDRD, temp ; 01111011 - "1"-выход, "0"-вход, 2-й бит на вход - внешнее прерывание INT0
clr temp
out PORTB, temp
ldi temp, 0xFF ; 11111111 все на выход
out DDRB, temp
ldi temp, 0x80 ; Аналог. компаратор откл.
out ACSR, temp
;-------------------------- Инициализация таймера T1 ------------------------------------
ldi temp, 0x0A ; 00001010 - режим СТС - сброс по совпадению и запуск таймера
sts 0x81, temp ; TCCR1B
ldi temp, deley_vkl_0
sts 0x88, temp ; в OCR1A записали число 35
ldi temp, 0x02
sts 0x6F, temp ; разрешаем прерывание по событию "Совпадение А" TIMSK1
;-------------------------- Инициализация стека ------------------------------------------
ldi temp,low(RAMEND) ; Выбор адреса вершины стека (адрес конца RAM)
out SPL,temp ; Запись его в регистр стека
ldi temp,high(RAMEND) ;
out SPH, temp
sei
;-------------------------- Начало основной программы
lp00:
loop5: sbic PIND, 7 ; ждём приход 1 втечение 0.51(мс) если 6-й бит регистра PIND = 0, то след. команда пропускается
jmp loop6
in temp, TIFR1
sbrs temp, 1
jmp loop5
jmp lp00
loop6:
;====================
; Подпрограмма обработки прерываний
;====================
TIMER1_COMPA:
clr temp
reti- Вложения
-
- ATmega164.gif
- (188.49 КБ) 522 скачивания
Истина где-то рядом...
Если ещё актуально. Проще явно указать адрес вектора
Регистр OCR1A двухбайтовый и для таких регистров периферии есть определенный порядок записи/чтения
Регистр OCR1A двухбайтовый и для таких регистров периферии есть определенный порядок записи/чтения
Спойлер
Код: Выделить всё
.org 0 ; Установка текущего адреса на ноль
jmp RESET ; Переход на начало программы
reti ; jmp EXT_INT0 ; Внешнее прерывание 0
reti ; jmp INT1 ; Внешнее прерывание 1
reti ; jmp INT2
reti ; jmp PCINT0 ; PCINT0 Handler
reti ; jmp PCINT1 ; PCINT1 Handler
reti ; jmp PCINT2 ; PCINT2 Handler
reti ; jmp PCINT3
reti ; jmp WDT ; Watchdog Timer Handler
reti ; jmp TIMER2_COMPA ; Timer2 Compare A Handler
reti ; jmp TIMER2_COMPB ; Timer2 Compare B Handler
reti ; jmp TIMER2_OVF ; Timer2 Overflow Handler
reti ; jmp TIMER1_CAPT ; Timer1 Capture Handler
.org 0x001A ; Установка вектора сравнения таймера 1А
jmp TIMER1_COMPA ; Timer1 Compare A Handler
;
;
;
;
;
;
;-------------------------- Инициализация таймера T1 ------------------------------------
LDI XH,HIGH(deley_vkl_0)
LDI XL,LOW(deley_vkl_0)
STS OCR1AH,XH
STS OCR1AL,XL
LDI R16,1<<OCIE1A
STS TIMSK1,R16 ; разрешаем прерывание по событию "Совпадение А" TIMSK1
LDI R16,1<<WGM12|1<<CS11
STS TCCR1B,R16 ;режим СТС - сброс по совпадению и запуск таймера Fclk/8
; ldi temp, 0x0A ; 00001010 - режим СТС - сброс по совпадению и запуск таймера
; sts 0x81, temp ; TCCR1B
; ldi temp, deley_vkl_0
; sts 0x88, temp ; в OCR1A записали число 35
; ldi temp, 0x02
; sts 0x6F, temp ; разрешаем прерывание по событию "Совпадение А" TIMSK1
Попадает оно на тот вектор, это Вы таблицу векторов неправильно заполнили. Поглядите таблицу векторов в ДШ, у данного камня один вектор занимает два слова памяти программ. Команда-затычка RETI однословная команда. На Вашем скрине как раз видно, что программный счетчик указывает на 0x1A, т.е. это адрес нужного Вам вектора.artemik32 писал(а):только оно попадает на другой вектор почему то.
Можно вставить двухсловные команды на неиспользуемые вектора, например
Код: Выделить всё
jmp RESETКод: Выделить всё
nop
nopМожно в вектор вставить директиву .dw 0x0000.
Или воспользуйтесь директивой .ORG, как указал akl.
тем более что для каждого адреса вектора уже определены соответствующие символьные константы. И это не только проще, но и правильнее - я об этом неоднократно говорил, и буду говорить.akl писал(а):Проще явно указать адрес вектора
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Реклама
Да спасибо, я уже написал конкретный адрес перехода на вектор как предложил akl. Так нормально работает, а с младшими мегами таких проблем не было, у которых используется команда rjmp вместо jmp, и памяти у них 8 кб и меньше.
Истина где-то рядом...
- Сообщения: 1491
- Зарегистрирован: Ср июн 25, 2008 15:19:44
[uquote="akl",url="/forum/viewtopic.php?p=3132093#p3132093"][/uquote]
Неправильно! JMP - два слова. RETI - одно слово. И два RETI займет один вектор. Правильно нужно писать так:
Такая запись будет верной:
Код: Выделить всё
.org 0 ; Установка текущего адреса на ноль
jmp RESET ; Переход на начало программы
reti ; jmp EXT_INT0 ; Внешнее прерывание 0
reti ; jmp INT1 ; Внешнее прерывание 1
reti ; jmp INT2
reti ; jmp PCINT0 ; PCINT0 Handler
reti ; jmp PCINT1 ; PCINT1 Handler
reti ; jmp PCINT2 ; PCINT2 Handler
reti ; jmp PCINT3
reti ; jmp WDT ; Watchdog Timer Handler
reti ; jmp TIMER2_COMPA ; Timer2 Compare A Handler
reti ; jmp TIMER2_COMPB ; Timer2 Compare B Handler
reti ; jmp TIMER2_OVF ; Timer2 Overflow Handler
reti ; jmp TIMER1_CAPT ; Timer1 Capture Handler
.org 0x001A ; Установка вектора сравнения таймера 1А
jmp TIMER1_COMPA ; Timer1 Compare A Handler
Неправильно! JMP - два слова. RETI - одно слово. И два RETI займет один вектор. Правильно нужно писать так:
Код: Выделить всё
.org 0x0000
jmp RESET ; Reset Handler
.org OC2addr
jmp TIM2_COMP ; Timer2 Compare Handler
.org URXC0addr
jmp RS232_VESS; USART0 RX Complete Handler
.org ADCCaddr
jmp ADC_Complet
.org URXC1addr
jmp USART1_RXC; USART1 RX Complete Handler
.org UDRE1addr
jmp USART1_UDRE; USART1 TX Complete Handler
Код: Выделить всё
.org UDRE1addr
reti ; jmp USART1_UDRE; USART1 TX Complete Handler
Друзья, всем привет.
Пытаюсь разобраться с таймерами, и столкнулся с непонятной для меня информацией. Пишу в Ардуино ИДЕ. Микроконтроллер: Атмега168
Цель: нужно вызывать функцию 1 раз в секунду (по сути это часы, только назначение другое). Решил все это делать на таймере. Залез в даташит: 0-й и 2-й таймеры 8-мибитные, значит отпадают, остается 1-й таймер. По настройке немного сложно, делаю в первый раз, но в принципе разобраться можно.
Вот примерно что я собираюсь делать, Так правильно? и нужно ли делать сброс таймера?:
Добавлено after 44 minutes 55 seconds:
Пробую, но ничего не работает... код:
Пытаюсь разобраться с таймерами, и столкнулся с непонятной для меня информацией. Пишу в Ардуино ИДЕ. Микроконтроллер: Атмега168
Цель: нужно вызывать функцию 1 раз в секунду (по сути это часы, только назначение другое). Решил все это делать на таймере. Залез в даташит: 0-й и 2-й таймеры 8-мибитные, значит отпадают, остается 1-й таймер. По настройке немного сложно, делаю в первый раз, но в принципе разобраться можно.
Вот примерно что я собираюсь делать, Так правильно? и нужно ли делать сброс таймера?:
Код: Выделить всё
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS12); // делитель 256
TIMSK |=(1<<OCIE1A); // прерывание по совпадению
OCR1AH = 0b11110100; // число для сравнения 62500
OCR1AL = 0b00100100;
....
ISR (TIMER1_COMPA_vect)
{
// какое-то действие
}Пробую, но ничего не работает... код:
Код: Выделить всё
int i=10;
ISR (TIM1_COMPA)
{
// какое-то действие
i=i+1;
}
void setup(void) {
// flip screen, if required
// u8g.setRot180();
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS12); // делитель 256
TIMSK1 |=(1<<OCIE1A); // прерывание по совпадению
OCR1AH = 0b11110100; // число для сравнения 62500
OCR1AL = 0b00100100;
Serial.begin(9600);
}
void loop(void) {
Serial.println(i);
// rebuild the picture after some delay
delay(100);
}Сделать своими руками всегда интересней чем просто купить и пользоваться
в режиме СТС он сам сбрасывается
Добавлено after 2 minutes 38 seconds:
разрешение прерываний (глобальное)?
Добавлено after 2 minutes 38 seconds:
разрешение прерываний (глобальное)?
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Да вроде как по умолчанию они включены.
Пробовал дописывать sei() но это ничего не изменило. В общем я в ступоре... Может что-то элементарное пропускаю? С тем же ISR не все понятно. В одних местах он прописан как TIM1_COMPA в других по-другому. Пробовал и так и так - нет результата.
Пробовал дописывать sei() но это ничего не изменило. В общем я в ступоре... Может что-то элементарное пропускаю? С тем же ISR не все понятно. В одних местах он прописан как TIM1_COMPA в других по-другому. Пробовал и так и так - нет результата.
Сделать своими руками всегда интересней чем просто купить и пользоваться
[uquote="forfrends",url="/forum/viewtopic.php?p=3161707#p3161707"]Пробую, но ничего не работает...[/uquote]
Попробуйте так. Глобальные прерывания нужно разрешать в вашем случае.
Попробуйте так. Глобальные прерывания нужно разрешать в вашем случае.
Спойлер
Код: Выделить всё
int i=10;
ISR (TIMER1_OVF_vect)
{
TCNT1 = 0xC2F7;
// какое-то действие
i++;
}
void setup(void) {
//Инициализация таймера 1
TCCR1B = 0b101; // делитель на 1024
TIMSK1 |= (1<<TOIE1); //активировать прерывание по переполнению таймера
TCNT1 = 0xC2F7; // частота прерываний 1 Гц для F_CPU = 16 000 000
Serial.begin(9600);
sei();
}
void loop(void) {
Serial.println(i);
// rebuild the picture after some delay
delay(100);
}volatile int i=10;forfrends писал(а):Пробую, но ничего не работает
[uquote="forfrends",url="/forum/viewtopic.php?p=3161707#p3161707"]... Так правильно?
[/uquote]Замечу, в OCR1x(ICR1) для точной выдержки времени нужно заносить значение на 1 меньшее, особенно при использовании предделителя. Т.е. 62500-1
Код: Выделить всё
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS12); // делитель 256
TIMSK |=(1<<OCIE1A); // прерывание по совпадению
OCR1AH = 0b11110100; // число для сравнения 62500
OCR1AL = 0b00100100;
...
ISR (TIMER1_COMPA_vect)
{
// какое-то действие
}- Сообщения: 31
- Зарегистрирован: Ср сен 13, 2017 05:53:24
Помогите. В протеусе все симулирует чётко. Загружаю в МК не отрабатывает прерывание по переполнению таймера1. Мк аттини85.
Правильно ли инициализировал прерывание?
Правильно ли инициализировал прерывание?
Код: Выделить всё
//инициализация таймера1
void timer1_ini (void){
TCCR1 |= (1 << CTC1) //режим CTC
|(0<<COM1A1)|(0<<COM1A0) //отключаем OC1A
|(1 << CS13)|(0 << CS12)|(1 << CS11)|(0 << CS10); //Делитель 512
TCNT1 = 0x00; //сброс счетчика
OCR1A = 0xFF; //регистр сравнения
TIMSK |=(1<<TOIE1); //включаем прерывания по переполнению
}
//обработка прерывания таймера1
ISR(TIMER1_OVF_vect){
PORTB |= (1<<PB1);
}- Сообщения: 1491
- Зарегистрирован: Ср июн 25, 2008 15:19:44
[uquote="akl",url="/forum/viewtopic.php?p=3205345#p3205345"]SEI не хватает.[/uquote]
В функции инициализации глобальное включение прерываний не обязано быть. Только после инициализации всей нужной периферии.
В функции инициализации глобальное включение прерываний не обязано быть. Только после инициализации всей нужной периферии.
- Сообщения: 31
- Зарегистрирован: Ср сен 13, 2017 05:53:24
SEI есть в программе, даже есть ещё одно прерывание по таймеру0 (TIMER0_COMPA_vect) и оно работает, а по этому вектору нет, да и интересно почему в протеусе все как надо работает, а в реальном МК нет? мб МК бракованный >_<
МК бракованный... еще может быть компилятор лажает - это две любимые причины всех проблем начинающих.fulky писал(а):интересно почему в протеусе все как надо работает, а в реальном МК нет? мб МК бракованный
у вас схема протеуса на 100% соответствует реальной? в реальной ошибок нет? что вы ждете от обработчика с единственным оператором, какие эффекты быть должны, а их нет? ни схемы, ни всей программы, одни загадки-догадки.
я вам точно скажу, в чем причина: у вас есть ошибка. полегчало?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Думаю, прерывание по переполнению никогда не возникает, т.к. таймер работает до 0xFF. Попробуйте прерывание OCIE1A
- Сообщения: 31
- Зарегистрирован: Ср сен 13, 2017 05:53:24
из-за оптимизации такое может происходить, (-O) выставлена?МК бракованный... еще может быть компилятор лажает - это две любимые причины всех проблем начинающих.
Режимы работы реле
1. Потенциометром задается режим от 1 до 4, как на картинке, удержанием кнопки переход на следующий шаг
2. Задается время t1
3. Указываются в чем считать С, М, Ч
4. Задается время t2
5. Указываются в чем считать С, М, Ч
6. Происходит запуск (PB1 рулит реле по выбранному режиму)
Косяк в том, что нет бегающей индикации во время работы
Добавлено after 31 minute 54 seconds:
[uquote="akl",url="/forum/viewtopic.php?p=3205391#p3205391"]Думаю, прерывание по переполнению никогда не возникает, т.к. таймер работает до 0xFF. Попробуйте прерывание OCIE1A[/uquote]
т.е. сделать по вектору TIMER1_COMPA и через сравнение с OCR1A??
- Вложения
-
- AVR.rar
- код и протеус
- (85.26 КБ) 208 скачиваний



