モダンOSのお砂場(50) Mbed OS2->OS6お引越し、I2CでAQM1602編

Joseph Halfmoon

開発環境を 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のページは以下です。

I2C

OS6の空プロジェクトの中にOS2用ソースをぶち込む

Keil Studio Cloud上で、OS6 の empty project を作成し、OS2用の以下のソースファイルを配置してみました。

    • main.cpp
    • AQM1602.h
    • AQM1602.cpp

配置した瞬間に Keil Studio Cloudはエラーを検知、赤の波線、黄色の波線多数が現れます。main.cppではこんな感じ。OS6errors

検出されたエラーとその対処方針

検出されたエラーをまとめると以下のようです。

    1. LED2 … 定数不在
    2. Serial … クラス無
    3. wait … 関数無
    4. wait_ms … 関数無

意外と少ないじゃん。それにI2CのAPIにかかわるところは無いし。対処方針は以下のようにしてみます。

    1. LED2はLED1にする
    2. Serialクラスは不要、USBシリアルなので単に printfとする
    3. waitは ThisThread::sleep_for() で置き換える
    4. wait_msも ThisThread::sleep_for() で置き換える

エラーの赤の波線だけではなかったです。黄色の警告もあり。以下を御覧じろ。

WarningC11

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;
    }
}
ビルドして実行

ノーエラーで一発完動であります。冒頭のアイキャッチ画像のとおり液晶に表示できました。

モダンOSのお砂場(49) Mbed OS6、「Serial」そういえばなくなってたのね へ戻る

モダンOSのお砂場(51) Mbed OS6、AD5626 12bit DAC SPI接続 へ進む