lcd1602C语言驱动
- 格式:docx
- 大小:19.56 KB
- 文档页数:3
1602是课程设计和毕业设计经常用到的显示器,还在愁怎么对1602操作吗?那么看完1602驱动程序,一切变得那么简单。
LCD1602驱动程序://===========LCD1602.H===============#ifndef _LCD1602_H__#define _LCD1602_H__#include<intrins.h>#include"delay.h"//lcd1602管脚定义#define LCD_Data P0 //第7~14脚:D0~D7为8位双向数据线#define Busy 0x80 //用于检测LCM状态字中的Busy标识sbit LCD_RS=P2^0; //寄存器选择位,将LCD_RS位定义为P2.0引脚sbit LCD_RW=P2^1; //读写选择位,将LCD_RW位定义为P2.1引脚sbit LCD_E=P2^2; //使能信号位,将E位定义为P2.2引脚sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚//函数定义声明bit BusyTest(void);//判断液晶模块的忙碌状态void WriteInstruction (unsigned char );//将模式设置指令或显示地址写入液晶模块//void WriteAddress(unsigned char ); //指定字符显示的实际地址void WriteData(unsigned char );//将数据(字符的标准ASCII码)写入液晶模块void CursorFlash(unsigned char,unsigned char); //光标在指定坐标闪烁void InitLcd(void);//初始化LCD1602/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。
51单片机进阶篇---LCD1602基本驱动函数本文作者:Cepark更新时间:2010/08/05作者博客:在本次课中我们将介绍LCD1602液晶的使用。
LCD:英文全称为Liquid Crystal Display,即为液态晶体显示,也就是我们常说的液晶显示了。
1602则是表示这个液晶一共能显示2行数据,每一行显示16个字符(英文字符,不是汉字)。
这个就是LCD1602的全部来由。
液晶显示的使用广泛,现在LCD的价格已经很便宜了,被广泛的应用的各种显示场合。
下面是LCD1602的实物图。
接下来进入LCD1602使用的重点:操作时序。
操作时序永远使用是任何一片IC芯片的最主要的内容。
一个芯片的所有使用细节都会在它的官方器件手册上包含。
所以使用一个器件事情,要充分做好的第一件事就是要把它的器件手册上有用的内容提取,掌握。
介于中国目前的芯片设计能力有限,所以大部分的器件都是主要外国几个IC巨头比如TI、AT、MAXIM这些公司生产的,器件资料自然也是英文的多,所以,英文的基础要在阅读这些数据手册时得到提高哦。
即便有中文翻译版本,还是建议看英文原版,看不懂时不妨再参考中文版,这样比较利于提高。
我们首先来看1602的引脚定义,1602的引脚是很整齐的SIP单列直插封装,所以器件手册只给出了引脚的功能数据表:我们只需要关注以下几个管脚:3脚:VL,液晶显示偏压信号,用于调整LCD1602的显示对比度,一般会外接电位器用以调整偏压信号,注意此脚电压为0时可以得到最强的对比度。
4脚:RS,数据/命令选择端,当此脚为高电平时,可以对1602进行数据字节的传输操作,而为电平时,则是进行命令字节的传输操作。
命令字节,即是用来对LCD1602的一些工作方式作设置的字节;数据字节,即使用以在1602上显示的字节。
值得一提的是,LCD1602的数据是8位的。
5脚:R/W,读写选择端。
当此脚为高电平可对LCD1602进行读数据操作,反之进行写数据操作。
1、关于1602液晶的电气参数一般市场上的1602液晶使用的驱动器为HD44780U或HD44780S,市场上大部分液晶用的是后者。
HD44780S的供电电压为5V±10%,而HD44780U 的供电电压为2.7V~5.5V。
也就是说,绝大部分1602液晶只能工作在5V 电压下,其供电电压必须为5V。
经过试验发现,1602液晶的供电虽然必须为5V,但其控制总线和数据总线可以用3.3V电平(因为对于TTL电平,一般大于2.5V以上都算高电平,不过最可靠的是大于3.6V),只不过在3.3V 电平下,数据的通信速度会大大降低,这一点需要在写驱动时注意。
需要时,可以将MCU的IO配置为漏极开路方式,用上拉电阻拉到5V电平;实在不能配置为漏极开路方式时,请查阅MCU的电气参数,在允许的条件下,直接使用电阻弱上拉也可以。
2、硬件连接1602液晶可以使用4位或8位通信模式,通信可以是双向的或单向的,双向通信主要是为了读取LCD忙标志和AC地址寄存器和DDRAM和CGRAM中的值,一般用处不大,因为1602不支持点阵绘图功能。
在连接时,注意4位通信方式下,LCD只使用DB7~DB4,一般情况下会使用MCU 某端口的高4位或低4位与之连接,注意写驱动时在必要的情况下对端口的其它几位要保护,防止破坏其数据;当然如果没有使用其它4位时则不必要保护(奇怪,不使用其它4位干嘛用4位通信方式嘛?)。
还要注意的是,如果需要双向通信,则必须选择既能做输入又能做输出的IO口,特别是对于RS、RW和E这三条控制线,若能选择支持位寻址的IO口则可以方便编程。
3、底层驱动问题通用1602液晶的时序如图:(1)、写时序(2)、读时序总的说来,按照这个时序图来编写驱动程序是不会出什么问题的,只是要深刻理解时序图中各参数的涵义。
编程中要特别关注E这根控制线。
写操作的时序应该是:①、RS=0(写指令寄存器)或RS=1(写数据寄存器);②、RW=0(写操作);③、将数据写到数据线上;④、E=1;⑤、E=0 。
程有华老师MCS51系列单片机教学(C语言)源代码——“DS1302+DS18B20+LCD1602”实验【文档构成】第一部分:Proteus仿真原理图第三部分:Keil C程序源代码(可copy使用)(程有华单片机培训工作室制作)第一部分:Proteus仿真原理图第2 页/ 共16 页第二部分:Keil C程序源代码(可copy使用)#include<reg52.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned intsbit p20=P2^0;sbit p21=P2^1;sbit p22=P2^2;sbit p23=P2^3;sbit p24=P2^4;sbit p25=P2^5;sbit LCDRS = P2^7;sbit LCDE = P2^6;sbit SCLK = P1^0;sbit IO = P1^1;sbit REST = P1^2;sbit p34 = P3^4;sbit p17 = P1^7;sbit DQ = P1^6;float n;bit sanyear; bit sanmonth; bit sanday; bit sanweek;bit sanhour; bit sanmin; bit sansec;bit san;ucharseccs=0X55,mincs=0X59,hourcs=0X22,daycs=0X09,monthcs=0X10,yearcs=0X07,weekcs=0X01; uchar sec,min,hour,day,month,year,week;uchar key=0xaa;uchar rl=0; uint qq,time,yy;uint TEMPL,TEMPH,aa,bb;uchar code zimo[]={0x00,0x0E,0x00,0x0E,0x00,0x1F,0x00,0x00, // 三0x00,0x1F,0x15,0x15,0x1B,0x11,0x1F,0x00, // 四0x00,0x1E,0x08,0x1E,0x0A,0x0A,0x1F,0x00, // 五0x00,0x04,0x00,0x1F,0x0A,0x11,0x00,0x00, // 六0x04,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02, // 年0x0F,0x09,0x0F,0x09,0x0F,0x09,0x13,0x00, // 月0x1F,0x11,0x11,0x1F,0x11,0x11,0x1F,0x00, // 日0x04,0x0E,0x1C,0x1F,0x1C,0x0E,0x04,0x00};uchar code lcdadd[]={0x86,0x8a,0x8e,0xc8,0xcb,0xce,0x82};uchar code sz[]={"0123456789"};void keyer(void)p20=1;p21=0;if(!p22) { while(!p22);key=0x01; }if(!p23) { while(!p23);key=0x02; }if(!p24) { while(!p24);key=0x03; }if(!p25) { while(!p25);key=0x04; }p20=0;p21=1;if(!p22) {while(!p22); key=0x05; }if(!p23) { while(!p23);key=0x06; }if(!p24) { while(!p24);key=0x07; }if(!p25) { while(!p25);key=0x08; }} /**************盼键*************/ void into0init(void){TMOD = 0X01;TH0 = 15536/256;TL0 = 5536%256;IE = 0X82;TR0 = 1;} /************ INTO0 INITIALIZTION ***/ void into0deal(void) interrupt 1{TH0 = (65536-50000)/256;TL0 = (65536-50000)%256;time=time+1;if(time==8){time=0;san=!san;}}void delayus(uchar n){while(--n);} /************ US DELAY *************/ void delay(uint m){uint i,j;for(i=0;i<m;i++)for(j=0;j<125;j++);} /************ MS DELAY ************/ void LCD_WC(uchar i){LCDRS = 0;LCDE = 1;P0 = i;delay(5);delay(1);} /************ LCD WTIRE COMMAND ****/ void LCD_WD(uchar i){LCDRS=1;LCDE=1;P0=i;delay(5);LCDE=0;delay(2);} /*********** LCD WTIRE DATA *******/ void LCD_WB(void){uchar i;LCD_WC(0x40);for(i=0;i<64;i++)LCD_WD(zimo[i]);} /************ LCD WTIRE WORD ******/ void LCD_CS(void){LCD_WC(0x01);LCD_WC(0x02);LCD_WC(0x06);LCD_WC(0x0C);LCD_WC(0x14);LCD_WC(0x38);delay(10);LCD_WB();} /************ LCD INITIALIZTION **/ bit DS18b20_CS(void){bit dp;DQ=0;delayus(237);DQ=1;delayus(27);dp=DQ;delayus(237);return(dp);} /*********** DS18b20 INITIALIZTION */ void wbit(bit bp){DQ=0;delayus(3);if(bp)DQ=bp;delayus(20);DQ=1;} /*********** DS18b20 WRITE BIT *****/ void wbyte(uchar m){uchar i;for(i=0;i<8;i++){wbit(m&0x01);m=m>>1;}} /*********** DS18b20 WRITE BYTE ***/ bit rbit(void){bit bp;DQ=0;delayus(3);DQ=1;if(DQ)bp=1;else bp=0;delayus(20);return(bp);} /*********** DS18b20 READ BIT *****/ uchar rbyte(void){uchar i,m=0;for(i=0;i<8;i++){m=m>>1;if(rbit())m=m|0x80;}return(m);} /*********** DS18b20 READ BYTE ****/ void STARTUPDS18b20(void){while(DS18b20_CS());wbyte(0xcc);wbyte(0x44);// delay(750);for (yy=0;yy<10;yy++){keyer();if(key!=0xaa)break;}} /*********** STARTUP DS18b20 ******/ void READTEMP(void){STARTUPDS18b20();while(DS18b20_CS());// delay(1);wbyte(0xcc);wbyte(0xbe);TEMPL=rbyte();TEMPH=rbyte();n=(TEMPL+TEMPH*256)*0.0625;n=n*100;} /*********** READ TEMP IN DS18b20 */ void DISPDS18b20(void){uint m;READTEMP();LCD_WC(0x0c0);m=(uint)n;LCD_WD(sz[m/1000]);aa=sz[m/1000];m=m%1000;LCD_WD(sz[m/100]);bb=sz[m/100];m=m%100;LCD_WD('.');LCD_WD(sz[m/10]);m=m%10;LCD_WD(sz[m]);LCD_WD('C');if((aa>=sz[2])&&(bb>=sz[5])){p17=!p17;}if((aa>=sz[2])&&(bb==sz[5]))p17=0;if((aa<=sz[2])&&(bb<sz[4]))p17=1;} /* DS18b20 TEMP DEAL WITH AND RENOVATE */ uchar DS1302read(uchar address){uint b,c,e;e = address;SCLK = 0; REST = 0; REST = 1;for (b=0;b<8;b++){SCLK = 0;IO = (bit)(e & 0x01);SCLK = 1;e = e >> 1;}for (b=0;b<8;b++){SCLK = 0;c = c >> 1;if(IO)c=c|0x80;SCLK = 1;}REST = 0;SCLK = 1;return (c);}void DS1302wirte(uchar address,uchar dataes){uint a,adddat;SCLK = 0; REST = 0; REST = 1;adddat = address;for(a=0;a<8;a++){SCLK = 0;IO = (bit)(adddat & 0x01); //adddat & 0x01;////ddress&0x01);SCLK = 1;adddat = adddat >> 1;}adddat = dataes;for(a=0;a<8;a++){SCLK = 0;IO = (bit)(adddat & 0x01); //adddat & 0x01;//dataes&0x01;SCLK = 1;adddat = adddat >> 1;}REST = 0;}void DS1302readrealtime(void){sec = DS1302read(0x81);min = DS1302read(0x83);hour = DS1302read(0x85);day = DS1302read(0x87);month= DS1302read(0x89);year = DS1302read(0x8d);week = DS1302read(0x8b);}void DS1302init (void){DS1302wirte(0x8e,0x00);DS1302wirte(0x90,0xa9);DS1302wirte(0x80,seccs);DS1302wirte(0x82,mincs);DS1302wirte(0x84,hourcs);DS1302wirte(0x86,daycs);DS1302wirte(0x88,monthcs);DS1302wirte(0x8a,weekcs);DS1302wirte(0x8c,yearcs);}void OnlyMeSee (void){seccs = sec; mincs = min; hourcs = hour; weekcs = week;daycs = day; monthcs = month; yearcs = year;}void realtimedisplay(void){LCD_WC(0x80);LCD_WD('2');LCD_WD('0');if(sanyear==0){LCD_WD(sz[year/16]);LCD_WD(sz[year%16]);}else{LCD_WD(' ');LCD_WD(' ');}LCD_WC(0x84);LCD_WD(4);LCD_WD(' ');if(sanmonth==0){LCD_WD(sz[month/16]);LCD_WD(sz[month%16]);}else{LCD_WD(' ');LCD_WD(' ');}LCD_WC(0x88);LCD_WD(5);LCD_WD(' ');if(sanday==0){LCD_WD(sz[day/16]);LCD_WD(sz[day%16]);}else{LCD_WD(' ');LCD_WD(' ');}LCD_WC(0x8C);LCD_WD(6);LCD_WD('<');if(sanweek==0){if (1==week%16)LCD_WD('-');if (2==week%16)LCD_WD('=');if (3==week%16)LCD_WD(0);if (4==week%16)LCD_WD(1);if (5==week%16)LCD_WD(2);if (6==week%16)LCD_WD(3);if (7==week%16)LCD_WD(6);}else{LCD_WD(' ');}LCD_WD('>');LCD_WC(0xc8);if(sanhour==0){LCD_WD(sz[hour/16]);LCD_WD(sz[hour%16]);}else{LCD_WD(' ');LCD_WD(' ');}LCD_WC(0xca);LCD_WD(':');if(sanmin==0){LCD_WD(sz[min/16]);LCD_WD(sz[min%16]);}else{LCD_WD(' ');LCD_WD(' ');}LCD_WC(0xcd);LCD_WD(':');if(sansec==0){LCD_WD(sz[sec/16]);LCD_WD(sz[sec%16]);}else{LCD_WD(' ');LCD_WD(' ');}}void OnlyMeSee1(void){EA=0;sanyear=0;sanmonth=0;sanday=0;sanweek=0;sanhour=0;sanmin=0;sansec=0;}void keywith (void){keyer();if(key==0x08){key=0xaa;EA=1;while(1){loop: realtimedisplay();if(rl==0){sanyear = san;sanmonth=0;sanday=0;sanweek=0;sanhour=0;sanmin=0;sansec=0; }if(rl==1){sanmonth= san;sanyear=0;sanday=0;sanweek=0;sanhour=0;sanmin=0;sansec=0; }if(rl==2){sanday = san;sanyear=0;sanmonth=0;sanweek=0;sanhour=0;sanmin=0;sansec=0; }if(rl==3){sanweek = san;sanyear=0;sanmonth=0;sanday=0;sanhour=0;sanmin=0;sansec=0; }if(rl==4){sanhour = san;sanyear=0;sanmonth=0;sanday=0;sanweek=0;sanmin=0;sansec=0; }if(rl==5){sanmin = san;sanyear=0;sanmonth=0;sanday=0;sanweek=0;sanhour=0;sansec=0; }if(rl==6){sansec = san;sanyear=0;sanmonth=0;sanday=0;sanweek=0;sanhour=0;sanmin=0; }keyer();if(key==0x08){break;}if(key==0x03){OnlyMeSee();DS1302init();break;}if(key==0x05){key=0xaa;rl=rl-1;if(rl==255)rl=6;goto loop;}if(key==0x07){key=0xaa;rl=rl+1;if(rl==7)rl=0;goto loop;}if(key==0x02){ key=0xaa;switch(rl){case 0: {LCD_WC(0x82); year=year+0x01;switch(year){case 0x0a :year=0x10; break;case 0x1a :year=0x20; break;case 0x2a :year=0x30; break;case 0x31 :year=0x00; break;}LCD_WD(sz[year/16]);LCD_WD(sz[year%16]);LCD_WC(0x82);goto loop;case 1: {LCD_WC(0x86);month = month+0x01;switch(month){case 0x0a :month=0x10; break;case 0x13 :month=0x01; break;}LCD_WD(sz[month/16]);LCD_WD(sz[month%16]);LCD_WC(0x86);goto loop;}case 2: {LCD_WC(0x8a);day = day+0x01;switch(day){case 0x0a :day=0x10; break;case 0x1a :day=0x20; break;case 0x2a :day=0x30; break;case 0x32 :day=0x01; break;}LCD_WD(sz[day/16]);LCD_WD(sz[day%16]);LCD_WC(0x8a);goto loop;}case 3: {LCD_WC(0x8e);week = week+1;if(week==8){week=1;if (1==week%16)LCD_WD('-');LCD_WC(0x8e);goto loop;}if (1==week%16)LCD_WD('-');if (2==week%16)LCD_WD('=');if (3==week%16)LCD_WD(0);if (4==week%16)LCD_WD(1);if (5==week%16)LCD_WD(2);if (6==week%16)LCD_WD(3);if (7==week%16)LCD_WD(6);LCD_WC(0x8e);goto loop;}LCD_WC(0xc8);hour = hour+0x01;switch(hour){case 0x0a :hour=0x10; break;case 0x1a :hour=0x20; break;case 0x24 :hour=0x00; break;}LCD_WD(sz[hour/16]);LCD_WD(sz[hour%16]);LCD_WC(0xc8);goto loop;}case 5: {LCD_WC(0xcb); min = min+0x01;switch(min){case 0x0a :min=0x10; break;case 0x1a :min=0x20; break;case 0x2a :min=0x30; break;case 0x3a :min=0x40; break;case 0x4a :min=0x50; break;case 0x5a :min=0x00; break;}LCD_WD(sz[min/16]);LCD_WD(sz[min%16]);LCD_WC(0xcb);goto loop;}case 6: {LCD_WC(0xce);sec = sec+0x01;switch(sec){case 0x0a :sec=0x10; break;case 0x1a :sec=0x20; break;case 0x2a :sec=0x30; break;case 0x3a :sec=0x40; break;case 0x4a :sec=0x50; break;case 0x5a :sec=0x00; break;}LCD_WD(sz[sec/16]);LCD_WD(sz[sec%16]);LCD_WC(0xce);goto loop;}}}if(key==0x06){ key=0xaa;switch(rl){case 0: {LCD_WC(0x82); year=year-0x01;switch(year){case 0xff :year=0x30; break;case 0x2f :year=0x29; break;case 0x1f :year=0x19; break;case 0x0f :year=0x09; break;}LCD_WD(sz[year/16]);LCD_WD(sz[year%16]);LCD_WC(0x82);goto loop;}case 1: {LCD_WC(0x86);month = month-0x01;switch(month){case 0x00 :month=0x12; break;case 0x0f :month=0x09; break;}LCD_WD(sz[month/16]);LCD_WD(sz[month%16]);LCD_WC(0x86);goto loop;}case 2: {LCD_WC(0x8a);day = day-0x01;switch(day){case 0x00 :day=0x31; break;case 0x2f :day=0x29; break;case 0x1f :day=0x19; break;case 0x0f :day=0x09; break;}LCD_WD(sz[day/16]);LCD_WD(sz[day%16]);LCD_WC(0x8a);goto loop;}case 3: {LCD_WC(0x8e);week = week-1;switch(week){}if (1==week%16)LCD_WD('-');if (2==week%16)LCD_WD('=');if (3==week%16)LCD_WD(0);if (4==week%16)LCD_WD(1);if (5==week%16)LCD_WD(2);if (6==week%16)LCD_WD(3);if (7==week%16)LCD_WD(6);LCD_WC(0x8e);goto loop;}case 4: {LCD_WC(0xc8);hour = hour-0x01;switch(hour){case 0xff :hour=0x23; break;case 0x1f :hour=0x19; break;case 0x0f :hour=0x09; break;}LCD_WD(sz[hour/16]);LCD_WD(sz[hour%16]);LCD_WC(0xc8);goto loop;}case 5: {LCD_WC(0xcb); min = min-0x01;switch(min){case 0xff :min=0x59; break;case 0x4f :min=0x49; break;case 0x3f :min=0x39; break;case 0x2f :min=0x29; break;case 0x1f :min=0x19; break;case 0x0f :min=0x09; break;}LCD_WD(sz[min/16]);LCD_WD(sz[min%16]);LCD_WC(0xcb);goto loop;}case 6: {LCD_WC(0xce);sec = sec-0x01;switch(sec){case 0xff :sec=0x59; break;case 0x4f :sec=0x49; break;case 0x2f :sec=0x29; break;case 0x1f :sec=0x19; break;case 0x0f :sec=0x09; break;}LCD_WD(sz[sec/16]);LCD_WD(sz[sec%16]);LCD_WC(0xce);goto loop;}}}}}key=0xaa;OnlyMeSee1();rl=0;}void main(void){into0init(); EA=0;DS18b20_CS(); LCD_CS(); DS1302init();while(1){DS1302readrealtime();realtimedisplay();DISPDS18b20();keywith();}}。
//头文件#include <reg51.h>#include <INTRINS.H>//宏定义#define uchar unsigned char#define uint unsigned intsbit LCD_RS=P1^0;//定义引脚 L指令和H数据sbit LCD_RW=P1^1; //H读L写sbit LCD_E=P1^2; //串行时钟输入sbit LCD_PSB =P1^3; /*LCD_PSB脚为12864-12系列的串、并通讯功能切换,我们使用8位并行接口,LCD_PSB=1*/sbit LCD_RST =P1^4; //程序没有用上/*LCD_PSB脚为12864-12系列的串、并通讯功能切换,我们使用8位并行接口,LCD_PSB=1复位信号低电平有效*/#define LCD_Data P0#define Busy 0x80 //用于检测LCD状态字中的Busy标识//函数声明void WriteDataLCD(unsigned char WDLCD); //写数据void WriteCommandLCD(unsigned char WCLCD,BuysC);//写指令unsigned char ReadDataLCD(void);//读数据unsigned char ReadStatusLCD(void); //读状态void LCDInit(void); //初始化void LCDClear(void); //清屏void LCDFlash(void);//闪烁效果void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);//按指定位置显示一个字符void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData); //按指定位置显示一串字符void DisplayImage (unsigned char code *DData);//图形显示128*64void Delay5Ms(void);void Delay400Ms(void);//写数据void WriteDataLCD(unsigned char WDLCD){//ReadStatusLCD(); //检测忙LCD_RS = 1;LCD_RW = 0;LCD_Data = WDLCD;LCD_E = 0;Delay5Ms();LCD_E = 1;}//写指令void WriteCommandLCD(unsigned char WCLCD,BuysC) //BuysC为0时忽略忙检测{//if (BuysC)//ReadStatusLCD(); //根据需要检测忙LCD_RS = 0;LCD_RW = 0;LCD_Data = WCLCD;LCD_E=0;Delay5Ms();LCD_E=1;}//读数据unsigned char ReadDataLCD(void){LCD_RS = 1;LCD_RW = 1;LCD_E = 0;LCD_E = 0;LCD_E = 1;return(LCD_Data);}//读状态unsigned char ReadStatusLCD(void){LCD_Data = 0xFF;LCD_RS = 0;LCD_RW = 1;LCD_E = 1;while (LCD_Data & Busy); //检测忙信号LCD_E = 0;return(LCD_Data);}//LCM初始化void LCDInit(void){WriteCommandLCD(0x30,1); //显示模式设置,开始要求每次检测忙信号WriteCommandLCD(0x01,1); //显示清屏WriteCommandLCD(0x06,1); // 显示光标移动设置WriteCommandLCD(0x0C,1); // 显示开及光标设置}//清屏void LCDClear(void){WriteCommandLCD(0x01,1); //显示清屏WriteCommandLCD(0x34,1); // 显示光标移动设置WriteCommandLCD(0x30,1); // 显示开及光标设置}//闪烁效果void LCDFlash(void){WriteCommandLCD(0x08,1); //显示清屏Delay400Ms();WriteCommandLCD(0x0c,1); // 显示开及光标设置Delay400Ms();WriteCommandLCD(0x08,1); //显示清屏Delay400Ms();WriteCommandLCD(0x0c,1); // 显示开及光标设置Delay400Ms();WriteCommandLCD(0x08,1); //显示清屏Delay400Ms();}//按指定位置显示一个字符void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData) {if(Y<1)Y=1;if(Y>4)Y=4;X &= 0x0F; //限制X不能大于16,Y不能大于1switch(Y){case 1:X|=0X80;break;case 2:X|=0X90;break;case 3:X|=0X88;break;case 4:X|=0X98;break;}WriteCommandLCD(X, 0); //这里不检测忙信号,发送地址码WriteDataLCD(DData);}//按指定位置显示一串字符,用到void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData) {unsigned char ListLength,X2;ListLength = 0;X2=X;if(Y<1)Y=1;if(Y>4)Y=4;X &= 0x0F; //限制X不能大于16,Y在1-4之内switch(Y){case 1:X2|=0X80;break; //根据行数来选择相应地址case 2:X2|=0X90;break;case 3:X2|=0X88;break;case 4:X2|=0X98;break;}WriteCommandLCD(X2, 1); //发送地址码while (DData[ListLength]>=0x20) //若到达字串尾则退出{if (X <= 0x0F) //X坐标应小于0xF{WriteDataLCD(DData[ListLength]); //ListLength++;X++;Delay5Ms();}}}//图形显示128*64void DisplayImage (unsigned char code *DData){unsigned char x,y,i;unsigned int tmp=0;for(i=0;i<9;){ //分两屏,上半屏和下半屏,因为起始地址不同,需要分开for(x=0;x<32;x++){ //32行WriteCommandLCD(0x34,1);WriteCommandLCD((0x80+x),1);//列地址WriteCommandLCD((0x80+i),1); //行地址,下半屏,即第三行地址0X88WriteCommandLCD(0x30,1);for(y=0;y<16;y++)WriteDataLCD(DData[tmp+y]);//读取数据写入LCDtmp+=16;}i+=8;}WriteCommandLCD(0x36,1); //扩充功能设定WriteCommandLCD(0x30,1);}//5ms延时void Delay5Ms(void){unsigned int TempCyc = 5552;while(TempCyc--);}//400ms延时void Delay400Ms(void){unsigned char TempCycA = 5;unsigned int TempCycB;while(TempCycA--){TempCycB=7269;while(TempCycB--);}}void main(void){//Delay400Ms(); //启动等待,等LCD讲入工作状态LCDInit(); //LCM初始化Delay5Ms(); //延时片刻(可不要)LCD_PSB = 1;//并口输出0为串口输出while(1){LCDClear();DisplayListChar(2,1,"绿盾电子"); //显示字库中的中文数字DisplayListChar(0,2," ");Delay400Ms();Delay400Ms();Delay400Ms();Delay400Ms();LCDFlash(); //闪烁效果}}。
#ifndef __LCD1602_H#define __LCD1602_H//单片机与LCD1602连接数据线定义#define CLK PORTDbits.RD6#define AB PORTDbits.RD7#define TRIS_LCD_CLK TRISDbits.TRISD6#define TRIS_LCD_AB TRISDbits.TRISD7#define LCD_RS PORTAbits.RA1 // PORT for RS */#define TRIS_LCD_RS TRISAbits.TRISA1 // TRIS for RS */#define LCD_EN PORTAbits.RA3 // PORT for EN */#define TRIS_LCD_EN TRISAbits.TRISA3 // TRIS for EN *///-------------------1602液晶命令定义-------------------//初始化命令#define DISP_CLR 0b00000001 //清显示,光标复位到第一行首(地址00H)#define CUR_HOME 0b00000010 //光标复位,光标返回到第一行首//光标和显示模式设置#define CUR_AUTO_R 0b00000110 //设置光标在文字插入后自动右移#define CUR_AUTO_L 0b00000100 //设置光标在文字插入后自动左移#define DISP_AUTO_R 0b00000111 //设置显示在文字插入后自动右移*/#define DISP_AUTO_L 0x00000101 //设置显示在文字插入后自动左移*///显示开关控制*/#define DISP_ON 0b00001111 //显示开*/#define DISP_OFF 0b00001011 //显示关*/#define CUR_ON 0b00001111 //光标开*/#define CUR_OFF 0b00001101 //光标关*/#define BLINK_ON 0b00001111 //光标闪烁开*/#define BLINK_OFF 0b00001110 //光标闪烁关*///光标或显示移位*/#define CUR_SHIFT_L 0b00010000 //光标左移*/#define CUR_SHIFT_R 0b00010100 //光标右移*/#define DISP_SHIFT_L 0b00011000 //显示左移*/#define DISP_SHIFT_R 0b00011100 //显示右移*///工作模式设置#define LCD_MODE_STD 0x38 //1602标准工作模式:8位数据传送,2行显示,字符点阵5*7*///字符发生器RAM地址设置*/#define SET_ADDR_CGRAM 0x40 //设置CGRAM地址*///数据存储器地址设置*/#define SET_ADDR_DDRAM 0x80 //设置DDRAM地址*///自定义字符*/#define USER_CHAR1 0x00//自定义字符1:年*/#define USER_CHAR2 0x01//自定义字符2:月*/#define USER_CHAR3 0x02//自定义字符3:日*/#define USER_CHAR4 0x03//自定义字符4:¥*/#define USER_CHAR5 0x04//自定义字符5:元*/#define USER_CHAR6 0x05//自定义字符6:℃*/#define USER_CHAR7 0x06//自定义字符7:↑*/#define USER_CHAR8 0x07//自定义字符8:小喇叭图标*/// 函数原型*/void LCD_init(void) ;//初始化*/void xianshi(unsigned int a);void LCD_wrcmd(unsigned char cmd) ;//写入控制命令*/void LCD_setxy(char x,char y) ;//设定显示位置,行x=1/2,列y=1~16的任意整数*/void LCD_wrchar(char str) ;//写入要显示的字符*/void LCD_wrstr(const rom char *s);//写入要显示的字符串常量,该函数相当于C18 库中的putrsXLCD函数,从程序存储器写一个字符串到LCD*/void LCD_wrul(unsigned long num);//写入要显示的无符号长整型数*/void LCD_wrlval(unsigned long num,unsigned char bits,unsigned char dp);//写入要显示的长变量*/ void CG_Write(void);//建立自定义字符块*/#endif//函数实现*/#include <p18cxxx.h>#include <stdlib.h>#include <delays.h>#include"LCD1602.h"const rom char cgtab[64]={0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02,0x0f,0x09,0x0f,0x09,0x0f,0x09,0x11,0x00,0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00,0x11,0x0a,0x04,0x1f,0x04,0x1f,0x04,0x00,0x0e,0x00,0x1f,0x0a,0x0a,0x0a,0x13,0x00,0x18,0x18,0x07,0x08,0x08,0x08,0x07,0x00,0x04,0x0a,0x15,0x04,0x04,0x04,0x04,0x00,0x01,0x03,0x1d,0x15,0x1d,0x03,0x01,0x00}; //年、月、日、¥、元、℃、↑、小喇叭图标*/void DELAY10mS(){Delay1KTCYx(25);}void delayzz(unsigned int n) //延时函数{unsigned int x,y;for(x=n;x>0;x--)for(y=110;y>0;y--);}void xianshi(unsigned int a){//CLR=0;//CLR=1;if((a&0x80)==0X80){AB=1;CLK=0;CLK=1;}//第7位else{AB=0;CLK=0;CLK=1;}if((a&0x40)==0X40){AB=1;CLK=0;CLK=1;}//第6位else{AB=0;CLK=0;CLK=1;}if((a&0x20)==0X20){AB=1;CLK=0;CLK=1;}//第5位else{AB=0;CLK=0;CLK=1;}if((a&0x10)==0X10){AB=1;CLK=0;CLK=1;}//第4位else{AB=0;CLK=0;CLK=1;}if((a&0x08)==0X08){AB=1;CLK=0;CLK=1;}//第3位else{AB=0;CLK=0;CLK=1;}if((a&0x04)==0X04){AB=1;CLK=0;CLK=1;}//第2位else{AB=0;CLK=0;CLK=1;}if((a&0x02)==0X02){AB=1;CLK=0;CLK=1;}//第1位else{AB=0;CLK=0;CLK=1;}if((a&0x01)==0X01){AB=1;CLK=0;CLK=1;}//第0位else{AB=0;CLK=0;CLK=1;}}void LCD_init(void){ADCON1=0x0F;//所有引脚均设置为数字IO脚*/DELAY10mS();//延时100ms*///设置单片机LCD控制引脚全为输出*/TRIS_LCD_RS=0;TRIS_LCD_EN=0;CLK=0;AB=0;TRIS_LCD_CLK=0;TRIS_LCD_AB=0;LCD_wrcmd(LCD_MODE_STD);//LCD标准工作模式:8位数据传送,2行显示,字符点阵5*7*/DELAY10mS();LCD_wrcmd(DISP_OFF);//显示关闭*/DELAY10mS();LCD_wrcmd(DISP_CLR);//清屏*/DELAY10mS();//清屏和光标归位需要较长的时间*/LCD_wrcmd(CUR_AUTO_R);//设置光标在文字插入后自动右移*/DELAY10mS();LCD_wrcmd(DISP_ON & CUR_OFF & BLINK_OFF);//显示开,无光标, 光标不闪烁*///LCD_wrcmd(DISP_ON & CUR_ON & BLINK_ON);/*显示开,光标, 光标闪烁*/DELAY10mS();CG_Write();//建立自定义字符块*/DELAY10mS();}//void LCD_wrcmd(Uchar cmd)/*写入控制命令*/void LCD_wrcmd(unsigned char cmd)//写入控制命令*/{xianshi(0X00);Nop();Nop();LCD_EN=0;Nop();Nop();Nop();Nop();LCD_RS=0;Nop();Nop();Nop();Nop();Nop();Nop();Nop();xianshi(cmd);delayzz(25);Nop();Nop();Nop();Nop();LCD_EN=1;Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();LCD_EN=0;Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();xianshi(0X00);}void LCD_wrchar(char str)//写入要显示的字符*/ {xianshi(0X00);Nop();Nop();Nop();LCD_EN=0;Nop();Nop();Nop();Nop();LCD_RS=1;Nop();Nop();Nop();Nop();Nop();Nop();Nop();xianshi(str);delayzz(25);Nop();Nop();Nop();Nop();LCD_EN=1;Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();LCD_EN=0;Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();xianshi(0X00);}void LCD_setxy(char x,char y) //设定显示位置,行x=1/2,列y=1~16的任意整数*/ {char temp;if(x==1){temp=0x80+y-1;LCD_wrcmd(temp);}else{temp=0xC0+y-1;LCD_wrcmd(temp);}}void LCD_wrstr(const rom char *s)//写入要显示的字符串*/{for(;*s!='\0';s++)LCD_wrchar(*s);}void LCD_wrul(unsigned long num)//写入要显示的无符号长整型数*/{char str[11];//无符号长整型数转换为字符串是10个,所以需要11个单元存储*/ int i=0;int j=0;ultoa(num,str);//将无符号长整型数转换为字符串*/LCD_wrcmd(CUR_AUTO_L);//设置光标在文字插入后自动左移*/while(str[i]!='\0')//搜索字符串结束符*/{i++;}while(i>0)//显示前面的有效数字*/{i--;LCD_wrchar(str[i]);j++;}while(j<10)//往前写满10位,也就是前面都写空格*/{LCD_wrchar(0x20);j++;}LCD_wrcmd(CUR_AUTO_R);//设置光标在文字插入后自动右移*/}void LCD_wrlval(unsigned long num,unsigned char bits,unsigned char dp)//写入要显示的长变量{char str[11];//无符号长整型数转换为字符串是10个,所以需要11个单元存储*/int i=0;int j=0;ultoa(num,str);//将无符号长整型数转换为字符串*/LCD_wrcmd(CUR_AUTO_L);//设置光标在文字插入后自动左移*/while(str[i]!='\0')//搜索字符串结束符*/{i++;}if (i>bits)//要显示的数据比规定的显示位数多,数据显示溢出*/{while(j<bits)//往前写满规定的位数,也就是前面都写空格,直到规定的位数*/ {LCD_wrchar('-'); //规定的位全部写-,表示数据溢出*/j++;if (j==dp) LCD_wrchar('.');//插入小数点*/}}else{while(i>0)//显示前面的有效数字*/{i--;LCD_wrchar(str[i]);j++;if (j==dp) LCD_wrchar('.');//插入小数点*/}while(j<bits)//往前写满规定的位数,也就是前面都写空格,直到规定的位数*/ {if (j==dp) LCD_wrchar('.');//插入小数点*/if (j<=dp) LCD_wrchar('0');//小数点前后补0字符*/else LCD_wrchar(0x20); //小数点前后补空字符*/j++;}}LCD_wrcmd(CUR_AUTO_R);//设置光标在文字插入后自动右移*/}void CG_Write(void)//建立自定义字符块*/{int i;LCD_wrcmd(SET_ADDR_CGRAM);//字符发生器CGRAM地址设置*/ for(i=0;i<64;i++){LCD_wrchar(cgtab[i]);};}。
/*LCD1602驱动程序*//*程序用法:1、按行显示:display(行号,数据指针)2、定位显示:displayUser(行号,列号,字符/字符串)3、动态显示:Ddisplay(行号、列号、字符/字符串)4、闪烁显示:Fldisplay(行号、列号、字符/字符串)*//*声明代码(放工程中需要包含的自定义头文件中):void delay(unsigned char n);void init();void display(unsigned char a,unsigned char table[]);void write_date(uchar);void write_command(uchar);void displayUser(unsigned char hang,unsigned lie,unsigned char table[]); void Ddisplay(unsigned char hang,unsigned lie,unsigned char table[]); void Fldisplay(unsigned char hang,unsigned lie,unsigned char table[]); */#include <reg51.h>#define uchar unsigned charsbit rs=P2^4;sbit rw=P2^5;sbit e=P2^6;uchar busyc,line;void delay(uchar n){uchar x,y;for(x=n;x>0;x--)for(y=110;y>0;y--);}void busy(uchar busyc){rs=0;rw=1;e=1;delay(1);busyc=P0;e=0;}void write_command(uchar command) {busy(busyc);while(busyc); //判断LCD 是否冗忙rs=0;rw=0;e=1;P0=command;delay(10);e=0;}void write_date(uchar date){busy(busyc);while(busyc); //判断LCD 是否冗忙rs=1;rw=0;e=1;P0=date;delay(10);e=0;}void init(){e=0;write_command(0x38);delay(15);write_command(0x0c);write_command(0x06);write_command(0x01);}void display(unsigned int a,unsigned char *table){uchar i;if(a==1){write_command(0x80); //设置显示位置(第一行开头)for(i=0;i<16;i++)write_date(*(table+i)); //显示字符}if(a==2){write_command(0xc0); //设置显示位置(第二行开头)for(i=0;i<16;i++)write_date(*(table+i)); //显示字符}}void displayUser(unsigned char hang,unsigned lie,unsigned char table[])和列号//定位显示,定位行号{unsigned char add,i;if(hang==1){add=0x80+lie-1;}if(hang==2){add=0xc0+lie-1;}write_command(add);for(i=0;i<(add%15);i++)write_date(table[i]); //显示字符}void Ddisplay(unsigned char hang,unsigned lie,unsigned char table[]) //动态、定位显示,定位行号和列号{unsigned char add,i,m;if(hang==1){add=0x80+lie-1;}if(hang==2){add=0xc0+lie-1;}write_command(add);for(i=0;i<(add%15);i++){write_date(table[i]); //显示字符for(m=0;m<4;m++)delay(250);}}void Fldisplay(unsigned char hang,unsigned lie,unsigned char table[])//闪烁、定位显示,定位行号和列号{unsigned char add,i;if(hang==1){add=0x80+lie-1;}if(hang==2){add=0xc0+lie-1;}write_command(add);while(1){for(i=0;i<(add%15);i++){write_date(table[i]); //显示字符}delay(250);delay(250);delay(250);write_command(0x01); delay(250);delay(250);delay(250);}}。
加个模块,实现IIC驱动LCD1602 PCF8574模块使实现IIC驱动LCD1602成为现实。
下图是PCF8574模块与1602的连接电路图:实物接法如下:想要使用PCF8574模块来实现IIC驱动LCD1602,首先非常必要弄清楚IIC的时序、PCF8574设备地址、四线控制LCD1602方法。
下面是两个重要的h文件。
通过修改这两个h文件中的部分代码(接线有所不同)即可移植到你的程序中去。
PCF8574.h程序:sbit scl=P1^6;sbit sda=P1^7;void delay()//{ ;; }void init()//IIC初始化{sda=1;delay();scl=1;delay();}void start() //IIC开始信号{sda=1;delay();sda=0;delay();}void stop() //IIC停止{sda=0;delay();scl=1;delay();sda=1;delay();}void respons() //IIC应答{uchar i;scl=1;delay();while((sda==1)&&(i<250))i++;}void write_byte(uchar date)//IIC写入数据{uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl=0;delay();sda=CY;delay();scl=1;delay();}scl=0;delay();sda=1;uchar read_byte()//IIC读取字节{uchar i,k;scl=0;delay();sda=1;delay();for(i=0;i<8;i++){scl=1;delay();k=(k<<1)|sda;scl=0;delay();}return k;}start();write_byte(0x7e); //8574设备地址(写)respons();write_byte(date1);respons();stop();}uchar read_add()//向IO读取数据{uchar date1;start();write_byte(0x71); //8574设备地址(读)respons();date1=read_byte();respons();stop();return date1;}PCF8574+LCD1602_4.h程序:uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}void write_com(uchar com) //写命令函数{ uchar com1,com2;com1=com|0x0f;write_add(com1&0xfc);delay1(2);write_add(com1&0xf8);com2=com<<4;com2=com2|0x0f;write_add(com2&0xfc);delay1(2);write_add(com2&0xf8);}void write_date(uchar date) //写数据函数{date1=date|0x0f;write_add(date1&0xfd);delay1(2);write_add(date1&0xf9);date2=date<<4;date2=date2|0x0f;write_add(date2&0xfd);delay1(2);write_add(date2&0xf9);}void init_lcd() //初始化函数{write_com(0x33); //显示模式设置delayms(6);write_com(0x32); //显示模式设置delayms(6);write_com(0x28); //4位总线,双行显示,显示5×7的点阵字符delayms(6);write_com(0x01); //清屏write_com(0x06); //字符进入模式:屏幕不动,字符后移delayms(6);write_com(0x0c); //显示开,关光标//write_LCD_Command(0x0f); //显示开,开光标,光标闪烁delayms(6);}//显示字符串:第x行第y列显示什么内容void ShowString(unsigned char x,unsigned char y,unsigned char *str){//设置起始位置if(x == 1){write_com(0x80 | y-1);// |相当于加法}if(x == 2){write_com(0xc0 | y-1);}//输出字符串while(*str!='\0') {write_date(*str);str++;}}。
/*LCD1602 驱动程序 */
display (行号,数据指针) displayUser (行号,列号,字符/字符串) Ddisplay (行号、列号、字符/字符串) Fldisplay (行号、列号、字符/字符串)
/*
声明代码(放工程中需要包含的自定义头文件中)
void delay(unsigned char n);
void init();
void display(unsigned char a,unsigned char table[]);
void write_date(uchar);
void write_command(uchar);
void displayUser(unsigned char hang,unsigned lie,unsigned char table[]); void Ddisplay(unsigned char hang,unsigned lie,unsigned char table[]);
void Fldisplay(unsigned char hang,unsigned lie,unsigned char table[]);
*/
#include <reg51.h>
#define uchar unsigned char
sbit rs=P2A 4;
sbit rw=P2A5;
sbit e=P2A6;
uchar busyc,line;
void delay(uchar n)
{
uchar x,y;
for(x=n;x>0;x--)
for(y=110;y>0;y--);
}
void busy(uchar busyc)
{
rs=0;
rw=1;e=1;
delay(1);
busyc=P0;
e=0;
}
void write_command(uchar command)
{
/* 程序用法: 1、按行显示:
2、定位显示
3、动态显示
4、闪烁显示
*/
busy(busyc);
while(busyc); // 判断LCD 是否忙碌
rs=0;
rw=0;
e=1;
P0=command;
delay(10);
e=0;
}
void write_date(uchar date)
{
busy(busyc);
while(busyc); // 判断LCD 是否忙碌
rs=1;
rw=0;
e=1;
P0=date;
delay(10);
e=0;}
void init()
{
e=0;
write_command(0x38);
delay(15);
write_command(0x0c);
write_command(0x06);
write_command(0x01);
}
void display(unsigned int a,unsigned char *table)
{
uchar i;
if(a==1)
{
write_command(0x80); // 设置显示位置(第一行开头) for(i=0;i<16;i++)
write_date(*(table+i)); // 显示字符
}
if(a==2)
{
write_command(0xc0); // 设置显示位置(第二行开头)
for(i=0;i<16;i++)
write_date(*(table+i)); // 显示字符
}
}
void displayUser(unsigned char hang,unsigned lie,unsigned char table[]) // 定位显示,定位行号和列号。