📜 ⬆️ ⬇️

Almost real-time OS: event-driven

A few words of introduction:
I make a control system based on AtMega32. The goal is to track the value of temperature and pressure sensors, load control and dump debug logs to a computer.

Plus screen 2x16 characters and a keyboard for 7 keys. The hardware used the ready - set NM8036 from MasterKita . But with the software part of the ambush: the standard algorithm, already stitched in the set, is primitive and universal, there are no source codes for the firmware, the updates are in encrypted form. I had to write myself.

Originally painted "fast and dirty" - just to work. Then the system evolved - the work algorithms became more complex, the interface grew, the number of parameters increased, there was a need to train another person to work with the system. Making a change without destroying the old code became harder and harder. Plus, some architectural flaws, laid down from the very beginning, made life very difficult.
')
In forums dedicated to microcontroller programming, I came across the mention of rtos, real-time operating systems. I read, downloaded a couple of freebies, tried it and made a decision: write my own.



The eternal question: why from scratch, and not to take ready. That is because ready-made universal systems become monstrous. There, as in a food processor, there is everything, but it does not bring joy. All the same I will use 10% of the pledged functions. And if so, why ship more?

So let's start with what is in the existing rtos and I do not need :

Thinking a little more, I settled on event-driven architecture (“events rule”).
For this I have introduced such entities:


Which immediately arises plus:
- a hardware interrupt handler dries up to a dozen instructions - create a specific event. Accordingly, there is no need to prohibit interruptions in critical sections - the delay due to interruptions rarely exceeds 1 microsecond, which is quite enough even with software implementation of 1-wire protocols.

So, for the cause. First, some structures:

#define maxHandlers 64
#define maxMessages 64
#define maxTimers 64

#define MSG_ADC_CYCLE 1
#define MSG_KEY_PRESS 2
#define MSG_KEY_REPEAT 3
#define MSG_LCD_REFRESH 4
#define MSG_BRESENHAM 5
#define MSG_MENU_SELECT 6
#define MSG_MENU_CANCEL 7
#define MSG_1W_TEMP 8
#define MSG_CHECK_TEMP 9
#define MSG_DISP_REFRESH 10
#define MSG_TIMER_SEC 11

typedef unsigned char msg_num; // -
typedef int msg_par; //
typedef unsigned char (*handler)(msg_par); // -

//
typedef struct {
msg_num msg; //
handler hnd; //
} iHandler;

//
typedef struct {
msg_num msg; //
msg_par par; //
} iMessage;

//
typedef struct {
msg_num msg; //
msg_par par; //
unsigned int time; // ( 10 )
} iTimer;

iTimer lTimer[maxTimers]; //
iHandler lHandler[maxHandlers]; //

iMessage lMessage[maxMessages]; //
unsigned int lMesPointer=0,hMesPointer=0; //

* This source code was highlighted with Source Code Highlighter .


Maybe I’ll break the first hundred rules for naming variables and functions. Well, do not kick hurt :)
Well, it has historically been the case that I call events as messages - as for me, so these entities in this system are equivalent.

We go further. Working with event handlers:
//
// : setHandler(MSG_KEY_PRESS, &checkKey);
void setHandler(msg_num msg, handler hnd) {
unsigned char i,j;
i=0; j=0;
while (i<maxHandlers) {
if (lHandler[i].msg==0) { //
lHandler[i].hnd = hnd; //
lHandler[i].msg = msg;
break ;
}
i++;
}
}

//
// : killHandler(MSG_KEY_PRESS, &checkKey);
void killHandler(msg_num msg, handler hnd) {
unsigned char i,j;
i=0; j=0;
while (i<maxHandlers) {

if ((lHandler[i].msg==msg) && (lHandler[i].hnd==hnd)) {
lHandler[i].msg = 0; // ,
}

if (lHandler[i].msg != 0) {
if (i != j) { // ,
lHandler[j].msg = lHandler[i].msg;
lHandler[j].hnd = lHandler[i].hnd;
lHandler[i].msg = 0;
}
j++;
}
i++;
}
}

* This source code was highlighted with Source Code Highlighter .


Work with events:

//
// : sendMessage(MSG_KEY_PRESS, KEY_MENU)
void sendMessage(msg_num msg, msg_par par) {
hMesPointer = (hMesPointer+1) & (maxMessages-1); //

lMessage[hMesPointer].msg = msg; //
lMessage[hMesPointer].par = par;
if (hMesPointer == lMesPointer) { // ,
lMesPointer = (lMesPointer+1) & (maxMessages-1);
}
};

//
void dispatchMessage() {
char i;
unsigned char res;

if (hMesPointer == lMesPointer) { // -
return ;
}

lMesPointer = (lMesPointer+1) & (maxMessages-1); //

msg_num msg = lMessage[lMesPointer].msg;
msg_par par = lMessage[lMesPointer].par;

if (msg==0)
return ;

for (i=maxHandlers-1; i>=0; i--) { //
if (lHandler[i].msg==msg) { //
res = lHandler[i].hnd(par); //
if (res) { // 1,
break ;
}
}
}
}

* This source code was highlighted with Source Code Highlighter .


And work with timers:
//
// : setTimer(MSG_LCD_REFRESH, 0, 50);
void setTimer(msg_num msg, msg_par par, unsigned int time) {
unsigned char i,firstFree;
firstFree = maxTimers+1;
if (time == 0) {
sendMessage(msg, par);
} else {

for (i=0; i<maxTimers; i++) { //
if (lTimer[i].msg == 0) {
firstFree = i;
} else { // -
if ((lTimer[i].msg == msg) && (lTimer[i].par == par)) {
lTimer[i].time = time;
return ;
}
}
}
if (firstFree <= maxTimers) { // -
lTimer[firstFree].msg = msg;
lTimer[firstFree].par = par;
lTimer[firstFree].time = time;
}
}
}

//
// - ,
//
void killTimer(msg_num msg) {
unsigned char i;
for (i=0; i<maxTimers; i++) {
if (lTimer[i].msg == msg) {
lTimer[i].msg = 0;
}
}
}

//
void dispatchTimer() {
unsigned char i;
msg_num msg;
msg_par par;

for (i=0; i<maxTimers; i++) {
if (lTimer[i].msg == 0)
continue ;

if (lTimer[i].time == 0) { //
msg = lTimer[i].msg;
par =lTimer[i].par;
lTimer[i].msg = 0;
sendMessage(msg, par); //
} else {
lTimer[i].time--; //
}
}
}

* This source code was highlighted with Source Code Highlighter .


Oddly enough, this is enough for further easy development of the application. Well, about this - further. :)

Source: https://habr.com/ru/post/58366/


All Articles