LCDデバイステスト
自作機器には、2行x16桁のLCDを接続して
使うことが多いです。
このLCDには、データバスを4ビットで使うか
8ビットで使うのかを初期化時に指定可能。
配線数を少なくするため、マイコンとは10ピン
のリボンケーブルで接続。
多数所有しているLCDが使えるかを調べるため
Arduinoを使うことにしました。
Arduinoには、LCDを扱うライブラリが用意されて
いるので、デジタルピンを次のように使うことに。
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
10ピンケーブルの1から10の信号割り当ては
次のように指定。
- Vcc
- D7(7)
- D6(6)
- D5(5)
- D4(4)
- e (3)
- rs(2)
-
-
- GND
信号線は、写真の上にあるコネクタの6ピンを利用。
電源は、写真の下にあるコネクタの2ピンを利用。
(5Vと0Vを使うことに。)
LCDは、コネクタを利用して、基板に取り付けられる
ようにしておきます。
10ピンコネクタを使い、リボンケーブルでArduinoと
接続できます。
コントラス調整の可変抵抗器を使い、トリマーを回して
文字と記号を見やすく調整できるようにしてあります。
ブレッドボードに使うワイヤーとリボンケーブルを
接続すると、次のようになります。
ブレッドボードのワイヤーだと、リボンケーブルから
抜けることもあるので、半田付けでコネクタワイヤー
を用意して対応しました。
ハードウエアができたので、Arduinoスケッチを作成。
ソースコードは、以下。
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#define OFF 0
#define ON OFF+1
#define LED_BIT 5
#define XINTERVAL 1000
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void init_lcd();
/* variables */
boolean tflag ;
boolean uflag ;
boolean eflag ;
char sbuf[8] ;
byte sindex ;
char cmd ;
/* state machine */
byte state ;
byte ycnt ;
/* LED handling counter */
byte xcnt ;
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
show_help();
/* clear flags */
tflag = OFF ;
uflag = OFF ;
eflag = OFF ;
/* initialize port values */
PORTB = 0x04 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xf7 ;
DDRC = 0x00 ;
DDRD = 0xfe ;
/* 1000ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
/* initialize LCD */
init_lcd();
/* others */
state = 0 ;
xcnt = 0 ;
ycnt = 0 ;
}
void loop()
{
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* LCD */
if ( cmd == 'I' ) { init_lcd(); }
/* timer start */
if ( cmd == 'T' ) {
state = 0 ;
/* set execute flag */
eflag = ON ;
}
/* timer stop */
if ( cmd == 't' ) {
/* clear execute flag */
eflag = OFF ;
init_lcd();
}
/* new line */
crlf() ;
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* execute */
if ( eflag == ON ) {
switch ( state ) {
case 0 :
lcd.setCursor(0, 0);
lcd.print("*** TEST LCD ***");
lcd.setCursor(0, 1);
lcd.print("----------------");
break ;
case 1 :
lcd.setCursor(0, 0);
lcd.print("----------------");
lcd.setCursor(0, 1);
lcd.print("*** TEST LCD ***");
break ;
case 2 :
lcd.setCursor(0, 0);
lcd.print("--- test lcd ---");
lcd.setCursor(0, 1);
lcd.print("****************");
break ;
case 3 :
lcd.setCursor(0, 0);
lcd.print("****************");
lcd.setCursor(0, 1);
lcd.print("--- test lcd ---");
break ;
default :
break ;
}
state++ ;
if ( state >= 4 ) { state = 0 ; }
}
}
}
void update_trigger()
{
/* impress LED */
PORTB &= ~(1 << LED_BIT) ;
if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
/* update */
xcnt++ ;
/* judge */
if ( ycnt & ON ) { tflag = ON ; }
ycnt++ ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("I initialize LCD"); crlf();
rs_puts("T timer start") ; crlf();
rs_puts("t timer stop") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void init_lcd()
{
lcd.begin( 16, 2 );
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("+-+-+-+-+-+-+-+-");
lcd.setCursor(0, 1);
lcd.print("-+-+-+-+-+-+-+-+");
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
端末ソフトを使い、次のコマンドでLCDに表示する
文字列を決定します。
- ? コマンド一覧表示
- I 初期化
- T 2秒周期で表示文字列更新開始
- t 表示文字列更新終了
LCDを初期化すると、次のように文字列が表示されます。
+-+-+-+-+-+-+-+-
-+-+-+-+-+-+-+-+
2秒周期で表示文字列更新するときは、次の4パターン
を繰り返していきます。
*** TEST LCD ***
----------------
↓
----------------
*** TEST LCD ***
↓
--- test lcd ---
****************
↓
****************
--- test lcd ---
↓
最初にもどる
簡単なシーケンス処理ですが、LCDの動作試験には
充分役に立ちます。
通信プロトコルは、以下。
- データ転送速度 9600bps
- ストップビット 1ビット
- パリティ なし
- フロー制御 なし
WindowsであればTeratermを使うと簡単に
LCDのGood、No Goodを判定できます。
Arduinoスケッチを見直すと、タイマーによる
LCD表示処理の一部が冗長だったので変更。
Arduinoが動作中であることがわかるように
基板上のLEDを点滅するように、専用関数を
用意。その内容は、以下。
void flash_led()
{
/* impress LED */
PORTB &= ~(1 << LED_BIT) ;
if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
/* update */
xcnt++ ;
}
この専用関数を呼び出すのは、タイマー割込みが発生した
ときとして、タイマー割込み処理の部分に埋め込みます。
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* LED handling */
flash_led();
LED点滅は、LCDの動作試験には無関係ですが、周期的に
表示文字列を変更するために、上のようにしました。
これで、タイマー割込み発生のときには、フラグをセット
するだけで、loop()に処理を任せられます。
void update_trigger()
{
/* judge */
if ( ycnt & ON ) { tflag = ON ; }
/* increment */
ycnt++ ;
}
LCDに周期的に文字列を表示するとき、周期を1秒としたいので
MsTimer2に指定する周期を500msに変更。
変更は、マクロ定義してある数値を書き換えるだけ。
#define XINTERVAL 500
変更したArduinoスケッチは、以下。
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#define OFF 0
#define ON OFF+1
#define LED_BIT 5
#define XINTERVAL 500
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void init_lcd();
void flash_led();
/* variables */
boolean tflag ;
boolean uflag ;
boolean eflag ;
char sbuf[8] ;
byte sindex ;
char cmd ;
/* state machine */
byte state ;
byte ycnt ;
/* LED handling counter */
byte xcnt ;
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
show_help();
/* clear flags */
tflag = OFF ;
uflag = OFF ;
eflag = OFF ;
/* initialize port values */
PORTB = 0x04 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xf7 ;
DDRC = 0x00 ;
DDRD = 0xfe ;
/* 1000ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
/* initialize LCD */
init_lcd();
/* others */
state = 0 ;
xcnt = 0 ;
ycnt = 0 ;
}
void loop()
{
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* LCD */
if ( cmd == 'I' ) { init_lcd(); }
/* timer start */
if ( cmd == 'T' ) {
state = 0 ;
/* set execute flag */
eflag = ON ;
}
/* timer stop */
if ( cmd == 't' ) {
/* clear execute flag */
eflag = OFF ;
init_lcd();
}
/* new line */
crlf() ;
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* LED handling */
flash_led();
/* execute */
if ( eflag == ON ) {
switch ( state ) {
case 0 :
lcd.setCursor(0, 0);
lcd.print("*** TEST LCD ***");
lcd.setCursor(0, 1);
lcd.print("----------------");
break ;
case 1 :
lcd.setCursor(0, 0);
lcd.print("----------------");
lcd.setCursor(0, 1);
lcd.print("*** TEST LCD ***");
break ;
case 2 :
lcd.setCursor(0, 0);
lcd.print("--- test lcd ---");
lcd.setCursor(0, 1);
lcd.print("****************");
break ;
case 3 :
lcd.setCursor(0, 0);
lcd.print("****************");
lcd.setCursor(0, 1);
lcd.print("--- test lcd ---");
break ;
default :
break ;
}
state++ ;
if ( state >= 4 ) { state = 0 ; }
}
}
}
void update_trigger()
{
/* judge */
if ( ycnt & ON ) { tflag = ON ; }
/* increment */
ycnt++ ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("I initialize LCD"); crlf();
rs_puts("T timer start") ; crlf();
rs_puts("t timer stop") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void init_lcd()
{
lcd.begin( 16, 2 );
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("+-+-+-+-+-+-+-+-");
lcd.setCursor(0, 1);
lcd.print("-+-+-+-+-+-+-+-+");
}
void flash_led()
{
/* impress LED */
PORTB &= ~(1 << LED_BIT) ;
if ( xcnt & ON ) { PORTB |= (1 << LED_BIT) ; }
/* update */
xcnt++ ;
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
このスケッチは、ATmega8、ATmega168、ATmega328と
デバイスを載せかえても、問題なく動作しました。
ATmega8を利用したときだけ、端末ソフトでの起動が
ゆっくりでした。
TeraTermでの操作は、次のようになります。
目次
前
次