2015年8月2日日曜日

Arduino Unoで秋月のI2C LCDのAQM0802を3.3V駆動で動かす

去年の今頃行き当たりばったりでAQM0802のDIP化基板セット(http://akizukidenshi.com/catalog/g/gK-06795/)をArduinoで動かせたのでその後あまりさわらないでいた
「秋月のI2CのLCDを使ってみた」(http://dad8893.blogspot.jp/2014/08/i2clcd.html
Sim's blogさんのブログの記事(Strawberry LinuxさんのLCD用)をそのまま参考にさせていただいて動作させた

http://blog.goo.ne.jp/sim00/e/ab138be751d447bcdb0eecaaca232214

この時はAQM0802を5V駆動で動作させたが、あれから多少知識や技術が向上したと思うので、AQM0802の仕様どおり3.3Vで駆動させることを考えてみた。

Aruduinoでは「I2CLiquidCrystal」(http://n.mtng.org/ele/arduino/i2c.html)というライブラリを公開されていたので(このライブラリは、いろいろな液晶やOLEDに対応されています)使ってみたが、そのままでは動かず。

ソースも追い切れないので2秒であきらめて(多少誇張)コマンドをベタ書きされているSim's blogさんのスケッチを元に改変してみた。


ArduinoのA4、A5はI2Cの信号線のSCLとSDAで、ブレッドボード上で10kΩのRでプルアップした。
AQM0802のキットははんだを盛ってプリントパターンをショートさせれば、基板上でプルアップ抵抗を有効化するようになっているが、今回は基板上のプルアップを有効化していない。

Aruduino側のI2Cコントローラーがオープンドレインなのでここの信号は0V..3.3Vになるはずだ。

また、LCDのRSTはArduinoからの出力を1.2kΩと2.2kΩの抵抗で分圧して5V→(だいたい)3.3Vに降圧させた。

これで、LCDの入る電圧は全部0V..3.3V(程度)になっていると思う


Fritzingの作図通りだとオシロのプローブが当てられないのでLCDの位置を若干ずらした。

テスタで測定すると
Arduino 5V: 4.95V
Arduino D2: 4.91V
LCD VDD: 3.30V
LCD RST: 2.94V
となった

オシロでI2CのSCL、SDAを計測


赤色がSCL、黄色がSDA

縦軸は2V/divなので、信号レベルはだいたいMax3.6Vぐらいになっているようだ。


赤色のクロックの方を横に数えると4区間で波形は8個なので
20[uS] * 4 / 8 = 10[uS]
なので、逆数をとって100kHzとなる。

特に指定しないとArduinoのWireライブラリのクロック(I2Cのクロック)は100kHzになるようだ。

AQM0802を3.3V駆動するように改変したAruduinoのスケッチ

#include <Wire.h>

// Customize for Arduino Uno Rev.3 & Akizuki AQM0802 (feed 3.3V)

// Arduino     i2c-lcd
// Dig 2 ----- 1pin rst (volatage divided by 1.2k ohm & 2.2k ohm: 5V -> 3.3V)
// Ana 5 ----- 2pin scl (pull-up 10k ohm)
// Ana 4 ----- 3pin sda (pull-up 10k ohm)
// GND ------- 4pin
// 3.3V ------ 5pin

int ledPin = 13;
int resetPin = 2;
int sdaPin = 18; // analog pin 4
int sclPin = 19; // analog pin 5
int i2cadr = 0x3e;
byte contrast = 32; // 最初は大きめにして調整する

void lcd_cmd(byte x)
{
  Wire.beginTransmission(i2cadr);
  Wire.write(0x00);
  Wire.write(x);
  Wire.endTransmission();
}

void lcd_data(byte x)
{
  Wire.beginTransmission(i2cadr);
  Wire.write(0x40);
  Wire.write(x);
  Wire.endTransmission();
}

void lcd_puts(const char *s)
{
  while(*s) lcd_data(*s++);
}

void lcd_init()
{
  // reset
  delay(500);
  pinMode(resetPin, OUTPUT);
  digitalWrite(resetPin, LOW);
  delay(1);
  digitalWrite(resetPin, HIGH);
  delay(10);
  // LCD initialize
  delay(40);
  Wire.begin();
  lcd_cmd(0x38); // function set
  lcd_cmd(0x39); // function set
  lcd_cmd(0x14); // interval osc
  lcd_cmd(0x70 | (contrast & 15)); // contrast low
  lcd_cmd(0x5c | (contrast >> 4 & 3)); // contrast high / icon / power
  lcd_cmd(0x6c); // follower control
  delay(300);
  lcd_cmd(0x38); // function set
  lcd_cmd(0x0c); // display on
  lcd_cmd(0x01); // clear display
  delay(2);
}

void lcd_move(byte pos){
  lcd_cmd(0x80 | pos);
}

void setup()
{
  lcd_init();
  lcd_puts("Hello");
  lcd_move(0x40);
  lcd_puts("Fed 3.3V");
  
  pinMode(ledPin, OUTPUT); // Lチカ
}

void loop()
{
  lcd_puts("Hello");
  lcd_move(0x40);
  lcd_puts("Fed 3.3V");
  delay(500);
}