大家好,又見(jiàn)面了,我是你們的朋友全棧君。
lcd1602 +c51 介紹
LCD1602液晶在實(shí)際的產(chǎn)品運(yùn)用中也是比較多產(chǎn)品,應(yīng)為前一段時(shí)間也正好用到了,所以今天就對(duì)LCD1602液晶做一個(gè)總結(jié),方便以后閱讀同時(shí)也希望能夠幫住到需要的人,總結(jié)的可能存在錯(cuò)誤歡迎指出!
所謂的1602是指顯示的時(shí)候,有2行內(nèi)容每行有16個(gè)字符。其實(shí)這類字符型產(chǎn)品都可以這樣解讀比如:lcd12864就是有128行64列。目前市面上字符液晶大多數(shù)是基于HD44780液晶芯片的,控制原理大多相同。因此基于HD44780寫(xiě)的液晶控制程序可以很方便適用于市面上大多數(shù)字符型液晶產(chǎn)品。
字符型LCD1602通常分為14條引腳和16引腳兩種,16引腳多出來(lái)的是背光電源線VCC(15引腳)和地線(16引腳),其控制原理與14引腳LCD完全一樣,引腳定義如下表:
引腳號(hào) | 引腳名 | 電平 | 輸入/輸出 | 作用 |
---|---|---|---|---|
1 | Vss | 電源地 | ||
2 | Vcc | 電源(+5V) | ||
3 | Vee | 對(duì)比調(diào)整電壓 | ||
4 | RS | 0/1 | 輸入 | 0=輸入指令;1=輸出數(shù)據(jù) |
5 | R/W | 0/1 | 輸入 | 0=向LCD寫(xiě)入指令或數(shù)據(jù); 1=從LCD讀取信息 |
6 | E | 1,1->0 | 輸入 | 使能信號(hào),1時(shí)讀取信息,1->0(下降沿)執(zhí)行指令 |
7 | DB0 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line0(最低位) |
8 | DB1 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line1 |
9 | DB2 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line2 |
10 | DB3 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line3 |
11 | DB4 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line4 |
12 | DB5 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line5 |
13 | DB6 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line6 |
14 | DB7 | 0/1 | 輸入/輸出 | 數(shù)據(jù)總線line7 |
15 | A | +Vcc | LCD背光燈源正極 | |
16 | K | 接地 | LCD背光燈源負(fù)極 |
STA7 D7 | STA6 D6 | STA5 D5 | STA4 D4 | STA3 D3 | STA2 D2 | STA1 D1 | STA0 D0 |
---|
STA0-6 | 當(dāng)前數(shù)據(jù)地址指針的數(shù)值 | |
---|---|---|
STA7 | 讀寫(xiě)操作使能 | 1:禁止 0:允許 |
對(duì)控制器每次進(jìn)行讀寫(xiě)操作前,都必須進(jìn)行讀寫(xiě)檢測(cè),確保STA7為0
初始化設(shè)置 顯示模式設(shè)置
顯示開(kāi)/關(guān)光標(biāo)設(shè)置
數(shù)據(jù)控制 控制器內(nèi)部沒(méi)有一個(gè)數(shù)據(jù)地址指針,可以通過(guò)他們來(lái)訪問(wèn)內(nèi)部的全部80字節(jié)RAM。 其他設(shè)置
指令碼 | 功能 |
---|---|
01H | 顯示清屏:1.數(shù)據(jù)指針清零 2.所有顯示清零 |
02H | 顯示回車:1.數(shù)據(jù)指針清零 |
初始化過(guò)程:
延時(shí)
寫(xiě)指令38H
延時(shí)
寫(xiě)指令38H
延時(shí)
寫(xiě)指令38H
(每次寫(xiě)指令、讀/寫(xiě)數(shù)據(jù)操作之前均需檢測(cè)信號(hào))
寫(xiě)指令38H:顯示模式設(shè)置
寫(xiě)指令08H:顯示關(guān)閉
寫(xiě)指令01H:顯示清屏
寫(xiě)指令06H:顯示光標(biāo)移動(dòng)設(shè)置
寫(xiě)指令0CH:顯示開(kāi)及光標(biāo)設(shè)置
代碼:
void LcdInit(){
//LCD初始化程序
Delay1ms(15);
LcdWriteCom(0x38);
Delay1ms(5);
LcdWriteCom(0x38);
Delay1ms(5);
LcdWriteCom(0x38);//設(shè)置顯示模式
LcdWriteCom(0x0C);//開(kāi)顯示不顯示光標(biāo),光標(biāo)不閃爍
LcdWriteCom(0x06);//寫(xiě)一個(gè)數(shù)據(jù),指針加1
LcdWriteCom(0x01);//清屏
LcdWriteCom(0x80);//設(shè)置數(shù)據(jù)指針起點(diǎn)。
}
HD44780內(nèi)置DDRAM、CGROM和CGRAM。 DDRAM就是顯示數(shù)據(jù)RAM,用來(lái)寄存待顯示的字符代碼。共80個(gè)字節(jié),地址和屏幕的對(duì)應(yīng)關(guān)系如下:
顯示位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … … | 40 |
---|---|---|---|---|---|---|---|---|---|
第一行 | 00H | 01H | 02H | 03H | 04H | 05H | 06H | … … | 27H |
第二行 | 40H | 41H | 42H | 43H | 44H | 45H | 46H | … … | 67H |
也就是說(shuō)想要在LCD1602屏幕上的第一行第一個(gè)位置顯示一個(gè)“A”,就要向DDRAM的00H地址寫(xiě)“A”字的代碼就OK了,但具體的寫(xiě)入是要按照LCD模塊的指令格式來(lái)進(jìn)行的。 但是我們發(fā)現(xiàn)每一行有40個(gè)地址,而我們們每行只能顯示16個(gè)字符,其實(shí)際多的位置可以實(shí)現(xiàn)字符的移動(dòng),我們?cè)诳创罄凶髌返臅r(shí)候可能會(huì)見(jiàn)到有的字符是從左面移過(guò)來(lái),他的實(shí)現(xiàn)形式就用到了著些多的地址。將數(shù)據(jù)先寫(xiě)到未顯示的地址然后使用指令進(jìn)行左移就可以了。 那么1602顯示的地址又是什么吶?下圖就是DDRAM地址與現(xiàn)實(shí)位置的對(duì)應(yīng)關(guān)系。
1、讀操作時(shí)序圖:
2、寫(xiě)操作時(shí)序圖:
3、時(shí)序參數(shù)
LCDE = E //使能信號(hào)
RS=L,RW=L,D0~D7=指令碼,E=高脈沖。
void LcdWriteCom(unsigned char com){
//寫(xiě)入命令
RS = 0;
RW = 0;
GPIO_LCD=com;
Delay1ms(10);
LCDE = 1; //給一個(gè)高脈沖
Delay1ms(10);
LCDE = 0;
}
RS=H,RW=L,D0~D7=數(shù)據(jù),E=高脈沖。
void LcdWriteData(unsigned char dat){
//寫(xiě)入數(shù)據(jù)
RS = 1;
RW = 0;
GPIO_LCD=dat;
Delay1ms(10);
LCDE = 1; //給一個(gè)高脈沖
Delay1ms(10);
LCDE = 0;
main.c文件
#include<reg52.h>
#include'lcd.h'
unsigned char CnCh[] = '012345678912345';
unsigned char CnCh1[] = 'ABCDEFGIJKLMNOP';
unsigned char i,a =0,j,n;
unsigned char code Data_1[]=' I Love You '; // 第一行顯示,共十六個(gè)字符
unsigned char code Data_2[]='Good Good Study,Day Day Up !'; // 第二行顯示,共28個(gè)字符
unsigned char i;
void main(){
lcd_Init();
lcd_write_com(0x80);
for(i = 0;i<16;i++){
lcd_read_busy();
lcd_write_dat(CnCh[i]);
}
lcd_write_com(0xc0);
for(i = 0;i<16;i++){
lcd_read_busy();
lcd_write_dat(CnCh1[i]);
}
while(1);
}
void zimo(){
unsigned char code Data_0[]={
0x0f, 0x12, 0x0f, 0x0a, 0x1f, 0x02, 0x02, 0x02}; // 漢字 年 的字模
unsigned char code Data_1[]={
0x0f, 0x09, 0x0f, 0x09, 0x0f, 0x09, 0x0b, 0x11}; // 漢字 月 的字模
unsigned char code Data_2[]={
0x1f, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x1f, 0x00}; // 漢字 日 的字模
lcd_Init(); // LCD1602 初始化
lcd_write_com(0x40); // 0100 0000; 指令 0x40 向 CGRAM 地址0 寫(xiě)入自定義數(shù)據(jù)
for(i=0; i<8; i++){
lcd_write_dat(Data_0[i]); // 寫(xiě)入自定義字符字模
}
lcd_write_com(0x48); // 0100 1000; 指令 0x48 向 CGRAM 地址1 寫(xiě)入自定義數(shù)據(jù)
for(i=0; i<8; i++){
lcd_write_dat(Data_1[i]); // 寫(xiě)入自定義字符字模
}
lcd_write_com(0x50); // 0101 0000; 指令 0x50 向 CGRAM 地址2 寫(xiě)入自定義數(shù)據(jù)
for(i=0; i<8; i++){
lcd_write_dat(Data_2[i]); // 寫(xiě)入自定義字符字模
}
lcd_write_com(0x00 + 0x80); // 在第一行第一列顯示 第一個(gè)字符
lcd_write_dat(0);
lcd_write_com(0x02 + 0x80); // 在第一行第三列顯示 第二個(gè)字符
lcd_write_dat(1);
lcd_write_com(0x04 + 0x80); // 在第一行第五列顯示 第一個(gè)字符
lcd_write_dat(2);
while(1);
/* //分割線******************************************************************* unsigned char table[]={0x15,0x0A,0x15,0x0A,0x15,0x0A,0x15,0x0A}; lcd_Init(); lcd_write_com(0x40); for(i=0;i<8;i++){ lcd_write_dat(table[i]); } lcd_write_com(0x80); lcd_write_dat(0x00); while(1); */
}
//單行移動(dòng)顯示**************************************************************
void dh(){
lcd_Init();
lcd_write_com(0x80); // 第一行第一列地址
for(i=0; i<16; i++){
lcd_write_dat(Data_1[i]); // 顯示第一行
}
while(1){
lcd_read_busy();
lcd_write_com(0xc0); // 第二行第一列地址
for(j=n; j<28+n; j++){
lcd_write_dat(Data_2[j]); // 顯示第二行
}
n++;
if(n >= (28-15)){
// 當(dāng)數(shù)據(jù)移動(dòng)到最后時(shí),n 重置 0,停頓 500 ms,重新開(kāi)始移動(dòng)顯示
n = 0;
delay1ms(50);
}
delay1ms(20); // 控制移動(dòng)速度
}
}
lcd.c文件
#include'lcd.h'
void delay1ms(unsigned char d) //誤差 0us
{
unsigned char a,b,c;
for(c=0;c<d;c++)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
void lcd_Init(){
lcd_write_com(0x38);
delay1ms(1);
lcd_write_com(0x38); //設(shè)置顯示模式
lcd_write_com(0x0c); //開(kāi)顯示不顯示貫標(biāo)
lcd_write_com(0x06); //指針自動(dòng)加一
lcd_write_com(0x01); //清屏
lcd_write_com(0x80); //設(shè)置數(shù)據(jù)指針起點(diǎn)
}
void lcd_write_com(unsigned char com){
RS = 0;
RW = 0;
E = 0;
P0 = com;
delay1ms(10);
E = 1;
delay1ms(10);
E = 0;
}
void lcd_write_dat(unsigned char dat){
RS = 1;
RW = 0;
E = 0;
P0 = dat;
delay1ms(10);
E = 1;
delay1ms(10);
E = 0;
}
void lcd_xy(unsigned char x,unsigned char y){
lcd_write_com(x+y);
}
void lcd_read_busy(){
unsigned char he,a;
RS = 0;
RW = 1;
E = 1;
he = P0;
while(1){
he = P0;
E = 0;
if(!(he&0x80))//當(dāng)he&0x80為0時(shí)跳出循環(huán),表明不忙。
break;
E = 1;
a++;
if(a>=10)
break;
}
}
lcd.h文件
#ifndef __LCD_H_
#define __LCD_H_
#include<reg52.h>
sbit RS = P2^0;
sbit RW = P2^1;
sbit E = P2^2;
void delay1ms(unsigned char d); //延時(shí)函數(shù)
void lcd_Init(); //初始化
void lcd_write_com(unsigned char com); //寫(xiě)指令
void lcd_write_dat(unsigned char dat); //寫(xiě)數(shù)據(jù)
void lcd_xy(unsigned char x,unsigned char y); //寫(xiě)位置
void lcd_read_busy(); //檢測(cè)標(biāo)志位
#endif
這里說(shuō)明一下lcd1602液晶是不能顯示漢字的,因?yàn)樗娘@示原理是由若干個(gè)5X7或者5X11的點(diǎn)陣字符位組成的,又因?yàn)闈h字較為復(fù)雜,所以1602的主要作用就是顯示字母、數(shù)字、符號(hào)的。但是真的不能顯示漢字嗎?也并非絕對(duì)不能。接就是下面要說(shuō)的CGRAM自定義字模。
要顯示我們自定義的字符,就要用到LCD中的CGRAM存儲(chǔ)器(character generate RAM),而我們之前用的顯示自帶的字符用到的是DDRAM,兩個(gè)是不同的??词謨?cè)我們知道,CGRAM的容量是64個(gè)字節(jié),而一個(gè)字符是8個(gè)字節(jié),所以一共能顯示8個(gè)自定義的字符。內(nèi)部常用字符的顯示是從0x20開(kāi)始的,0x00 ~ 0x0F是專門留給自定義字符顯示用的,0x00-0x07和0x08~0x0F顯示的內(nèi)容是一樣的,也就是說(shuō)0x00=0x08,0x01=0x09,以此類推。CGRAM共128個(gè)位,地址是0x40-0x7F,128/8=16正好對(duì)應(yīng)的是0x00-0x0F共16個(gè),剛才說(shuō)了,0x00與0x08對(duì)應(yīng),0x01與0x09對(duì)應(yīng),共16個(gè),這并不矛盾!說(shuō)了這么多,那么怎樣顯示一個(gè)自定義字符呢? 首先我們要清楚LCD1602顯示字符的點(diǎn)陣大小,眼力好的可以看出來(lái),LCD1602一個(gè)顯示字符的位置是58的點(diǎn)陣,也就是說(shuō)它所能顯示的點(diǎn)陣圖形的大小是58的!要顯示一個(gè)自定義的字符,首先我們要知道所顯示自定義字符的點(diǎn)陣數(shù)據(jù),也就是在一個(gè)58的點(diǎn)陣上那個(gè)點(diǎn)是黑的(將該點(diǎn)點(diǎn)黑,就是高電平—-1),哪個(gè)點(diǎn)是白的(該點(diǎn)不顯示,為低電平—-0),但是我們送入到LCD中的是ASCII碼,它是8位的數(shù)據(jù),而一個(gè)顯示字符的點(diǎn)陣大小只是58的,顯然不夠,顯示的辦法是8*8點(diǎn)陣的前三列不用,也就是不顯示,我們只用后面的5列來(lái)顯示。 然后設(shè)定我們是要定義第幾個(gè)自定義字符,前面已經(jīng)介紹了,LCD1602最多顯示8個(gè)自定義字符;然后要規(guī)定在液晶的什么位置顯示自定義字符,看過(guò)數(shù)據(jù)手冊(cè)我們知道,第一行第一個(gè)位置的地址是0x80,第二行一個(gè)位置的地址是0xC0。最后就是要顯示我們定義的第幾個(gè)字符其對(duì)應(yīng)CGRAM地址的關(guān)系式是:
0x00:第一個(gè)(0x40) | 0x01:第二個(gè)(0x48) |
---|---|
0x02:第三個(gè)(0x50) | 0x03:第四個(gè)(0x58) |
0x04:第五個(gè)(0x60) | 0x05:第六個(gè)(0x68) |
0x06:第七個(gè)(0x70) | 0x07:第八個(gè)(0x78) |
每個(gè)字符由5X8點(diǎn)陣組成(也可選用5X10) ,想要實(shí)現(xiàn)顯示,只需如下圖: 例:以5X8點(diǎn)陣為例,顯示字符 A
0代表滅,1代表亮 只需將想要顯示的字符的對(duì)應(yīng)位置1,就能顯示該字符
01110 □█ █ █□
10001 █ □□□ █
10001 █ □□□ █
10001 █ □□□ █
11111 █ ███ █
10001 █ □□□ █
10001 █ □□□ █
10001 █ □□□ █
A={0x0e,0x11,0x11,0x11,0x1f,0x11,0x11,0x11}
代碼 流程
首先創(chuàng)建自定義字模 把字模存入CGRAM中對(duì)應(yīng)的自定義位置,位置在上表中以顯示出來(lái)了 在LCD1602中顯示出來(lái)
void type_model_diy(){
unsigned char code Data_0[]={
0x0e,0x11,0x11,0x11,0x1f,0x11,0x11,0x11}; // 字母A
lcd_Init(); // LCD1602 初始化
lcd_write_com(0x40); // 0100 0000; 指令 0x40 向 CGRAM 地址0 寫(xiě)入自定義數(shù)據(jù)
for(i=0; i<8; i++){
lcd_write_dat(Data_0[i]); // 寫(xiě)入自定義字符字模
}
lcd_write_com(0x00 + 0x80); // 在第一行第一列顯示 第一個(gè)字符
lcd_write_dat(0);
while(1);
}
END!
發(fā)布者:全棧程序員棧長(zhǎng),轉(zhuǎn)載請(qǐng)注明出處:https://javaforall.cn/160148.html原文鏈接:https://javaforall.cn
聯(lián)系客服