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

Joseph Halfmoon

別シリーズにてAD22100、電圧出力型温度センサを練習。-50℃から+150℃という広い温度範囲で装置の温度を簡単にモニタできる優れものです。規定の温度範囲を超えたらファンを回すとかいろいろ使えそう?今回は前回作成した「OLED表示」をお願いするだけのタスクの一方を温度監視タスク的な雰囲気にしてみます。

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

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

AD22100

アナデバAD22100を練習してみた別シリーズ記事は以下です。

お手軽ツールで今更学ぶアナログ(172) AD22100、電圧出力温度センサで温度を測定

AD22100はいくつかパッケージの種類があり、今回使用しているのは「ディスクリートのトランジスタみたい」なTO-92パッケージ品です。

今回実験の回路

前回のOLED表示の回路の横にAD22100を取り付けただけの回路です。ただね、ホントはAD22100の出力にはLPF入れた方が良いみたい。今回は入ってないケド。AD22100DUT_Schematic

回路図はシンプルなのに現物回路がゴタゴタしているのは、以前にも使ったテストJIG基板の傍らにAD22100の差し込み口を設けたため。ちょいと半田付けするだけで老眼の年寄は疲れます。UNO_R4_AD22100_DUT_EC

今回実験のソースコード

Arduino式(.ino形式「スケッチ」)ソース全文が以下に。前回のソースの「チョイ変」っす。Task2を温度監視用ということで、AD22100の出力を見張り、測定した電圧を摂氏温度に変換してOLEDに表示しているだけ。「現実のアプリ」であれば、ある温度を超えたら動作停止してファンを回して冷やすとか、あるいはヒータ入れるとか制御するのだろうけれども、今回は数字を表示するだけ。

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

#define AWAITMAX1  (1000)
#define AWAITMAX2  (2000)

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

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

int ad22100pin = A3;
int ad22100val = 0;

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;
  }
  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 (xQueueSend(msgQueue2, (void*)&msg2, 2) != pdTRUE) {
      ecount++;
    }
    vTaskDelay(AWAITMAX2);
  }
}
実機動作確認

現物写真のように、OLEDに室温らしきものが表示されております。

今回は、Arduino UNO R4のArduino環境のデフォルト設定ということで、頭から電源5V、ADのレゾリューションは10bitということで以下の換算式を作りました。

-(562650-2000*AREAD)/9207

AREADはanalogRead()で読み出せる10ビット整数値です。結果は℃です。AD22100は手元での調整不要で十分な精度、リニアリティがありそうな仕様ですが、電源電圧が変動するとそれなりに影響受けるみたいなので、現物の電圧とか確かめて定数など決定した方が良いかもです。

モダンOSのお砂場(78)UNO R4でFreeRTOS、Task発Queue経由OLED行 へ戻る

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