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を使ってしまいました。モッタイナイ、でも接続お楽なんだもの。
なお、どちらのボードにも描いてないですが、ホスト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を使えるので、以下のようにしています。「中継」しているだけね。
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という具合に「シーザー暗号」的な動作で返ってきます。
そのときのNUCLEO F446REのUSBシリアルの様子が以下に。こちらはメインループの中で毎秒、ループカウンタと割り込みハンドラで処理した最後の文字の文字コード(10進)が見えるものです。
予定通りの動作をしているようだね。