Страница 1 из 1

delay_ms & interrupts

Добавлено: Вт авг 18, 2009 10:30:43
zebrox
Всем привет!

Вот столкнулся с таой проблемой.
Есть у меня таймер, тикает с частотой 1 гц, происходит прерывание, а в этом прерывании мне нужно мигать светодиодом, частота его мигания достаточно низкая, что-бы можно было посчитать количество вспышек (от 1 до 12). Вспышки формирую функциями delay_ms()

Код: Выделить всё

void blink_led(char num, char time_on, int time_off){
char i = 0;
    for(i = 0; i< num; i++)
    {
        LED_pin = 0;
        delay_ms(time_on);
        LED_pin = 1;
        delay_ms(time_off);
    }
}
т.е. эта функция вызывается из прерывания таймера. И оказалось, что когда выполняется этот участок кода, прерывания от ЮАРТА не приходят вообще.
На каком-то заморском форуме вычитал, что вызывать delay_ms() в прерывании нельзя, но почему не понятнь. Хотя какая разница, delay_ms() это вроде обычный пустой цикл, и все прерывания должны приходить.
Может я чего напутал или недопонял....
В чем может быть причина НЕприхода юарт прерываний???

Re: delay_ms & interrupts

Добавлено: Вт авг 18, 2009 10:36:15
GRafGRay
Если я не ошибаюсь, то в момент запуска прерывания, флаг I в регистре SREG сбрасывается, запрещая другие прерывания.

У вас цикл выполняется внутри обрабочика прерывания, соответственно, пока весь цикл не отработает, все остальные прерывания будут запрещены.

По выходу из обработчика необходимо установить флаг для разрешения прерывний.

Добавлено: Вт авг 18, 2009 10:43:30
zebrox
вот смотрю асм код, при вызове прерывания первым делом вызывается эта процедура

Код: Выделить всё

;OPTIMIZER ADDED SUBROUTINE, CALLED 3 TIMES, CODE SIZE REDUCTION:19 WORDS
SUBOPT_0x1DA:
	ST   -Y,R0
	ST   -Y,R1
	ST   -Y,R15
	ST   -Y,R22
	ST   -Y,R23
	ST   -Y,R24
	ST   -Y,R25
	ST   -Y,R26
	ST   -Y,R27
	ST   -Y,R30
	ST   -Y,R31
	IN   R30,SREG
	ST   -Y,R30
	RET
я в асме не очень силен, а точнее очень не силен, IN R30,SREG
это и есть сброс флага т.е. запрет других прерываний?
Получается, что из прерывания нельзя уйти в прерывание?
А как можно это решить?

Добавлено: Вт авг 18, 2009 10:51:59
Goodefine
zebrox писал(а): ...Получается, что из прерывания нельзя уйти в прерывание?
А как можно это решить?
Разрешить вложенные прерывания. Но в вашем случае это не надо. Алгоритм программы необходимо пересмотреть. Не нужно делать делай в прерывании. Причину вы уже выяснили - не работают другие прерывания, до выхода из обработчика. Вложенные делать тоже не выход - стек не бесконечный, да и временная диаграмма не очевидная получается.
Лучший выход - в обработчике ставьте флаг, а в основном цикле по флагу выполняйте определенные действия. И лучше вместо делая также работать по флагам от таймера - МК вместо тупого ожидания может заняться работой...

Добавлено: Вт авг 18, 2009 10:57:44
GRafGRay
<b>zebrox </b>
настоятельно рекомендую почитать обучалку и со стеком разобраться

in R30,SREG - это в регистре R30 сохраняется значение регистра SREG, по выходу из прерывания необходимо SREG восстаналивать

проблема в том, что вы в прерывание, которое выполняется очень короткий промежуток времени запихнули цикл который выполняеся много - очень много дольше, соответственно основная программа с другими прерываниями не выполняется пока не выйдет из текущего прерывания.

Добавлено: Вт авг 18, 2009 11:00:24
zebrox
Goodefine писал(а): Лучший выход - в обработчике ставьте флаг, а в основном цикле по флагу выполняйте определенные действия.
Понял, так наверное и сделаю, конечно прийдется повозиться...
А для общего развития, как можно разрешить вложенные прерывания, где? Еще вроде есть иерархия прерываний, как можно руками добавить приоритета прерываниям от юарта? Сделать свой вектор прерываний?

Добавлено: Вт авг 18, 2009 11:13:05
Goodefine
zebrox писал(а): //А для общего развития, как можно разрешить вложенные прерывания, где? Еще вроде есть иерархия прерываний, как можно руками добавить приоритета прерываниям...
Просто в обработчике написать #asm ("sei") (CVAVR), если компилятор другой, смотреть документацию. Либо бит глобального разрешения установить руками (то бишь маской).
Иерархию изменить нельзя - выполнится то прерывание, вектор которого имеет младше адрес...

Добавлено: Вт авг 18, 2009 11:23:17
zebrox
Goodefine писал(а):Просто в обработчике написать #asm ("sei")
все гениальное просто!
Вот с вектором бы еще разобраться, в CAVR в настройках проэкта можно задать вектор во внешнем файле, надо хелп почитать.

Сейчас тему думаю создать про веб сервер на СИМ300 и МК, может кто сталкивался...

Добавлено: Вт авг 18, 2009 12:15:22
Goodefine
zebrox писал(а):...Вот с вектором бы еще разобраться, в CAVR в настройках проэкта можно задать вектор во внешнем файле, надо хелп почитать. ...
А чего с ним разбираться? От компилятора это не зависит. Вектора заданы аппаратно в самом контроллере - в даташите приоритеты прерываний подробно описаны. То что во внешнем файле - просто исполняемый код, вынесенный отдельно.
А вообще, пропуска прерываний не случится (только если прерывание два раза произойдет без входа в обработчик) - выполнятся все, но в определенной последовательности...

Добавлено: Вт авг 18, 2009 12:15:53
zebrox
вот-вот, эту страничку я и читал, что это не очень хорошая идея вызывать delay_ms() в прерывании...

Добавлено: Вт авг 18, 2009 13:32:00
BCluster
char flag =0;

...//обработчик прерывания
{
flag = 1;
}

...
while (1)
{
if (flag) blink_led(num,time_on,time_off);
flag=0;
}

Добавлено: Вт авг 18, 2009 16:10:54
__Alexander
А при чем тут delay? Прерывание от уапп никак не выполнится в любом другом прерывании, вектор которого выше. Пусть там даже одна команда.




------------------

Добавлено: Вт авг 18, 2009 17:18:48
Goodefine
__Alexander писал(а):...Прерывание от уапп никак не выполнится в любом другом прерывании, вектор которого выше. Пусть там даже одна команда.
Оно не выполнится в ЛЮБОМ обработчике, хоть ниже, хоть выше. Зато после выхода пожалуйста...
__Alexander писал(а): А при чем тут delay?
Делай делает обработчик долгим, притупляя реакцию МК... Потому и "причем"...

Код: Выделить всё

...
if (flag) blink_led(num,time_on,time_off);
flag=0; 
..
Не совсем так:

Код: Выделить всё

...
if (flag) {blink_led(num,time_on,time_off);
            flag=0;} 
...

Добавлено: Вт авг 18, 2009 17:40:33
zebrox
Спасибо всем, что отозвались!
Для себя сделал вывод, что нужно учить матчасть...И делей в прерывании не есть правильно.