本投稿では
FreeRTOS の Queue を使って、
- ボタン状態取得タスク
- LED 表示タスク
の間でタスク間通信を行い、ボタンを押下でON、解放でOFFするようなファームウェアを作成してみる。
環境
- IDE:e2studio
- ボード:RX72N Envision Kit
- コンパイラ:CC-RX(ツールチェーン Renesas CC-RX v3.07.00)
作業開始
まず、前回の作業を参考に、プロジェクト作成までは完成させておく。
https://qiita.com/yt1114/items/07f08d55bebd5efc71bf
1. Queue の追加
下図のように、FreeRTOS_Object の Queue タブを開き+を押下する。
すると、queue_handle_1という名前のハンドラができる。作成したときはキューの長さが100になっているが今回は気にしなくてよい。(正直言って、今回は1にしても動く)

2. タスクの作成
冒頭でお話しした、ボタン状態取得タスク(BTN_TASK)とLED表示タスク(LED_TASK)を追加する。

タスクを追加したら、コード生成を行う。すると、下記のように.cファイルができる。
3. 各タスク内の処理
BTN_TASK (送信側)
ボタンの状態を取得するタスク。
5msの周期で実行するように、vTaskDelayUntilを入れる。
また、キューに5ms周期で状態を毎回送るのはあまり気持ちとして良くないので、ボタンの状態が変わった時だけ送るようにした。
void button_task(void * pvParameters)
{
/* Start user code for function. Do not edit comment generated here */
TickType_t xLastWakeTime; // 最後にタスクが実行された時刻を記録する変数
const TickType_t xPeriod = pdMS_TO_TICKS(5); // 周期を500ミリ秒に設定
uint8_t current_state, previous_state = 1;
xLastWakeTime = xTaskGetTickCount();
extern QueueHandle_t queue_handle_1;
while(1)
{
// xPeriodの間隔でタスクが実行されるように待機
vTaskDelayUntil( &xLastWakeTime, xPeriod );
// ボタン状態を読み取る
current_state = PORT0.PIDR.BIT.B7;
// 状態が変化した場合、キューに送信
if (current_state != previous_state)
{
// 第1引数:キューハンドル
// 第2引数:キューに入れたい値
// 第3引数:キューが満タンの時に空きができるまで待機する時間(ブロッキング)
if (pdPASS == xQueueSend(queue_handle_1, ¤t_state, 0)) {
// もしキューが満タンでタイムアウトすれば、戻り値はpdFAIL
previous_state = current_state; // 現在の状態を保存
}
}
}
/* End user code. Do not edit comment generated here */
}
LED_TASK (受信側)
BTN_TASK から送られてきたボタンの状態をキューから取り出し、押下されているときはLEDをONにする。離されているときはLEDをOFFにする。
void led_task(void * pvParameters)
{
/* Start user code for function. Do not edit comment generated here */
uint8_t button_state;
extern QueueHandle_t queue_handle_1;
while (1)
{
// キューにメッセージが届くまでタスクをブロックする
// 第1引数:キューハンドル
// 第2引数:キューから取り出した値を入れる変数。
// 第3引数:キューからデータを取り出せるようになるまで待機する時間(ブロッキング)
if (xQueueReceive(queue_handle_1, &button_state, portMAX_DELAY) == pdPASS)
{
// メッセージ受信成功
if (button_state == 1) // ボタンが押された
{
// LEDを点灯
PORT4.PODR.BIT.B0 = 1;
}
else // ボタンが離された
{
// LEDを消灯
PORT4.PODR.BIT.B0 = 0;
}
}
}
/* End user code. Do not edit comment generated here */
}
結果
このように1つのモジュールに対して1つのタスク、というふうにコードを作っていけば、
タスク間通信もでき、簡単にできていきそうな気もする。
が、タスクが乱立するとそれはそれで、設計上よくないはず…これから勉強していくなかでより良い設計とは何ぞやというものを習得していこうと思う。
次回
RX72NとPCで通信を行い、メッセージでLEDをチカチカさせたい。
メッセージを受け取るのは、FITのSCIモジュール(ASYNCモード)で行う。受け取った情報(バイト列)はSCIモジュールのFIFO(R_BYTEQ)に格納される。
これを処理するために、「UART受信割込み」と「通信制御タスク」の2つ通信を行い、「LEDタスク」に情報を伝えて、点滅などさせるようにしたい。

