モダンOSのお砂場(91) ArduinoとNucleo(Mbed OS6)間シリアル通信

Joseph Halfmoon

Arduino APIと比較しながらArm純正RTOS、Mbed OS6の入出力API群を練習中。前回はUARTといいつつ自分に送信するループバック試験。今回は「通信」らしくお相手Arduino UNO R4と接続してみます。また前回はBufferedSerialでしたが、今回はUnbefferedSerialを使用。

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

今回実験の回路

今回はMCUの開発ボード、小さいとは言え2個使いなのでチョイとメンドイです。

    • NUCLEO-F446RE、Mbed OS6。オンライン開発環境 Keil Studio Cloudで開発。
    • Arduino UNO R4、Arduino環境、Arduino IDE 2.3.2で開発。

また、Arduino UNO R4のIO電圧は5V、NUCLEO-F446REは3.3Vなので、その繋ぎにFXMA108を使ってしまいました。モッタイナイ、でも接続お楽なんだもの。

現物写真が以下に。DUT20240513

ざっくりした回路図が以下に。Nucleo_Arduino_schematic

なお、どちらのボードにも描いてないですが、ホストPCとはUSBで接続されており、USBシリアルを通じてホストと通信も可能。全体構成はこんな感じ。

ホストPC <ーUSBシリアルー> UNO R4  <ーシリアルー> NUCLEO <ーUSBシリアルー> ホストPC

ホストPC上のシリアルモニタからUNO R4に送った文字をNUCLEOにそのまま転送し、NUCLEO側でチョイと加工してUNO R4に返信、UNO R4はNUCLEOから受け取った文字をそのままホストPCに報告します。なお、「チョイと加工」は、大文字のAからZを受け取ったらAならBという感じに次の文字に変換して送り返す(Zの場合はAに戻る)だけです。

Arduino UNO R4側の対向機の制御ソフト

UNO R4はUSBシリアル以外にもうひとつUARTを使えるので、以下のようにしています。「中継」しているだけね。UnoR4PGM

NUCLEO F446RE側のソフト(Mbed OS6)

大分以前の回から「継ぎ足し継ぎ足し」してきているコードが以下に。今回の追加部分は UnbufferedSerial APIに関わる部分で、以下のファイル内におさまってます。なお、 UnbufferedSerial の受信受けは前回のようなポーリングではなく、割り込みを使ってます。

#include "mbed.h"
#include "AQM0802.h"
#include "MYSTAT.h"

#define BLINKING_RATE   500ms
#define AIN_RATE        1000ms
#define AOUT_RATE        100ms
#define MAXIMUM_BUFFER_SIZE (32)

I2C i2c(I2C_SDA, I2C_SCL);

AQM0802 lcd(i2c);  

DigitalOut ledRED(ARDUINO_UNO_D2);
Thread threadLED;

AnalogIn ain5(ARDUINO_UNO_A5);
Thread threadAIN5;

PwmOut pwmD3(ARDUINO_UNO_D3);

AnalogOut ao2(ARDUINO_UNO_A2);
Thread threadAOUT2;

UnbufferedSerial uart4(ARDUINO_UNO_A0, ARDUINO_UNO_A1, 9600);
char X = 0;

void on_rx_interrupt()
{
    char c;
    if (uart4.read(&c, 1)) {
        X = c;
        if ((c >= 65) && (c <= 90)) {
            c = (c==90) ? 65 : c + 1;
        }
        uart4.write(&c, 1);
    }
}

void blink_thread()
{
    while (true) {
        ledRED = !ledRED;
        ThisThread::sleep_for(BLINKING_RATE);
    }
}

void ain_thread()
{
    char dstr[8];
    while (true) {
        sprintf(dstr, "%u", ain5.read_u16());
        lcd.displaySTR(LCD_LLINE, dstr);
        ThisThread::sleep_for(AIN_RATE);
    }
}

void aout_thread()
{
    while (true) {
        ao2 = 0.1f;
        ThisThread::sleep_for(AOUT_RATE);
        ao2 = 0.2f;
        ThisThread::sleep_for(AOUT_RATE);
        ao2 = 0.3f;
        ThisThread::sleep_for(AOUT_RATE);
    }

}

int main()
{
    lcd.init();
    lcd.displaySTR(LCD_HLINE, "Voltage");

    pwmD3.period_us(2041);
    pwmD3.pulsewidth_us(64);
    
    threadLED.start(blink_thread);
    threadAIN5.start(ain_thread);
    threadAOUT2.start(aout_thread);

    uart4.attach(&on_rx_interrupt, SerialBase::RxIrq);
    uart4.enable_output(true);
    uart4.enable_input(true);

    int count=0;
    while (true) {
        printf("Running %d: X=%d\n", count++, X);
        ThisThread::sleep_for(1000ms);
    }
}
実機動作の確認

まずArduino側のシリアルモニタの様子です。Arduino IDE付属のシリアルモニタは上部の入力行に1行入力してリターンキーを押すと、入力文字に続けてCR、LFを送り出す動作をします。以下では一文字入力してはリターンキーを押してます(リターンキーを押すと入力行が消去されます。)返信は下の領域に順次表示されます。小文字のa b c や数字の0 1 2 などはそのままの文字が返ってくるだけですが、大文字のAなど入力するとBという具合に「シーザー暗号」的な動作で返ってきます。
UnoR4Side

そのときのNUCLEO F446REのUSBシリアルの様子が以下に。こちらはメインループの中で毎秒、ループカウンタと割り込みハンドラで処理した最後の文字の文字コード(10進)が見えるものです。NucleoSide

予定通りの動作をしているようだね。

モダンOSのお砂場(90) NucleoでArduinoからMbed OS6、シリアル通信 へ戻る