
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進)が見えるものです。
予定通りの動作をしているようだね。

