組み込みシステムの代替スレッド
私は現在、電気工学を勉強しています。パンデミックのため、クラスは中断されました。今回は、電子機器とプログラミングについて詳しく学びます。
私は現在、Pic16f628a
と一般的なデジタルディスプレイを使用して、いくつかの機能を備えたデジタル時計を構築しようとしています。時計が表示されている間に、実行時にボタンを押してメニューにアクセスしなければならなかったということです。通常、私は時計表示用のスレッドを呼び出し、メインスレッドは入力を監視しますが、PICコントローラーの単純さのためにリソースを使用できません。
したがって、私のCコード(まだpicに特別に実装されていません)は次のようなものです。
void display_timer(){
static struct current_time timer;
static int is_time_set = 0;
set_current_time(&timer, &is_time_set);
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
sleep(1);
update_timer(&timer, &is_time_set);
}
}
int main ()
{
while (1){
display_menu();
}
}
sleep()の間、コントローラーは新しい入力を監視し、それに応じて動作できる必要があります。
しかし、私が行った代替案の1つは、ステートマシンを使用してボタンの押下を保存し、スリープ機能を4つまたは8つの間隔に分割することでした。
while (is_time_set){
system("clear");
printf("########\n");
printf("%d:%d:%d\n", timer.HOURS, timer.MINUTES, timer.SECONDS);
printf("########\n");
for (int i = 0; i<8; i++){
if (state_machine_input == 1){state_machine_input = 0; break;}
sleep(1/8);
}
update_timer(&timer, &is_time_set);
それは可能ですが、たとえば別のステートマシンを追加するなど、プロジェクトをさらに複雑にする必要がない場合はありがたいです。この機能を実装するために、ソフトウェアのサームで何ができますか?
回答
スレッド化は、マイクロコントローラープログラミングよりも高いレベルの概念です。簡単に言えば、スレッドはタイマー割り込みを使用するスケジューラーとして実装されます。これにより、プログラムカウンターとスタックポインターなどが保存され、それらが別の場所に設定されます。したがって、割り込みを使用して同様の概念を実装することは非常に可能で簡単です。一般的なマルチスレッドの代わりに特殊な割り込みを取得できるという利点があります。
これは、スタックの使用に関しては非常に制限されているPICのような制限されたレガシー8ビターでそれを行うための唯一の賢明な方法です。マイクロコントローラー用に作成されたものであっても、スレッドライブラリの使用を忘れてください。それは、何も得られずに、過度の膨満感と複雑さを追加するだけです。PCプログラミングの概念を組み込みの世界に引きずり込むことは一般的に悪い考えです。
あなたがしなければならないことは、ボタンスキャンを10msかそこらに一度実行される周期的なタイマー割り込みの中に置くことです。デバウンスの目的で、割り込みの内側からボタンをポーリングし、読み取ったボタンを前のボタンと比較します。この結果は、メインプログラムと共有される変数に格納され、volatile
競合状態として宣言され、競合状態から保護されます。割り込みの内部からのみ変数に書き込むため、読み取りが8ビットであることを確認するのに十分な保護である可能性がありますが、確実に逆アセンブルする必要があります。詳細については、組み込みC開発でのvolatileの使用をご覧ください。
割り込みを使用する
ボタンを押したときにコードを実行したいですか?ピン変更割り込みを使用する
あなたは一定の間隔で何かをしたいですか?タイマー割り込みを使用する
ある意味で、マイクロコントローラのハードウェアは、割り込みソースを監視する「スレッド」を実行し、各イベントに対して「コールバック」または割り込みルーチンを実行します。
メインプログラムは、割り込みの実行中に自動的に一時停止します。
割り込みとメインコード間でデータを共有する一般的な方法は、volatile
グローバル変数を使用し、これらのグローバルからデータを読み取るときに、コントローラーのワードサイズ(ほとんどの場合8ビットコントローラー)を超えると、割り込みを一時的に無効にすることです。
私はおそらく協調マルチタスクライブラリを提案するでしょう。私が過去に使用したものはProtothreadsです:http://www.dunkels.com/adam/pt/
適切な協調マルチタスクライブラリは、物事を追跡するために必要な暗黙のステートマシンを抽象化するのに役立ちます。
幸運を。
組み込みシステムに関しては、マルチタスクには一般的にさまざまなアプローチがあります。
- ポーリングまたは協調マルチタスク:すべてが1つの無限ループで実行され、タスクは、遅延を回避するために、可能な限り最小の時間を取り、可能な限り高速にメイン実行に戻るように設計されています。このアーキテクチャに適したタスクは、高レベルの概念の観点から考えるものではない場合があることに注意してください。たとえば、アプリケーションでは、あるタスク
update_display
と別のタスクがありcheck_button
、次のようなループを構築します。
while(1){
check_buttons();
update_display();
sleep(0.1); //seconds
}
割り込み:ハードウェア割り込みに接続されたすべての可能な入力とメイン実行は、割り込みをかけることができないもののために残されます(何もない場合があります。その場合、通常、マイクロコントローラーは電力消費を削減するためにスリープモードになります。これの詳細通常、実行されるのは、使用する特定のマイクロコントローラーとコンパイラーによって異なります。
RTOS:マイクロコントローラーが提供する電力の量によっては、リアルタイムオペレーティングシステム(RTOS)を実行できる場合があります。RTOSは、タスクやスレッドを作成するためのAPIを提供する場合があります。これは、アプリケーションとハードウェアの機能によって異なります。教育的な例では、必要ないはずです(または、推奨されます)。
また、アプリケーションの全体的なアーキテクチャを決定する際のもう1つの重要な部分は、タスクの分割とそれらの連携方法であることも考慮してください。使用されるパラダイムの1つはステートマシンです(リンクは、圧倒される可能性のある一般的なウィキペディアページへのリンクであり、組み込みプログラミングに固有のより単純なリソースは、教科書またはGoogleにあります)。
ほとんどの場合、8ビットデバイスではソースが制限されています。8ビットPICでは、単純なソリューションの方が優れたソリューションだと思います。
2つの異なるタスク用のハードウェアタイマーを作成できます。フラグを設定し、無限ループでフラグを確認し、タスクを実行してフラグをリセットします。遅延を使用しないでください。このメソッドは、フラグが立てられた場合に、無限ループでタスクを実行することを保証します。
ただし、フラグが立てられた正確な時間にタスクが実行されないことを知っておく必要があります。2つのフラグが同時に設定されている場合、どちらが最初に実行されるかを知ることはできません。無限ループのどこにあるのかわからないからです。ただし、タイムクリティカルではないインターフェイスアプリケーションの場合はほとんど問題ありません。