LoginSignup
2
1

More than 1 year has passed since last update.

Raspi Picoで Grove LCD を使う (C++)

Last updated at Posted at 2021-10-07

Grove Starter Kit for Raspberry Piに付属するGrove Shield for Pi PicoGrove - 16x2 LCDをRaspberry Pi Picoで使う方法を説明します。
公式にはMicroPythonのサンプルコードがありますが、ここではC++を使って実装しました。

Grove Starter Kit for Raspberry PiGrove Shield for Pi Picoについては、こちらの記事を参照してください。Starter Kitに付属する他のGroveモジュールの使い方へのリンクもこの記事にあります。

今回実装したソースコードはGithubにアップしています。

Grove - 16x2 LCDについて

image.png

横16文字、縦2行の文字を出力できるLCDです。文字と背景の色は変えられません。
PicoへはI2Cで接続します。よって、Grove ShieldのI2C0I2C1に接続します。

公式のwikiでデバイスの詳細説明やArduinoを使ったサンプルコードが説明されています。
また、Grove Shield for Pi Picoのwikiでは、Pico + MicroPythonを使ったサンプルコードが説明されています。

ソースコード

実装方針

今回ほしいのはLCDモジュールをPicoで使うためのC++コードです。しかし、以下3つのサンプルコードはいずれも今回ほしいコードから少しずつずれています。
そのため3つのサンプルコードを組み合わせて実装しました。

参考にしたサンプルコード:

  1. Grove-LCD RGB Backlight
    • LCDの公式wikiよりダウンロード可能
    • Arduino用のサンプルコード
    • rgb_lcd.cpp / rgb_lcd.hというC++で実装されたソースコードがある。
      • Arduinoで使うことを想定しているため、Picoではそのまま使えない。(具体的にはI2C通信の箇所を変更する必要がある)
      • 公式wikiでも説明されているが、背景色を自由に設定できるLCD用のコードとなっている。今回のLCDは背景色を変えられないので、背景色を設定する機能については使用できない
  2. Beginners Guide of Raspberry Pi Pico Based on MicroPython
    • Starter Kitのマニュアルや、それに含まれる複数のモジュールのサンプルコードが説明されている
    • Picoで使用できるMicroPythonのコード
  3. Picoのサンプルコード (pico-examples)
    • C++で実装されたサンプルコード
    • LCDのサンプルコードもあるが、今回のLCD用というわけではない
    • Arduino用のrgb_lcd.cppと比べるとかなり差分がある

実装方針は、はArduino用のソースコード(No.1)をベースとして、Arduinoに依存した実装をPicoサンプルコード(No.3)を参考にして修正しました。

ソースコード

実装したコードをここに全て載せると長くなるので、重要な箇所だけ抜粋します。ソースコード全体はGithubにアップしています。

1. I2Cへデータ送信する処理

WireはArduino用のライブラリなので、PicoのI2C用の関数i2c_write_blocking()に変更します。
変更前:

rgb_lcd.cpp
void i2c_send_byte(unsigned char dta) {
    Wire.beginTransmission(LCD_ADDRESS);        // transmit to device #4
    Wire.write(dta);                            // sends five bytes
    Wire.endTransmission();                     // stop transmitting
}

void i2c_send_byteS(unsigned char* dta, unsigned char len) {
    Wire.beginTransmission(LCD_ADDRESS);        // transmit to device #4
    for (int i = 0; i < len; i++) {
        Wire.write(dta[i]);
    }
    Wire.endTransmission();                     // stop transmitting
}

変更後:

lcd_1602.cpp
void Lcd1602::SendByte(unsigned char dta) {
  i2c_write_blocking(i2c_inst_, LCD_ADDRESS, &dta, 1, false);
}

void Lcd1602::SendByteS(const unsigned char* dta, unsigned char len) {
  i2c_write_blocking(i2c_inst_, LCD_ADDRESS, dta, len, false);
}

2. 文字列を出力する関数

文字列を出力するためにArduino用のサンプルではprint()関数を読んでいます(サンプルのHelloWorld.ino参照)がrgb_lcd.cppにはそのような関数の実装がありません。
これはrgb_lcdクラスがPrintクラス`を継承しており、その継承元クラスの関数を呼んでいるためです。Picoにはそのようなクラスがないため、独自で実装する必要があります。

rgb_lcd.cpp
class rgb_lcd : public Print {
  ...
lcd_1602.cpp
void Lcd1602::Print(const std::string& str) {
  for (int i = 0; i < str.length(); i++) {
    unsigned char dta[2] = {LCD_SETCGRAMADDR, str.c_str()[i]};
    SendByteS(dta, 2);
  }
}

3. I2Cの初期化処理

PicoのI2Cを使うために、初期化処理を実装します。Picoのサンプルコードではi2c_defaultを使うようになっています。これは実際にはi2c0です。
I2C0とI2C1のそれぞれに対応できるように、以下のように実装します。

lcd_1602.cpp

Lcd1602::Lcd1602(const ShieldPort i2c) {
  if (i2c == ShieldPort::kI2C0) {
    i2c_inst_ = i2c0;
  } else if (i2c == ShieldPort::kI2C1) {
    i2c_inst_ = i2c1;
  } else {
    i2c_inst_ = i2c0;
  }

  i2c_init(i2c_inst_, 100 * 1000);
  ...

4. 背景色設定機能の削除

今回使用するLCDでは背景色の設定ができないため、該当する関数を削除します。

void setRGB(unsigned char r, unsigned char g, unsigned char b);
void setPWM(unsigned char color, unsigned char pwm);
void setColor(unsigned char color);
void setColorAll();
void setColorWhite();

5. その他変更箇所

クラス名や変数名、コーディングスタイルなどを自分の好みに変更しています。

ビルド

pico-examplesと同じようなCMakeファイルを用意してビルドします。

CMakeLists.txt

set(GROVE_LIB grove-sensors)
file(GLOB SOURCE *.cpp) 
add_library(${GROVE_LIB} STATIC ${SOURCE})
target_link_libraries(${GROVE_LIB} pico_stdlib hardware_i2c)

実行結果

DSC_1112.JPG

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1