LCD(SC1602)4ビットモード 接 続 Sunlike 社 製 SC1602を 制 御 してみます. 今 回 は 結 線 数 を 節 約 して,マイコンとは6 本 のポートを 使 って 接 続 します. 接 続 の 概 要 LCDを4ビットモードで 制 御 LCDとマイコンの 接 続 は6 本 DB4~DB7:4ビットモードデータバス RS :レジスタセレクト (コマンド/データ) E :イネーブル 信 号 LCDのR/W 信 号 はW 固 定 常 時 ライトイネーブルでLCDへの 書 き 込 みのみ を 実 行 します.LCDのデータ/ステータスを 読 み 出 すことはできません. 制 御 概 要 表 示 用 RAMエリアを32 文 字 分 確 保 メイン 側 はテキストコードをRAMにセットする のみとし,LCDへの 転 送 はLCD 制 御 メインで ある l_main()に 任 せます. LCDへの 転 送 処 理 はメインルーチン 実 行 周 期 ( 1ms)に 対 し,1バイト 分 の 処 理 だけを 実 行 し ます.したがって, 画 面 全 体 を 書 き 換 える 時 間 は 32ms 必 要 となります( 詳 細 は 後 述 ). 使 用 ポート P1_3 -STB MJU3711 -STB P4_5 CLK MJU3711 CLK P1_7 DATA MJU3711 DATA 図 1.SC1602 接 続 回 路 図 ワークスペース LCD1602_シリアル 接 続 lcd1602_s_0
表 示 制 御 16 文 字 2 行 の 表 示 が 可 能 ですが, 内 部 アドレスと LCD 画 面 とは 連 続 したアドレスに 配 置 されていませ ん. +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0A +0B +0C +0D +0E +0F +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +4A +4B +4C +4D +4E +4F 1+00h +0Fhまでの16 文 字 はオートインク リメントで 連 続 して 書 き 込 みが 可 能 です. 表 示 用 RAM アドレスは 継 続 してインクリメント +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0A +0B +0C +0D +0E +0F +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +4A +4B +4C +4D +4E +4F 2 DDRAM アドレスを+40hに 変 更 MSB LSB 1 1 0 0 0 0 0 0 40h +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0A +0B +0C +0D +0E +0F +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +4A +4B +4C +4D +4E +4F 3+40h +4Fhまでの16 文 字 はオートインク リメントで 連 続 して 書 き 込 みが 可 能 です. +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0A +0B +0C +0D +0E +0F +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +4A +4B +4C +4D +4E +4F 4 DDRAM アドレスを+00hに 変 更 表 示 用 RAM ポインタは1 行 目 先 頭 に 補 正 が 必 要 です. MSB LSB 1 0 0 0 0 0 0 0 00h オートインクリメントについて +0Fhのあと,データを 書 き 込 むとLCD 内 部 の DDRAM アドレスは+10h +11h と 変 化 しているようです.そして+28hに 到 達 した 時 点 で 自 動 的 に+40h(2 行 目 先 頭 )に 補 正 されます. したがって,1 行 終 了 時 に DDRAM アドレスを 変 更 す る 必 要 があります. // LCD 変 数 定 義 unsigned char zlpdisp; unsigned char zlbdisp[32]; // 表 示 ポインタ (0 ~ 31,0x80,0xc0) // 表 示 バッファ
; リスト1 初 期 化 // LCD 初 期 化 データ typedef struct wait_cmd // ***** 構 造 体 定 義 ***** unsigned int wait; 時 間 ( 約 1.1us 単 位 ) unsigned char cmd; // コマンド WAIT_CMD; // ***** ウェイト 時 間,コマンド 構 造 体 テーブル ***** const WAIT_CMD LCD_INI[8] = // wait, cmd 実 測 で 微 調 整 65040,0x30, // 65000us, 00110000b 8bit 4100,0x30, // 4100us, 00110000b 8bit 100,0x30, // 100us, 00110000b 8bit 40,0x28, // 40us, 00111000b 4bit,2-lines 40,0x08, // 40us, 00001000b Display Off 40,0x01, // 40us, 00000001b Clear Display 1640,0x06, // 1640us, 00000110b Entry Mode Set 40,0x0c, // 40us, 00001100b Display On ; // LCD_ON 信 号 で 制 御 時 は 15ms 65ms にすること // 理 由 :マイコンの 方 が 先 に 起 動 するため // LCDは 4.5V になってから 起 動 する // ***** 初 期 画 面 データ ***** const char Q_G0[33] = "R8C/M120ANDD ROM32KB RAM1280 "; // LCD 初 期 化 void l_ini() unsigned char i; for (i = 0; i < 32; i++) // ***** 初 期 画 面 データ 転 送 *****; zlbdisp[i] = Q_G0[i]; for (i = 0; i < 4; i++) // ***** 初 期 設 定 コマンド ***** l_wait(lcd_ini[i].wait); l_outu(lcd_ini[i].cmd); // コマンド 出 力 ( 上 位 4ビットのみ ) for ( ; i < 8; i++) l_wait(lcd_ini[i].wait); l_out(lcd_ini[i].cmd); // コマンド 出 力 ( 8ビット:4ビット 2 回 ) zlpdisp = 0x00; // 表 示 ポインタ 初 期 化 続 く
// LCD 制 御 メイン void l_main() if (zlpdisp >= 0x80) // ***** コマンド 出 力 ***** l_out(zlpdisp); // 8ビット 出 力 zlpdisp &= 0x7f; // MSB=0(CMD 終 了 ) zlpdisp = zlpdisp >> 2; // (80h 時 は ポインタ 00h に 補 正 ) // (c0h 時 は ポインタ 10h に 補 正 ) else // ***** データ 出 力 ***** P_LCDRS = 1; // RS=1(DATA) l_out(zlbdisp[zlpdisp]); // 8ビット 出 力 zlpdisp++; // 表 示 ポインタ +1 if ((zlpdisp & 0x0f) == 0) // 1 行 分 の 出 力 終 了 なら zlpdisp = zlpdisp << 2; // (10h 時 は コマンド c0h に 補 正 ) zlpdisp = 0x80; // (20h 時 は コマンド 80h に 補 正 ) void l_wait(unsigned int cnt) for ( ; cnt > 0; cnt--); // 1ループ= 約 1.1μs( 実 測 ) // コマンド 出 力 void l_outc(unsigned char data) unsigned wk = data >> 2; // ワ-ク l_out6(wk); // 上 位 4ビット 出 力 RS=0(CMD) E=0 l_out6(wk 0x40); E=1 l_out6(wk); E=0 wk = (data << 2) & 0x3c; // 下 位 4ビット 出 力 l_out6(wk 0x40); E=1 l_out6(wk); E=0 // データ 出 力 void l_outd(unsigned char data) unsigned wk = (data >> 2) 0x80; // ワ-ク l_out6(wk); // 上 位 4ビット 出 力 RS=1(DATA) E=0 l_out6(wk 0x40); // RS=1(DATA) E=1 l_out6(wk); // RS=1(DATA) E=0 wk = (data << 2) & 0x3c 0x80; // 下 位 4ビット 出 力 l_out6(wk 0x40); // RS=1(DATA) E=1 l_out6(wk); // RS=1(DATA) E=0 続 く
// 6ビット 出 力 void l_out6(unsigned char data) unsigned char i; unsigned char wk; // ワーク for (i = 0; i < 6; i++) P_LCDD = (data & 0x80) == 0x80? 1: 0;// MSB セット P_LCDC = 1; // CLK=1 P_LCDC = 0; // CLK=0 data = data << 1; // 左 シフト P_LCDS = 0; // -STB=0 P_LCDS = 1; // -STB=1 動 作 確 認 MFを 利 用 して 任 意 の 文 字 列 を 表 示 してみましょう. 表 示 バッファアドレスは,0x040c からの 32byte です. MFのコマンド 入 力 で, 操 作 します. W40C:ABCDEFGHIJKLMNOP + 今 回 クリック 表 示 されたでしょうか. 入 力 コマンド 中 の : は,Ascii 文 字 列 であること を 指 定 しています.
CGRAMの 利 用 LCD1602にはユーザーキャラクタを8 個 まで 登 録 して 表 示 することが 可 能 です. lcd1602_4p_0 に 対 して, 下 記 の 変 更 を 行 います. CGRAM 用 キャラクタデータを 用 意 する l_ini() にて CGRAM 設 定 を 追 加 キャラクタコードは,0x00~0x0f までが 使 用 可 能 で すが,0x00~0x07 と 0x08~0x0f は 同 じ 扱 いになり ます. ワークスペース LCD1602_4ビット 接 続 lcd1602_4p_1 // 変 更 点 抜 粋 // CGRAM 用 キャラクタデータ const unsigned char Q_CG[8][8] = // code 0x04,0x0e,0x1f,0x04,0x04,0x04,0x04,0x00, // 00 : 0x04,0x04,0x04,0x04,0x1f,0x0e,0x04,0x00, // 01 : 0x00,0x04,0x0c,0x1f,0x0c,0x04,0x00,0x00, // 02 : 0x00,0x04,0x06,0x1f,0x06,0x04,0x00,0x00, // 03 : 0x00,0x04,0x0e,0x1f,0x00,0x00,0x00,0x00, // 04 : 0x00,0x1f,0x0e,0x04,0x00,0x00,0x00,0x00, // 05 : 0x1f,0x11,0x11,0x11,0x11,0x11,0x1f,0x00, // 06 : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f // 07 : _ ; // LCD 初 期 化 void l_ini() unsigned char i; for (i = 0; i < 32; i++) // ***** 初 期 画 面 データ 転 送 *****; zlbdisp[i] = Q_G0[i]; for (i = 0; i < 4; i++) // ***** 初 期 設 定 コマンド ***** l_wait(lcd_ini[i].wait); l_outu(lcd_ini[i].cmd); // コマンド 出 力 ( 上 位 4ビットのみ ) for ( ; i < 8; i++) l_wait(lcd_ini[i].wait); l_out(lcd_ini[i].cmd); // コマンド 出 力 ( 8ビット:4ビット 2 回 ) // ***** CGRAM 設 定 ***** l_cgini(); // CGRAM 設 定 l_out(0x80); // DDRAMアドレス 先 頭 セット P_LCDRS = 1; // RS=1(DATA) zlpdisp = 0x00; // 表 示 ポインタ 初 期 化 続 く
// CGRAM 設 定 void l_cgini() unsigned char i, j; l_out(0x40); // CGRAMアドレス 先 頭 セット P_LCDRS = 1; for (i = 0; i < 8; i++) for (j = 0; j < 8; j++) l_out(q_cg[i][j]); // RS=1(DATA) // CGRAMデータ 出 力 さらに, 複 数 文 字 の 点 滅 機 能 を 追 加 変 更 点 は, l_ini() にブリンクタイマ 初 期 値 セット 追 加 l_main() で 表 示 データ 出 力 時 に,blink 処 理 挿 入 ブリンク 処 理 用 変 数 追 加 ワークスペース LCD1602_4ビット 接 続 lcd1602_4p_2 ブリンク 処 理 データ 出 力 時 に,データを 横 取 りして,ブリンク ならば,ブリンクキャラクタを 表 示 します. ブリンクタイミングと 非 ブリンクタイミングにて 処 理 が 分 かれます. ブリンクコードは1 種 類 しか 指 定 できません. ブリンクのOn/Off 時 間 は 設 定 変 更 可 能 です. 動 作 確 認 ブリンク 位 置 の 指 定 :0x434~( 最 大 8カ 所 ) ブリンク 数 :0x443 ブリンクコード :0x444 MFを 使 って,いろいろ 確 かめて 下 さい. < 例 > 2 行 目 先 頭 から で3 文 字 を 点 滅 してみます. 0x434~ : 0x10,0x11,0x12 ----- 位 置 指 定 0x443 : 0x03----------------3カ 所 0x444 : 0x04 --------------- // LCD 変 数 定 義 unsigned char zlpdisp; // 表 示 ポインタ (0 ~ 31,0x80,0xc0) unsigned char zlbdisp[32]; // 表 示 バッファ unsigned int zlbtma; // Onタイマ 値 unsigned int zlbtmb; // Offタイマ 値 unsigned int zlctma; // Onタイマカウンタ unsigned int zlctmb; // Offタイマカウンタ unsigned char zlcblnk; // ブリンク 数 unsigned char zlbbldt; // ブリンクコード unsigned char zlbblnk[8]; // ブリンク 位 置 (8カ 所 )
// LCD 制 御 メイン void l_main() if (zlpdisp >= 0x80) // ***** コマンド 出 力 ***** l_out(zlpdisp); // 8ビット 出 力 zlpdisp &= 0x7f; // MSB=0(CMD 終 了 ) zlpdisp = zlpdisp >> 2; // (80h 時 は ポインタ 00h に 補 正 ) // (c0h 時 は ポインタ 10h に 補 正 ) else // ***** データ 出 力 ***** P_LCDRS = 1; // RS=1(DATA) l_out(l_blnk(zlbdisp[zlpdisp); // 8ビット 出 力 zlpdisp++; // 表 示 ポインタ +1 if ((zlpdisp & 0x0f) == 0) // 1 行 分 の 出 力 終 了 なら zlpdisp = zlpdisp << 2; // (10h 時 は コマンド c0h に 補 正 ) zlpdisp = 0x80; // (20h 時 は コマンド 80h に 補 正 ) // ブリンク 処 理 unsigned char l_blnk(unsigned char data) unsigned char i; if ((zlctma!= 0000) && (zlctma!= 0xffff)) zlctma--; // On タイムアップでなければ-1 if ((zlctmb!= 0000) && (zlctmb!= 0xffff)) zlctmb--; // Offタイムアップでなければ-1 if (zlcblnk!= 00) // ブリンク 有 り? for (i = 0; i < zlcblnk; i++) // 検 索 if (zlpdisp == zlbblnk[i]) // 現 在 表 示 位 置 =ブリンク 位 置? if (zlctma == 0000) // Onタイムアップなら zlctma = 0xffff; // Onタイマ 停 止 zlctmb = zlbtmb; // Offタイマスタート break; // 本 来 のデータ 表 示 if (zlctma!= 0xffff) return zlbbldt; // カウント 中 ならブリンクコード 表 示 if (zlctmb == 0000) // Offタイムアップなら zlctmb = 0xffff; // Offタイマ 停 止 zlctma = zlbtma; // Onタイマスタート return zlbbldt; // ブリンクコード 表 示 break; return data; // 本 来 のデータ 表 示