Проблема запуска прерывания по таймеру из аппаратного прерывания.

vktemp
Offline
Зарегистрирован: 07.09.2020

Добрый день.
Задача выполнить действие с заданным лагом от момента срабатывания аппаратного прерывания.
Код:

#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);
}
*/

В этом случае задержка по таймеру срабатывает корректно:

Можно ли прерывание по таймеру включать из аппаратного прерывания? и как это сделать
Спасибо

b707
Offline
Зарегистрирован: 26.05.2017

del

Green
Offline
Зарегистрирован: 01.10.2015

Аттач в конец сетапа. Сбрасывайте INT0F перед аттачем. cli()/sei() в ISR лишние.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

sei не лишнее. 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

А это нормально, что функция прерывания прописана внутри loop ?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Kakmyc пишет:
А это нормально, что функция прерывания прописана внутри loop ?

loop у него пустой. Внимательно паматри.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

DetSimen пишет:

Kakmyc пишет:
А это нормально, что функция прерывания прописана внутри loop ?

loop у него пустой. Внимательно паматри.

Угу, увидел.
А любом случае, вне зависимости от того включено прерывание по таймеру или нет(сравнение/переполнение и тд), счётчик тикает один фиг.
Есть смысл его обнулять перед запуском:
TCNT1=0;

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vktemp пишет:

Задача выполнить действие с заданным лагом от момента срабатывания аппаратного прерывания.

Вот здесь это делается очень красиво.

vktemp
Offline
Зарегистрирован: 07.09.2020

Заработало в таком виде:

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 пина отслеживать, но это неаккуратно.