Проблема запуска прерывания по таймеру из аппаратного прерывания.
- Войдите на сайт для отправки комментариев
Пнд, 07/09/2020 - 15:35
Добрый день.
Задача выполнить действие с заданным лагом от момента срабатывания аппаратного прерывания.
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
//2,056мс
unsigned int ArrS[] = {1, 4110, 5888, 7332, 8666, 9999, 11221, 12555, 13999, 15888, 19999};
volatile uint8_t nomer;
void setup(){
pinMode(9, OUTPUT);
pinMode(2, INPUT);
attachInterrupt(0, znak_plvln, CHANGE);
cli();
TCCR1A = 0;
TCCR1B = 0;
OCR1A = 9999;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
TIMSK1 |= (1 << OCIE1A);
sei();
}
void loop(){}
ISR(TIMER1_COMPA_vect){
digitalWrite(9, !digitalRead(9));
cli();
TIMSK1 &= ~ (1 << OCIE1A);
OCR1A = ArrS[nomer];
//TIMSK1 |= (1 << OCIE1A);
sei();
if (nomer == 10) nomer = 0;
else nomer++;
}
void znak_plvln(){
TIMSK1 |= (1 << OCIE1A);
}
в логическом анализаторе выдает
Прерывание по таймеру в основном срабатывает сразу после включения.
Пробовал для поиска ошибки отказаться от аппаратного прерывания:
#include <avr/io.h>
#include <avr/interrupt.h>
//2,056мс
unsigned int ArrS[] = {1, 4110, 5888, 7332, 8666, 9999, 11221, 12555, 13999, 15888, 19999};
volatile uint8_t nomer;
void setup(){
pinMode(9, OUTPUT);
pinMode(2, INPUT);
//attachInterrupt(0, znak_plvln, CHANGE);
cli();
TCCR1A = 0;
TCCR1B = 0;
OCR1A = 9999;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
TIMSK1 |= (1 << OCIE1A);
sei();
}
void loop(){}
ISR(TIMER1_COMPA_vect){
digitalWrite(9, !digitalRead(9));
cli();
TIMSK1 &= ~ (1 << OCIE1A);
OCR1A = ArrS[nomer];
TIMSK1 |= (1 << OCIE1A);
sei();
if (nomer == 10) nomer = 0;
else nomer++;
}
/*
void znak_plvln(){
TIMSK1 |= (1 << OCIE1A);
}
*/
В этом случае задержка по таймеру срабатывает корректно: 
Можно ли прерывание по таймеру включать из аппаратного прерывания? и как это сделать
Спасибо

del
Аттач в конец сетапа. Сбрасывайте INT0F перед аттачем. cli()/sei() в ISR лишние.
sei не лишнее.
А это нормально, что функция прерывания прописана внутри loop ?
loop у него пустой. Внимательно паматри.
loop у него пустой. Внимательно паматри.
Угу, увидел.
А любом случае, вне зависимости от того включено прерывание по таймеру или нет(сравнение/переполнение и тд), счётчик тикает один фиг.
Есть смысл его обнулять перед запуском:
TCNT1=0;
Задача выполнить действие с заданным лагом от момента срабатывания аппаратного прерывания.
Вот здесь это делается очень красиво.
Заработало в таком виде:
unsigned int ArrS[] = {1, 5888, 4110,7332, 8666, 9999, 11221, 12555, 13999, 15888, 19999}; uint8_t nomer; volatile bool n; void setup(){ pinMode(9, OUTPUT); pinMode(2, INPUT); attachInterrupt(0, znak_plvln, CHANGE); TCCR1A = 0; TCCR1B = 0; TCCR1B |= (1 << WGM12); TIMSK1 |= (1 << OCIE1A); } void loop(){} ISR(TIMER1_COMPA_vect){ TCNT1=0; cli(); if (!n){ digitalWrite(9, HIGH); OCR1A = 59; n = true; } else { digitalWrite(9, LOW); TCCR1B &= ~ (1 << CS11); } sei(); } void znak_plvln(){ TCNT1=0; n = false; cli(); TCCR1B |= (1 << CS11); OCR1A = ArrS[nomer]; sei(); if (nomer == 10) nomer = 0; else nomer++; }Kakmyc, спасибо за указание на TCNT1=0;. Стало включаться в нужный момент.
ЕвгенийП, прошу прощения, решая одну проблему, не описал задачу в целом. Не только включить из апп прерывания, но и выключить через период. С режимом Force Output Compare не нашел возможности это сделать. Разве что включение 9 пина отслеживать, но это неаккуратно.