(これはアメブロからの移植です)
こんにちは。Yukiです。
今回初めてI2Cを使用し、LCD ACM1602NIを使った際にはまったところやポイント点を残しておこうと思います。
・I2Cとは
I2Cとはアイスクエアドシーと読みます。
フィリップ社という日本では電気かみそりが有名な会社が開発したらしいです。(Wikipediaより)
SCLというクロックとSDAというデータ線のたった2本で通信できてしまいます。
しかもこの規格のすごいところはたった2本で最大112本のデバイスを接続できます。
・ACM1602NIの配線

このように配線します。1番端子はVss 2番端子はVdd 3番端子は画面のコントラスト調整
4番端子はSCL 5番端子はSDA 6番端子はバックライトのLED 7番端子はバックライトのLED
です。 今回は5Vで使用する予定なのでバックライトの保護として200Ωを入れています。
またSCL SDAはプルアップ抵抗が必要です。今回は20kΩを使用しています。
コントラスト調整用の可変抵抗は500Ωのものを使用しました。
なおArduinoUNOのSCL端子A5に当たります。
SDA端子はA4端子に当たります。

画像が非常に見づらいですが、次のようになりました。
・プログラムが分からん! (結果的に分かりました)
I2CをArduinoで使用するためのライブラリとしてWire.hが用意されています。
このWire.hとACM1602NIのデータシートを読み書いた結果がこちらです。

壊したかな?
この時にマジで壊したかと思いました。
このようになってしまったコードがこちらです
#include <Wire.h>
//////////////////////////
//引数 byte cmd -> 送信するコマンド 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_cmd(byte cmd)
{
Wire.beginTransmission(0x80);
Wire.write(0);
Wire.write(cmd);
Wire.endTransmission();
}
//////////////////////////////////////////////
//引数 byte data -> 送信するデータ 戻り値 void
//LCD 初期化
//////////////////////////////////////////////
void lcd_data(byte data)
{
Wire.beginTransmission(0x80);
Wire.write(0x80);
Wire.write(data);
Wire.endTransmission();
}
//////////////////////////
//引数 void 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_init()
{
lcd_cmd(0x01);
delay(10);
lcd_cmd(0x38);
delay(10);
lcd_cmd(0x0f);
delay(10);
lcd_cmd(0x06);
delay(10);
}
void setup() {
Wire.begin();
Wire.begin(0x80);
lcd_init();
}
void loop() {
}ここでもう一度データシートを見てみます。

I2Cのインターフェイスプロトコル(約束事)です。
アドレスは0x80だと思うのですが…
あれよーく見たら 7bit ???
これもしかして0x80じゃなくて0x50なの?(そもそもなんで16進数で書かないの?)
これらを検証するために0x50に書き直します。
#include <Wire.h>
//////////////////////////
//引数 byte cmd -> 送信するコマンド 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_cmd(byte cmd)
{
Wire.beginTransmission(0x50);
Wire.write(0);
Wire.write(cmd);
Wire.endTransmission();
}
//////////////////////////////////////////////
//引数 byte data -> 送信するデータ 戻り値 void
//LCD 初期化
//////////////////////////////////////////////
void lcd_data(byte data)
{
Wire.beginTransmission(0x50);
Wire.write(0x80);
Wire.write(data);
Wire.endTransmission();
}
//////////////////////////
//引数 void 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_init()
{
lcd_cmd(0x01);
delay(10);
lcd_cmd(0x38);
delay(10);
lcd_cmd(0x0f);
delay(10);
lcd_cmd(0x06);
delay(10);
}
void setup() {
Wire.begin();
Wire.begin(0x50);
lcd_init();
}
void loop() {
}
あっさり動きました。(動かないといっていた30分が消えた…)
次にHELLO WORLD!を表示してみたいと思います。
#include <Wire.h>
//////////////////////////
//引数 byte cmd -> 送信するコマンド 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_cmd(byte cmd)
{
Wire.beginTransmission(0x50);
Wire.write(0);
Wire.write(cmd);
Wire.endTransmission();
}
//////////////////////////////////////////////
//引数 byte data -> 送信するデータ 戻り値 void
//LCD 初期化
//////////////////////////////////////////////
void lcd_data(byte data)
{
Wire.beginTransmission(0x50);
Wire.write(0x80);
Wire.write(data);
Wire.endTransmission();
}
//////////////////////////
//引数 void 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_init()
{
lcd_cmd(0x01);
delay(10);
lcd_cmd(0x38);
delay(10);
lcd_cmd(0x0f);
delay(10);
lcd_cmd(0x06);
delay(10);
}
void setup() {
Wire.begin();
Wire.begin(0x50);
lcd_init();
lcd_data('H');
lcd_data('E');
lcd_data('L');
lcd_data('L');
lcd_data('O');
lcd_data(' ');
lcd_data('W');
lcd_data('O');
lcd_data('R');
lcd_data('L');
lcd_data('D');
lcd_data('!');
}
void loop() {
}lcd_data関数は一文字ずつしか送信できないため一文字ずつ送信します。

HELLO WORLD!と表示されました。
しかし横の点滅が気になります。
次は横の点滅を消すためにデータシートを読みます。
怪しいのはlcd_initの値です。そこら辺を集中的に読んでいきます。
lcd_cmd(0x01);
delay(10);
lcd_cmd(0x38);
delay(10);
lcd_cmd(0x0f);
delay(10);
lcd_cmd(0x06);
delay(10);delayを入れている理由は設定の時間を稼ぐためです。
最低時間を下回ったままで書き込むとLCD側がフリーズします。
それを防ぐためにdelayで時間稼ぎをしています。
lcd_cmd(0x01); //LCDのリセットです。 表示しているモノも消えます。
lcd_cmd(0x38); //おそらくLCDの設定です。おそらく何列とかの設定だと思います。
lcd_cmd(0x0f); //LCDのON/OFF設定とカーソルの設定です。
lcd_cmd(0x06); //新しい文字が入ってきたときのカーソルの移動だと思います。
今回設定する内容は
lcd_cmd(0x0f);
です。
0x0fを細かく見ていくと、
下4bitを設定する用です。
0000をABCDと置き換えて説明します。
A:LCDを設定するためにはこのフラグを1にする必要があります。
B:ディスプレイをON/OFFするためのフラグです LCDをONにするには1にします。
C:カーソルを表示するためにはこのフラグを1にします。
D:カーソル(?)を点滅させるためにはこのフラグを1にします。
今回はカーソルの表示もいりませんし、点滅もいりません。
そのため1100と設定します。
と言うことは 0x0Cとなると言うことですね。
#include <Wire.h>
//////////////////////////
//引数 byte cmd -> 送信するコマンド 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_cmd(byte cmd)
{
Wire.beginTransmission(0x50);
Wire.write(0);
Wire.write(cmd);
Wire.endTransmission();
}
//////////////////////////////////////////////
//引数 byte data -> 送信するデータ 戻り値 void
//LCD 初期化
//////////////////////////////////////////////
void lcd_data(byte data)
{
Wire.beginTransmission(0x50);
Wire.write(0x80);
Wire.write(data);
Wire.endTransmission();
}
//////////////////////////
//引数 void 戻り値 void
//LCD 初期化
//////////////////////////
void lcd_init()
{
lcd_cmd(0x01);
delay(10);
lcd_cmd(0x38);
delay(10);
lcd_cmd(0x0C);
delay(10);
lcd_cmd(0x06);
delay(10);
}
void setup() {
Wire.begin();
Wire.begin(0x50);
lcd_init();
lcd_data('H');
lcd_data('E');
lcd_data('L');
lcd_data('L');
lcd_data('O');
lcd_data(' ');
lcd_data('W');
lcd_data('O');
lcd_data('R');
lcd_data('L');
lcd_data('D');
lcd_data('!');
}
void loop() {
}
動いたああああああああ!
無事カーソルも点滅しなくなり、すっきりしました。
やっぱりこのように動いてくれると電子工作は楽しいですね。


コメント