Страница 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
Спасибо всем, что отозвались!
Для себя сделал вывод, что нужно учить матчасть...И делей в прерывании не есть правильно.