モダンOSのお砂場(80)UNO R4でFreeRTOS、規定温度越えたらブザーを鳴らす

Joseph Halfmoon

前回AD22100温度センサで「温度監視」。といいながら温度をOLEDに表示するだけでお茶を濁してました。何か監視した結果っぽいアクションを起こしたいデス(形だけですが。)そこでブザー(パッシブ型)を接続、規定温度を超えたらブザーを鳴らして警告するようにしてみました。タスク間の通知にNotification使用。

※「モダンOSのお砂場」投稿順Indexはこちら

※Arduino IDE上で「スケッチ」形式のソースからFreeRTOSを使って実験してみてます。ターゲット機はArduino UNO R4 Minima。泣く子も黙る?ArmコアのルネサスRA4M1マイコン搭載機です。

ブザー(Passive)

手元にはActive型、Passive型ともに圧電ブザーの在庫あり。どっちを使用かと迷ったのですが、別シリーズの以下の回で「Groveモジュール」化されたPassive型ブザーを使ってました(自分のやったことなのに年寄には記憶なく、検索してみつけましたぞ。忘却力。)

部品屋根性(27) ActiveブザーとPassiveブザー

Groveコネクタから配線引き出し用のコネクタ付ケーブルを相当昔に自作してあるので、Groveコネクタ付のモジュールは接続がお楽。接続は電源、グラウンドとSIGの3端子。Passive型なので、PWMなど使ってテキトーな波形をSIG端子に印加しないと鳴りませぬ。

今回実験の回路

前回の回路にPassive型ブザーモジュールを追加しただけです。UNO R4はArduino UNO3と互換性通りの端子にPWM可能な信号が出ているので、D6端子で制御することにいたしました。UNOR4_Buzzor_Schematic

 

今回実験のソースコード

Arduino式(.ino形式「スケッチ」)ソース全文が以下に。いつもの通り、前回ソースの「チョイ変」です。Task3というタスクを追加して、これをブザーの制御に割り当てました。Task3は、

    1. 誰か他のTaskからNotificationが到来するのを待つ(Take)
    2. Nortificationが到来するとブザーを3秒ならす
    3. その後、Notification待ちに戻る

上記だけのタスクです。一方前回温度センサを監視するお役目を与えたTask2には、前回同様の以下の1だけでなく、2のお仕事も与えました。

    1. 測定した温度をOLED表示タスクにQueue経由で送る
    2. 測定した温度が40℃を超えたらブザーが鳴るようにTask3にNotificationをGiveする。

なお、Arduino環境の場合、PWM波形はanalogWrite()関数で簡単に出力できるのでお楽(周波数はキメウチだけれども。)

ソースが以下に。

#include <Arduino_FreeRTOS.h>
#include <U8x8lib.h>

#define AWAITMAX1  (1000)
#define AWAITMAX2  (2000)
#define BuzzorON (128)
#define BuzzorOFF (0)
#define BuzzorWait (3000)

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE); 	      

TaskHandle_t oled_task, task1, task2, task3;
const uint8_t queueSize = 1;
QueueHandle_t msgQueue1, msgQueue2;
int msg1, msg2;

int ad22100pin = A3;
int ad22100val = 0;
int buzzor = 6;

int getTemperature() {
  ad22100val = analogRead(ad22100pin);
  return -(562650-2000*ad22100val)/9207;
}

void setup()
{
  Serial.begin(115200);
  while (!Serial) { }
  u8x8.begin();
  u8x8.setPowerSave(0);

  msgQueue1 = xQueueCreate(queueSize, sizeof(int));
  msgQueue2 = xQueueCreate(queueSize, sizeof(int));
  auto const rc_oled = xTaskCreate (
      oled_thread_func, static_cast<const char*>("OLED Thread"), 512 / 4, nullptr, 1, &oled_task
    );
  if (rc_oled != pdPASS) {
    Serial.println("Failed to create 'OLED' thread.");
    return;
  }
  auto const rc_task1 = xTaskCreate (
      task1_func, static_cast<const char*>("Task1"), 512 / 4, nullptr, 1, &task1
    );
  if (rc_task1 != pdPASS) {
    Serial.println("Failed to create 'task1' thread");
    return;
  }
  auto const rc_task2 = xTaskCreate (
      task2_func, static_cast<const char*>("Task2"), 512 / 4, nullptr, 1, &task2
    );
  if (rc_task2 != pdPASS) {
    Serial.println("Failed to create 'task2' thread");
    return;
  }
  auto const rc_task3 = xTaskCreate (
      task3_func, static_cast<const char*>("Task3"), 512 / 4, nullptr, 1, &task3
    );
  if (rc_task3 != pdPASS) {
    Serial.println("Failed to create 'task3' thread");
    return;
  }
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  u8x8.setInverseFont(1);
  u8x8.drawString(0,0,"TASK->OLED");
  u8x8.setInverseFont(0);
  u8x8.drawString(0,1,"TASK1: ");
  u8x8.drawString(0,2,"TEMP : ");
  Serial.println("Starting scheduler ...");
  vTaskStartScheduler();
  for( ;; ); /* Never! */
}

/* NEVER CALLED! */
void loop()
{
  Serial.println(millis());
  vTaskDelay(configTICK_RATE_HZ);
}

void oled_thread_func(void *pvParameters)
{
  char buf[16];
  int ts1, ts2;
  while (1) {
    if (xQueueReceive(msgQueue1, (void *)&ts1, 0) == pdTRUE) {
      sprintf(buf, "%d", ts1);
      u8x8.drawString(7,1,buf);
    }
    if (xQueueReceive(msgQueue2, (void *)&ts2, 0) == pdTRUE) {
      sprintf(buf, "%d", ts2);
      u8x8.drawString(7,2,buf);
    }
    sprintf(buf, "%d", ad22100val);
    u8x8.drawString(0,3,buf);
    u8x8.refreshDisplay();
    taskYIELD();
  }
}

void task1_func(void *pvParameters)
{
  int count = 0;
  while (1) {
    msg1 = count;
    if (xQueueSend(msgQueue1, (void*)&msg1, 2) == pdTRUE) {
      count++;
    }
    vTaskDelay(AWAITMAX1);
  }
}

void task2_func(void *pvParameters)
{
  int ecount = 0;
  while (1) {
    msg2 = getTemperature();
    if (msg2 > 40) {
      xTaskNotifyGive(task3);
    }
    if (xQueueSend(msgQueue2, (void*)&msg2, 2) != pdTRUE) {
      ecount++;
    }
    vTaskDelay(AWAITMAX2);
  }
}

void task3_func(void *pvParameters)
{
  while (1) {
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
    analogWrite(buzzor, BuzzorON);
    vTaskDelay(BuzzorWait);
    analogWrite(buzzor, BuzzorOFF);
  }
}
実機動作確認

以下写真のAD22100付近に、ドライヤーで熱風を吹きかけました。UNOR4_buzzor_DUT

OLEDに表示される温度はぐんぐん上昇します。40℃超えた、60℃近いのだけれど、Buzzorの音が聞こえんぜよ。

ドライヤーを止めたらブザーの音が聞こえました。

なんだドライヤーの音が大きくてブザー音がかき消されてたのね。大丈夫か耳も悪くなってないか。

モダンOSのお砂場(79)UNO R4でFreeRTOS、AD22100で温度監視? へ戻る

モダンOSのお砂場(81)UNO R4でFreeRTOS、第2のUARTで指令を送る(だけ) へ進む