51单片机的电子钟以及lcd1602显示器的工作原理基于51单片机的电子钟C语言程序#include<reg51.h>#include<absacc.h>#define uchar unsigned char#define uint unsigned int/*七段共阴管显示定义*/uchar codedispcode[ ]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0xBF,0x86,0xCB,0xCF,0x EF,0xED,0xFD,0x87,0xFF,0xDF};/*定义并初始化变量*/uchar seconde=0;uchar minite=0;uchar hour=12;uchar mstcnt=0;sbit P1_0=P1^0; // second 调整定义sbit P1_1=P1^1; //minite调整定义sbit P1_2=P1^2; //hour调整定义/*函数声明*/void delay(uchar k ); //延时子程序void time_pro( ); //时间处理子程序void display( ); //显示子程序void keyscan( ); //键盘扫描子程序/*****************************//*延时子程序*//****************************/void delay (uchar k){uchar j;while((k--)!=0){for(j=0;j<125;j++){;}}}/**************************//*时间处理子程序*//**************************/void time_pro( void){if(seconde==60)//秒钟设为60进制{ seconde=0;minite++;if( minite==60) //分钟设为60进制{ minite=0;hour++;if(hour==24) //时钟设为24进制{hour=0; }}}}/*****************************//* 显示子程序*//*****************************/void display(void){P2=0xfe;P0=dispcode[hour/10];//显示小时的十位delay(4);P2=0xfd;P0=(dispcode[(hour%10)])|0X80; //显示小时的个位delay(4);P2=0xfb;P0=dispcode[minite/10]; //显示分的十位delay(4);P2=0xf7;P0=(dispcode[minite%10])|0X80; //显示分的个位delay(4);P2=0xef;P0=dispcode[seconde/10]; //显示秒的十位delay(4);P2=0xdf;P0=dispcode[seconde%10]; //显示秒的个位delay(4);}/*******************************//*键盘扫描子程序*//*******************************/void keyscan (void){if(P1_0==0) //按键1秒的调整{delay(30);if(P1_0==0){seconde++;if(seconde==60){seconde=0; }}}if(P1_1==0) //按键2分的调整{delay(30);if(P1_1==0){minite++;if(minite==60){minite=0;}}}if(P1_2==0) //按键3小时的调整{delay(30);if(P1_2==0){hour++;if(hour==24){hour=0; }}}}void timer0(void) interrupt 1 using 0 //定时器0方式1,50ms 中断一次{TH0=0x3c;TL0=0xb0;TMOD = 0x11;mstcnt++;if(mstcnt==20){seconde++;mstcnt=0; //注意点。
对计数单元的清零十分的重要,本次调试中就是} //因为忽略了这一点,给我早成了很大的被动。
}/**************************//*主函数*//**************************/void main(void){ P1=0xff; //初始化p1口,全设为1TMOD = 0x11; //time0为定时器,方式1TH0=0x3c; //预置计数初值TL0=0xb0;EA=1;ET0=1;TR0=1;while (1){keyscan( ); //按键扫描time_pro( ); //时间处理display( ); //显示时间}}1602的工作原理1602LCD 分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别1602LCD 主要技术参数:显示容量:16×2 个字符芯片工作电压:4.5—5.5V工作电流:2.0mA(5.0V)模块最佳工作电压:5.0V字符尺寸:2.95×4.35(W×H)mm引脚功能说明1602LCD 采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表10-13 所示:编号符号引脚说明编号符号引脚说明1 VSS 电源地9 D2 数据2 VDD 电源正极10 D3 数据3 VL 液晶显示偏压11 D4 数据4 RS 数据/命令选择12 D5 数据5 R/W 读/写选择13 D6 数据6 E 使能信号14 D7 数据7 D0 数据15 BLA 背光源正极8 D1 数据16 BLK 背光源负极表10-13:引脚接口说明表第1 脚:VSS 为地电源。
第2 脚:VDD接5V正电源。
第 3 脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K 的电位器调整对比度。
第4 脚:RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5 脚:R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和R/W 共同为低电平时可以写入指令或者显示地址,当RS 为低电平R/W 为高电平时可以读忙信号,当RS 为高电平R/W为低电平时可以写入数据。
第6 脚:E端为使能端,当 E 端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8 位双向数据线。
第15脚:背光源正极。
第16脚:背光源负极。
DL=1:数据长度为8位,DL=0:数据长度为4位 N=1:双列字,N=0:单列字;F=1:5x10字形,F=0:5x7字形CG RAM地址设定0 0 0 1 CG RAM地址将所要操作的CG RAM地址放入地址计数器DD RAM地址设定0 0 1 DD RAM地址将所要操作的DD RAM地址放入地址计数器忙碌标志位BF 0 1 BF 地址计数器内容读取地址计数器,并查询LCM是否忙碌,BF表示LCM忙碌写入数据1 0 写入数据将数据写入CG RAM或DD RAM读取数据1 1 读取数据读取CG RAM或DD RAM的数据图10-57 1602LCD 内部显示地址例如第二行第一个字符的地址是40H,那么是否直接写入40H 就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平 1 所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。
在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。
每次输入指令前都要判断液晶模块是否处于忙的状态。
1602 液晶模块内部的字符发生存储器(CGROM)已经存储了160 个不同的点阵字符图形,如图10-58 所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B (41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”图表1写数据流程图表2写命令流程图表3判断LCD是否忙碌,忙则返回1#include <reg51.h>#include <intrins.h>sbit rs= P3^5; //寄存器类型,1表示数据寄存器,2表示指令寄存器sbit rw = P3^6; //读写选择,1表示读,0表示写sbit ep = P3^7; //读写使能,下降沿使能void delay(unsigned char ms) //延时n ms{unsigned char i;while(ms--){for(i = 0; i<123; i++){;}}}bit lcd_bz() //判断LCD是否忙碌,1忙碌{bit result;rs = 0;rw = 1;ep = 1;_nop_();_nop_();_nop_();_nop_();result = (bit)(P1 & 0x80);ep = 0;return result;}void lcd_wcmd(unsigned char cmd) //写指令{while(lcd_bz());//判断LCD是否忙碌rs = 0;rw = 0;ep = 0;_nop_();_nop_();P1 = cmd;_nop_();_nop_();_nop_();_nop_();ep = 1;_nop_();_nop_();_nop_();_nop_();ep = 0;}void lcd_pos(unsigned char pos) //显示地址{lcd_wcmd(pos | 0x80);}//写数据void lcd_wdat(unsigned char dat){while(lcd_bz());//判断LCD是否忙碌rs = 1;rw = 0;ep = 0;P1 = dat;_nop_();_nop_();_nop_();_nop_();ep = 1;_nop_();_nop_();_nop_();_nop_();ep = 0;}void lcd_wstr(const unsigned char *s) //写字符串{unsigned char i = 0;while(s[i] != '\0'){lcd_wdat(s[i]);// 显示字符delay(1000);i++;}}void lcd_init() //LCD初始化{lcd_wcmd(0x38); //功能设定delay(1);lcd_wcmd(0x0c); //显示器开关delay(1);lcd_wcmd(0x06); //设定进入模式delay(1);lcd_wcmd(0x01); //清除显示屏,把光标移至左上角delay(1);}void main(void){lcd_init();// 初始化LCDdelay(10);lcd_pos(0x01);//设置显示位置//i = 0;while(1){lcd_wstr("abcdefg");lcd_pos(0x42);lcd_wstr("abcdefg");lcd_wcmd(0x01);delay(3);}}。