C言語で、キャラクタLCDを制御したいと思います。
前回で作成したpiob_init(uint8_t)、io_out(uint8_t,uint8_t)、sleep(uint16_t)を使用します。
LCDは以前から使用しているキャラクタLCDの「KKHMF DC 5V 1602 LCD ディスプレイモジュール 16×2キャラクタ LCDブルーブラックライト」を使用します。
回路図はこちらを参考にしてください aki-80 CN3-PBポートに接続しています。
LCDコントラストを調整する半固定抵抗器2KΩは手持ちのものを使用しています。
ソフトは以前作成した「RP2040(RaspberryPi Pico)に萌えたい。例題PIO I2C その2」のソフトを手直しして使用しました。
LCDへの書き込みは4ビットごとに書き込みします。
書き込みには、コマンドデータと表示用データの書き込みの2種類があります。
モードの切り替えは RS端子で行います。
コマンドデータ >> RS=0
表示用データ >> RS=1
書き込みと読み出しのモード切替はRW端子で行います。
読み出し >> RW=1
書き込み >> RW=0
今回の場合は、読み出しは行わないので、RW端子は常に 0のままです。
実際の書き込みタイミングは、Eを正論理でパルスを送ります。
つまり、 E >> 0>1>0のタイミングの1発だけのパルスを生成します。
コマンドデータの4ビットの書き込みは下記のようになりました
void lcd4bitwrite(uint8_t command){
command <<= 4;
command |= (uint8_t)0b00001000;
command &= (uint8_t)0b11111000;
io_out(PortBD,command);
command |= (uint8_t)0b00001100;
command &= (uint8_t)0b11111100;
io_out(PortBD,command);
command |= (uint8_t)0b00001000;
command &= (uint8_t)0b11111000;
io_out(PortBD,command);
}
同じような手順で、表示データの4ビットの書き込みは下記のようになります。
コマンドデータの書き込みと統合するとプログラムは短くなりますが、あえてわかりやすいように(ちょっと言い訳)分けてみました。
void data_lcd4bitwrite(uint8_t command){
command <<= 4;
command |= (uint8_t)0b00001001;
command &= (uint8_t)0b11111001;
io_out(PortBD,command);
command |= (uint8_t)0b00001101;
command &= (uint8_t)0b11111101;
io_out(PortBD,command);
command |= (uint8_t)0b00001001;
command &= (uint8_t)0b11111001;
io_out(PortBD,command);;
}
8ビット単位の書き込みは、上位4ビットを書き込みに続いて下位4ビットを書き込みしています。
コマンド書き込みと表示データ書き込みは次のようになります。
void lcd8bitwrite(uint8_t command){
uint8_t command2;
command2 = command;
command >>= 4;
lcd4bitwrite(command);
lcd4bitwrite(command2);
}
void data_lcd8bitwrite(uint8_t command){
uint8_t command2;
command2 = command;
command >>= 4;
data_lcd4bitwrite(command);
data_lcd4bitwrite(command2);
}
プログラム全体
実際のプログラムは下記のようになります。
#include <stdio.h>
#include <stdint.h>
extern uint8_t piob_init(uint8_t);
extern uint8_t io_out(uint8_t,uint8_t);
extern uint8_t sleep(uint16_t);
void lcd4bitwrite(uint8_t command);
void lcd8bitwrite(uint8_t command);
void data_lcd4bitwrite(uint8_t command);
void data_lcd8bitwrite(uint8_t command);
const uint8_t PortBD = 0x1e;
const uint8_t PortBC = 0x1f;
int main() {
piob_init(0x00); //B port output mode
uint8_t message1[]=" **TMPZ84C015** ";
uint8_t message2[]="Hello SDCC World";
//Display initialization
uint8_t data_set;
data_set=0x03;
lcd4bitwrite(data_set);
sleep(5);
lcd4bitwrite(data_set);
lcd4bitwrite(data_set);
data_set=0x02;
lcd4bitwrite(data_set); //4bit mode
data_set=0x28;
lcd8bitwrite(data_set); //function set 4bit bus,2 line ,1 line=8
data_set=0x0c;
lcd8bitwrite(data_set); //disp on,under cursor off,block
data_set=0x01;
lcd8bitwrite(data_set); //disp clr
sleep(2);
data_set=0x06;
lcd8bitwrite(data_set); //disp address incrmant on,disp shift off
data_set=0x02;
lcd8bitwrite(data_set); //cursor home set
sleep(2);
for (int i=0;message1[i] != '\0';i++){
data_lcd8bitwrite(message1[i]);
// printf("%c\n",message1[i]);
}
data_set = 0xc0;
lcd8bitwrite(data_set); //x80 + 0x40(2 line top address)
for (int i=0;message2[i] != '\0';i++){
data_lcd8bitwrite(message2[i]);
// printf("%c\n",message2[i]);
}
return(0);
}
void lcd4bitwrite(uint8_t command){
command <<= 4;
command |= (uint8_t)0b00001000;
command &= (uint8_t)0b11111000;
io_out(PortBD,command);
command |= (uint8_t)0b00001100;
command &= (uint8_t)0b11111100;
io_out(PortBD,command);
command |= (uint8_t)0b00001000;
command &= (uint8_t)0b11111000;
io_out(PortBD,command);
}
void lcd8bitwrite(uint8_t command){
uint8_t command2;
command2 = command;
command >>= 4;
lcd4bitwrite(command);
lcd4bitwrite(command2);
}
void data_lcd4bitwrite(uint8_t command){
command <<= 4;
command |= (uint8_t)0b00001001;
command &= (uint8_t)0b11111001;
io_out(PortBD,command);
command |= (uint8_t)0b00001101;
command &= (uint8_t)0b11111101;
io_out(PortBD,command);
command |= (uint8_t)0b00001001;
command &= (uint8_t)0b11111001;
io_out(PortBD,command);;
}
void data_lcd8bitwrite(uint8_t command){
uint8_t command2;
command2 = command;
command >>= 4;
data_lcd4bitwrite(command);
data_lcd4bitwrite(command2);
}
以上のCプログラムを 「lcd_main.c] として保存します。
コンパイルします。
$ sdcc -mz80 --out-fmt-ihx --code-loc 0xa000 --no-std-crt0 -o lcd_main.ihx mycrt0.rel lcd_main.c io_out.rel piob_init.rel sleep.rel
Conflicting flags in area _CODE
Conflicting flags in area _DATA
Conflicting flags in area _CODE
Conflicting flags in area _DATA
Conflicting flags in area _CODE
Conflicting flags in area _DATA
Conflicting flags in area _CODE
Conflicting flags in area _DATA
モニタ上のlコマンドで読みこみます。A000をコールします
>l 20A00000DDE5DD210000DD3921DCFF39F9AFF533CD26A333211100394D443E200269602354
20A02000362A69602323362A6960232323365421040009364D2105000936502106000936C9
20A040005A210700093638210800093634210900093643210A00093630210B000936312168
20A060000C00093635210D0009362A210E0009362A210F0009362021100009360021000011
20A0800039DD75FEDD74FF3648DD6EFEDD66FF233665DD6EFEDD66FF2323366CDD6EFEDD87
20A0A00066FF232323366CDD7EFEC6046FDD7EFFCE0067366FDD7EFEC6056FDD7EFFCE00AF
中略
00000001FF
OK
>
>c a000 y:
LCDに
**TMPZ84C015**
Hello SDCC World
と表示されたらOKです。