開発環境を Mbed Online Compilerから Keil Studio Cloud に移行中です。ついでにMbed OS2の古いソースもOS6へ移行予定。前回はUARTで移行を試行、コマケー違いで引っかかりました。今回はI2CでOS2->OS6をやってみたいと思います。ターゲットはAQM1602液晶。
※「モダンOSのお砂場」投稿順Indexはこちら
Keil Studio Cloud環境でMbed OS2が使えないわけではないのです。しかし前回も見たようにOS2時代のAPIの中にはもはや廃止されたものもあり、せっかくKeil Studio Cloudを使うのであれば、Mbed OS6に移行するというもんではないかと思いました。
今回はI2CインタフェースでAQM1602液晶を接続するプログラムの移行を試してみたいと思います。相当以前に「Mbed OS2、Mbedオンラインコンパイラ、Nucleo F072RBボード」という組み合わせでプログラムを動かしていました。記事が以下に。
IoT何をいまさら(14) 工作1、LCDで表示、AQM1602XA
今回は、上記を以下の組みあわせに変えて動作させてみます。
Mbed OS6、Keil Studio Cloud、Nucleo F401REボード
なお、Mbed OS v6.15 のI2C関係のAPIのページは以下です。
OS6の空プロジェクトの中にOS2用ソースをぶち込む
Keil Studio Cloud上で、OS6 の empty project を作成し、OS2用の以下のソースファイルを配置してみました。
-
- main.cpp
- AQM1602.h
- AQM1602.cpp
配置した瞬間に Keil Studio Cloudはエラーを検知、赤の波線、黄色の波線多数が現れます。main.cppではこんな感じ。
検出されたエラーとその対処方針
検出されたエラーをまとめると以下のようです。
-
- LED2 … 定数不在
- Serial … クラス無
- wait … 関数無
- wait_ms … 関数無
意外と少ないじゃん。それにI2CのAPIにかかわるところは無いし。対処方針は以下のようにしてみます。
-
- LED2はLED1にする
- Serialクラスは不要、USBシリアルなので単に printfとする
- waitは ThisThread::sleep_for() で置き換える
- wait_msも ThisThread::sleep_for() で置き換える
エラーの赤の波線だけではなかったです。黄色の警告もあり。以下を御覧じろ。
C++11では、以下のようなズボラな書き方すると怒られるみたいっす。ズボラなのはdisplaySTRの第2引数に const がついてないからです。
lcd.displaySTR(LCD_HLINE, "Hello World!");
そこで、displaySTR関数の定義とプロトタイプ宣言の第2引数に const をつけました。すると黄色波線も消滅。
Keil Studio Cloudになってコンパイラの設定も変わっているようなので、ちゃんと「近代化」しないとなりません。
OS6化したソース
まずは AQM1602.h ヘッダファイル。
#ifndef AQM1602_H #define AQM1602_H #include "mbed.h" #define LCD_ADDR (0x7c) #define LCD_HLINE (0x80) #define LCD_LLINE (0xC0) #define LCD_MAXLEN (16) class AQM1602 { private: I2C& i2cRef; char wdata[2]; int status; public: AQM1602(I2C& ch); int writeCommand(char cmd); int writeData(char dat); int clear(); int displaySTR(char Lin, const char* message); int init(); }; #endif //AQM1602_H
続いて AQM1602クラスのメソッド群、AQM1602.cpp。
#include "AQM1602.h" AQM1602::AQM1602(I2C& ch) : i2cRef(ch) { wdata[0]=0; wdata[1]=0; } int AQM1602::writeCommand(char cmd) { status =0; wdata[0] = 0x0; wdata[1] = cmd; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); return status; } int AQM1602::writeData(char dat) { status =0; wdata[0] = 0x40; wdata[1] = dat; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); return status; } int AQM1602::clear() { status =0; wdata[0] = 0x0; wdata[1] = 0x01; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); return status; } int AQM1602::displaySTR(char Lin, const char* message) { int idx = 0; status =0; wdata[0] = 0x0; wdata[1] = Lin; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); wdata[0] = 0x40; while ((status == 0) && (idx < LCD_MAXLEN) && (*message != 0)) { wdata[1] = *message++; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); idx++; } return status; } int AQM1602::init() { status =0; wdata[0] = 0x0; wdata[1] = 0x38; ThisThread::sleep_for(100ms); status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x39; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x14; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x73; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x56; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x6c; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x38; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x01; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); ThisThread::sleep_for(20ms); wdata[1] = 0x0c; status = i2cRef.write(LCD_ADDR, wdata, 2, 0); return status; }
最後に 本体 main.cpp。
#include "mbed.h" #include "AQM1602.h" DigitalOut myled(LED1); I2C i2c(I2C_SDA, I2C_SCL); int main() { AQM1602 lcd(i2c); int i=0; char buffer[2]; int status; printf("AQM1602 LCD TEST\r\n"); lcd.init(); lcd.displaySTR(LCD_HLINE, "Hello World!"); while (1) { buffer[0]=0x20 + i; buffer[1]=0; status = lcd.displaySTR(LCD_LLINE, buffer); if (buffer[0] >= 0x7F) i = 0; printf("IDX:%d --- STAT:%d \r\n",i, status); ThisThread::sleep_for(500ms); i++; myled = !myled; } }
ビルドして実行
ノーエラーで一発完動であります。冒頭のアイキャッチ画像のとおり液晶に表示できました。