#include unsigned char code dis_week[]={\"SUN,MON,TUE,WED,THU,FRI,SAT\ unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; //星期月参变数 unsigned char data dis_buf1[16]; //lcd上排显示缓冲区 unsigned char data dis_buf2[16]; //lcd下排显示缓冲区 unsigned char data year,month,date,week;//年、月、日、星期 unsigned char data armhour,armmin,armsec;//闹钟时、分、秒 unsigned char data hour,min,sec,sec100; //时、分、秒、百分之一秒 unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值 bit alarm; //标识是否启用闹钟,1--启用,0--关闭 sbit rs = P2^0; //LCD数据/命令选择端(H/L) sbit rw = P2^1; //LCD读/写选择端(H/L) sbit ep = P2^2; //LCD使能控制 sbit PRE = P1^6; //调整键(k3) sbit SET = P1^7; //调整键(k4) sbit SPK = P3^7; void delayms(unsigned char ms); //延时程序 bit lcd_busy(); //测试LCD忙碌状态程序 void lcd_wcmd(char cmd); //写入指令到LCD程序 void lcd_wdat(char dat); //写入数据到LCD程序 void lcd_pos(char pos); //LCD数据指针位置程序 void lcd_init(); //LCD初始化设定程序 void pro_timedate(); //时间日期处理程序 void pro_display(); //显示处理程序 void pro_key(); //按键处理程序 void time_alarm(); //定时报警功能(闹钟) unsigned char scan_key(); //按键扫描程序 unsigned char week_proc(); //星期自动计算与显示函数 bit leap_year(); //判断是否为闰年 void lcd_sef_chr(); //LCD自定义字符程序 void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s); //更新显示缓冲区函数 // 延时程序 void delay(unsigned char ms) { while(ms--) { unsigned char i; for(i = 0; i 250; i++) { _nop_(); //执行一条_nop_()指令为一个机器周期 _nop_(); _nop_(); _nop_(); } } } //测试LCD忙碌状态 bit lcd_busy() { bit result; rs = 0; rw = 1; ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); result =(bit)(P0&0x80); //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲 ep = 0; return result; } //写入指令到LCD void lcd_wcmd(char cmd) { while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令 rs = 0; rw = 0; ep = 0; _nop_(); _nop_(); P0 = cmd; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; } //写入数据到LCD void lcd_wdat(char dat) { while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据 rs = 1; rw = 0; ep = 0; P0 = dat; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; } //LCD数据指针位置程序 void lcd_pos(char pos) { lcd_wcmd(pos|0x80); //数据指针=80+地址码(00H~27H,40H~67H) } //设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符) //这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001) void lcd_sef_chr() { //第一个自定义字符 lcd_wcmd(0x40); //\"01 000 000\" 第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7)) lcd_wdat(0x1f); //\"XXX 11111\" 第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭) lcd_wcmd(0x41); //\"01 000 001\" 第2行地址 lcd_wdat(0x11); //\"XXX 10001\" 第2行数据 lcd_wcmd(0x42); //\"01 000 010\" 第3行地址 lcd_wdat(0x15); //\"XXX 10101\" 第3行数据 lcd_wcmd(0x43); //\"01 000 011\" 第4行地址 lcd_wdat(0x11); //\"XXX 10001\" 第4行数据 lcd_wcmd(0x44); //\"01 000 100\" 第5行地址 lcd_wdat(0x1f); //\"XXX 11111\" 第5行数据 lcd_wcmd(0x45); //\"01 000 101\" 第6行地址 lcd_wdat(0x0a); //\"XXX 01010\" 第6行数据 lcd_wcmd(0x46); //\"01 000 110\" 第7行地址 lcd_wdat(0x1f); //\"XXX 11111\" 第7行数据 lcd_wcmd(0x47); //\"01 000 111\" 第8行地址 lcd_wdat(0x00); //\"XXX 00000\" 第8行数据 //第二个自定义字符 lcd_wcmd(0x48); //\"01 001 000\" 第1行地址 lcd_wdat(0x01); //\"XXX 00001\" 第1行数据 lcd_wcmd(0x49); //\"01 001 001\" 第2行地址 lcd_wdat(0x1b); //\"XXX 11011\" 第2行数据 lcd_wcmd(0x4a); //\"01 001 010\" 第3行地址 lcd_wdat(0x1d); //\"XXX 11101\" 第3行数据 lcd_wcmd(0x4b); //\"01 001 011\" 第4行地址 lcd_wdat(0x19); //\"XXX 11001\" 第4行数据 lcd_wcmd(0x4c); //\"01 001 100\" 第5行地址 lcd_wdat(0x1d); //\"XXX 11101\" 第5行数据 lcd_wcmd(0x4d); //\"01 001 101\" 第6行地址 lcd_wdat(0x1b); //\"XXX 11011\" 第6行数据 lcd_wcmd(0x4e); //\"01 001 110\" 第7行地址 lcd_wdat(0x01); //\"XXX 00001\" 第7行数据 lcd_wcmd(0x4f); //\"01 001 111\" 第8行地址 lcd_wdat(0x00); //\"XXX 00000\" 第8行数据 } //LCD初始化设定 void lcd_init() { lcd_wcmd(0x38); //设置LCD为16X2显示,5X7点阵,八位数据借口 delay(1); lcd_wcmd(0x0c); //LCD开显示及光标设置(光标不闪烁,不显示\"-\") delay(1); lcd_wcmd(0x06); //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动) delay(1); lcd_wcmd(0x01); //清除LCD的显示内容 delay(1); } //闰年的计算 bit leap_year() { bit leap; if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件 leap=1; else leap=0; return leap; } //星期的自动运算和处理 unsigned char week_proc() { unsigned char num_leap; unsigned char c; num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数 if( leap_year()&& month=2 ) //既是闰年且是1月和2月 c=5; else c=6; week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期 return week; } //更新显示缓冲区 void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s) { dis_buf1[0]=t1; // dis_buf1[1]=0x20; //空格 dis_buf1[2]=50; //'2' dis_buf1[3]=48; //'0' dis_buf1[4]=year/10+48; dis_buf1[5]=year%10+48; dis_buf1[6]=0x2d; dis_buf1[7]=month/10+48; dis_buf1[8]=month%10+48; dis_buf1[9]=0x2d; //'-' dis_buf1[10]=date/10+48; dis_buf1[11]=date%10+48; dis_buf1[12]=0x20; dis_buf1[13]=dis_week[4*week]; dis_buf1[14]=dis_week[4*week+1]; dis_buf1[15]=dis_week[4*week+2]; dis_buf2[0]=t2[0]; dis_buf2[1]=t2[1]; dis_buf2[2]=t2[2]; dis_buf2[3]=t2[3]; dis_buf2[4]=t2[4]; dis_buf2[5]=t2[5]; dis_buf2[6]=0x20; //空格 if (alarm) dis_buf2[7]=0x01; //alarm=1,显示闹钟启用标致(第二个自定义字符) else dis_buf2[7]=0x20; //alarm=0,不显示闹钟启用标致 dis_buf2[8]=dis_h/10+48; dis_buf2[9]=dis_h%10+48; dis_buf2[10]=0x3a; //':' dis_buf2[11]=dis_m/10+48; dis_buf2[12]=dis_m%10+48; dis_buf2[13]=0x3a; dis_buf2[14]=dis_s/10+48; dis_buf2[15]=dis_s%10+48; } //时间和日期处理程序 void pro_timedate() { sec++; if(sec > 59) {sec = 0; min++; if(min>59) {min=0; hour++; if(hour>23) {hour=0; date++; if (month==1||month==3||month==5||month==7||month==8||month==10||month==12) if (date>31) {date=1;month++;} //大月31天 if (month==4||month==6||month==9||month==11) if (date>30) {date=1;month++;} //小月30天 if (month==2) {if( leap_year()) //闰年的条件 {if (date>29) {date=1;month++;}} //闰年2月为29天 else {if (date>28) {date=1;month++;}} //平年2月为28天 } if (month>12) {month=1;year++;} if (year>99) year=0; } } } week_proc(); if (sec==armsec && min==armmin && hour==armhour) {if (alarm) TR1=1; //闹钟启用时,报警时间到,启动Timer1 } } //显示处理程序 void pro_display() { unsigned char i; lcd_pos(0x00); for (i=0;i=15;i++) {lcd_wdat(dis_buf1[i]);} lcd_pos(0x40); for (i=0;i=15;i++) {lcd_wdat(dis_buf2[i]);} } //Timer0中断处理程序,秒的产生 void timer0() interrupt 1 { TH0=0xdc; //Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D) TL0=0x00; //定时时间 =(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz) sec100++; if(sec100 >= 100) //1秒时间 (100*10ms=1000ms=1s) {sec100 = 0; pro_timedate();//调用时间和日期处理程序 } if (sec&0x01) /\"willar\"闪一秒,停一秒 update_disbuf(0x00,\" \0表示显示00位置的自定义字符 else update_disbuf(0x00,\"willar\ pro_display(); //调用显示处理函数 } //按键扫描程序 unsigned char scan_key() { skey=0x00; 给变量vkey置初值 skey|=PRE; 读取PRE键的状态 skey=skey<<1; PRE键的状态存于skey的B1位 skey|=SET; 读取SET键的状态,并存于skey的B0位 return skey; 返回skey的键值(即PRE,SET的状态) / //0x0 // //将 // // // } //外部中断INT0中断处理程序 void int0() interrupt 0 { TR0=0; //禁止Timer0 IE=0; //禁止中断 lcd_wcmd(0x0e); //显示光标\"_\整个光标不闪烁 alarm=1; update_disbuf(0x50,\"alarm:\更新显示数据,0x50表示要显示\"P\" pro_display(); //调用显示处理程序 lcd_pos(0x47); //使光标位于第一个调整项下 flag=0; vkey=0x03; while(flag^0x0a) {skey = scan_key(); //扫描按键状态 if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体 { delay(10); //去按键抖动 skey = scan_key(); //转回扫描按键状态 if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体 { vkey=skey; //将skey的值付给vkey if (skey==0x01) //PRE键按下 { flag++; //调整标志位加1 switch (flag) //将光标置于相应调整位置 { case 1: lcd_pos(0x49);break; //光标置小时报警设置位置 case 2: lcd_pos(0x4c);break; //光标置分钟报警设置位置 case 3: lcd_pos(0x4f);break; //光标置秒时报警设置位置 e 4: update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x05);break; //光标置年调整位 置 e 5: lcd_pos(0x08);break; //光标置月调整位置 e 6: lcd_pos(0x0b);break; //光标置日调整位置 e 7: lcd_pos(0x49);break; //光标置时调整位置 e 8: lcd_pos(0x4c);break; //光标置分调整位置 e 9: lcd_pos(0x4f);break; //光标置秒调整位置 ault:break; } } if (skey==0x02) //SET键按下 { pro_key(); //转设置按键处理程序 } } } cas cas cas cas cas cas def } lcd_wcmd(0x0c); //设置LCD开显示及光标不闪烁,不显示\"-\" lcd_wcmd(0x01); //清除LCD的显示内容 IE=0x8f; //CPU开中断,INT0,INT1,开中断 TR0=1; //Timer0启动 } //主程序,初始化及初值设定 void main() { lcd_init(); //初始化LCD lcd_sef_chr(); //写入自定义字符号 hour=0;min=0;sec=0; //开机时的时,分,秒显示 armhour=0;armmin=0;armsec=0; //开机时的时,分,秒报警初值 year= 5; month=1;date=1; //开机时的年,月,日,星期显示 week_proc(); alarm=1; //初始开机,启用闹钟 IE = 0x8f; //CPU开中断,INT0,INT1,Timer0,Timer1开中断 IP = 0x04; //设置INT0为中断最高优先级 IT0=0;IT1=0; //外部 INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动) TMOD = 0x11; //Timer0,Timer1工作于模式1, 16位定时方式 TH0 = 0xdc;TL0 = 0x00; //Timer0置10ms定时初值 TH1 = 0xff;TL1 = 0x00; //Timer1置初值 TR0 = 1; //Timer0启动 TR1 = 0; while(1); } //设置按键处理程序 void pro_key() { switch (flag) { case 0:alarm=!alarm; //启用或关闭闹钟(alarm=1:启用,alarm=0:关闭) update_disbuf(0x50,\"alarm:\msec); //更新显示数据 pro_display(); //调用显示处理 lcd_pos(0x47);break; //光标回到原调整位置 case 1:armhour++; if (armhour>23) armhour=0; update_disbuf(0x50,\"alarm:\msec); //更新显示数据 pro_display(); //调用显示处理 lcd_pos(0x49);break; //光标回到原调整位置 case 2:armmin++; if (armmin>59) armmin=0; update_disbuf(0x50,\"alarm:\msec); pro_display(); lcd_pos(0x4c);break; case 3:armsec++; if (armsec>59) armsec=0; update_disbuf(0x50,\"alarm:\msec); pro_display(); lcd_pos(0x4f);break; case 4:year++; if (year> 99) year= 0; week_proc(); //星期自动运算 update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x05);break; case 5:month++; if (month>12) month=1; week_proc(); //星期自动运算 update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x08);break; case 6:date++; if (month==1||month==3||month==5||month==7||month==8||month==10||month==12) if (date>31) date=1; //大月31天 if (month==4||month==6||month==9||month==11) if (date>30) date=1; //小月30天 if (month==2) {if(leap_year()) //闰年的条件 {if (date>29) date=1;} //闰年2月为29天 else {if (date>28) date=1;}} //平年2月为28天 week_proc(); //星期自动运算 update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x0b);break; case 7:hour++; if (hour>23) hour=0; update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x49);break; case 8:min++; if (min>59) min=0; update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x4c);break; case 9:sec++; if (sec>59) sec=0; update_disbuf(0x50,\"time: \ pro_display(); lcd_pos(0x4f);break; default: break ; } } //Timer1中断处理程序,产生报警的声音 void timer1() interrupt 3 { TH1=0xff; TL1=0x00; SPK=~SPK; } //外部中断INT1中断处理程序,停止报警声音 void int1() interrupt 2 { if(TR1) TR1=0; } //DS1302时钟程序 #include /********************************************************************/ //少占鱼制作 河北正定欢迎您 长沙航空职业技术学院 //2010 年QQ:4116534 //版权所有:www.51hei.com #define LCD1602_RS P2_5 //定义引脚 #define LCD1602_RW P2_6 #define LCD1602_E P2_7 #define LCD1602_IO P0 #define Busy 0x80 //用于检测LCD1602状态字中的Busy标识 const uchar num[]=\" 34567+\"; uchar code a[] = {\" E N v\void WriteData(uchar DAT); void WriteCommand(uchar command,BuysC); uchar ReadData(void); void Readbusy(void); void LCD1602_Init(void); void DisplayOneChar(uchar X, uchar Y, uchar DData); void Displaystring(uchar X, uchar Y, uchar *DData); void Delay5Ms(void); void Delay400Ms(void); void delayms(uint); void delays(uint m) ; void delayus(uchar x) ; sbit DS1302_CLK =P2^0;// P1^0; sbit DS1302_IO =P2^1;// P1^1; sbit DS1302_RST =P2^2;// P1^2; uchar shuju; unsigned char time[]={0x11,0x03,0x28,0x01,0x12,0x39,0x00};// 初始化时间年月日星期时分秒 uchar Display_Buffer[12]={\"12:25:00\时、分、秒 的格式 uchar riqi[12]={\"11-03-28\年、月、日 的格式 uchar xingqi[5]=\"week\";//星期 unsigned char second,minute,hour,week,day,month,year; /******************1602函数********************************/ /********************************************************************/ void delays(uint m) { uint i,j; for(i=0;i void Delay(void) { unsigned char i; unsigned int j; for(i=0;i<200;i++) for(j=300;j>0;j--); } /***************************************************************************** 函数功能:向DS1302送一字节数据子程序 入口参数: 出口参数: *****************************************************************************/ void InputByte(unsigned char BYTE) { char i; for(i=8;i>0;i--) { //前面在read_ds1302()函数里已经把CLK清0了 DS1302_CLK=0;//这里再清0一次,看着清楚。呵呵 _nop_(); DS1302_IO=(bit)(BYTE&0x01);//取出低位数据给数据引脚 _nop_(); _nop_(); DS1302_CLK=1;//置1,时钟上升沿,引脚上的数据传入1302寄存器中 _nop_(); _nop_(); BYTE>>=1;//因为这里移位的BYTE不是最后要的结果,虽然最后循环完会多移一位,但没影响。 _nop_(); //循环最后一次后,时钟状态是高电平。 } _nop_(); _nop_(); } /***************************************************************************** 函数功能:读DS1302一个字节子程序,读数据是下降沿读 入口参数: 出口参数: *****************************************************************************/ unsigned char OutputByte(void) { unsigned char i; unsigned char ucdat=0; for(i=8;i>0;i--) { //前面时钟状态是高电平。 ucdat>>=1; //移位注意,移位不能放在循环语句末,否则最后循环完会多移一位。得到结果就错了。 DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。 DS1302_CLK=0;//紧接着时钟变低,下降沿数据输出。 if(DS1302_IO)//数据已经输出,判断是1还是0. ucdat|=0x80;//如果引脚是高则此位保存1。低不保存,右移的时候自然补0了。 _nop_(); DS1302_CLK=1;//读完一位数据,再置高时钟,准备读下一个。 _nop_();//延时一下。 } //读完数据还是把时钟清0,下次好直接用。 DS1302_CLK=0;//读完数据还是把时钟清0,下次好直接用。 _nop_(); _nop_(); DS1302_RST=0; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); DS1302_CLK=0; _nop_(); _nop_(); _nop_(); _nop_(); DS1302_RST=0; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); return(ucdat); } /***************************************************************************** 函数功能:向DS1302某地址写一字节数据子程序 入口参数:addr,TDat 出口参数: *****************************************************************************/ void write_ds1302(unsigned char addr,unsigned char TDat) { DS1302_RST=0; _nop_(); _nop_(); DS1302_CLK=0; _nop_(); _nop_(); DS1302_RST=1; _nop_(); _nop_(); _nop_(); _nop_(); InputByte(addr);//先写地址 _nop_(); _nop_(); InputByte(TDat);//再写数据 DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。 DS1302_RST=0; delayus(10); DS1302_CLK=0; delayus(10); } /***************************************************************************** 函数功能:读DS1302地址子程序 入口参数:add 出口参数:timedata *****************************************************************************/ unsigned char read_ds1302(unsigned char addr) { unsigned char timedata; DS1302_RST=0; _nop_(); DS1302_CLK=0; _nop_(); DS1302_RST=1; InputByte(addr);//先写入读命令 timedata=OutputByte();//再读出数据 DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。 DS1302_RST=0; delayus(10); DS1302_CLK=0; delayus(10); return(timedata); } /***************************************************************************** 函数功能:初始化DS1302子程序 入口参数:time[](全局变量) 出口参数: *****************************************************************************/ void initial_ds1302() { DS1302_IO=1;//单片机端置高防止破坏1302传来的数据,开始接收1302端的高低数据对数据线的改变。 DS1302_RST=0; delayms(100); DS1302_CLK=0; delayms(100); write_ds1302(0x8e,0x00); //写保护寄存器,在对时钟或RAM写前WP一定要为0 write_ds1302(0x8c,time[0]); //年 write_ds1302(0x88,time[1]); //月 write_ds1302(0x86,time[2]); //日 write_ds1302(0x8A,time[3]); //星期 write_ds1302(0x84,time[4]); //时 write_ds1302(0x82,time[5]); //分 write_ds1302(0x80,time[6]); //秒 write_ds1302(0x8e,0x80); //写保护寄存器 } /***************************************************************************** 函数功能:读DS1302时间子程序 入口参数: 出口参数:全局变量(second,minute,hour,week,day,month,year) *****************************************************************************/ void read_time() { second=read_ds1302(0x81); //秒寄存器 _nop_(); minute=read_ds1302(0x83); //读分 _nop_(); hour=read_ds1302(0x85); //读时 _nop_(); week=read_ds1302(0x8B); //读星期 _nop_(); day=read_ds1302(0x87); //日 _nop_(); month=read_ds1302(0x); //月 _nop_(); year=read_ds1302(0x8d); //年 _nop_(); } void main(void) {uchar shuju; delayms(2); Delay400Ms(); //启动等待,等LCM讲入工作状态 delays(1); LCD1602_Init(); //LCM初始化 Delay5Ms(); //延时片刻(可不要) DS1302_RST=0; delayms(1000); DS1302_CLK=0; delayms(1000); shuju=ReadData(); Displaystring(2, 0, a); Delay();Delay(); delayms(2000); Displaystring(3,0,riqi); Displaystring(12,0,xingqi); delayms(4000); // initial_ds1302(); //初始化DS1302 delayms(1200); while(1) { read_time();//读取时间 Display_Buffer[0]=hour/16+'0';//存储下时的高位进数组 Display_Buffer[1]=hour%16+'0';//存储下时的低位进数组 Display_Buffer[3]=minute/16+'0';//注意+'0'后存储的是ASCII。用于下面液晶显示。 Display_Buffer[4]=minute%16+'0';//注意+'0'后存储的是ASCII。用于下面液晶显示。 Display_Buffer[6]=second/16+'0'; Display_Buffer[7]=second%16+'0'; riqi[0]=year/16+'0'; riqi[1]=year%16+'0'; riqi[3]=month/16+'0'; riqi[4]=month%16+'0'; riqi[6]=day/16+'0'; riqi[7]=day%16+'0'; Displaystring(3,0,riqi); delayms(1); DisplayOneChar(14,1,week+'0'); Displaystring(3,1,Display_Buffer); } } //写数据 void WriteData(uchar DAT) { Readbusy(); LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_IO = DAT; LCD1602_E = 0; //若晶振速度太高可以在这后加小的延时 LCD1602_E = 0; //延时 LCD1602_E = 1; LCD1602_E=1; LCD1602_E=0; } //写指令 void WriteCommand(uchar command,BuysC) //BuysC为0时忽略忙检测 { LCD1602_IO=0x00; if (BuysC) Readbusy(); //根据需要检测忙 LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_IO = command; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; LCD1602_E = 1; LCD1602_E=0; } //读数据 uchar ReadData(void) { Readbusy(); LCD1602_RS = 1; LCD1602_RW = 1; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; delayms(1); LCD1602_E = 0; return(LCD1602_IO); } //读忙 void Readbusy(void) { LCD1602_IO = 0xff; LCD1602_RS = 0; LCD1602_RW = 1; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; delayms(2); while (LCD1602_IO&0x80); //检测忙信号 LCD1602_E = 0; } //初始化 void LCD1602_Init(void) //LCM初始化 { Delay400Ms(); LCD1602_E = 0; LCD1602_IO=0x00; WriteCommand(0x38,0); //三次显示模式设置,不检测忙信号 Delay5Ms(); WriteCommand(0x38,0); Delay5Ms(); WriteCommand(0x38,0); Delay5Ms(); WriteCommand(0x38,1); //显示模式设置,开始要求每次检测忙信号 Delay5Ms(); WriteCommand(0x08,1); //关闭显示 ] Delay5Ms(); WriteCommand(0x01,1); //显示清屏 Delay5Ms(); WriteCommand(0x06,1); // 显示光标移动设置 Delay5Ms(); WriteCommand(0x0f,1); // 显示开及光标设置 Delay5Ms(); } //按指定位置显示一个字符 void DisplayOneChar(uchar X, uchar Y, uchar DData) { Y &= 0x01; X &= 0x0f; //X不能大于15,Y不能大于1 if (Y) X |= 0x40; //当要显示第二行时地址码+0x40; X |= 0x80; // 算出指令码 WriteCommand(X, 0); //这里不检测忙信号,发送地址码 WriteData(DData); } //按指定位置显示一串字符 void Displaystring(uchar X, uchar Y, uchar *DData) { uchar ListLength; ListLength = 0; Y &= 0x01; X &= 0x0f; //X不能大于15,Y不能大于1 while (DData[ListLength]>0x20) //若到达字串尾则退出 { if (X <= 0x0f) //X坐标应小于0x0f { DisplayOneChar(X, Y, DData[ListLength]); //显示单个字符 ListLength++; X++; } } } //5ms延时 void Delay5Ms(void) { unsigned int t = 5552; while(t--); } //400ms延时 void Delay400Ms(void) { uchar i = 5; uint j; while(i--) { j=7269; while(j--); } } // void delayms(uint k) { uint data i,j; for(i=0;i void delayus(uchar x) { while(--x); }
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- gamedaodao.com 版权所有 湘ICP备2022005869号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务