можно ли как-то просто организовать в Keil-ском C51 прерывания по таймеру с одного таймера:
0,5мсек для вызова п/программ с временем выполнения < 0,5 мсек,
50 мсек - для п/п < 50 мсек
1 сек - для п/п < 1 сек
Чтобы обеспечить их паралельное выполнение.
Раньше было что-то такое
Hand_Timer3:
; проверки повторности вхождения, стека,
; сбросы флагов прерываний, watchdog-а,
; проталкивание в стек регистров
lcall Call_RetI ; разрешение новых прерываний
; ввод данных с АЦП, счетных (внешних импульсов) входов в буфер
; управление выходами с точностью 0,5 мсек (например
; фазовое управление тиристорами)
; отсчет задержек в 0,5 мсек
inc c50msec
CJNE c50msec,#100,End_Interrupt ; 50 мсек
mov c50msec,#0
; проверка повторного вхождения на этот уровень
; первичная обработка введенных данных (фильтрация), управление
; медленными устройствами (модуляция ЖКИ, пускатели),
; обработка дребезга кнопок и тому подобное
; вычисления управляющих воздействий регуляторов (ПИ,ПИД)
; отсчет задержек в 50 мсек
inc cSecond
CJNE cSecond,#20,End_Interrupt ; 1 sec
mov cSecond,#0 ;
; проверка повторного вхождения на этот уровень
; отсчет времени, отсчет задержек в секундах
End_Interrupt:
; восстановление регистров из стека
ret
Call_RetI:
RetI ; разрешение повторных прерываний
Обычно хватает таймера 1кГц
Был случай необходимости 10кГц:
дла равномерности загрузки процессора основной цикл 1мс разбивался на примерно равновременные
модули с вызовом 0.1мс
В общем случае (мой личный подход

):
если требуется <0.1мс - использовать асинхронные прерывания
(м.б. даже внешний RS-триггер, хотя обычно достаточно стандартных Int 0,1)
Или вопрос о другом?
Я так понял, у автора что-то вроде иерархии периодических задач с разной длительностью спячки. Я обычно программирую таймер на наименьший квант времени, которому кратны периоды всех задач, а сами задачи разбиваю на конечные автоматы, состояние которых зависит от внешних событий и внутреннего счётчика квантов. Общий цикл блокируется на "привете" от обработчика таймера. По событию "кванта" каждая задача активируется по очереди. В итоге получается монстр

, суть которого отражена в приведённом автором примере.
Цитата(LMT @ Mar 5 2007, 18:47)

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

, суть которого отражена в приведённом автором примере.
Именно так, только я все не могу понять: у меня формально не цикл, а прерывание таймера в котором "натыкано" на разных уровнях иерархии разные задачи по длительности выполнения. Мне на вопрос и в других конфах, говорят о цикле в фоновой программе (main) которая запускает задачи по семафорам от обработчика таймера. НО в фоновой программе и своих задач хватает, точнее я там обычно размещаю задачи с непредсказумым временем выполнения, но требующих обработки, например - прием и передача на "хост" данных по последовательному каналу.
Ага, Вам нужна так называемая преемптивность, т.е. срочный и безусловный захват процессора по внешнему событию (в данном случае от таймера) задачей с наивысшим приоритетом. По моему в отсутсвие RTOS, которая Вам предоставила бы средства для этого, подход через обработчик самый естественный.
Цитата
у меня формально не цикл, а прерывание таймера в котором "натыкано" на разных уровнях иерархии разные задачи по длительности выполнения
Не, аппаратное прерывание оканчивается на "lcall Call_RetI".
Цитата(LMT @ Mar 6 2007, 11:28)

Ага, Вам нужна так называемая преемптивность, т.е. срочный и безусловный захват процессора по внешнему событию (в данном случае от таймера) задачей с наивысшим приоритетом. По моему в отсутсвие RTOS, которая Вам предоставила бы средства для этого, подход через обработчик самый естественный.
Теперь вопрос сначала: как это сделать на С? вставку ассемблерную - вызов LCALL RETI? Мне кажеться будут глюки связанные с сохранением контекста компилятором при входе в прерывание.
Цитата
Цитата
у меня формально не цикл, а прерывание таймера в котором "натыкано" на разных уровнях иерархии разные задачи по длительности выполнения
Не, аппаратное прерывание оканчивается на "lcall Call_RetI".
Это да, но возрат управления фоновой программе произойдет только при выходе.
Также, наверное:
Код
#pragma src
int raddr;
char Counter = 0; // Dummy var
void Hello(void)
{
// Do something
++ Counter;
#pragma asm
; Restore context here
#pragma endasm
}
void falarm (void) interrupt 1 using 3
{
#pragma asm
push raddr + 1
push raddr
reti
#pragma endasm
}
void main(void)
{
raddr = (int)Hello;
while(1);
}
По ассемблерному выходу понять, чего спасать надо, и принимать меры по ходу.
Цитата(Osti @ Mar 2 2007, 14:54)

можно ли как-то просто организовать в Keil-ском C51 прерывания по таймеру с одного таймера:
0,5мсек для вызова п/программ с временем выполнения < 0,5 мсек,
50 мсек - для п/п < 50 мсек
1 сек - для п/п < 1 сек
Чтобы обеспечить их паралельное выполнение.
...я бы подпрограммы с периодом < 0,5 мсек вызывал в обработчике прерывания (при условии что подпрограммы достаточно короткие), а остальные (50 мсек и 1 сек) в основном цикле программы через флаги... не имеет смысла городить все в одном обработчике прерывания