Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/DetSimen/Arduino-MessageList
работаем по взрослому, с очередью сообщений
https://github.com/DetSimen/Arduino-MessageList
arduino message-queue
Last synced: 2 months ago
JSON representation
работаем по взрослому, с очередью сообщений
- Host: GitHub
- URL: https://github.com/DetSimen/Arduino-MessageList
- Owner: DetSimen
- Created: 2017-06-19T04:28:52.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-02-06T08:30:20.000Z (almost 6 years ago)
- Last Synced: 2024-08-02T15:47:04.809Z (5 months ago)
- Topics: arduino, message-queue
- Language: C++
- Size: 26.4 KB
- Stars: 5
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Arduino-MessageList
Другая идея, прямо вытекает из https://github.com/DetSimen/Arduino-. Дело в том, что процедура срабатывания таймера выполняется в контексте прерывания, поэтому не может быть длинной, да и вапще, нехорошо это. Поэтому, придумывать я ничего не стал, просто взял идею из не всеми нами любимой Виндовс. Нужно создать на Ардуине простенькую, плохонькую, но очередь сообщений. Каждый датчик меряет какие-то значения и генерирует какие-то события. Если ждать их наступления в loop(), то эта несчасная функция в оконцовке вырастает до неприемлемо огромных значений, а, как мы помним из детсадовского курса пограммирования, если текст фунции не помещается в один экран - значит ее написала очень плохая и неумная киса, и функцию надо разбивать на более мелкие части, а кису - по спине лопатой и на биржу труда. Поэтому, для своих проектов я применяю достаточно простое решение, существенно облегчающее (мне) жизнь.
Для начала определим, какие сообщения мы хотим видеть в своей программе, и запишем их в файл DEF_Message.h. Файл имеет самую обычную простецкую структуру, ничего, кроме #define там нет.
#pragma once
// коды используемых сообщений, размер - byte
// system messages
#define msg_Empty 0x00
#define msg_Error 0x01
#define msg_Paint 0x02// user messages
#define msg_SecondTick 0x10 // секунда тикнула
#define msg_ReadMQ2 0x12 //читать данные с датчика MQ2
#define msg_MQ2Changed 0x13 // показания c MQ2 изменились
#define msg_ReadKey 0x14 // читать клавиатуру#define msg_KeyDown 0x20 // кнопка нажата
#define msg_KeyUp 0x21 // кнопка отпущена#define msg_VentON 0x22 // включить вытяжку
#define msg_VentOFF 0x23 // выключить вытяжкуПросто определяем числовые значения для всех используемых нами сообщений 0-255 (1 байт). Смотрим только, чтобы разные сообщения имели разные номера, иначе аяяй (будет всегда выполняться функция обработки первого сообщения)
первые 16 сообщений я выделил как системные, разницу между ними и другими расскажу позже.
Теперь о том, что есть сообщение. Сообщение, сопсно, это структура, содержащая код сообщения и два параметра типа int,
описана какstruct TMessage
{
public:
byte Message; // код сообщения, константа, описанная в DEF_Message.h
word LoParam; // два необязательных параметра, младший
word HiParam; // и старшийTMessage(); // конструктор, создает системное пустое сообщение msg_Empty
TMessage(byte msg, word loparam, word hiparam = 0); // конструктор. Полностью создает сообщение со всеми параметрами
TMessage(byte msg); // конструктор. создает сообщение с кодом msg и обоими параметрами равными нулюbool operator ==(TMessage msg); // переопределенный оператор сравнения. С другим сообщением
bool operator ==(PMessage msg); // с указателем на сообщение
bool operator ==(byte msg); // и просто с числом (с кодом сообщения) (для внутреннего использования)
};
Далее. Одно сообщение малоинтересно, нужно собрать их в очередь и по очереди обрабатывать.
Следующий класс, TMessageList, является агрегатором записей типа TMessagе, грубо говоря - массивом,
организованным в очередь, первым пришел - первым выйдешь (обработаешься). выглядит это кактотак:
class TMessageList
{
private:
PMessage *Items; // массив указателей на сообщенияbyte flength; // емкость очереди (максимальное число сообщений в очереди) задается в конструкторе
byte fcount; // счетчик сообщений, которые находятся в очереди
void DeleteFirst(void); // удалить первое сообщение, со сдвигом остальных вперед
bool FindMessage(PMessage msg); //проверить, есть ли такое сообщение в очереди
public:TMessageList(); // конструктор. По умолчанию максимальная ёмкость очереди - 16 сообщений
TMessageList(byte length); // а тут емкость можно задать самому (макс значение - 255, но память сломаеца гораздо раньше)bool Available(); // проверка, что очередь сообщений не пуста (fcount>0)
TMessage GetMessage(); // взять сообщение из очереди
bool Add(byte msg, word lo, word high); // добавить полностью описанное сообщение в очередь, с кодом и параметрами
bool Add(byte msg); // добавить в очередь сообщение с кодом msg и обоими параметрами == 0
bool AddEmpty(void); // добавить в очередь пустое сообщение (msg_Empty, 0, 0)
bool Paint(void); // добавить в очередь сообщение перерисовать экран (msg_Paint,0,0)
bool Error(int errornum); // добавить в очередь системное сообщение об ошибке, errornum - номер ошибки
// аналог Add(msg_Error, errornum, 0)
bool Error() { return Add(msg_Error); } // добавить в очередь системное сообщение об ошибке с обоими параметрами == 0byte Count(); // отдает число сообщений в очереди, которые ждут обработки
};
Например. В сетапе создаем таймер, который будет тикать раз в секунду (часы будем строить)
byte hour, minutes, seconds = 0; // глобальные переменные для времени
THandle hClockTimer;
void setup()
{
MessageList=new TMessageList(); // очередь глубиной 16 сообщений
TimerList.AddSeconds(tmrClock,1); // функция tmrClock будет вызываца 1 раз в секунду
}void tmrClock(void)
{
seconds++;
if (seconds<60) return; // так как мои часы показывают только часы и минуты, если меняются только секунды - выходим
seconds=0; minutes++;
if (minutes>59){minutes=0; hour++;};
if (hour>23) hour = 0;
MessageList.AddPaint(); // добавляем в очередь сообщение msg_Paint, экран надо перерисовать,
// потому что изменились показания часов или минут
}
Вот чем отличаются системные сообщения - для них у очереди сообщений есть специальные функции для быстрого помещения такого сообщения в очередьа в loop() начинаем крутить бесконечную карусель
void loop()
{if (NOT MessageList->Available()) return; // если очередь пуста - выходим
TMessage msg = MessageList->GetMessage(); // иначе - берем первое сообщение и обрататываемswitch (msg.Message)
{
case msg_Empty: break; // пустое сообщение, просто убираем его из очереди
case msg_Paint: evtPaint(); break; // перерисовать икранчег
case msg_MQ2Changed: evtMQChange(msg); break; // сигнал с датчика дыма
default: Serial << "Error in MessageList\n";
}
}
void evtMQChange(TMessage &msg)
{
if (msg.LoParam>250) Vent.On(); else Vent.Off(); // включить вытажку, если значение с дыма > 250
}void evtPaint()
{
// сопсно, здесь и перерисовываем экран
}
так как сообщения могут иметь параметры, можно в функцию обработки сообщения передавать эти параметры для последующей обработки. Ну и так как параметры имеют тип int, ничто не мешает передавать всё, что угодно, включая указатель (да! даже на класс) и приводить к нужному типу в обрабоччике.применение:
скачать 3 файла, 2 - h, 1 - срр.
бросить в папку с проектом, подключить хидеры.
обьявить глобально extern TMessageList *MessageList;
в сетапе написать MessageList = new TMessageList();
Если очередь планируеца больше 16 сообщений, написать MessageList = new TMessageList(ваше число);
дописать в DEF_Message.h коды ваших сообщений.
в функции срабатывания таймеров добавлять ваши сообщения MessageList->Add(msg_xxx, loparam, hiparam)
в loop() добавлять в оператор switch обработку своих сообщений через case msg_xxx: ..... break;Наслаждацца.
По вопросам пишите впочту [email protected] или на форумы amperka.ru и arduino.ru