akira.kei が 2026年06月11日18時46分57秒 に編集
コメント無し
本文の変更
[<前の記事](https://elchika.com/article/e82c2871-c24c-4905-bed0-f859ada7fb2f/) : 次の記事> ## 自前ライブラリAQMCHAR Arduino IDEでスケッチを新規で作って名前をつけて保存した後、そのinoファイルが含まれるフォルダにArduinoライブラリの公式ページから```LyquidCrystal.cpp```および```LyquidCrystal.h```をコピーする。更にそれぞれを```AQMCHAR.cpp```と```AQMCHAR.h```に変更したコピーを同じフォルダに入れておく。 例えばスケッチを```AQM1602test.ino```とすると、同じフォルダ内には以下の5つのファイルが含まれる。 1. ```AQM1602test.ino``` 1. ```AQMCHAR.cpp``` 1. ```AQMCHAR.h``` 1. ```LyquidCrystal.cpp``` 1. ```LyquidCrystal.h``` Arduino IDEでこのスケッチを開いていると以下のように上部にタブが並ぶようになる。


ちなみに、この自前ライブラリが出来たらスケッチの内容は以下のように出来るようになる。 ```Arduino:AQM1602test.ino #include <Wire.h> #include "AQM1602.h" AQM1602 lcd=AQM1602(0x3E); void setup() { Wire.begin(); lcd.begin(16,2); lcd.setContrast(10); lcd.print("AQM1602XA-RN-GBW"); lcd.setCursor(0,1); for(byte i=0xB1;i<0xB1+16;i++) lcd.write(i); delay(3000); lcd.home(); } byte cnt=0; void loop() { lcd.write(cnt++); delay(10); } ``` ## まずはヘッダファイルAQMCHAR.h 冒頭のラベル```LiquidCrystal_h```を```AQMCHAR_h```に変更する。但し、変更しなくても問題ない。単に重複しないラベルならなんでもいいからだ。 この下にはHD44780(日立)の定義が並んでいるが、その最後に以下を追加する。 ```Arduino: #define LCD_EXTENDED_IS 0x01 #define LCD_NORMAL_IS 0x00 ``` これは拡張モードに関する定義でオリジナルのHD44780には無い。今は初期化とコントラスト調整に少しだけ簡易的に使っているが、そのうち整理していきたい。 コンストラクタの定義は前の記事にも示したように、以下のようなシンプルなものだ。 ```Arduino:
class AQM1602 : public Print {
class AQMCHAR : public Print {
public:
AQM1602(uint8_t addr);
AQMCHAR(uint8_t addr);
void begin(uint8_t cols, uint8_t rows); ``` ```LyquidCrystal```の方には初期化シーケンスとして```init```が用意されていたが、初期化は```begin```内で行うことにしてある。```setup()```内で```Wire.bigin()```してから```lcd.begin(16,2);```のように初期化する。 コントラストはコマンドで設定する必要があるので```void command(uint8_t);```の後に ```Arduino: void setContrast(uint8_t); ``` を追加する。```private```の辺りは以下のようにハードウェア関連の接続情報は全て削除してある。I2Cアドレスを保管しておく```uint8_t adr;```を追加してある。 ```Arduino: private: uint8_t _adrs; uint8_t _displayfunction; uint8_t _displaycontrol; uint8_t _displaymode; uint8_t _numlines; uint8_t _row_offsets[4]; }; ``` ## ライブラリ本体: AQMCHAR.cpp ライブラリの本体である```AQMCHAR.cpp```の冒頭には```#include "Wire.h"を追加しておく。コンストラクタはシンプルで、I2Cアドレスを内部変数に保管するだけだ。 ```Arduino:
AQMCHAR::AQMCHAR(uint8_t adrs) { _adrs=adrs; } ``` LCD側の初期化は```LiquidCrystal```では4ビットモードと8ビットモードを選べるようになっているが、I2C版だと8ビットモード固定でいい。また8ビットモードを確定するために ```Arduino: command(LCD_FUNCTIONSET | _displayfunction); ``` を4回呼んでいるが、この部分はこのまま残しておいても削除してもどちらでもいい。 [秋月の使用例](https://akizukidenshi.com/goodsaffix/AQM1602_rev2.pdf)では、初期化中に送るコマンドは```0x38, 0x39, 0x14, 0x73, 0x52, 0x6c, 0x38, 0x01, 0x0c```だったが、特有部分は「0x39, 0x14, 0x73, 0x52, 0x6c,」の拡張モードだけである。コメント行を削除した初期化ルーチン全体を以下に示す。拡張モードに関するところはちょとゴニョゴニョと誤魔化した。そのうち整理する。 ```Arduino: void AQMCHAR::begin(uint8_t cols, uint8_t lines) { _numlines = lines; setRowOffsets(0x00, 0x40, 0x00 + cols, 0x40 + cols); if(lines==1) _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x10DOTS; else _displayfunction = LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS; command(LCD_FUNCTIONSET | _displayfunction | LCD_NORMAL_IS); delay(20); command(LCD_FUNCTIONSET | _displayfunction | LCD_EXTENDED_IS); delay(20);
```
byte inits[]={0x14,0x73,0x52,0x6c,}; for(byte i=0;i<sizeof(inits);i++) { command(inits[i]); delay(20); } command(LCD_FUNCTIONSET | _displayfunction | LCD_NORMAL_IS); delay(20); _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; display(); clear(); _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; command(LCD_ENTRYMODESET | _displaymode); } ``` 新たに追加すべき関数としてコントラスト設定```setContrast(uint8_t)```がある。ほとんどGeminiに書いてもらったが初期化直後じゃない場合はちょっと設定が変わってしまうかもしれない。 ```Arduino: void AQMCHAR::setContrast(uint8_t contrast) { if (contrast > 63) contrast = 63; command(LCD_FUNCTIONSET | _displayfunction | LCD_EXTENDED_IS); command(0x70 | (contrast & 0x0F)); command(0x54 | ((contrast >> 4) & 0x03)); command(LCD_FUNCTIONSET | _displayfunction | LCD_NORMAL_IS); delay(1); ``` 肝心のコマンドとデータ送信部分は以下のようにした。```send```関数を用意してみたがなぜか```_adr```がスコープ外と言われてコンパイルできなかったので、commandとwriteの中身はそのままI2Cの2バイト送信とした。 ```Arduino: void AQMCHAR::command(uint8_t value) { Wire.beginTransmission(_adrs); Wire.write(0x00); Wire.write(value); Wire.endTransmission(); delay(10); } size_t AQMCHAR::write(uint8_t value) { Wire.beginTransmission(_adrs); Wire.write(0x40); Wire.write(value); Wire.endTransmission(); return 1; // assume success } ``` これでライブラリ化は完了であり、特に問題なくコンパイルできている。 ## 結論 元のライブラリがあれば修正は容易であることがわかったので、ダウンロードしたライブラリの中身が心配だったり自分で書きたかったりした場合にすぐに対応できそうだ。こういう車輪の再発見みたいな作業も暇つぶしになる。 --- [<前の記事](https://elchika.com/article/e82c2871-c24c-4905-bed0-f859ada7fb2f/) : 次の記事>