本帖最后由 51黑电子会员 于 2020-4-25 09:50 编辑
- #include<reg52.h>//单片机头文件
- #define uchar unsigned char//宏定义,用uchar表示unsigned char,叫无符号字符型数据类型,取值范围为:0到255。
- #define uint unsigned int//宏定义,用uint表示unsigned int,叫无符号整数型数据类型,取值范围为:0到65535。
- sbit RS=P0^7;//位定义LCD1602字符型液晶显示器的数据/命令选择引脚
- sbit RW=P0^6;//位定义LCD1602字符型液晶显示器的读写引脚
- sbit EN=P0^5; //位定义LCD1602字符型液晶显示器的使能引脚
- sbit S1=P3^5;//移位按键S1
- sbit S2=P3^4;//增加按键S2
- sbit S3=P3^3;//减少按键S3
- sbit S4=P3^2;//启停按键S4
- uchar count,S1num,S4num;//count为定时器0中断次数变量,S1num为移位按键S1按键按下次数变量,S4num为启停按键S4按下次数变量。
- uchar shi,fen,miao;//未做时间修改的计时时钟、分钟、秒钟变量
- uchar secondge,secondshi; //秒钟个位、十位的变量
- uchar minutange,minutanshi;//分钟个位、十位的变量
- uchar hourge,hourshi;//时钟个位、十位的变量
- uchar table0[]="2019-11-11";//LCD1602第一行初始显示
- uchar table1[]="00:00:00";//LCD1602第二行初始显示
- void Delay(uint z)//延时程序
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- void WriteCommand(uchar command)//LCD1602字符型液晶显示器写指令函数
- {
- RS=0;//LCD1602字符型液晶显示器指令寄存器低电平
- RW=0;//LCD1602字符型液晶显示器写指令操作低电平
- P2=command;//LCD1602字符型液晶显示器写指令函数写指令到单片机P2组端口,再输送到LCD1602字符型液晶显示器指令寄存器中执行。
- Delay(5);//实际单片机演示,可以去掉延时。Proteus 仿真,需要保留延时。
- EN=1;//LCD1602字符型液晶显示器使能端高电平
- Delay(5);//实际单片机演示,可以去掉延时。Proteus 仿真,需要保留延时。
- EN=0;//LCD1602字符型液晶显示器使能端低电平
- }
- void WriteData(uchar information)//LCD1602字符型液晶显示器写数据函数
- {
- RS=1;//LCD1602字符型液晶显示器数据寄存器高电平
- RW=0;//LCD1602字符型液晶显示器写数据操作低电平
- P2=information;//LCD1602字符型液晶显示器写数据函数写数据到单片机P2组端口,再输送到LCD1602字符型液晶显示器上显示。
- Delay(5);//实际单片机演示,可以去掉延时。Proteus 仿真,需要保留延时。
- EN=1;//LCD1602字符型液晶显示器使能端高电平
- Delay(5);//实际单片机演示,可以去掉延时。Proteus 仿真,需要保留延时。
- EN=0;//LCD1602字符型液晶显示器使能端低电平
- }
- void LCD1602Init()//LCD1602初始化函数
- {
- WriteCommand(0x38);//设置LCD1602字符型液晶显示器16x2显示,5*7或5*8点阵,8位数据并口,简称显模。
- WriteCommand(0x08);//设置LCD1602字符型液晶显示器显示开,简称亮屏。
- WriteCommand(0x01);//设置清除LCD1602字符型液晶显示器屏上所有内容,并让光标复位到LCD1602字符型液晶显示器屏左上角,简称清屏。
- WriteCommand(0x06);//设置开光标(或字符)地址指针自增1,光标右移动一个字符位,整屏显示不移动。
- WriteCommand(0x0c);//设置开LCD1602字符型液晶显示器显示,关光标,关光标(字符)闪烁。
- }
- void Timer0Init()//定时器0初始化函数
- {
- TMOD=0x01;//设定定时器0工作模式为模式1
- TH0=(65536-50000)/256;//TH0装初值
- TL0=(65536-50000)%256;//TL0装初值
- EA=1;//开启定时器总中断
- ET0=1;//开启定时器0中断开关
- TR0=1;//启动定时器0
- }
- void LCD1602Display()//LCD1602字符型液晶显示器显示函数
- {
- uchar j;//j表示数组元素个数变量
- WriteCommand(0x80+0x00);//LCD1602字符型液晶显示器第一行第一个位置显示
- for(j=0;j<10;j++)//有10个字符,要循环10次。
- {
- WriteData(table0[j]);//显示字符串
- Delay(5);
- }
- WriteCommand(0x80+0x40);//LCD1602字符型液晶显示器第二行第一个位置显示
- for(j=0;j<8;j++)//有8个字符,要循环8次。
- {
- WriteData(table1[j]);//显示字符串
- Delay(5);
- }
- }
- void LCD1602DisplayTime(uchar address,uchar num)//LCD1602显示时间两位数分解函数
- {
- uchar shi,ge;//十位、个位的变量
- shi=num/10;//十位数
- ge=num%10;//个位数
- WriteCommand(0x80+0x40+address);//LCD1602字符型液晶显示器第二行某个显示位
- WriteData(0x30+shi);//0x30表示字符库的数字0,整个代码表示十位可显示0到9的数字。
- WriteData(0x30+ge);//0x30表示字符库的数字0,整个代码表示个位可显示0到9的数字。
- }
- void LCD1602DisplayGeDigitResolve(uchar address,uchar num)//LCD1602字符型液晶显示器显示修改时间个位数分解函数
- {
- uchar ge;//个位的变量
- ge=num%10;//个位数
- WriteCommand(0x80+0x40+address);//LCD1602字符型液晶显示器第二行某个显示位
- WriteData(0x30+ge);//0x30表示字符库的数字0,整个代码表示个位可显示0到9的数字。
- }
- void LCD1602DisplayShiDigitResolve(uchar address,uchar num)//LCD1602字符型液晶显示器修改时间十位数分解函数
- {
- uchar shi;//十位变量
- shi=num%10;//十位数
- WriteCommand(0x80+0x40+address);//LCD1602字符型液晶显示器第二行某个显示位
- WriteData(0x30+shi);//0x30表示字符库的数字0,整个代码表示十位可显示0到9的数字。
- }
- void KeyScan()//按键扫描函数
- {
- if(S1==0)//判断移位按键S1是否按下
- {
- Delay(5);
- if(S1==0)//再次判断移位按键S1是否按下
- {
- S1num++;//移位按键S1按键次数变量先赋值再自加
- while(!S1);//等待移位按键S1弹起
- switch(S1num)
- {
- case 1:
- TR0=0;//关定时器0
- S4num=0;//启停按键S4按下次数清零
- secondge=miao%10;//关掉定时器0定时后,把秒钟计时时间数值取余赋给秒钟个位显示位。
- secondshi=miao/10;//关掉定时器0定时后,把秒钟计时时间数值取除赋给秒钟十位显示位。
- WriteCommand(0x80+0x40+0x07);//LCD1602字符型液晶显示器第二行第8个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 2:
- secondshi=secondshi;//关掉定时器0定时后,把秒钟计时时间数值取除后得到的值再赋给秒钟十位显示位。
- WriteCommand(0x80+0x40+0x06);//LCD1602字符型液晶显示器第二行第7个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 3:
- minutange=fen%10;//关掉定时器0定时后,把分钟计时时间数值取余赋给分钟个位显示位。
- minutanshi=fen/10;//关掉定时器0定时后,把分钟计时时间数值取除赋给分钟十位显示位。
- WriteCommand(0x80+0x40+0x04);//LCD1602字符型液晶显示器第二行第5个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 4:
- minutanshi=minutanshi;//关掉定时器0定时后,把分钟计时时间数值取除后得到的值再赋给分钟十位显示位。
- WriteCommand(0x80+0x40+0x03);//LCD1602字符型液晶显示器第二行第4个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 5:
- hourge=shi%10;//关掉定时器0定时后,把时钟计时时间数值取余赋给时钟个位显示位。
- hourshi=shi/10;//关掉定时器0定时后,把时钟计时时间数值取除赋给时钟十位显示位。
- WriteCommand(0x80+0x40+0x01);//LCD1602字符型液晶显示器第二行第2个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 6:
- hourshi=hourshi;//关掉定时器0定时后,把时钟计时时间数值取除后得到的值再赋给时钟十位显示位。
- WriteCommand(0x80+0x40+0x00);//LCD1602字符型液晶显示器第二行第1个位置的显示位
- WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- break;
- case 7:
- WriteCommand(0x80+0x40+0x07);//LCD1602字符型液晶显示器第二行第8个位置的显示位
- WriteCommand(0x0c);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
- TR0=1;//打开定时器0
- S1num=0;//移位按键S1按键按下次数清零
- break;
- default:
- S1num=0;//移位按键S1按键按下次数清零
- break;
- }
- }
- }
- if(S1num!=0)//判断移位按键S1按键按下次数变量是否为0
- {
- if(S2==0)//判断增加按键S2是否按下
- {
- if(S2==0)//判断增加按键S2是否按下
- {
- Delay(5);
- if(S2==0)//再次判断增加按键S2是否按下
- {
- while(!S2);//等待增加按键S2弹起
- switch(S1num)//移位按键S1按键按下次数变量选择位
- {
- case 1://移位按键S1按键第一次按下
- secondge++;//秒钟个位数先赋值再加加
- if(secondge==10)//判断秒钟个位数设定值是否达到10
- secondge=0;//秒钟个位数归零
- LCD1602DisplayGeDigitResolve(0x07,secondge);//LCD1602字符型液晶显示器第二行第8个位置的秒钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x07);//写入LCD1602字符型液晶显示器第二行第8个位置的秒钟个位显示位
- miao=secondshi*10+secondge;//移位修改秒钟个位显示位的数值后,需要通过秒钟十位显示位的数值加上秒钟个位显示位的数值之和赋给秒钟变量,才能在修改秒钟个位或十位显示位的数值后重新计时。(原因:秒钟个位或十位显示位的数值是在秒钟的数值上分解得来,当秒钟个位或十位显示位的数值发生变化后,秒钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 2://移位按键S1按键第二次按下
- secondshi++;//秒钟十位数先赋值再加加
- if(secondshi==6)//判断秒钟十位数设定值是否达到6
- secondshi=0;//秒钟十位数归零
- LCD1602DisplayShiDigitResolve(0x06,secondshi);//LCD1602字符型液晶显示器第二行第7个位置的秒钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x06);//写入LCD1602字符型液晶显示器第二行第7个位置的秒钟十位显示位
- miao=secondshi*10+secondge;//移位修改秒钟十位显示位的数值后,需要通过秒钟十位显示位的数值加上秒钟个位显示位的数值之和赋给秒钟变量,才能在修改秒钟个位或十位显示位的数值后重新计时。(原因:秒钟个位或十位显示位的数值是在秒钟的数值上分解得来,当秒钟个位或十位显示位的数值发生变化后,秒钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 3://移位按键S1按键第三次按下
- minutange++;//分钟个位数先赋值再加加
- if(minutange==10)//判断分钟个位数设定值是否达到10
- minutange=0;//分钟个位数归零
- LCD1602DisplayGeDigitResolve(0x04,minutange);//LCD1602字符型液晶显示器第二行第5个位置的分钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x04);//写入LCD1602字符型液晶显示器第二行第5个位置的分钟个位显示位
- fen=minutanshi*10+minutange;//移位修改分钟个位显示位的数值后,需要通过分钟十位显示位的数值加上分钟个位显示位的数值之和赋给分钟变量,才能在修改分钟个位或十位显示位的数值后重新计时。(原因:分钟个位或十位显示位的数值是在分钟的数值上分解得来,当分钟个位或十位显示位的数值发生变化后,分钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 4://移位按键S1按键第四次按下
- minutanshi++;//分钟十位数先赋值再加加
- if(minutanshi==6)//判断分钟十位数设定值是否达到6
- minutanshi=0;//分钟十位数归零
- LCD1602DisplayShiDigitResolve(0x03,minutanshi);//LCD1602字符型液晶显示器第二行第4个位置的分钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x03);//写入LCD1602字符型液晶显示器第二行第7个位置的分钟十位显示位
- fen=minutanshi*10+minutange;//移位修改分钟十位显示位的数值后,需要通过分钟十位显示位的数值加上分钟个位显示位的数值之和赋给分钟变量,才能在修改分钟个位或十位显示位的数值后重新计时。(原因:分钟个位或十位显示位的数值是在分钟的数值上分解得来,当分钟个位或十位显示位的数值发生变化后,分钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 5://移位按键S1按键第五次按下
- hourge++;//时钟个位数先赋值再加加
- if(hourge==4)//判断时钟个位数设定值是否达到4
- hourge=0;//时钟个位数归零
- LCD1602DisplayGeDigitResolve(0x01,hourge);//LCD1602字符型液晶显示器第二行第2个位置的时钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x01);//写入LCD1602字符型液晶显示器第二行第2个位置的时钟个位显示位
- shi=hourshi*10+hourge;//移位修改时钟个位显示位的数值后,需要通过时钟十位显示位的数值加上时钟个位显示位的数值之和赋给时钟变量,才能在修改时钟个位或十位显示位的数值后重新计时。(原因:时钟个位或十位显示位的数值是在时钟的数值上分解得来,当时钟个位或十位显示位的数值发生变化后,时钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 6://移位按键S1按键第六次按下
- hourshi++;//时钟十位数先赋值再加加
- if(hourshi==3)//判断时钟十位数设定值是否达到3
- hourshi=0;//时钟十位数归零
- LCD1602DisplayShiDigitResolve(0x00,hourshi);//LCD1602字符型液晶显示器第二行第1个位置的时钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x00);//写入LCD1602第二行第1个位置的时钟十位显示位
- shi=hourshi*10+hourge;//移位修改时钟十位显示位的数值后,需要通过时钟十位显示位的数值加上时钟个位显示位的数值之和赋给时钟变量,才能在修改时钟个位或十位显示位的数值后重新计时。(原因:时钟个位或十位显示位的数值是在时钟的数值上分解得来,当时钟个位或十位显示位的数值发生变化后,时钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- default:
- S1num=0;//移位按键S1按键按下次数清零
- break;
- }
- }
- }
- if(S3==0)//判断减少按键S3是否按下
- {
- Delay(5);
- if(S3==0)//再次判断减少按键S3是否按下
- {
- while(!S3);//等待减少按键S3弹起
- switch(S1num)//移位按键S1按键按下次数变量选择位
- {
- case 1://移位按键S1按键第一次按下
- secondge--;//秒钟个位数先赋值再减减
- if(secondge==-1)//判断秒钟个位数设定值是否达到-1
- secondge=9;//秒钟个位数归9
- LCD1602DisplayGeDigitResolve(0x07,secondge);//LCD1602字符型液晶显示器第二行第8个位置的秒钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x07);//写入LCD1602字符型液晶显示器第二行第8个位置的秒钟个位显示位
- miao=secondshi*10+secondge;//移位修改秒钟个位显示位的数值后,需要通过秒钟十位显示位的数值加上秒钟个位显示位的数值之和赋给秒钟变量,才能在修改秒钟个位或十位显示位的数值后重新计时。(原因:秒钟个位或十位显示位的数值是在秒钟的数值上分解得来,当秒钟个位或十位显示位的数值发生变化后,秒钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 2://移位按键S1按键第二次按下
- secondshi--;//秒钟十位数先赋值再减减
- if(secondshi==-1)//判断秒钟十位数设定值是否达到-1
- secondshi=5;//秒钟十位数归5
- LCD1602DisplayShiDigitResolve(0x06,secondshi);//LCD1602字符型液晶显示器第二行第7个位置的秒钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x06);//写入LCD1602字符型液晶显示器第二行第7个位置的秒钟十位显示位
- miao=secondshi*10+secondge;//移位修改秒钟十位显示位的数值后,需要通过秒钟十位显示位的数值加上秒钟个位显示位的数值之和赋给秒钟变量,才能在修改秒钟个位或十位显示位的数值后重新计时。(原因:秒钟个位或十位显示位的数值是在秒钟的数值上分解得来,当秒钟个位或十位显示位的数值发生变化后,秒钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 3://移位按键S1按键第三次按下
- minutange--;//分钟个位数先赋值再减减
- if(minutange==-1)//判断分钟个位数设定值是否达到-1
- minutange=9;//分钟个位数归9
- LCD1602DisplayGeDigitResolve(0x04,minutange);//LCD1602字符型液晶显示器第二行第5个位置的分钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x04);//写入LCD1602字符型液晶显示器第二行第5个位置的分钟个位显示位
- fen=minutanshi*10+minutange;//移位修改分钟个位显示位的数值后,需要通过分钟十位显示位的数值加上分钟个位显示位的数值之和赋给分钟变量,才能在修改分钟个位或十位显示位的数值后重新计时。(原因:分钟个位或十位显示位的数值是在分钟的数值上分解得来,当分钟个位或十位显示位的数值发生变化后,分钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 4://移位按键S1按键第四次按下
- minutanshi--;//分钟十位数先赋值再减减
- if(minutanshi==-1)//判断分钟十位数设定值是否达到6
- minutanshi=5;//分钟十位数归5
- LCD1602DisplayShiDigitResolve(0x03,minutanshi);//LCD1602字符型液晶显示器第二行第4个位置的分钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x03);//写入LCD1602字符型液晶显示器第二行第7个位置的分钟十位显示位
- fen=minutanshi*10+minutange;//移位修改分钟十位显示位的数值后,需要通过分钟十位显示位的数值加上分钟个位显示位的数值之和赋给分钟变量,才能在修改分钟个位或十位显示位的数值后重新计时。(原因:分钟个位或十位显示位的数值是在分钟的数值上分解得来,当分钟个位或十位显示位的数值发生变化后,分钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 5://移位按键S1按键第五次按下
- hourge--;//时钟个位数先赋值再减减
- if(hourge==-1)//判断时钟个位数设定值是否达到-1
- hourge=3;//时钟个位数归3
- LCD1602DisplayGeDigitResolve(0x01,hourge);//LCD1602字符型液晶显示器第二行第2个位置的时钟个位显示位的显示数
- WriteCommand(0x80+0x40+0x01);//写入LCD1602字符型液晶显示器第二行第2个位置的时钟个位显示位
- shi=hourshi*10+hourge;//移位修改时钟个位显示位的数值后,需要通过时钟十位显示位的数值加上时钟个位显示位的数值之和赋给时钟变量,才能在修改时钟个位或十位显示位的数值后重新计时。(原因:时钟个位或十位显示位的数值是在时钟的数值上分解得来,当时钟个位或十位显示位的数值发生变化后,时钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- case 6://移位按键S1按键第六次按下
- hourshi--;//时钟十位数先赋值再减减
- if(hourshi==-1)//判断时钟十位数设定值是否达到-1
- hourshi=2;//时钟十位数归2
- LCD1602DisplayShiDigitResolve(0x00,hourshi);//LCD1602字符型液晶显示器第二行第1个位置的时钟十位显示位的显示数
- WriteCommand(0x80+0x40+0x00);//写入LCD1602字符型液晶显示器第二行第1个位置的时钟十位显示位
- shi=hourshi*10+hourge;//移位修改时钟十位显示位的数值后,需要通过时钟十位显示位的数值加上时钟个位显示位的数值之和赋给时钟变量,才能在修改时钟个位或十位显示位的数值后重新计时。(原因:时钟个位或十位显示位的数值是在时钟的数值上分解得来,当时钟个位或十位显示位的数值发生变化后,时钟的数值也要变化,否则不能在原基础上修改后重新计时,只能返回原基础上计时。)
- break;
- default:
- S1num=0;//移位按键S1按键按下次数清零
- break;
- }
- }
- }
- }
- if(S4==0)//判断启停按键S4是否按下
- {
- Delay(5);
- if(S4==0)//再次判断启停按键S4是否按下
- {
- S4num++;//启停按键S4按下次数先赋值再加加
- while(!S4);//等待启停按键S4弹起
- if(S4num==1)//判断启停按键S4是否第一次按下过。实现直接停止。
- {
- TR0=0;//关定时器0
- }
- if(S1num>=1&&S4num==1)//判断移位按键S1按键和启停按键S4是否按下过。实现移位停止后,可移位修改时间数值或不修改时间数值,然后再启动。
- {
- TR0=1;//开定时器0
- WriteCommand(0x0c);//开LCD1602显示,关光标,关光标(或字符)闪烁。
- S4num=0;//启停按键S4按下次数变量清零
- S1num=0;//移位按键S1按键按下次数变量清零
- }
- if(S4num==2)//判断移位按键S4按键是否第二次按下过
- {
- TR0=1;//开定时器0
- S4num=0;//启停按键S4按下次数变量清零
- }
- }
- }
- }
- void Timer0() interrupt 1//定时器0中断函数
- {
- TH0=(65536-50000)/256;//TH0重新装值
- TL0=(65536-50000)%256;//TL0重新装值
- count++;//定时器0中断次数先赋值再加
- if(count==18)//判断定时器0中断次数是否为18次
- {
- count=0;//定时器0中断次数归零
- miao++;//秒钟先赋值再加
- if(miao==60)//判断秒钟是否达到60秒
- {
- miao=0;//秒钟归零
- fen++;//分钟先赋值再加
- if(fen==60)//判断分钟是否达到60分
- {
- fen=0;//分钟归零
- shi++;//时钟先赋值再加
- if(shi==24)//判断时钟是否达到24时
- {
- shi=0;//时钟归零
- }
- LCD1602DisplayTime(0x00,shi);//时钟显示两位数分解函数
- }
- LCD1602DisplayTime(0x03,fen);//分钟显示两位数分解函数
- }
- LCD1602DisplayTime(0x06,miao);//秒钟显示两位数分解函数
- }
- }
- void main()//主函数
- {
- LCD1602Init();//LCD1602字符型液晶显示器初始化函数
- Timer0Init();//定时器0初始化函数
- LCD1602Display();//LCD1602字符型液晶显示器显示函数
- while(1)
- {
- KeyScan();//按键扫描函数
- }
- }
复制代码
|