|
|
  |
Структура программы, Вырабатываю хороший стиль программирования |
|
|
|
Mar 18 2009, 11:33
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Добрый день. Возник у меня вопрос, который терзает моё эго и не даёт спокойно работать. Вопрос заключается в организации программы. В общем вот: Допустим есть ТЗ: сделать прибор, который должен: - считывать температуру с датчика по шине TWI - считывать значение напряжения с АЦП с датчика влажности - расчитывать значение влажности в общепринятых единицах - выдать предупреждающие сигналы в случае превышения норм - показать значения на дисплее Зада просто и понятна (хоть и высосана из пальца). Реализовал бы всё это дело я так: Код #include <io.h> volatile int counter; int main() { //инициализирую всё и вся
for(;;) //пустой бесконечный цикл ; }
ISR(SIG_OUTPUT_COMPARE1A) { switch(counter) { case 100: BeginTempConvers(); break; //посылаю запрос для начала считывания температуры case 200: GetADCValue(); break; //считываю значение с АЦП case 300: ProcessADCValue(); break; //раситываю необходимые значения case 400: GetTempValue(); break; //считываю температуру case 500: SetAlarm(); break; //проверяю значения и вывожу аварийные сигналы если надо case 600: DisplayValues(); break; //вывожу все данные на экран };
counter++; if(counter == 601) counter = 0; } Так вот вопрос - хорошо ли я делаю? Какие есть ещё способы реализации поставленной задачи. Просто мне почему то кажется, что всю логику работы прибора нехорошо запихивать в таймер...
|
|
|
|
|
Mar 18 2009, 13:50
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Цитата(Палыч @ Mar 18 2009, 14:40)  Очень правильно кажется! Кстате, а почему плохо? Спрашиваю для общего развития, а не для спора))) Цитата(Палыч @ Mar 18 2009, 14:40)  Желательно как-то так: в таймере выставлять флаги операций, а в бесконечном цикле (тот, что в main) Код #include <io.h> volatile int counter; int main() { //инициализирую всё и вся
for(;;) //уже не пустой бесконечный цикл { switch(counter) { case 100: BeginTempConvers(); counter++; break; //посылаю запрос для начала считывания температуры case 200: GetADCValue(); counter++; break; //считываю значение с АЦП case 300: ProcessADCValue(); counter++; break; //раситываю необходимые значения case 400: GetTempValue(); counter++; break; //считываю температуру case 500: SetAlarm(); counter++; break; //проверяю значения и вывожу аварийные сигналы если надо case 600: DisplayValues(); counter++; break; //вывожу все данные на экран } //counter инкрементируется для того, что бы функция невызывалась повторно в случае когда время итерации цикла меньше перода таймера } }
ISR(SIG_OUTPUT_COMPARE1A) { counter++; if(counter == 601) counter = 0; } ммм.... так? Цитата(XVR @ Mar 18 2009, 14:42)  Все в таймер явно нехорошо  Можно сделать так - в прерываниях обрабатывается взаимодействие с датчиками (самое простое, без дальнейшей обработки). Вся основная логика реализуется в процедуре, которая циклически вызывается из процедуры UI (какой бы он не был - кнопки и индикатор или RS232 к PC). Если логика не тривиальная - делается один или более взаимодействующих конечных автомата. Да логика то в моих реальных заданиях такая же простая как в примере))) А начсёт процедур - что за процедура UI?
|
|
|
|
|
Mar 18 2009, 14:35
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(UniBomb @ Mar 18 2009, 16:50)  Кстате, а почему плохо? Спрашиваю для общего развития, а не для спора Процедуры обработки прерывания желательно писать так, чтобы время выполнения её было минимальным. Причин несколько. Формулировать все - лень... Например, время обработки прерывания от таймера превысит интервал таймера. Что будет? Поскольку Ваша разача сводится к периодическому выполнению одной и той же последовательности действий, то, наверное, лучше как-то так: Код #include <io.h> volatile char flag; int main() { //инициализирую всё и вся flag= 0; for(;;) //уже не пустой бесконечный цикл { if(flag) { flag= 0; BeginTempConvers(); //посылаю запрос для начала считывания температуры GetADCValue(); //считываю значение с АЦП ProcessADCValue(); //раситываю необходимые значения GetTempValue(); //считываю температуру SetAlarm(); //проверяю значения и вывожу аварийные сигналы если надо DisplayValues(); //вывожу все данные на экран } } }
ISR(SIG_OUTPUT_COMPARE1A) { flag= ~0; } P.S. Пардон, не всё лишнее убрал из программы. Поправил...
|
|
|
|
|
Mar 19 2009, 04:38
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
Цитата(UniBomb @ Mar 18 2009, 19:33)  Добрый день. Возник у меня вопрос, который терзает моё эго и не даёт спокойно работать. Вопрос заключается в организации программы. Здравствуйте! В прерываниях обрабатывайте то, что там обрабатывать нужно. Обработчики прерываний делайте максимально быстрыми. Весь функционал программы (обработки информации с датчиков, выдача данных на дисплей, обработка данных от клавиатуры) разместите в отдельных функциях, которые вызывайте из бесконечного цикла в main(). А вот работу с шиной I2C, сбор данных с АЦП можно (и даже лучше) разместить прерывания. Таким образом, в обработчике прерывания от АЦП Вы будете считывать данные и ложить их в буфер, а также анализировать ошибки АЦП. Все. В обработчики прерываний шины TWI вы будете анализировать состояние шины, ошибки, принимать данные и ложить в буфер или брать данные из буфера и передавать их. Все. А вот ложить данные в буферы, читать их оттуда, уже задача основной программы. Ну примерно так. Дальше уже с опытом понимание придет. Цитата(UniBomb @ Mar 18 2009, 21:50)  Кстате, а почему плохо? Спрашиваю для общего развития, а не для спора))) Тут дискутировали недавно.
--------------------
Выбор.
|
|
|
|
|
Mar 19 2009, 10:26
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Спасибо всем за ответы, я подчерпнул для себя много нового Палыч, если бы все эти функции могли бы выполняться одна за одной, то я бы таймер вообще не использовал. Так например между вызовами функциями BeginTempConvers(); и GetTempValue(); должно пройти по крайней мере полсекунды. Это особенность микросхемы-термометра. Плюс я ещё оставляю между вызовами функций много времени для того, чтобы свободного процессорного времени было много. Это делается для того, чтобы при использовании USART было бы побольше времени для выполнения функций, реализующих какой-либо протокол. Плюс ко всему в последнем проекте используеться микросхема памяти, запись данных в которую происходит очень много времени. _Pasha, ммм... а что такое "атомарный"? DpInRock, насчёт алгоритма понятно. Просто задачи я решаю в основном однотипные, которые сводятся к элементарной линейноти и очерёдности... haker_fox, ваши слова заставили меня задуматься... Чуствую в моих программах грядут большие изменения XVR ясно)))
|
|
|
|
|
Mar 19 2009, 10:29
|
Профессионал
    
Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347

|
я делаю примерно как в http://electronix.ru/forum/index.php?showt...st&p=564433 . один из таймеров заряжаю на 200..2000 Гц, в его прерывании обновляю динамическую индикацию из буфера в памяти, сканирую клавиатуру (для экономии выводов она обычно завязана на линии индикации) в буфер клавиатуры. плюс есть несколько счетчиков для получения опорных частот 100, 10, 1Гц. в основном цикле на частоте 100 Гц производится опрос и обработка клавиатуры, индикация обновляется с частотой 10 Гц, и т.д.
|
|
|
|
|
Mar 19 2009, 12:39
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(UniBomb @ Mar 19 2009, 13:26)  если бы все эти функции могли бы выполняться одна за одной, то я бы таймер вообще не использовал. Так например между вызовами функциями BeginTempConvers(); и GetTempValue(); должно пройти по крайней мере полсекунды... .... Плюс ко всему в последнем проекте используеться микросхема памяти, запись данных в которую происходит очень много времени. В простейшем случае можно поставить и задержку  . Правда на полсекунды - это, наверное, очень "круто" (даже для "простых" задач). Грамотнее использовать автомат состояний и использовать таймер как источник сигналов для него. Автоматы обсуждаются тут - рядом. Цитата(UniBomb @ Mar 19 2009, 13:26)  ... Это делается для того, чтобы при использовании USART было бы побольше времени для выполнения функций, реализующих какой-либо протокол. Обычно ввод/вывод по USART делают буферированным, и по прерываниям от USART извлекают/помещают из/в буфера очередной байт, при этом сама аппаратура USART (собственно ввод/вывод) работает в параллель с программой и, возможно, приёмник впараллель с передатчиком...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|