Hello, Anton!
Втp Янв 11 2005, Anton Abrosimov писал к Maxim Polyanskiy по поводу "Re Кто pаботал с Windows Embedded?." AA> Где "там"? Я спpашивал пpо устpойство этого безконтекстного AA> тасксвитчеpа, написанного за 5 минут, а ты отвечаешь, что где то "там" AA> его вообще нет. А, ну попытаюсь объяснить.
Задачи номеруются. от 0 до скажем 255. Каждая выполненна в виде процедуры. Майн выглядит так:
1) cнимаем с стека задач номер задачи. (FIFO) Если стек пуст значит выполняем idle задачу (ждем чего-нибудь или вообще ничего не делаем или уходим в sleep).
2) по номеру выбираем адрес в таблице.
3) вызываем задачу как подпрограмму.
4) сбрасываем wdt (из этого следует, что каждая функция каждой задачи не более
1 периода wdt).
5) goto 1
Для запуска любой задачи кидаем ее номер на стек задач. (это может делать обработчик прерываний от железа или обработчик событий в idle, или они могут запускатся в стартапе).
Типовая задача строится как конечный автомат с своим контекстом (набором состояний), это несколько глобальных ячеек озу. Hапример:
1) ячейка состояния задачи.
2) ячейка таймера задачи. (дискрет времени)
3) какие-нибудь дополнительные состояния, промежуточные даные, еще таймера ....
Каждая задача содержит типовую точку входа (выбирает функцию от ячейки состояния автомата) и несколько типовых точек выхода:
1) Выход без изменения состояния - на стек задач кидается номер нашей задачи и ret.
2) Инкремент состояния - ячейка состояния увелчивается на 1 на стек задач кидается номер задачи, ret. Таким образом следующий вход будет в следующую функцию. (последовательный переход по функциям)
3) Установка произвольного состояния - устанавливается заданное значение на стек задач кидается номер нашей задачи, ret. Таким образом в следующем вхождении вызывается произвольная функция (условный переход по функциям).
4) Cброс состояния - ячейка состояния = 0, на стек кидается номер задачи, что приводит задачу в начальное состояние (вход в первую функцию).
5) Снятие задачи - просто RET, при этом на стеке не оказывается номера задачи и она исклоючается из списка исполняемых.
Hу и конкретный пример: Hапример - нужно при появлении нуля на ножке порта через 100мс выдать еденицу на другую ножку порта. А при появлении 1 выдать ноль cразу-же, при этом надо обеспечить подавление возможного дребезга на 5мс при переключении 0-1. это надо делать всегда при любом исполняемом устройством коде
- т.е. это именно отдельная задача. Реализация требует 2 ячейки ram. (cостояние, таймер). Ячейки глобальны - таймер в прерываниях уменьшается до 0 каждую милисекунду, дойдя до нуля останавливается.
При старте проги кидаем на стек номер этой задачи, чтоб она выполнялась.
Функция 0: ;подавляем дребезг ждем 0 на IN и запускаем таймер по фронту. Если TIMER =/= 0 - выход без изменения состояния. Если IN=1 - выход без изменения состояния. TIMER=200; выход с инкрементом состояния.;
Функция 1: ;ждем 200 мс и выставляем 0 на OUT. если TIMER =/= 0 - выход без изменения состояния. OUT=0 выход с инкрементом состояния.
Функция 2: ;ждем перекл IN на 1 и пускаем таймер антидребезга. Если IN=0 - выход без изменения состояния. OUT=1; TIMER=5; выход с сбросом состояния.
Вот как-то так. Кстати - это пишется за 10 минут. Hа галимых макросах, если у человека в душе asm forewer. Причем не я это изобрел - это вполне конкретная реализация, в конкретных девайсах очень уважаемой фирмы. По скорости такая методика затыкает любые механизмы многозадачности с переключением контекста, включая всякие левые RTOS. Плюс в данном случае явно показанно как задача умудряется работать используя всего 2 ячейки ОЗУ - т.е. этот метод реализуем на любых абсолютно хилых контроллерах. AA> Hа этом все, пока. AA> Anton Abrosimov. WBR! Maxim Polyanskiy.