| 記号 | タイトル | 作成日 |
| 0009 | RaspberryPi-Pico + freeRTOSで遊んでみる 「LCDを利用して出力する②改」 |
2026/01/01 |
先に掲載のコードをイベントキューを利用した一般的なプロセス間通信で実装してみた。
main.cpp以外に変更点はないので、main.cpp以外は先の掲載分をご参考ください。
挙動も同様なので、記載を割愛する。
【改良版main.cpp】main (CPP 4.26KB)
/*既存のsample04と挙動が同じだが
* プロセス間制御を適用してイベントキューにタッチイベントをエンキューして、それを定期的にデキューすることで、画面遷移するように改良した。
*
*/
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "pico/stdlib.h"
#include "LCD_driver.h"
// 【IPC仕様】プロセス間通信用キュー
QueueHandle_t xTouchQueue = NULL;
// 【排他仕様】SPIバス保護用セマフォ(Mutexの代わりに使用)
SemaphoreHandle_t xDisplaySemaphore = NULL;
// ---------------------------------------------------------
// Task 1: [P1] スキャナプロセス (20ms周期)
// ---------------------------------------------------------
void vScanTask(void *pvParameters) {
vTaskDelay(pdMS_TO_TICKS(2000));
printf("[T1] P1: Input Scanner Online\n");
int event_signal = 1;
bool last_state = false;
while (true) {
bool current_state = false;
// セマフォでバスを確保
if (xDisplaySemaphore != NULL && xSemaphoreTake(xDisplaySemaphore, portMAX_DELAY) == pdTRUE) {
current_state = is_touched();
xSemaphoreGive(xDisplaySemaphore);
}
// 変化点検知
if (current_state && !last_state) {
xQueueSend(xTouchQueue, &event_signal, 0);
}
last_state = current_state;
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// ---------------------------------------------------------
// Task 2: [P2]制御 & [P4]TFT描画 (1000ms周期)
// ---------------------------------------------------------
void vDisplayTask(void *pvParameters) {
printf("[T2] Initializing TFT...\n");
LCD_Driver lcd;
// 初期化をセマフォで保護
if (xDisplaySemaphore != NULL && xSemaphoreTake(xDisplaySemaphore, portMAX_DELAY) == pdTRUE) {
lcd.init();
lcd.drawHSBBackground();
xSemaphoreGive(xDisplaySemaphore);
printf("[T2] TFT Initialization Complete\n");
}
int total_count = 0;
int received_val;
printf("[T2] P2&P4: Display Controller Online\n");
while (true) {
vTaskDelay(pdMS_TO_TICKS(1000));
bool has_event = false;
while (xQueueReceive(xTouchQueue, &received_val, 0) == pdPASS) {
total_count++;
has_event = true;
}
if (has_event) {
printf("[P2] Control: Event Detected. Total Count = %d\n", total_count);
// 描画処理をセマフォで保護
if (xDisplaySemaphore != NULL && xSemaphoreTake(xDisplaySemaphore, portMAX_DELAY) == pdTRUE) {
update_hue_on_tap();
lcd.drawHSBBackground();
xSemaphoreGive(xDisplaySemaphore);
printf("[P4] TFT Draw Update Done\n");
}
}
}
}
// ---------------------------------------------------------
// Main
// ---------------------------------------------------------
int main() {
stdio_init_all();
sleep_ms(2000);
printf("\n====================================\n");
printf(" IPC Specification: Semaphore Model \n");
printf("====================================\n");
// 【IPC仕様】キュー作成
xTouchQueue = xQueueCreate(100, sizeof(int));
// 【修正】xSemaphoreCreateMutex がエラーになるため、
// バイナリセマフォを作成し、即座に Give して「空き」状態にする
xDisplaySemaphore = xSemaphoreCreateBinary();
if (xDisplaySemaphore != NULL) {
xSemaphoreGive(xDisplaySemaphore);
}
if (xTouchQueue != NULL && xDisplaySemaphore != NULL) {
xTaskCreate(vDisplayTask, "Display", 4096, NULL, 1, NULL);
xTaskCreate(vScanTask, "Scanner", 1024, NULL, 2, NULL);
printf("[Main] Starting Scheduler...\n");
vTaskStartScheduler();
}
while(1) {
tight_loop_contents();
}
}
// Hooks
extern "C" {
void vApplicationIdleHook(void) {}
void vApplicationTickHook(void) {}
void vApplicationMallocFailedHook(void) {
printf("[CRITICAL] Malloc Failed!\n");
for(;;);
}
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
printf("[CRITICAL] Stack Overflow in: %s\n", pcTaskName);
for(;;);
}
}