紹介の言葉:
AtMega32に基づいて制御システムを作成します。 目標は、温度および圧力センサーの値を追跡し、負荷管理を行い、デバッグログをコンピューターにリセットすることです。
さらに、2x16文字の画面と7キーのキーボード。 ハードウェアは完成したものを使用しました
-MasterKitaのNM8036のセット。 しかし、待ち伏せのソフトウェア部分では、すでにセットでフラッシュされている標準アルゴリズムは原始的で普遍的であり、ファームウェアのソースコードはありません。更新は暗号化された形式で行われます。 私は自分で書かなければなりませんでした。
当初、彼は「素早く、汚い」絵を描きました-ただ働くために。 その後、システムが進化しました-作業アルゴリズムがより複雑になり、インターフェースが拡大し、パラメーターの数が増加し、システムの操作方法を他の人に教える必要性が現れました。 古いコードを壊さずに変更を加えることは、ますます難しくなりました。 さらに、最初から築かれたいくつかの建築上の欠陥により、生活は非常に困難になりました。
マイクロコントローラのプログラミング専用のフォーラムで、リアルタイムオペレーティングシステムであるrtosについて言及しました。 私は読んで、いくつかの無料のものをダウンロードし、試して決定しました:自分で書いてください。
永遠の質問:なぜゼロから、そして完成したものではありません。 既製のユニバーサルシステムが巨大になるためです。 そこには、フードプロセッサーのように、すべてがありますが、それは喜びをもたらしません。 それでも同じように、組み込み関数の10%を使用します。 もしそうなら、なぜもっと出荷するのですか?
それでは、既存のrtoの内容から始めましょう。
必要ありません 。
- プリエンプティブマルチタスク(コンテキストの保存と切り替えのための多くのリソース);
- マルチスレッド(私はすべてのタスクを開発していますが、クリスタルリソースはそれほど多くありません。したがって、この開発における孤立したフローは複雑なものです)。
- 優先タスクのシステム(あまり多くのタスクではなく、反応時間にそれほど重要ではない);
- 保証された応答時間(まったく必要なかったわけではありませんが、タスクはほとんど時間的に気取られません。主なことは処理されることです)。
もう少し考えた後、彼はイベント駆動型アーキテクチャ(「イベントルール」)に落ち着きました。
このため、次のエンティティを導入しました。
- イベント(メッセージ):タイマーによって、または直接対応する関数を呼び出すことによってトリガーできます。
- イベントハンドラ:イベントが発生したときに呼び出される関数。 1つのイベントで複数のハンドラーをハングさせることができ、それらは順番に呼び出されます。
- タイマー:タイマーを有効にすると、指定したイベントが1回生成されます。
- メッセージキュー:FILOリングメッセージバッファ。
- タイマーマネージャー:タイマーの中断時に呼び出される関数。
- イベントディスパッチャ:メインループでスピンする関数。
すぐに生じるプラス:
-ハードウェア割り込みハンドラーは、1ダースの命令まで乾燥します-特定のイベントを作成します。 したがって、クリティカルセクションで割り込みを禁止する必要はありません。割り込みによる遅延が1マイクロ秒を超えることはほとんどありません。これは、1-wireなどのプロトコルのソフトウェア実装でも十分です。
だから、ポイントに。 まず、いくつかの構造:
#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 .
おそらく、変数と関数の命名に関する最初の100の規則を破るでしょう。 まあ、あまり傷つけないでください:)
まあ、それは非常に歴史的に発展してきたので、私はイベントメッセージと呼んでいます-私にとっては、このシステムのこれらのエンティティは同等です。
さらに進んでいます。 イベントハンドラーの操作:
//
// : 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 .
イベントを操作する:
//
// : 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 .
そして、タイマーを操作します。
//
// : 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 .
奇妙なことに、これでアプリケーション開発がさらに簡単になります。 それについては後で詳しく説明します。 :)