
開発環境を 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;
}
}
ビルドして実行
ノーエラーで一発完動であります。冒頭のアイキャッチ画像のとおり液晶に表示できました。

