2019-12-28 15:26:51 CWQLTYH 阅读数 12
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程

一、前言

1、通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程包括用Keil软件编写单片机C语言程序和用Proteus软件仿真单片机外围电路

2、通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程构思

(1)、实现什么功能:LCD1602字符型液晶显示器先显示时分秒,在点击移位按键后,停止计时,LCD1602字符型液晶显示器光标闪烁,每次按下移位键,LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁,当LCD1602字符型液晶显示器的时分秒个位十位有闪烁后,可修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位上的数值,再通过移位按键或启停按键启动或停止计时。

(2)、如何实现功能:如何让LCD1602字符型液晶显示器先显示时分秒:采用定时器0工作方式1计时,计时得到的数值赋给LCD1602字符型液晶显示器显示时间两位数分解函数进行分解,分解得到的个位数值与十位数值用变量代替分别由LCD1602字符型液晶显示器写指令函数和LCD1602字符型液晶显示器写数据函数写入LCD1602字符型液晶显示器,通过LCD1602字符型液晶显示器显示出来。如何让LCD1602字符型液晶显示器的时分秒个位十位闪烁:采用按键扫描函数扫描,每次按下移位键(此时定时器0停止计时),执行LCD1602字符型液晶显示器光标闪烁指令和LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁的位置指令。如何修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位数值并在原计时基础上实现计时:当移位键按下后,定时器0停止计时,计时得到的数值采用两位数分解公式(如:shi=num/10,ge=num%10。)进行分解,分解得到的个位数值与十位数值用变量代替写入按键扫描函数,此时也要采用两位数合成公式(如:miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数(原因:时分秒的个位或十位显示位的数值是在原计时数值上分解得来,当时分秒的个位或十位显示位的数值发生变化后,原计时数值也要变化,否则启动定时器0计时后,LCD1602字符型液晶显示器显示的是原计时时间,而不是修改时分秒的个位或十位显示位的数值后的计时,因此要采用两位数合成公式(miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数。)。

二、通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程的Keil软件编写的单片机C语言程序

#include<reg52.h>//单片机头文件
#define uchar unsigned char//宏定义,用uchar表示unsigned char,叫无符号字符型数据类型,取值范围为:0到255。
#define uint unsigned int//宏定义,用uint表示unsigned int,叫无符号整数型数据类型,取值范围为:0到65535。
sbit Duan=P2^0;//位定义数码管段选                 
sbit Wei=P1^7;//位定义数码管位选                  
sbit S1=P1^0;//移位按键S1 
sbit S2=P1^2;//增加按键S2 
sbit S3=P1^4;//减少按键S3 
sbit S4=P1^6;//启停按键S4
uchar count,num,S1num,S4num,flag,suojianflag;//count为定时器0中断次数变量,num为定时器1中断次数变量,S1num为移位按键S1按键按下次数变量,S4num为启停按键S4按下次数变量,flag为数码管显示函数是否显示标志位变量。
uchar second,minutan,hour;//计时时钟变量、分钟变量、秒钟变量
uchar secondge,secondshi;//秒钟的个位变量、十位变量。
uchar minutange,minutanshi;//分钟的个位变量、十位变量。
uchar hourge,hourshi;//时钟的个位变量、十位变量。
uchar ge,shi,bai,qian,wan,shiwan;//数码管的个位变量、十位变量、百位变量、千位变量
uchar address,time;//数码管的显示位地址变量、时间变量。
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//共阳数码管显示数字的数组,单片机输送低电平给共阳数码管段位,输送高电平给共阳数码管位选,可点亮数码管。
  void Delay(uint z)//延时程序
{
   uint x,y;
   for(x=z;x>0;x--)
    for(y=110;y>0;y--);
 }
  void TimerInit()//定时器0初始化函数
{
   TMOD=0x11;//设定定时器0和定时器1工作模式都为模式,切记不能分开设定定时器0和定时器1,否则发生冲突,也就是不管用哪两个定时器,不能分开设定初始化函数。
   TH0=(65536-50000)/256;//TH0装初值
   TL0=(65536-50000)%256;//TL0装初值
   EA=1;//开启定时器总中断
   ET0=1;//开启定时器0中断开关
   TR0=1;//启动定时器0
   ET1=1;//开启定时器1中断开关
   TR1=0;//关闭定时器1
 }
  void ShuMaGuanDisplayTime()//数码管显示时间函数,也是显示时间两位数分解函数。
{
   ge=second%10;//秒钟分解一个秒钟个位变量
   shi=second/10;//秒钟分解一个秒钟十位变量
   bai=minutan%10;//分钟分解一个分钟个位变量
   qian=minutan/10;//分钟分解一个分钟十位变量
   wan=hour%10;//时钟分解一个时钟个位变量
   shiwan=hour/10;//时钟分解一个时钟十位变量
   Duan=1;//开数码管段选
   P0=table[ge];//数码管个位(即秒钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[shi];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位(即秒钟十位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[bai];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;///关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时
   
   Duan=1;//开数码管段选
   P0=table[qian];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;///关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[wan];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;///关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[shiwan];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;///关数码管所有段选,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)选通
   Wei=0;//关数码管位选
   Delay(1);//延时
   Duan=0;//关数码管段位
 }
  void ShuMaGuanGeWeiShanShuoDisplayTime(uchar address,uchar second)//数码管个位(即秒钟个位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟个位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;///关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管个位(即秒钟个位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanShiWeiShanShuoDisplayTime(uchar address,uchar second)//数码管十位(即秒钟十位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管十位(即秒钟十位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanBaiWeiShanShuoDisplayTime(uchar address,uchar minutan)//数码管百位(即分钟个位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管百位(即分钟个位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanQianWeiShanShuoDisplayTime(uchar address,uchar minutan)//数码管千位(即分钟十位闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管千位(即分钟十位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanWanWeiShanShuoDisplayTime(uchar address,uchar hour)//数码管万位(即时钟个位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管万位(即时钟个位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanShiWanWeiShanShuoDisplayTime(uchar address,uchar hour)//数码管十万位(即时钟十位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)闪烁位
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时

   Duan=1;//开数码管段选
   P0=table[10];//关掉数码管十万位(即时钟十位)显示
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=address;//数码管显示位地址
   Wei=0;//关数码管位选
   Delay(5);//延时
 }
  void ShuMaGuanNoGeWeiDisplayTime()//数码管没有个位(即秒钟个位)显示闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位(即秒钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)显示位
   Wei=0;//关数码管位选;
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时
 }
  void ShuMaGuanNoShiWeiDisplayTime()//数码管没有十位(即秒钟十位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时
 }
  void ShuMaGuanNoBaiWeiDisplayTime()//数码管没有百位(即分钟个位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位(即秒钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时
 }
  void ShuMaGuanNoQianWeiDisplayTime()//数码管没有千位(即分钟十位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位(即秒钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时
 }
  void ShuMaGuanNoWanWeiDisplayTime()//数码管没有万位(即时钟个位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位(即秒钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour/10];//数码管十万位(即时钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x01;//数码管十万位(即时钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

 }
  void ShuMaGuanNoShiWanWeiDisplayTime()//数码管没有十万位(即时钟十位)闪烁显示时间函数
{
   Duan=1;//开数码管段选
   P0=table[second%10];//数码管个位(即秒钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x20;//数码管个位(即秒钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[second/10];//数码管十位(即秒钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x10;//数码管十位显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan%10];//数码管百位(即分钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x08;//数码管百位(即分钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[minutan/10];//数码管千位(即分钟十位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x04;//数码管千位(即分钟十位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时

   Duan=1;//开数码管段选
   P0=table[hour%10];//数码管万位(即时钟个位)显示数
   Duan=0;//关数码管段选
   P0=0xff;//关数码管所有显示,防止数码管显示乱码。
   Wei=1;//开数码管位选
   P3=0x02;//数码管万位(即时钟个位)显示位
   Wei=0;//关数码管位选
   Delay(1);//延时
 }
  void KeyScan()//按键扫描函数
{
   if(S1==0)//判断移位按键S1是否按下        
  {
    ShuMaGuanDisplayTime();//数码管显示时间函数延时
    if(S1==0)//再次判断移位按键S1是否按下
   {
     while (!S1)//等待移位按键S1弹起
	 ShuMaGuanDisplayTime();//数码管显示时间函数延时
	 S1num++;//移位按键S1按键次数变量先赋值再自加
	 switch(S1num)//移位按键S1按键按下次数选择位,其中S1num为移位按键S1按键按下次数变量。
    {
   	  case 1://判断移位按键S1是否第1次按下
   			 TR0=0;//关定时器0定时
             TR1=1;//开定时器1定时,秒钟个位(也是数码管个位)开闪烁。
             flag=!flag;//flag=!flag相当于flag=!0=1,关数码管显示时间函数,开数码管没有个位闪烁显示时间函数。
			 S4num=0;//启停按键S4按下次数变量清零
             secondge=second%10;//秒钟分解一个秒钟个位
             secondshi=second/10;//秒钟分解一个秒钟十位
             minutange=minutan%10;//分钟分解一个分钟个位
             minutanshi=minutan/10;//分钟分解一个分钟十位
	         hourge=hour%10;//时钟分解一个时钟个位
	         hourshi=hour/10;//时钟分解一个时钟十位
             time=hourshi*100000+hourge*10000+minutanshi*1000+minutange*100+secondshi*10+secondge; //time表示数码管显示一个4位数的时间变量
			 break;
	  case 2://判断移位按键S1是否第2次按下
             flag=flag;
			 break;
	  case 3://判断移位按键S1是否第3次按下
             flag=flag;
			 break;
	  case 4://判断移位按键S1是否第4次按下
             flag=flag;
			 break;
	  case 5://判断移位按键S1是否第5次按下
             flag=flag;
			 break;
	  case 6://判断移位按键S1是否第6次按下
             flag=flag;
    		 break;
	  case 7://判断移位按键S1是否第7次按下
             flag=!flag;
			 TR0=1;
			 S1num=0;//移位按键S1按键按下次数变量清零
			 suojianflag=0;//移位键锁键标志位
			 break;
	 }     
    }
   }
   if(S2==0)//判断增加按键S2是否按下        
  {
	ShuMaGuanDisplayTime();//数码管显示时间函数延时
    if(S2==0)//再次判断增加按键S2是否按下
   { 
     while (!S2)//等待增加按键S2弹起
	 ShuMaGuanDisplayTime();//数码管显示时间函数延时
	 switch(S1num)//移位按键S1按键按下次数选择位,其中S1num为移位按键S1按键按下次数变量。
    {
   	  case 1://判断移位按键S1是否第1次按下
   			 secondge++;//秒钟的个位(也就是数码管个位)变量先赋值再自加
             if(secondge==10)//判断秒钟的个位(也就是数码管个位)变量是否为10
             secondge=0;//秒钟的个位(也就是数码管个位)变量清0
             second=secondshi*10+secondge;//修改秒钟的个位(也就是数码管个位)上的数值后,再合成秒钟,为了给秒钟的个位(也就是数码管个位)闪烁显示时间函数调用分解来闪烁显示和数码管没有个位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。   
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 2://判断移位按键S1是否第2次按下
			 secondshi++;//秒钟的十位(也就是数码管十位)变量先赋值再自加
             if(secondshi==6)//判断秒钟的十位(也就是数码管十位)变量是否为6
             secondshi=0;//秒钟的十位(也就是数码管十位)变量清0
             second=secondshi*10+secondge;//修改秒钟的十位(也就是数码管十位)上的数值后,再合成秒钟,是为了给秒钟的十位(也就是数码管十位)闪烁显示时间函数调用分解来闪烁显示和数码管没有十位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 3://判断移位按键S1是否第3次按下
			 minutange++;//分钟的个位(也就是数码管百位)变量先赋值再自加
             if(minutange==10)//判断分钟的个位(也就是数码管百位)变量是否为10
             minutange=0;//分钟的个位(也就是数码管百位)变量清0
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//修改分钟的个位(也就是数码管百位)上的数值后,再合成分钟,为了给分钟的个位(也就是数码管百位)闪烁显示时间函数调用分解来闪烁显示和数码管没有百位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 4://判断移位按键S1是否第4次按下
			 minutanshi++;//分钟的十位(也就是数码管千位)变量先赋值再自加
             if(minutanshi==6)//判断分钟的十位(也就是数码管千位)变量是否为6
             minutanshi=0;//分钟的十位(也就是数码管千位)变量清0
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//修改分钟的十位(也就是数码管千位)上的数值后,再合成分钟,为了给分钟的十位(也就是数码管千位)闪烁显示时间函数调用分解来闪烁显示和数码管没有千位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 5://判断移位按键S1是否第5次按下
			 hourge++;//时钟的个位(也就是数码管万位)变量先赋值再自加
             if(hourge==4)//判断时钟的个位(也就是数码管万位)变量是否为4
             hourge=0;//时钟的个位(也就是数码管万位)变量清0
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
             hour=hourshi*10+hourge;//修改时钟的个位(也就是数码管万位)上的数值后,再合成时钟,为了给时钟的个位(也就是数码管万位)闪烁显示时间函数调用分解来闪烁显示和数码管没有万位闪烁显示时间函数调用分解来让其他位不闪烁显示。
			 break;
	  case 6://判断移位按键S1是否第6次按下
   			  hourshi++;//时钟的十位(也就是数码管十万位)变量先赋值再自加
              if(hourshi==3)//判断时钟的十位(也就是数码管十万位)变量是否为3
              hourshi=0;//时钟的十位(也就是数码管十万位)变量清0
              second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
              minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。
              hour=hourshi*10+hourge;//修改时钟的十位(也就是数码管十万位)上的数值后,再合成时钟,为了给时钟的十位(也就是数码管十万位)闪烁显示时间函数调用分解来闪烁显示和数码管没有十万位闪烁显示时间函数调用分解来让其他位不闪烁显示。
    		  break;
	 }
    }
   }
   if(S3==0)//判断减少按键S3是否按下        
  {
	ShuMaGuanDisplayTime();//数码管显示时间函数延时
    if(S3==0)//再次判断减少按键S3是否按下
   { 
     while (!S3)//等待减少按键S3弹起
	 ShuMaGuanDisplayTime();//数码管显示时间函数延时
	 switch(S1num)//移位按键S1按键按下次数选择位,其中S1num为移位按键S1按键按下次数变量。
    {
   	  case 1://判断移位按键S1是否第1次按下
   			 secondge--;//秒钟的个位(也就是数码管个位)变量先赋值再自减
             if(secondge==-1)//判断秒钟的个位(也就是数码管个位)变量是否为-1
             secondge=9;//秒钟的个位(也就是数码管个位)变量变9
             second=secondshi*10+secondge;//修改秒钟的个位(也就是数码管个位)上的数值后,再合成秒钟,为了给秒钟的个位(也就是数码管个位)闪烁显示时间函数调用分解来闪烁显示和数码管没有个位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。   
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 2://判断移位按键S1是否第2次按下
			 secondshi--;//秒钟的十位(也就是数码管十位)变量先赋值再自减
             if(secondshi==-1)//判断秒钟的十位(也就是数码管十位)变量是否为-1
             secondshi=5;//秒钟的十位(也就是数码管十位)变量变5
             second=secondshi*10+secondge;//修改秒钟的十位(也就是数码管十位)上的数值后,再合成秒钟,是为了给秒钟的十位(也就是数码管十位)闪烁显示时间函数调用分解来闪烁显示和数码管没有十位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 3://判断移位按键S1是否第3次按下
			 minutange--;//分钟的个位(也就是数码管百位)变量先赋值再自减
             if(minutange==-1)//判断分钟的个位(也就是数码管百位)变量是否为-1
             minutange=9;//分钟的个位(也就是数码管百位)变量变9
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//修改分钟的个位(也就是数码管百位)上的数值后,再合成分钟,为了给分钟的个位(也就是数码管百位)闪烁显示时间函数调用分解来闪烁显示和数码管没有百位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 4://判断移位按键S1是否第4次按下
			 minutanshi--;//分钟的十位(也就是数码管千位)变量先赋值再自减
             if(minutanshi==-1)//判断分钟的十位(也就是数码管千位)变量是否为-1
             minutanshi=5;//分钟的十位(也就是数码管千位)变量变5
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//修改分钟的十位(也就是数码管千位)上的数值后,再合成分钟,为了给分钟的十位(也就是数码管千位)闪烁显示时间函数调用分解来闪烁显示和数码管没有千位闪烁显示时间函数调用分解来让其他位不闪烁显示。
             hour=hourshi*10+hourge;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
			 break;
	  case 5://判断移位按键S1是否第5次按下
			  hourge--;//时钟的个位(也就是数码管万位)变量先赋值再自减
              if(hourge==-1)//判断时钟的个位(也就是数码管万位)变量是否为-1
              hourge=3;//时钟的个位(也就是数码管万位)变量变3
              second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
              minutan=minutanshi*10+minutange;//合成时钟,是为了给数码管显示时间函数调用分解来显示。
              hour=hourshi*10+hourge;//修改时钟的个位(也就是数码管万位)上的数值后,再合成时钟,为了给时钟的个位(也就是数码管万位)闪烁显示时间函数调用分解来闪烁显示和数码管没有万位闪烁显示时间函数调用分解来让其他位不闪烁显示。
			  break;
	  case 6://判断移位按键S1是否第6次按下
   			 hourshi--;//时钟的十位(也就是数码管十万位)变量先赋值再自减
             if(hourshi==-1)//判断时钟的十位(也就是数码管十万位)变量是否为-1
             hourshi=2;//时钟的十位(也就是数码管十万位)变量变2
             second=secondshi*10+secondge;//合成秒钟,是为了给数码管显示时间函数调用分解来显示。
             minutan=minutanshi*10+minutange;//合成分钟,是为了给数码管显示时间函数调用分解来显示。
             hour=hourshi*10+hourge;//修改时钟的十位(也就是数码管十万位)上的数值后,再合成时钟,为了给时钟的十位(也就是数码管十万位)闪烁显示时间函数调用分解来闪烁显示和数码管没有十万位闪烁显示时间函数调用分解来让其他位不闪烁显示。
    		 break;
	 }
    }
   }
   if(S4==0)//判断启停按键S4是否按下
  {
	ShuMaGuanDisplayTime();//数码管显示时间函数延时
	if(S4==0)//再次判断启停按键S4是否按下
   {
	 while (!S4)//等待启停按键S4弹起
	 ShuMaGuanDisplayTime();//数码管显示时间函数延时
	 S4num++;//启停按键S4按下次数变量先赋值再加加
	 if(S4num==1)//判断启停按键S4是否第一次按下过。实现直接停止。
	{
	  TR0=0;//关定时器0
	 }
	 if(S1num>=1&&S4num==1)//判断移位按键S1按键和启停按键S4是否按下过。实现移位停止后,可移位修改时间数值或不修改时间数值,然后再启动。
	{
	  TR0=1;//开定时器0
	  TR1=0;//关定时器1
	  flag=!flag;
	  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中断次数变量归零
    second++;//秒钟变量先赋值再加
    if(second==60)//判断秒钟变量是否达到60秒
   {
     second=0;//秒钟变量归零 
     minutan++;//分钟变量先赋值再加
     if(minutan==60)//判断分钟变量是否达到60分
    {
      minutan=0;//分钟变量归零
      hour++;//时钟变量先赋值再加
      if(hour==24)//判断时钟变量是否达到24时
     { 
       hour=0;//时钟变量归零
      }
     } 
    }
   }
  }
  void Timer1() interrupt 3//定时器1中断函数
{
   TH1=(65536-50000)/256;//TH1重新装值
   TL1=(65536-50000)%256;//TL1重新装值
   num++;//定时器0中断次数变量先赋值再加
   if(num==18)//判断定时器1中断次数变量是否到达18
  {
    num=0;//定时器1中断次数变量清零
	switch(S1num)//移位按键S1按键按下次数选择位,其中S1num为移位按键S1按键按下次数变量。
   {
   	 case 1://判断移位按键S1是否第1次按下
   			ShuMaGuanGeWeiShanShuoDisplayTime(0x20,second);//秒钟的个位(也就是数码管个位)闪烁显示时间函数
			break;
	 case 2://判断移位按键S1是否第2次按下
			ShuMaGuanShiWeiShanShuoDisplayTime(0x10,second);//秒钟的十位(也就是数码管十位)闪烁显示时间函数
			break;
	 case 3://判断移位按键S1是否第3次按下
			ShuMaGuanBaiWeiShanShuoDisplayTime(0x08,minutan);//分钟的个位(也就是数码管百位)闪烁显示时间函数
			break;
	 case 4://判断移位按键S1是否第4次按下
			ShuMaGuanQianWeiShanShuoDisplayTime(0x04,minutan);//分钟的十位(也就是数码管千位)闪烁显示时间函数
			break;
	 case 5://判断移位按键S1是否第5次按下
			ShuMaGuanWanWeiShanShuoDisplayTime(0x02,hour);//时钟的个位(也就是数码管万位)闪烁显示时间函数
			break;
	 case 6://判断移位按键S1是否第6次按下
   			ShuMaGuanShiWanWeiShanShuoDisplayTime(0x01,hour);//时钟的十位(也就是数码管十万位)闪烁显示时间函数
    		break;
	}
   }
  }
  void main()//主函数
{
   TimerInit();//定时器初始化函数
   while(1)
 {
    KeyScan();//按键扫描函数
    if(!flag)//flag为无符号字符型数据类型,取值范围为0到255,初始值是0,!flag相当于flag=1,开数码管显示函数显示标志位。
    ShuMaGuanDisplayTime();//数码管显示时间函数
    switch(S1num)//移位按键S1按键按下次数选择位,其中S1num为移位按键S1按键按下次数变量。
   {
   	 case 1://判断移位按键S1是否第1次按下
   			ShuMaGuanNoGeWeiDisplayTime();//数码管没有个位(即秒钟个位)闪烁显示时间函数
			break;
	 case 2://判断移位按键S1是否第2次按下
			ShuMaGuanNoShiWeiDisplayTime();//数码管没有十位(即秒钟十位)闪烁显示时间函数
			break;
	 case 3://判断移位按键S1是否第3次按下
			ShuMaGuanNoBaiWeiDisplayTime();//数码管没有百位(即分钟个位)闪烁显示时间函数
			break;
	 case 4://判断移位按键S1是否第4次按下
			ShuMaGuanNoQianWeiDisplayTime();//数码管没有千位(即分钟十位)闪烁显示时间函数
			break;
	 case 5://判断移位按键S1是否第5次按下
			ShuMaGuanNoWanWeiDisplayTime();//数码管没有万位(即时钟个位)闪烁显示时间函数
			break;
	 case 6://判断移位按键S1是否第6次按下
   			 ShuMaGuanNoShiWanWeiDisplayTime();//数码管没有十万位(即时钟十位)闪烁显示时间函数
    		 break;
	}
   }
  } 


三、通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程的Proteus软件仿真单片机外围电路

在这里插入图片描述

四、通过点击移位键控制数码管显示时分秒某位闪烁后进行增加键或减少键修改时分秒数值的计时项目工程的操作功能描述

(1)、不修改时分秒个位十位数值,只是启动或停止计时的情况:如果第一次按下移位键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。如果第一次按下启停键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。

(2)、修改时分秒个位十位数值,再启动或停止计时的情况:要修改时分秒个位十位上的数值,再启动或停止计时,首先必须按下移位键,此时停止计时,通过点击移位键让LCD1602字符型液晶显示器光标移到时分秒相应个位十位数值上,利用点击增加键或减少键修改数值,修改完毕后,启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,停止计时可按下移位键或按下启停键,当按下移位键时,又可修改时分秒个位十位上的数值,再次启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,周而复始。

2019-07-31 23:14:36 qq_43212668 阅读数 64
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

@TOC用51单片机设置一个时钟显示,按K1显示时分秒(八个数码管,想如此显示“88-88-88”),按K2显示年月日,以下是代码。但怎么烧录完成后显示时分秒,按下K2就不显示了,再按K1也不显示,被我一阵乱按才显示,而且有时显示时分秒有时显示年月日,很不稳定。。。请求大神告知是那个地方错了,或者应该怎么写。。。万分感谢!!!

ds1302.c文件

#include"ds1302.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0x12, 0x04, 0x22, 0x31, 0x07, 0x03, 0x19};//0, 0, 0x12, 0x07, 0x05, 0x06, 0x16

/*******************************************************************************
* 函 数 名         : Ds1302Write
* 函数功能		   : 向DS1302命令(地址+数据)
* 输    入         : addr,dat
* 输    出         : 无
*******************************************************************************/

void Ds1302Write(uchar addr, uchar dat)
{
	uchar n;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1; //然后将RST(CE)置高电平。
	_nop_();

	for (n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();
	}
	for (n=0; n<8; n++)//写入8位数据
	{
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	
		 
	RST = 0;//传送数据结束
	_nop_();
}

/*******************************************************************************
* 函 数 名         : Ds1302Read
* 函数功能		   : 读取一个地址的数据
* 输    入         : addr
* 输    出         : dat
*******************************************************************************/

uchar Ds1302Read(uchar addr)
{
	uchar n,dat,dat1;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;//然后将RST(CE)置高电平。
	_nop_();

	for(n=0; n<8; n++)//开始传送八位地址命令
	{
		DSIO = addr & 0x01;//数据从低位开始传送
		addr >>= 1;
		SCLK = 1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}

	RST = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat;	
}

/*******************************************************************************
* 函 数 名         : Ds1302Init
* 函数功能		   : 初始化DS1302.
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302Init()
{
	uchar n;
	Ds1302Write(0x8E,0X00);		 //禁止写保护,就是关闭写保护功能
	for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
	{
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);	
	}
	Ds1302Write(0x8E,0x80);		 //打开写保护功能
}

/*******************************************************************************
* 函 数 名         : Ds1302ReadTime
* 函数功能		   : 读取时钟信息
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds1302ReadTime()
{
	uchar n;
	for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
	{
		TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
	}
		
}

.h文件

#ifndef __DS1302_H_
#define __DS1302_H_

//---包含头文件---//
#include<reg52.h>
#include<intrins.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;

//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();

//---加入全局变量--//
extern uchar TIME[7];	//加入全局变量

#endif

主函数main

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器
#include"ds1302.h"	

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 j=0;
sbit K1=P3^1;
sbit K2=P3^0;
char num=0;
u8 DisplayData[8];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	while(i--);	
}


/*******************************************************************************
* 函 数 名         : datapros()
* 函数功能		   : 时间读取处理转换函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void datapros() 	 
{
   		Ds1302ReadTime();
	if(j==0)
	{  
	DisplayData[0] = smgduan[TIME[2]/16];				//时
	DisplayData[1] = smgduan[TIME[2]&0x0f];				 
	DisplayData[2] = 0x40;
	DisplayData[3] = smgduan[TIME[1]/16];				//分
	DisplayData[4] = smgduan[TIME[1]&0x0f];	
	DisplayData[5] = 0x40;
	DisplayData[6] = smgduan[TIME[0]/16];				//秒
	DisplayData[7] = smgduan[TIME[0]&0x0f];
	}
	else if(j==1)
	{
	DisplayData[0] = smgduan[TIME[6]/16];				//时
	DisplayData[1] = smgduan[TIME[6]&0x0f];				 
	DisplayData[2] = 0x40;
	DisplayData[3] = smgduan[TIME[4]/16];				//分
	DisplayData[4] = smgduan[TIME[4]&0x0f];	
	DisplayData[5] = 0x40;
	DisplayData[6] = smgduan[TIME[3]/16];				//秒
	DisplayData[7] = smgduan[TIME[3]&0x0f];
	}  
}
/*******************************************************************************
* 函数名         :Keybord()
* 函数功能		 :按键扫描
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/	  

void Keybord()
{
	if(K1==0)
	{
		delay(1000);//消抖
		if(K1==0)
		{
			j=0;
		}
		while(K1!=0);
	}
	if(K2==0)
	{
		delay(1000);
		if(K2==0)
		{
			j=1;
		}
		while(K2!=0);
	}
}

/*******************************************************************************
* 函数名         :DigDisplay()
* 函数功能		 :数码管显示函数
* 输入           : 无
* 输出         	 : 无
*******************************************************************************/
void DigDisplay()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)	 //位选,选择点亮的数码管,
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位
			case(3):
				LSA=1;LSB=1;LSC=0; break;//显示第3位
			case(4):
				LSA=0;LSB=0;LSC=1; break;//显示第4位
			case(5):
				LSA=1;LSB=0;LSC=1; break;//显示第5位
			case(6):
				LSA=0;LSB=1;LSC=1; break;//显示第6位
			case(7):
				LSA=1;LSB=1;LSC=1; break;//显示第7位	
		}
		P0=DisplayData[7-i];//发送数据
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}		
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	Ds1302Init();
	while(1)
	{
		Keybord();  //按键扫描
		datapros();	 //数据处理函数
		DigDisplay();//数码管显示函数
	}		
}

2019-12-23 22:03:10 CWQLTYH 阅读数 87
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目

一、前言

1、基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目包括用Keil软件编写单片机C语言程序和用Proteus软件仿真单片机外围电路

2、基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目构思

(1)、实现什么功能:LCD1602字符型液晶显示器先显示时分秒,在点击移位按键后,停止计时,LCD1602字符型液晶显示器光标闪烁,每次按下移位键,LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁,当LCD1602字符型液晶显示器的时分秒个位十位有闪烁后,可修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位上的数值,再通过移位按键或启停按键启动或停止计时。

(2)、如何实现功能:如何让LCD1602字符型液晶显示器先显示时分秒:采用定时器0工作方式1计时,计时得到的数值赋给LCD1602字符型液晶显示器显示时间两位数分解函数进行分解,分解得到的个位数值与十位数值用变量代替分别由LCD1602字符型液晶显示器写指令函数和LCD1602字符型液晶显示器写数据函数写入LCD1602字符型液晶显示器,通过LCD1602字符型液晶显示器显示出来。如何让LCD1602字符型液晶显示器的时分秒个位十位闪烁:采用按键扫描函数扫描,每次按下移位键(此时定时器0停止计时),执行LCD1602字符型液晶显示器光标闪烁指令和LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁的位置指令。如何修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位数值并在原计时基础上实现计时:当移位键按下后,定时器0停止计时,计时得到的数值采用两位数分解公式(如:shi=num/10,ge=num%10。)进行分解,分解得到的个位数值与十位数值用变量代替写入按键扫描函数,此时也要采用两位数合成公式(如:miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数(原因:时分秒的个位或十位显示位的数值是在原计时数值上分解得来,当时分秒的个位或十位显示位的数值发生变化后,原计时数值也要变化,否则启动定时器0计时后,LCD1602字符型液晶显示器显示的是原计时时间,而不是修改时分秒的个位或十位显示位的数值后的计时,因此要采用两位数合成公式(miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数。)。

二、基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目的Keil软件编写的单片机C语言程序

#include<reg52.h>//包含51单片机内部寄存器头文件
#define uchar unsigned char // 自定义uchar为unsigned char(即无符号字符型数据,数据范围:0到255。)
#define uint unsigned int//自定义uint为unsigned int(即无符号字符整数型数据,数据范围:0到6355。)
sbit RS=P0^7;//位定义LCD1602字符型液晶显示器的数据/命令选择引脚                 
sbit RW=P0^6;//位定义LCD1602字符型液晶显示器的读写引脚                        
sbit EN=P0^5; //位定义LCD1602字符型液晶显示器的使能引脚
sbit DQ=P1^6;//位定义DS18B20数据端口
sbit S=P3^7;//设时按键S
sbit S0=P3^6;//设温按键S0
sbit S1=P3^5;//调时按键S1 
sbit S2=P3^4;//增加按键S2 
sbit S3=P3^3;//减少按键S3 
sbit S4=P3^2;//启停按键S4
sbit FengNingQi=P3^1;//位定义蜂鸣器口
uchar count,Snum,S0num,S1num,S4num,S2numflag,S3numflag,TR0flag,setsecondflag,setminutanflag,sethourflag,miaoflag,fenflag,shiflag,settemperatureflag;//定时器0中断次数变量、设时按键S按键按下次数变量、设温按键S0按键按下次数变量、调时按键S1按下次数变量、启停按键S4按下次数标志位变量、增加键标志位变量、减少键标志位变量、定时器0标志位变量、设时秒钟标志位变量、设时分钟标志位变量、设时时钟标志位变量、秒钟标志位变量、分钟标志位变量、时钟标志位变量、设温标志位变量、
uchar sethour,setminutan,setsecond;//设时时钟变量、设时分钟变量
uchar setsecondge,setsecondshi;//设时秒钟个位变量、设时秒钟十位变量
uchar setminutange,setminutanshi;//设时分钟个位变量、设时分钟十位变量
uchar sethourge,sethourshi;//设时时钟个位变量、设时时钟十位变量
uchar shi,fen,miao;//时钟变量、分钟变量、秒钟变量
uchar secondge,secondshi; //秒钟个位变量、秒钟十位变量
uchar minutange,minutanshi;//分钟个位变量、分钟十位变量
uchar hourge,hourshi;//时钟个位变量、时钟十位变量
uchar qitingflag,temperaturedisplayflag,lcd1602displaytimeflag,settimedisplayflag,settemperaturedisplayflag,tiaotimedisplayflag,timebaojingflag,temperatruebaojingflag;//启停键标志位变量、温度显示标志位变量、液晶显示器显示时间标志位变量、设时显示标志位变量、设温显示标志位变量、调时显示标志位变量、时间报警标志位变量、温度报警标志位变量
uint temperature,t;//读温度值变量
uint temperatureflag;//负温度标志位变量
uint wendu,wendubai,wendushi,wenduge,xiaoshudian,wenduxiaoshu,fuhaowei,setwendu,setwendubai,setwendushi,setwenduge,setwenduxiaoshu,settemperature;//温度值变量、温度百位变量、温度十位变量、温度个位变量、小数点变量、小数变量、符号位变量、设温变量、设温百位变量、设温十位变量、设温个位变量、设温小数变量、设温变量
//uchar table0[]="00:00:00";//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=0;//启动定时器0
 }
  void LCD1602Display()//LCD1602字符型液晶显示器显示函数
{
   uchar j;//j表示数组元素个数变量
//   WriteCommand(0x80+0x00);//LCD1602字符型液晶显示器第一行第一个位置显示
//   for(j=0;j<8;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 SetTimeKeyScan()//设时按键扫描函数
{
   if(S==0)//判断设时按键S是否按下
  {
  	Delay(5);//延时
	if(S==0)//再次判断设时按键S是否按下
   {
	 settemperatureflag=0;//设温标志位变量置0,在温度报警函数执行后但不报警的情况下,温度报警函数里边余留settemperatureflag==1和TR0=1,当操作设时按键扫描函数时,计时依然在执行,导致计时不恰当,因此在设时按键扫描函数里边添加settemperatureflag=0和TR0=0,执行设时按键扫描函数后,温度报警函数里边settemperatureflag==1和TR0=1被置换成settemperatureflag=0和TR0=0,很好地解决了在操作设时按键扫描函数时,计时依然在执行,导致计时不恰当的问题。
	 Snum++;//设时按键S按键次数变量先赋值再自加
	 while(!S);//等待设时按键S弹起
	 switch(Snum)//设时按键S按键按下次数变量选择位
	{
	  case 1://设时按键S按键第一次按下
	         TR0=0;//关定时器0
			 TR0flag=0;//定时器0标志位变量置0,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留TR0flag==1,当再次操作设时按键扫描函数设时时,会发生在设时过程中触发设时报警条件而报警,因此在设时按键扫描函数里边添加TR0flag=0,再次执行设时按键扫描函数后,温度报警函数里边TR0flag==1被置换成TR0flag=0,很好地解决了再次操作设时按键扫描函数设时时,在设时过程中触发设时报警条件而报警的问题。
			 tiaotimedisplayflag=1;//调时显示标志位变量置1,在操作设时按键扫描函数的情况下,不能操作调时按键扫描函数。
			 settemperaturedisplayflag=1;//设温显示标志位变量置1,在操作设时按键扫描函数的情况下,不能操作设温按键扫描函数。
			 lcd1602displaytimeflag=1;//液晶显示器显示时间标志位变量置1,在操作设时按键扫描函数的情况下,不受时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数影响。
			 temperaturedisplayflag=1;//温度显示标志位变量置1,在操作设时按键扫描函数的情况下,不受温度分解函数和温度显示函数影响。
			 WriteCommand(0x80+0x00+0x07);//LCD1602字符型液晶显示器第一行第7个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 2://设时按键S按键第二次按下 
			 WriteCommand(0x80+0x00+0x06);//LCD1602字符型液晶显示器第一行第6个(从第0开始数)个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 3://设时按键S按键第三次按下
			 WriteCommand(0x80+0x00+0x04);//LCD1602字符型液晶显示器第一行第4个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 4://设时按键S按键第四次按下
			 WriteCommand(0x80+0x00+0x03);//LCD1602字符型液晶显示器第一行第3个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 5://设时按键S按键第五次按下
			 WriteCommand(0x80+0x00+0x01);//LCD1602字符型液晶显示器第一行第1个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 6://设时按键S按键第六次按下
			 WriteCommand(0x80+0x00+0x00);//LCD1602字符型液晶显示器第一行第0个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
      case 7://设时按键S按键第七次按下
			 WriteCommand(0x80+0x00+0x07);//LCD1602字符型液晶显示器第一行第0个(从第0开始数)位置的显示位
	         WriteCommand(0x0c);//关光标(或字符)闪烁。
			 TR0=1;//开定时器0
			 TR0flag=1;//定时器0标志位变量置1,为了在操作设时按键扫描函数进行设时后,可以执行时间报警函数。
			 Snum=0;//设时按键S按键按下次数清零,可以反复操作设时按键。
			 tiaotimedisplayflag=0;//调时显示标志位变量置0,让设时按键扫描函数执行后,可允许调时按键扫描函数执行。
			 settemperaturedisplayflag=0;//设温显示标志位变量置0,让设时按键扫描函数执行后,可允许设温按键扫描函数执行。
			 lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量等于0,让设时按键扫描函数执行后,可允许时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数执行。
			 temperaturedisplayflag=0;//温度显示标志位变量等于0,让设时按键扫描函数执行后,可允许温度分解函数和温度显示函数执行。
			 break;
	 default:
	         S0num=0;//设温按键S0按键按下次数清零,可以反复操作设时按键。
			 break;  
	  }
	 }
	}
	if(Snum!=0)//判断设时按键S按键按下次数变量是否为0
  {
     if(S2==0)//判断增加按键S2是否按下
	{
	  Delay(5);//延时
	  if(S2==0)//再次判断增加按键S2是否按下
	 {
	   S2numflag=1;//增加键标志位变量置1,可以在时间报警函数内进行设时报警。
	   while(!S2);//等待增加按键S2弹起
       switch(Snum)//设时按键S按键按下次数变量选择位
	  {
	    case 1://设时按键S按键第一次按下
		       setsecondflag=1;//设时秒钟标志位变量置1,表示设时秒钟数值修改。
			   setsecondge++;//设时秒钟个位变量先赋值再加加
		       if(setsecondge==10)//判断设时秒钟个位变量设定值是否达到10
		       setsecondge=0;//设时秒钟个位变量归零
		       WriteCommand(0x80+0x00+0x07);//写入LCD1602字符型液晶显示器第一行第7个(从第0个开始数)位置的设时秒钟个位变量显示位
			   WriteData(0x30+setsecondge);//0x30表示字符库的数字0,整个代码表示设时秒钟个位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x07);//写入LCD1602字符型液晶显示器第一行第7个(从第0个开始数)位置的设时秒钟个位变量显示位
			   setsecond=setsecondshi*10+setsecondge;//设时秒钟变量求值
			   break;
		case 2://设时按键S按键第二次按下
			   setsecondflag=1;//设时秒钟标志位变量置1,表示设时秒钟数值修改。
			   setsecondshi++;//设时秒钟十位变量先赋值再加加
		       if(setsecondshi==6)//判断设时秒钟十位变量设定值是否达到6
		       setsecondshi=0;//设时秒钟十位变量数归零
			   WriteCommand(0x80+0x00+0x06);//写入LCD1602字符型液晶显示器第一行第6个(从第0个开始数)位置的设时秒钟十位变量显示位
			   WriteData(0x30+setsecondshi);//0x30表示字符库的数字0,整个代码表示设时秒钟十位变量变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x06);//写入LCD1602字符型液晶显示器第一行第6个(从第0个开始数)位置的设时秒钟十位变量显示位
			   setsecond=setsecondshi*10+setsecondge;//设时秒钟变量求值
			   break;
	   	case 3://设时按键S按键第三次按下
			   setminutanflag=1;//设时分钟标志位变量置1,表示设时分钟数值修改。
			   setminutange++;//设时分钟个位变量先赋值再加加
		       if(setminutange==10)//判断设时分钟个位变量设定值是否达到10
		       setminutange=0;//设时分钟个位变量归零
			   WriteCommand(0x80+0x00+0x04);//写入LCD1602字符型液晶显示器第一行第4个(从第0个开始数)位置的设时分钟个位变量显示位
			   WriteData(0x30+setminutange);//0x30表示字符库的数字0,整个代码表示设时分钟个位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x04);//写入LCD1602字符型液晶显示器第一行第4个(从第0个开始数)位置的设时分钟个位变量显示位
			   setminutan=setminutanshi*10+setminutange;//设时分钟变量求值
			   break;
		case 4://设时按键S按键第四次按下
			   setminutanflag=1;//设时分钟标志位变量置1,表示设时分钟数值修改。
			   setminutanshi++;//设时分钟十位变量先赋值再加加
		       if(setminutanshi==6)//判断设时分钟十位变量设定值是否达到6
		       setminutanshi=0;//设时分钟十位变量归零
			   WriteCommand(0x80+0x00+0x03);//写入LCD1602字符型液晶显示器第一行第3个(从第0个开始数)位置的设时分钟十位变量显示位
			   WriteData(0x30+setminutanshi);//0x30表示字符库的数字0,整个代码表示设时分钟十位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x03);//写入LCD1602字符型液晶显示器第一行第3个(从第0个开始数)位置的设时分钟十位变量显示位
			   setminutan=setminutanshi*10+setminutange;//设时分钟变量求值
			   break;
	   	case 5://设时按键S按键第五次按下
		       sethourflag=1;//设时时钟标志位变量置1,表示设时时钟数值修改。
		       sethourge++;//设时时钟个位变量先赋值再加加
		       if(sethourge==4)//判断设时时钟个位变量设定值是否达到4
		       sethourge=0;//设时时钟个位变量归零
			   WriteCommand(0x80+0x00+0x01);//写入LCD1602字符型液晶显示器第一行第1个(从第0个开始数)位置的设时时钟个位显示位
			   WriteData(0x30+sethourge);//0x30表示字符库的数字0,整个代码表示设时时钟个位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x01);//写入LCD1602字符型液晶显示器第一行第1个(从第0个开始数)位置的设时时钟个位显示位
			   sethour=sethourshi*10+sethourge;//设时时钟变量求值
			   break;
		case 6://设时按键S按键第六次按下
		       sethourflag=1;//设时时钟标志位变量置1,表示设时时钟数值修改。
			   sethourshi++;//设时时钟十位变量先赋值再加加
		       if(sethourshi==3)//判断设时时钟十位设定值是否达到3
		       sethourshi=0;//设时时钟十位归零
			   WriteCommand(0x80+0x00+0x00);//写入LCD1602字符型液晶显示器第一行第0个(从第0个开始数)位置的设时时钟十位显示位
			   WriteData(0x30+sethourshi);//0x30表示字符库的数字0,整个代码表示设时时钟十位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x00);//写入LCD1602字符型液晶显示器第一行第0个(从第0个开始数)位置的设时时钟十位显示位
			   sethour=sethourshi*10+sethourshi;//设时时钟变量求值
			   break;
	   }
      }
	 }
	}
	if(Snum!=0)//判断设时按键S按键按下次数变量是否为0
  {
     if(S3==0)//判断减少按键S3是否按下
	{
	  Delay(5);//延时
	  if(S3==0)//再次判断减少按键S3是否按下
	 {
	   S3numflag=1;//减少键标志位变量,可以在时间报警函数内进行设时报警。
	   while(!S3);//等待减少按键S3弹起
       switch(Snum)//设时按键S按键按下次数变量选择位
	  {
	    case 1://设时按键S按键第一次按下
			   setsecondflag=1;//设时秒钟标志位变量置1,表示设时秒钟数值修改。
			   setsecondge--;//设时秒钟个位变量先赋值再减减
		       if(setsecondge==-1)//判断设时秒钟个位变量设定值是否达到-1
		       setsecondge=9;//设时秒钟个位变量置9
			   WriteCommand(0x80+0x00+0x07);//写入LCD1602字符型液晶显示器第一行第7个(从第0个开始数)位置的设时秒钟个位变量显示位
			   WriteData(0x30+setsecondge);//0x30表示字符库的数字0,整个代码表示设时秒钟个位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x07);//写入LCD1602字符型液晶显示器第一行第7个(从第0个开始数)位置的设时秒钟个位变量显示位
			   setsecond=setsecondshi*10+setsecondge;//设时秒钟变量求值
			   break;
		case 2://设时按键S按键第二次按下
			   setsecondflag=1;//设时秒钟标志位变量置1,表示设时秒钟数值修改。
			   setsecondshi--;//设时秒钟十位变量先赋值再减减
		       if(setsecondshi==-1)//判断设时秒钟十位变量设定值是否达到-1
		       setsecondshi=5;//设时秒钟十位变量数置5
			   WriteCommand(0x80+0x00+0x06);//写入LCD1602字符型液晶显示器第一行第6个(从第0个开始数)位置的设时秒钟十位变量显示位
			   WriteData(0x30+setsecondshi);//0x30表示字符库的数字0,整个代码表示设时秒钟十位变量变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x06);//写入LCD1602字符型液晶显示器第一行第6个(从第0个开始数)位置的设时秒钟十位变量显示位
			   setsecond=setsecondshi*10+setsecondge;//设时秒钟变量求值
			   break;
	   	case 3://设时按键S按键第三次按下
			   setminutanflag=1;//设时分钟标志位变量置1,表示设时分钟数值修改。
			   setminutange--;//设时分钟个位变量先赋值再减减
		       if(setminutange==-1)//判断设时分钟个位变量设定值是否达到-1
		       setminutange=9;//设时分钟个位变量置9
			   WriteCommand(0x80+0x00+0x04);//写入LCD1602字符型液晶显示器第一行第4个(从第0个开始数)位置的设时分钟个位变量显示位
			   WriteData(0x30+setminutange);//0x30表示字符库的数字0,整个代码表示设时分钟个位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x04);//写入LCD1602字符型液晶显示器第一行第4个(从第0个开始数)位置的设时分钟个位变量显示位
			   setminutan=setminutanshi*10+setminutange;//设时分钟变量求值
			   break;
		case 4://设时按键S按键第四次按下
			   setminutanflag=1;//设时分钟标志位变量置1,表示设时分钟数值修改。
			   setminutanshi--;//设时分钟十位变量先赋值再减减
		       if(setminutanshi==-1)//判断设时分钟十位变量设定值是否达到-1
		       setminutanshi=5;//设时分钟十位变量置9
			   WriteCommand(0x80+0x00+0x03);//写入LCD1602字符型液晶显示器第一行第3个(从第0个开始数)位置的设时分钟十位变量显示位
			   WriteData(0x30+setminutanshi);//0x30表示字符库的数字0,整个代码表示设时分钟十位变量可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x03);//写入LCD1602字符型液晶显示器第一行第3个(从第0个开始数)位置的设时分钟十位变量显示位
			   setminutan=setminutanshi*10+setminutange;//设时分钟变量求值
			   break;
	   	case 5://设时按键S按键第五次按下
		       sethourflag=1;//设时时钟标志位变量置1,表示设时时钟数值修改。
			   sethourge--;//设时时钟个位变量先赋值再减减
		       if(sethourge==-1)//判断设时时钟个位变量设定值是否达到-1
		       sethourge=3;//设时时钟个位变量置3
			   WriteCommand(0x80+0x00+0x01);//写入LCD1602字符型液晶显示器第一行第1个(从第0个开始数)位置的设时时钟个位显示位
			   WriteData(0x30+sethourge);//0x30表示字符库的数字0,整个代码表示设时时钟个位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x01);//写入LCD1602字符型液晶显示器第一行第1个(从第0个开始数)位置的设时时钟个位显示位
			   sethour=sethourshi*10+sethourge;//设时时钟变量求值
			   break;
		case 6://设时按键S按键第六次按下
		       sethourflag=1;//设时时钟标志位变量置1,表示设时时钟数值修改。
			   sethourshi--;//设时时钟十位变量先赋值再减减
		       if(sethourshi==-1)//判断设时时钟十位设定值是否达到-1
		       sethourshi=2;//设时时钟十位置2
			   WriteCommand(0x80+0x00+0x00);//写入LCD1602字符型液晶显示器第一行第0个(从第0个开始数)位置的设时时钟十位显示位
			   WriteData(0x30+sethourshi);//0x30表示字符库的数字0,整个代码表示设时时钟十位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x00);//写入LCD1602字符型液晶显示器第一行第0个(从第0个开始数)位置的设时时钟十位显示位
			   sethour=sethourshi*10+sethourge;//设时时钟变量求值
			   break;
	   }
      }
	 }
	}
 }    
  void SetTemperatureKeyScan()//设温按键扫描函数
{
   if(S0==0)//判断设温按键S0是否按下
  {
  	Delay(5);//延时
	if(S0==0)//再次判断设温按键S0是否按下
   {
	 settemperatureflag=0;//设温标志位变量置0,在温度报警函数执行后但不报警的情况下,余留settemperatureflag==1,当再次操作设温按键扫描函数设温时,会发生在设温过程中触发设温报警条件而报警,因此在设温按键扫描函数里边添加settemperatureflag=0,再次执行设温按键扫描函数后,温度报警函数里边settemperatureflag==1被置换成settemperatureflag=0,很好地解决了再次操作设温按键扫描函数设温时,在设温过程中触发设温报警条件而报警的问题。
	 TR0flag=0;//定时器0标志位变量置0,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留TR0flag==1,假若时间报警函数里边存在TR0=1,当操作设温按键扫描函数时,计时依然在执行,导致计时不恰当,因此在设温按键扫描函数里边添加TR0flag=0,执行设温按键扫描函数后,时间报警函数里边TR0flag==1被置换成TR0flag=1,很好地解决了在操作设温按键扫描函数时,计时依然在执行,导致计时不恰当的问题
	 setsecondflag=0;//设时秒钟标志位变量置0,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留setsecondflag==1,假若时间报警函数里边存在TR0=1,当操作设温按键扫描函数时,计时依然在执行,导致计时不恰当,因此在设温按键扫描函数里边添加setsecondflag=0,执行设温按键扫描函数后,时间报警函数里边setsecondflag==1被置换成setsecondflag=0,很好地解决了在操作设温按键扫描函数时,计时依然在执行,导致计时不恰当的问题
	 setminutanflag=0;//设时分钟标志位变量置0,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留setminutanflag==1,假若时间报警函数里边存在TR0=1,当操作设温按键扫描函数时,计时依然在执行,导致计时不恰当,因此在设温按键扫描函数里边添加setminutanflag=0,执行设温按键扫描函数后,时间报警函数里边setminutanflag==1被置换成setminutanflag=0,很好地解决了在操作设温按键扫描函数时,计时依然在执行,导致计时不恰当的问题
	 sethourflag=0;//设时时钟标志位变量置0,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留sethourflag==1,假若时间报警函数里边存在TR0=1,当操作设温按键扫描函数时,计时依然在执行,导致计时不恰当,因此在设温按键扫描函数里边添加sethourflag=0,执行设温按键扫描函数后,时间报警函数里边sethourflag==1被置换成sethourflag=0,很好地解决了在操作设温按键扫描函数时,计时依然在执行,导致计时不恰当的问题
	 S0num++;//设温按键S0按键次数变量先赋值再自加
	 while(!S0);//等待设温按键S0弹起
	 switch(S0num)//设温按键S0按键按下次数变量选择位
	{
	  case 1://设温按键S0按键第一次按下
	         TR0=0;//关定时器0
			 settimedisplayflag=1;//设时显示标志位变量置1,在操作设温按键扫描函数的情况下,不能操作设时按键扫描函数。
			 tiaotimedisplayflag=1;//调时显示标志位变量置1,在操作设温按键扫描函数的情况下,不能操作调时按键扫描函数。
			 lcd1602displaytimeflag=1;//液晶显示器显示时间标志位变量置1,在操作设温按键扫描函数的情况下,不受时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数影响。
			 temperaturedisplayflag=1;//温度显示标志位变量置1,在操作设温按键扫描函数的情况下,不受温度分解函数和温度显示函数影响。
			 WriteCommand(0x80+0x00+0x0d);//LCD1602字符型液晶显示器第一行第13个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 2://设温按键S0按键第二次按下 
			 WriteCommand(0x80+0x00+0x0b);//LCD1602字符型液晶显示器第一行第11个(从第0开始数)个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 3://设温按键S0按键第三次按下
			 WriteCommand(0x80+0x00+0x0a);//LCD1602字符型液晶显示器第一行第10个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 4://设温按键S0按键第四次按下
			 WriteCommand(0x80+0x00+0x09);//LCD1602字符型液晶显示器第一行第9个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 5://设温按键S0按键第五次按下
			 WriteCommand(0x80+0x00+0x08);//LCD1602字符型液晶显示器第一行第8个(从第0开始数)位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 6://设温按键S0按键第六次按下
			 WriteCommand(0x80+0x00+0x0d);//LCD1602字符型液晶显示器第一行第13个(从第0开始数)位置的显示位
	         WriteCommand(0x0c);//关光标(或字符)闪烁。
			 TR0=1;//开定时器0
			 S0num=0;//设温按键S0按键按下次数清零,可以反复操作设温按键。
			 settimedisplayflag=0;//设时显示标志位变量置0,让设温按键扫描函数执行后,可允许设时按键扫描函数执行。
			 tiaotimedisplayflag=0;//调时显示标志位变量置0,让设温按键扫描函数执行后,可允许调时按键扫描函数执行。
			 lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量置0,让设温按键扫描函数执行后,可允许时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数执行。
			 temperaturedisplayflag=0;//温度显示标志位变量置0,让设温按键扫描函数执行后,可允许温度分解函数和温度显示函数执行。
			 settemperatureflag=1;//设温标志位变量置1,为了在操作设温按键扫描函数进行设温后,可以执行温度报警函数。
			 break;
	 default:
	         S0num=0;//设温按键S0按键按下次数清零
			 break;
	 		  
	 }
    }
   }
    if(S0num!=0)//判断设温按键S0按键按下次数变量是否为0
  {
     if(S2==0)//判断增加按键S2是否按下
	{
	  Delay(5);//延时
	  if(S2==0)//再次判断增加按键S2是否按下
	 {
	   S2numflag=1;//增加键标志位变量置1,可以在温度报警函数内进行设报警。
	   while(!S2);//等待增加按键S2弹起
       switch(S0num)//设温按键S0按键按下次数变量选择位
	  {
	    case 1://设温按键S0按键第一次按下
			   setwenduxiaoshu++;//设温小数位变量先赋值再加加
		       if(setwenduxiaoshu==10)//判断设温小数位变量设定值是否达到10
		       setwenduxiaoshu=0;//设温小数位变量归零
		       WriteCommand(0x80+0x00+0x0d);//写入LCD1602字符型液晶显示器第一行第13个(从第0个开始数)位置的设温小数位显示位
			   WriteData(0x30+setwenduxiaoshu);//0x30表示字符库的数字0,整个代码表示设温小数位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0d);//写入LCD1602字符型液晶显示器第一行第13个(从第0个开始数)位置的设温小数位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
		case 2://设温按键S0按键第二次按下
			   setwenduge++;//设温个位变量先赋值再加加
		       if(setwenduge==6)//判断设温个位变量设定值是否达到6
		       setwenduge=0;//设温个位变量数归零
		       WriteCommand(0x80+0x00+0x0b);//写入LCD1602字符型液晶显示器第一行第11个(从第0个开始数)位置的设温个位显示位
			   WriteData(0x30+setwenduge);//0x30表示字符库的数字0,整个代码表示设温个位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0b);//写入LCD1602字符型液晶显示器第一行第11个(从第0个开始数)位置的设温个位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
	   	case 3://设温按键S0按键第三次按下
			   setwendushi++;//设温十位变量先赋值再加加
		       if(setwendushi==3)//判断设温十位变量设定值是否达到3
		       setwendushi=0;//设温十位变量归零
		       WriteCommand(0x80+0x00+0x0a);//写入LCD1602字符型液晶显示器第一行第10个(从第0个开始数)位置的设温十位显示位
			   WriteData(0x30+setwendushi);//0x30表示字符库的数字0,整个代码表示设温十位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0a);//写入LCD1602字符型液晶显示器第一行第10个(从第0个开始数)位置的设温十位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
		case 4://设温按键S0按键第四次按下
			   setwendubai++;//设温百位变量先赋值再加加
		       if(setwendubai==2)//判断设温百位变量设定值是否达到2
		       setwendubai=0;//设温百位变量归零
		       WriteCommand(0x80+0x00+0x09);//写入LCD1602字符型液晶显示器第一行第9个(从第0个开始数)位置的设温百位显示位
			   WriteData(0x30+setwendubai);//0x30表示字符库的数字0,整个代码表示设温百位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x09);//写入LCD1602字符型液晶显示器第一行第9个(从第0个开始数)位置的设温百位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
	   	case 5://设温按键S0按键第五次按下
		       WriteCommand(0x80+0x00+0x08);//写入LCD1602字符型液晶显示器第一行第8个(从第0个开始数)位置的设温负符号显示位
			   WriteData(0x2b);//0x2d表示字符库的正符号
			   WriteCommand(0x80+0x00+0x08);//写入LCD1602字符型液晶显示器第一行第8个(从第0个开始数)个位置的设温负符号显示位
			   break;
	   }
      }
	 }
	}
	if(S0num!=0)//判断设温按键S0按键按下次数变量是否为0
  {
     if(S3==0)//判断减少按键S2是否按下
	{
	  Delay(5);//延时
	  if(S3==0)//再次判断减少按键S2是否按下
	 {
	   S3numflag=1;//减少键标志位变量置1,可以在温度报警函数内进行设报警。
	   while(!S3);//等待减少按键S2弹起
       switch(S0num)//设温按键S0按键按下次数变量选择位
	  {
	    case 1://设温按键S0按键第一次按下
			   setwenduxiaoshu--;//设温小数位变量先赋值再减减
		       if(setwenduxiaoshu==-1)//判断设温小数位变量设定值是否达到-1
		       setwenduxiaoshu=9;//设温小数位变量置9
		       WriteCommand(0x80+0x00+0x0d);//写入LCD1602字符型液晶显示器第一行第13个(从第0个开始数)位置的设温小数位显示位
			   WriteData(0x30+setwenduxiaoshu);//0x30表示字符库的数字0,整个代码表示设温小数位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0d);//写入LCD1602字符型液晶显示器第一行第13个(从第0个开始数)位置的设温小数位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
		case 2://设温按键S0按键第二次按下
			   setwenduge--;//设温个位变量先赋值再减减
		       if(setwenduge==-1)//判断设温个位变量设定值是否达到-1
		       setwenduge=5;//设温个位变量数置5
		       WriteCommand(0x80+0x00+0x0b);//写入LCD1602字符型液晶显示器第一行第11个(从第0个开始数)位置的设温个位显示位
			   WriteData(0x30+setwenduge);//0x30表示字符库的数字0,整个代码表示设温个位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0b);//写入LCD1602字符型液晶显示器第一行第11个(从第0个开始数)位置的设温个位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
	   	case 3://设温按键S0按键第三次按下
			   setwendushi--;//设温十位变量先赋值再减减
		       if(setwendushi==-1)//判断设温十位变量设定值是否达到-1
		       setwendushi=2;//设温十位变量置2
		       WriteCommand(0x80+0x00+0x0a);//写入LCD1602字符型液晶显示器第一行第10个(从第0个开始数)位置的设温十位显示位
			   WriteData(0x30+setwendushi);//0x30表示字符库的数字0,整个代码表示设温十位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x0a);//写入LCD1602字符型液晶显示器第一行第10个(从第0个开始数)位置的设温十位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
		case 4://设温按键S0按键第四次按下
			   setwendubai--;//设温百位变量先赋值再减减
		       if(setwendubai==-1)//判断设温百位变量设定值是否达到-1
		       setwendubai=1;//设温百位变量置1
		       WriteCommand(0x80+0x00+0x09);//写入LCD1602字符型液晶显示器第一行第9个(从第0个开始数)位置的设温百位显示位
			   WriteData(0x30+setwendubai);//0x30表示字符库的数字0,整个代码表示设温百位可显示0到9的数字。
			   WriteCommand(0x80+0x00+0x09);//写入LCD1602字符型液晶显示器第一行第9个(从第0个开始数)位置的设温百位显示位
			   settemperature=setwendubai*1000+setwendushi*100+setwenduge*10+setwenduxiaoshu;//设温变量求值
			   break;
	   	case 5://设温按键S0按键第五次按下
		       WriteCommand(0x80+0x00+0x08);//写入LCD1602字符型液晶显示器第一行第8个(从第0个开始数)位置的设温负符号显示位
			   WriteData(0x2d);//0x2d表示字符库的负符号
			   WriteCommand(0x80+0x00+0x08);//写入LCD1602字符型液晶显示器第一行第8个(从第0个开始数)个位置的设温负符号显示位
			   break;
	   }
      }
	 }
	}
   } 
  void TiaoTimeKeyScan()//调时按键扫描函数
{
   if(S1==0)//判断调时按键S1是否按下					   
  {
	Delay(5);//延时
	if(S1==0)//再次判断调时按键S1是否按下
   {	
	 settemperatureflag=0;//设温标志位变量置0,在温度报警函数执行后但不报警的情况下,温度报警函数里边余留settemperatureflag==1和TR0=1,当操作调时按键扫描函数时,计时依然在执行,导致计时不恰当,因此在调时按键扫描函数里边添加settemperatureflag=0和TR0=0,执行调时按键扫描函数后,温度报警函数里边settemperatureflag==1和TR0=1被置换成settemperatureflag=0和TR0=0,很好地解决了在操作调时按键扫描函数时,计时依然在执行,导致计时不恰当的问题。
	 S1num++;//调时按键S1按键次数变量先赋值再自加
	 while(!S1);//等待调时按键S1弹起
	 switch(S1num)//调时按键S1按键按下次数变量选择位
	{
	  case 1://调时按键S1按键第一次按下
	         TR0=0;//关定时器0
			 settimedisplayflag=1;//设时显示标志位变量置1,在操作调时按键扫描函数的情况下,不能操作设时按键扫描函数。
			 settemperaturedisplayflag=1;//设温显示标志位变量置1,在操作调时按键扫描函数的情况下,不能操作设温按键扫描函数。
	         lcd1602displaytimeflag=1;//液晶显示器显示时间标志位变量等于1,在操作调时按键扫描函数的情况下,不受时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数影响。
			 temperaturedisplayflag=1;//温度显示标志位变量等于1,在操作调时按键扫描函数的情况下,不受温度分解函数和温度显示函数影响。
			 secondge=miao%10;//关掉定时器0定时后,把秒钟计时时间数值取余赋给秒钟个位显示位。 
	         secondshi=miao/10;//关掉定时器0定时后,把秒钟计时时间数值取除赋给秒钟十位显示位。
			 WriteCommand(0x80+0x40+0x07);//LCD1602字符型液晶显示器第二行第8个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 2://调时按键S1按键第二次按下
	         secondshi=secondshi;//关掉定时器0定时后,把秒钟计时时间数值取除后得到的值再赋给秒钟十位显示位。
	         WriteCommand(0x80+0x40+0x06);//LCD1602字符型液晶显示器第二行第7个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 3://调时按键S1按键第三次按下
	         minutange=fen%10;//关掉定时器0定时后,把分钟计时时间数值取余赋给分钟个位显示位。
			 minutanshi=fen/10;//关掉定时器0定时后,把分钟计时时间数值取除赋给分钟十位显示位。
	         WriteCommand(0x80+0x40+0x04);//LCD1602字符型液晶显示器第二行第5个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 4://调时按键S1按键第四次按下
	         minutanshi=minutanshi;//关掉定时器0定时后,把分钟计时时间数值取除后得到的值再赋给分钟十位显示位。
	         WriteCommand(0x80+0x40+0x03);//LCD1602字符型液晶显示器第二行第4个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 5://调时按键S1按键第五次按下
	         hourge=shi%10;//关掉定时器0定时后,把时钟计时时间数值取余赋给时钟个位显示位。
			 hourshi=shi/10;//关掉定时器0定时后,把时钟计时时间数值取除赋给时钟十位显示位。
	         WriteCommand(0x80+0x40+0x01);//LCD1602字符型液晶显示器第二行第2个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 6://调时按键S1按键第六次按下
	         hourshi=hourshi;//关掉定时器0定时后,把时钟计时时间数值取除后得到的值再赋给时钟十位显示位。
	         WriteCommand(0x80+0x40+0x00);//LCD1602字符型液晶显示器第二行第1个位置的显示位
	         WriteCommand(0x0f);//开LCD1602字符型液晶显示器显示,开光标,开光标(或字符)闪烁。
			 break;
	  case 7://调时按键S1按键第七次按下
	         WriteCommand(0x80+0x40+0x07);//LCD1602字符型液晶显示器第二行第8个位置的显示位
	         WriteCommand(0x0c);//关光标(或字符)闪烁。
			 TR0=1;//开定时器0
			 S1num=0;//调时按键S1按键按下次数清零,可以反复操作调时按键。
			 settimedisplayflag=0;//设时显示标志位变量置0,让调时按键扫描函数执行后,可允许设时按键扫描函数执行。
			 settemperaturedisplayflag=0;//设温显示标志位变量置0,让调时按键扫描函数执行后,可允许设温按键扫描函数执行。
	         lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量等于0,让调时按键扫描函数执行后,可允许时钟两位数分解函数和分钟两位数分解函数和秒钟两位数分解函数执行。
			 temperaturedisplayflag=0;//温度显示标志位变量等于0,让调时按键扫描函数执行后,可允许温度分解函数和温度显示函数执行。
			 miaoflag=0;//秒钟标志位变量置0,在操作调时按键扫描函数进行调时后,调时按键扫描函数里边余留miaoflag==1,不解除会导致时间报警函数不能启动报警判别,因此在调时按键扫描函数里边添加miaoflag=0,执行调时按键扫描函数后,时间报警函数就可以做出相应时间报警。
	         fenflag=0;//分钟标志位变量置0,在操作调时按键扫描函数进行调时后,调时按键扫描函数里边余留fenflag==1,不解除会导致时间报警函数不能启动报警判别,因此在调时按键扫描函数里边添加fenflag=0,执行调时按键扫描函数后,时间报警函数就可以做出相应时间报警。
	         shiflag=0;//时钟标志位变量置0,在操作调时按键扫描函数进行调时后,调时按键扫描函数里边余留shiflag==1,不解除会导致时间报警函数不能启动报警判别,因此在调时按键扫描函数里边添加shiflag=0,执行调时按键扫描函数后,时间报警函数就可以做出相应时间报警。
			 break;
	 default:
	         S1num=0;//调时按键S1按键按下次数清零,可以反复操作调时按键。
			 break;
	 }
	}
   }
    if(S1num!=0)//判断调时按键S1按键按下次数变量是否为0
   {
     if(S2==0)//判断增加按键S2是否按下
	{
	  Delay(5);//延时
	  if(S2==0)//再次判断增加按键S2是否按下
	 {
	   while(!S2);//等待增加按键S2弹起
       switch(S1num)//调时按键S1按键按下次数变量选择位
	  {
	    case 1://调时按键S1按键第一次按下
			   miaoflag=1;//秒钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留miaoflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加miaoflag=1,时间报警函数里边miaoflag==0被置换成miaoflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第二次按下
			   miaoflag=1;//秒钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留miaoflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加miaoflag=1,时间报警函数里边miaoflag==0被置换成miaoflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第三次按下
			   fenflag=1;//分钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留fenflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加fenflag=1,时间报警函数里边fenflag==0被置换成fenflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第四次按下
			   fenflag=1;//分钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留fenflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加fenflag-=1,时间报警函数里边fenflag==0被置换成fenflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第五次按下
			   shiflag=1;//时钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留shiflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加shiflag=1,时间报警函数里边shiflag==0被置换成shiflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第六次按下
			   shiflag=1;//时钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留shiflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加shiflag=1,时间报警函数里边shiflag==0被置换成shiflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第一次按下
			   miaoflag=1;//秒钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留miaoflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加miaoflag=1,时间报警函数里边miaoflag==0被置换成miaoflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第二次按下
			   miaoflag=1;//秒钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留miaoflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加miaoflag=1,时间报警函数里边miaoflag==0被置换成miaoflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第三次按下
			   fenflag=1;//分钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留fenflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加fenflag=1,时间报警函数里边fenflag==0被置换成fenflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第四次按下
			   fenflag=1;//分钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留fenflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加fenflag=1,时间报警函数里边fenflag==0被置换成fenflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第五次按下
			   shiflag=1;//时钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留shiflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加shiflag=1,时间报警函数里边shiflag==0被置换成shiflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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按键第六次按下
			   shiflag=1;//时钟标志位变量置1,在时间报警函数执行后但不报警的情况下,时间报警函数里边余留shiflag==0,当操作调时按键扫描函数调时时,会发生在调时过程中触发时间报警条件而报警,因此在调时按键扫描函数里边添加shiflag=1,时间报警函数里边shiflag==0被置换成shiflag=1,很好地解决了在操作调时按键扫描函数调时时,在调时过程中触发时间报警条件而报警的问题。
			   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; 
	   }
	  }
	 }
	}
   }
void SumKeyScan()//总按键扫描函数
{
   if(S4==0)//判断启停按键S4是否按下
  {
	Delay(5);//延时
	if(S4==0)//再次判断启停按键S4是否按下
   {
	 S4num++;//启停按键S4按下次数先赋值再加加
	 while(!S4);//等待启停按键S4弹起
	 if(S4num==1)//判断启停按键S4是否第一次按下过,实现直接停止。
	{
	  qitingflag=1;//启停标志位变量置1,用来启动时间报警函数和温度报警函数和设时按键扫描函数和设温按键扫描函数和调时按键扫描函数和秒钟显示两位数分解函数和分钟显示两位数分解函数和时钟显示两位数分解函数和温度分解函数和温度显示函数。
	  TR0=1;//启动定时器0
	 }
	 if(S4num==2&&settimedisplayflag==0&&settemperaturedisplayflag==0&&tiaotimedisplayflag==0&&timebaojingflag==0)//判断启停按键S4是否第二次按下过及设时显示标志位变量是否为0和设温显示标志位变量是否为0和调时显示标志位变量是否为0和时间报警标志位变量是否为0,相当于第一次按下启停键启动后,在没有按其他按键的情况下,第二次按下启停键就停止。
	{
	  qitingflag=1;//启停标志位变量置1,用来启动时间报警函数和温度报警函数和设时按键扫描函数和设温按键扫描函数和调时按键扫描函数和秒钟显示两位数分解函数和分钟显示两位数分解函数和时钟显示两位数分解函数和温度分解函数和温度显示函数,相当于总开关。
	  TR0=0;//关定时器0
	  S4num=0;//启停按键S4按下次数清零,可以反复操作启停按键。
	  settimedisplayflag=1;//设时显示标志位变量置1,限制操作设时按键扫描函数。
	  settemperaturedisplayflag=1;//设温显示标志位变量置1,限制操作设温按键扫描函数。
	  tiaotimedisplayflag=1;//调时显示标志位变量置1,限制操作调时按键扫描函数。
	 }
	 if(S4num==1&&settimedisplayflag==1&&settemperaturedisplayflag==1&&tiaotimedisplayflag==1)//判断启停按键S4是否第一次按下过以及调时显示标志位变量为1及设温显示标志位变量是否为1和调时显示标志位变量是否为1,相当于第一次按下启停键启动后,第二次按下启停键停止后,在没有按其他按键的情况下,第三次按下启停键就启动。
	{
	  qitingflag=1;//启停标志位变量置1,用来启动时间报警函数和温度报警函数和设时按键扫描函数和设温按键扫描函数和调时按键扫描函数和秒钟显示两位数分解函数和分钟显示两位数分解函数和时钟显示两位数分解函数和温度分解函数和温度显示函数,相当于总开关。
	  TR0=1;//启动定时器0
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
	  settimedisplayflag=0;//设时显示标志位变量置0,可操作设时按键扫描函数。
	  settemperaturedisplayflag=0;//设温显示标志位变量置0,可操作设温按键扫描函数。
	  tiaotimedisplayflag=0;//调时显示标志位变量置0,可操作调时按键扫描函数。 
	 }
	 if(S4num==2&&timebaojingflag==1)//判断启停按键S4是否第二次按下过及时间报警标志位变量是否为1,相当于时间报警解除。
	{
	  TR0=1;//开定时器0
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
	  timebaojingflag=0;//时间报警标志位变量置0,释放时间报警标志位。
	  setsecondge=0;//设时秒钟个位变量变0,释放设时秒钟个位标志位。
	  setsecondshi=0;//设时秒钟十位变量变0,释放设时秒钟十位标志位。
	  setminutange=0;//设时分钟个位变量变0,释放设时分钟个位标志位。
	  setminutanshi=0;//设时分钟十位变量变0,释放设时分钟十位标志位。
	  sethourge=0;//设时时钟个位变量变0,释放设时时钟个位标志位。
	  sethourshi=0;//设时时钟十位变量变0,释放设时时钟十位标志位。
	  WriteCommand(0x80+0x07);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时秒钟个位。
      WriteData(0x30+setsecondge);//0x30表示字符库的数字0,整个代码表示设时秒钟个位显示0。
	  WriteCommand(0x80+0x06);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时秒钟十位。
      WriteData(0x30+setsecondshi);//0x30表示字符库的数字0,整个代码表示设时秒钟十位显示0。
	  WriteCommand(0x80+0x04);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时分钟个位。
      WriteData(0x30+setminutange);//0x30表示字符库的数字0,整个代码表示设时分钟个位显示0。
	  WriteCommand(0x80+0x03);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时分钟十位。
      WriteData(0x30+setminutanshi);//0x30表示字符库的数字0,整个代码表示设时分钟十位显示0。
	  WriteCommand(0x80+0x01);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时时钟个位。
      WriteData(0x30+sethourge);//0x30表示字符库的数字0,整个代码表示设时时钟个位显示0。
	  WriteCommand(0x80+0x00);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时时钟十位。
      WriteData(0x30+sethourshi);//0x30表示字符库的数字0,整个代码表示设时时钟十位显示0。
	  S2numflag=0;//增加键标志位变量置0,释放增加键标志位。
	  S3numflag=0;//减少键标志位变量置0,释放减少键标志位。
	  TR0flag=0;//定时器0标志位变量置0
	  settimedisplayflag=0;//设时显示标志位变量置0,释放设时显示标志位。
	  settemperaturedisplayflag=0;//设温显示标志位变量置0,释放设温显示标志位。
	  tiaotimedisplayflag=0;//调时显示标志位变量置0,释放调时显示标志位。
	  setsecondflag=0;//设时秒钟标志位变量置0,释放设时秒钟标志位。
	  setminutanflag=0;//设时分钟标志位变量置0,释放设时分钟标志位。
	  sethourflag=0;//设时时钟标志位变量置0,释放设时时钟标志位。
	 }
	 
	 if(S4num==2&&temperatruebaojingflag==1)//判断启停按键S4是否第二次按下过及温度报警标志位变量是否为1,相当于温度报警解除。
	{ 
	  TR0=1;//开定时器0
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
	  temperatruebaojingflag=0;//温度报警标志位变量置0,释放温度报警标志位。
	  setwenduxiaoshu=0;//设温小数位变量置0,释放设温小数位标志位。
	  setwenduge=0;//设温个位变量置0,释放设温个位标志位。
	  setwendushi=0;//设温十位变量置0,释放设温十位标志位。
	  setwendubai=0;//设温百位变量置0,释放设温百位标志位。
	  WriteCommand(0x80+0x09);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时秒钟个位。
      WriteData(0x30+setwendubai);//0x30表示字符库的数字0,整个代码表示设时秒钟个位显示0。
	  WriteCommand(0x80+0x0A);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时秒钟十位。
      WriteData(0x30+setwendushi);//0x30表示字符库的数字0,整个代码表示设时秒钟十位显示0。
	  WriteCommand(0x80+0x0B);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时分钟个位。
      WriteData(0x30+setwenduge);//0x30表示字符库的数字0,整个代码表示设时分钟个位显示0。
	  WriteCommand(0x80+0x0D);//LCD1602字符型液晶显示器第一行第七个(从第零开始数)显示位,即设时分钟十位。
	  WriteData(0x30+setwenduxiaoshu);//0x30表示字符库的数字0,整个代码表示设时分钟个位显示0。
	  S2numflag=0;//增加键标志位变量置0,释放增加键标志位。
	  S3numflag=0;//减少键标志位变量置0,释放减少键标志位。
	  settemperatureflag=0;//设温标志位变量置0,释放设温标志位。
	  settimedisplayflag=0;//设时显示标志位变量置0,释放设时显示标志位。
	  settemperaturedisplayflag=0;//设温显示标志位变量置0,释放设温显示标志位。
	  tiaotimedisplayflag=0;//调时显示标志位变量置0,释放调时显示标志位。
	  temperaturedisplayflag=0;//温度显示标志位变量等于0,释放温度显示标志位。  
	 }
	 if(S4num>=2&&settemperaturedisplayflag==1&&tiaotimedisplayflag==1)//判断启停按键S1是否第二或二以上次按下过及设温显示标志位变量为1及调时显示标志位变量为1,相当于设时启动。
	{
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
	  Snum=0;//设时按键S0按下次数清零,可以反复操作设时按键。
	  TR0=1;//启动定时器0
	  TR0flag=1;//定时器0标志位变量置1,进入时间报警函数判断是否可执行时间报警。
	  WriteCommand(0x0c);//关光标(或字符)闪烁
	  settemperaturedisplayflag=0;//设温显示标志位变量置0,释放设温显示标志位。
	  tiaotimedisplayflag=0;//调时显示标志位变量置0,释放调时显示标志位。
	  lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量等于0,释放液晶显示器显示时间标志位。
	  temperaturedisplayflag=0;//温度显示标志位变量置0,释放温度显示标志位。
	 }
	 if(S4num>=2&&settimedisplayflag==1&&tiaotimedisplayflag==1)//判断启停按键S1是否第二或二以上次按下过及设时显示标志位变量为1及调时显示标志位变量为1,相当于设温启动。
	{
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
	  S0num=0;//设温按键S0按下次数清零,可以反复操作设温按键。
	  TR0=1;//启动定时器0
	  WriteCommand(0x0c);//关光标(或字符)闪烁
	  settemperatureflag=1;//设温标志位变量置1,进入温度报警函数判断是否可执行温度报警。
	  settimedisplayflag=0;//设时显示标志位变量置0,释放设时显示标志位。
	  tiaotimedisplayflag=0;//调时显示标志位变量置0,释放调时显示标志位。
	  lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量等于0,释放液晶显示器显示时间标志位。
	  temperaturedisplayflag=0;//温度显示标志位变量置0,释放温度显示标志位。
	 }
	 if(S4num>=2&&settimedisplayflag==1&&settemperaturedisplayflag==1)//判断启停按键S0是否第二或二以上次按下过及设时显示标志位变量为1和设温显示标志位变量为1,相当于调时启动。
	{
	  S4num=1;//启停按键S4按下次数置1,为下一次按下启停键实现停止做准备。
      S1num=0;//调时按键S1按下次数清零,可以反复操作调时按键。
	  TR0=1;//启动定时器0
	  WriteCommand(0x0c);//关光标(或字符)闪烁 
	  settimedisplayflag=0;//设时显示标志位变量置0,释放设时显示标志位。
	  settemperaturedisplayflag=0;//设温显示标志位变量置0,释放设温显示标志位。
	  lcd1602displaytimeflag=0;//液晶显示器显示时间标志位变量置0,释放液晶显示器显示时间标志位。
	  temperaturedisplayflag=0;//温度显示标志位变量置0,释放温度显示标志位。
	  miaoflag=0;//秒钟标志位变量置0,释放秒钟标志位。
	  fenflag=0;//分钟标志位变量置0,释放分钟标志位。
	  shiflag=0;//时钟标志位变量置0,释放时钟显示标志位。
	 }
	}
   }     
  }
  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 DS18B20_Delay(uint i)//微妙级延时函数
{
   while(i--);
 }
  void FengNingQi_Alarm(uint t)//蜂鸣器报警函数
{
   uint x,y;
   for(x=0;x<t;x++)
  {
    for(y=0;y<50;y++);
    FengNingQi=~FengNingQi ;//蜂鸣器按位取反FengNingQi
   }
 }
  bit DS18B20Init()//DS18B20初始化函数
{
   uchar x=0;
   DQ = 1;//单片机将DS18B20通信端口DQ拉高复位  
   DS18B20_Delay(8);//稍做延时
   DQ = 0;//单片机将DS18B20通信端口DQ拉低 
   DS18B20_Delay(80);//延时在480us与960us之间
   DQ = 1;//单片机将DS18B20通信端口DQ拉高
   DS18B20_Delay(4);//延时在15us与60us之间
   x=DQ;//稍做延时后,如果x=0,则初始化成功,若x=1则初始化失败。
   DS18B20_Delay(20);//延时在60us与240us之间
   return x;
 }
  void DS18B20_WriteOneByte(uchar j)//DS18b20写一个字节函数
{
   uchar i=0;
   for (i=8; i>0; i--)//单片机向DS18B20写入数据
  {
    DQ = 0;//单片机将DS18B20通信端口DQ从高电平拉至低电平时,单片机向DS18B20写数据开始。
	DQ = j&0x01;//单片机按将字节低位写入DS18B20
    DS18B20_Delay(5);//延时在60us与120us之间
    DQ = 1;//单片机将DS18B20通信端口DQ拉高 
	j>>=1;//变量j右移一位,最高位补零。例如当j=1,换成二进制是0000 0001,右移一位就是0000 000。扩展:单片机无符号或有符号数左移几位,高位就依次补几位0,低位也依次去掉几位,让左移几位依次代替低位去掉的几位。单片机有符号数,如果是正数,右移几位,先是确定最高位用0,低位也依次去掉几位,让右移几位依次代替低位去掉的几位,如果是负数,右移几位,先是确定最高位用1,低位也依次去掉几位,让右移几位依次代替低位去掉的几位。       
   }
 }
  uchar DS18B20_ReadOneByte()//DS18B20读一个字节函数
{
   uchar i=0;
   uchar j = 0;
   for (i=8;i>0;i--)//单片机读取DS18B20采集的温度数据转换成一个字节
  {
    DQ = 0;//单片机将DS18B20通信端口DQ从高电平拉成低电平时,单片机读取DS18B20所采集到温度数据开始。
    j>>=1;//变量j右移一位,最高位补零。例如当j=1,换成二进制是0000 0001,右移一位就是0000 000。扩展:单片机无符号或有符号数左移几位,高位就依次补几位0,低位也依次去掉几位,让左移几位依次代替低位去掉的几位。单片机有符号数,如果是正数,右移几位,先是确定最高位用0,低位也依次去掉几位,让右移几位依次代替低位去掉的几位,如果是负数,右移几位,先是确定最高位用1,低位也依次去掉几位,让右移几位依次代替低位去掉的几位。
    DQ = 1;//单片机将DS18B20通信端口DQ拉高
    if(DQ)//判断DQ是否等于1
    j|=0x80;//若DQ=1,则让当前j最高位为1,在下次循环中移位至次高位,最后达到从低位到高位接收的目的;若DQ=0,则可跳过此语句,直接在下次循环对byte进行移位补0。  
    DS18B20_Delay(4);//稍做延时
  }
   return j;
}
  uint DS18B20_ReadTemperature()//单片机读取DS18b20当前温度
{
   uchar L=0;//定义温度值低8位变量
   uchar H=0;//定义温度值高8位变量	
   DS18B20Init( );//DS18B20初始化函数
   DS18B20_WriteOneByte(0xcc);//单片机只连一个DS18B20温度传感器时,可写该段代码,表示单片机向DS18B20写入跳过读DS18B20序号列号指令。
   DS18B20_WriteOneByte(0x44);//单片机向DS18B20九字节暂存器(包括两个字节储温温度寄存器、一字节高温触发器、一字节低温触发器、一字节温度精度转换配置寄存器、三个字节的保留位、一字节DS18B20的64位ROM前56位编码校验CRC发生器)中前两个字节温度寄存器写入启动DS18B20温度转换指令
//   DS18B20_Delay(100);//稍作延时
   DS18B20Init( );//DS18B20初始化函数
   DS18B20_WriteOneByte(0xcc);//单片机只连一个DS18B20温度传感器时,可写该段代码,表示单片机向DS18B20写入跳过读DS18B20序号列号指令。
   DS18B20_WriteOneByte(0xbe);//单片机向DS18B20九字节暂存器(包括两个字节储温温度寄存器、一字节高温触发器、一字节低温触发器、一字节温度精度转换配置寄存器、三个字节的保留位、一字节DS18B20的64位ROM前56位编码校验CRC发生器)中前两个字节温度寄存器写入读取温度的指令
//   DS18B20_Delay(100);//稍作延时
   L=DS18B20_ReadOneByte( );//单片机向DS18B20发送读取温度值低8位指令,把读到的温度值低8位赋给温度值低8位变量
   H=DS18B20_ReadOneByte( );//单片机向DS18B20发送读取温度值高8位指令,把读到的温度值高8位赋给温度值高8位变量
   temperature = H;//DS18B20读到的温度值高8位赋给温度值变量,变成高8位温度值变量,还不是一个温度值变量,由于一个温度值变量是由高8位低8位共16位组成。
   temperature = temperature << 8;//温度值高8位变量左移8位,就可以变成一个只有高8位低8位全0的温度值变量。
   temperature = temperature | L;//只有高8位低8位全0的温度值变量与温度值低8位变量或运算后就变成一个真正有高8位低8位共16位的温度值变量 
   if(temperature>0x0fff)//判断表示温度寄存器16位二进制数的温度值变量是否大于表示温度寄存器16位二进制数的正温度值,假若大于且当表示温度寄存器16位二进制数的温度值变量的前5位二进制数全为1时,该温度值变量表示负温度值。
  {
	temperature = ~temperature+2;//负温度值
	temperatureflag=1;//负温度标志变量等于1
   }
   else
  {  	
	temperatureflag=0;//负温度标志变量等于0
   }
   temperature = temperature*0.0625*10;//扩大10倍的温度值
   return temperature;//返回扩大10倍的温度值
     
 }
  void TemperatureFenJie()//LCD1602的温度显示函数   
{
   wendu=DS18B20_ReadTemperature();//DS18B20读到的温度值赋给温度值变量
   if(temperatureflag==1)//判断负温度标志变量是否等于1
  {	
	fuhaowei=0x2d;//负符号
	wendubai=wendu/1000;//温度值百位
    wendushi=wendu%1000/100;//温度值十位
    wenduge=wendu%100/10;//温度值个位
	xiaoshudian=0x2e;//小数点
	wenduxiaoshu=wendu%10;//小数位
   }
   else
  {
 	fuhaowei=0x2b;//正符号
	if(wendu==0)//判断温度是否等于0
   {
   	 fuhaowei=0x20;//无符号
    }
	wendubai=wendu/1000;//温度值百位
    wendushi=wendu%1000/100;//温度值十位
    wenduge=wendu%100/10;//温度值个位
	xiaoshudian=0x2e;//小数点
	wenduxiaoshu=wendu%10;//小数位
   } 		
 }
  void TemperatureDisplay()//LCD1602的温度显示函数   
{ 
   WriteCommand(0x80+0x48);//LCD1602字符型液晶显示器第二行第九个(从第零开始数)显示位
   WriteData(fuhaowei);//符号位显示。
   WriteData(0x30+wendubai);//0x30表示字符库的数字0,整个代码表示温度值百位可显示0到9的数字。
   WriteData(0x30+wendushi);//0x30表示字符库的数字0,整个代码表示温度值十位可显示0到9的数字。
   WriteData(0x30+wenduge);//0x30表示字符库的数字0,整个代码表示温度值个位可显示0到9的数字。
   WriteData(xiaoshudian);//小数点
   WriteData(0x30+wenduxiaoshu);//0x30表示字符库的数字0,整个代码表示小数位可显示0到9的数字。
   WriteData(0xdf);//0xdf表示字符库中摄氏度左上角的符号
   WriteData(0x43);//0x43表示字符库中大写字母C	
 }
//  void SetAlarmTemperatrueFenJie(uint alarmwendu)
//{
//   fuhaowei=0x20;//无符号
//   alarmwendubai=alarmwendu/1000;//温度值百位
//   alarmwendushi=alarmwendu%1000/100;//温度值十位
//   alarmwenduge=alarmwendu%100/10;//温度值个位
//   alarmxiaoshu=alarmwendu%10;//小数位
//  } 		
  void SetTemperatrueInit()//设温初始化函数
{
   WriteCommand(0x80+0x08);//LCD1602字符型液晶显示器第一行第九个(从第零开始数)显示位
   WriteData(fuhaowei);//符号位显示。
   WriteData(0x30+setwendubai);//0x30表示字符库的数字0,整个代码表示设温百位变量可显示0到9的数字。
   WriteData(0x30+setwendushi);//0x30表示字符库的数字0,整个代码表示设温十位变量可显示0到9的数字。
   WriteData(0x30+setwenduge);//0x30表示字符库的数字0,整个代码表示设温个位变量可显示0到9的数字。
   WriteData(0x2e);//小数点
   WriteData(0x30+setwenduxiaoshu);//0x30表示字符库的数字0,整个代码表示设温小数位变量可显示0到9的数字。
   WriteData(0xdf);//0xdf表示字符库中摄氏度左上角的符号
   WriteData(0x43);//0x43表示字符库中大写字母C
 
  }
  void SetTimeInit()//设时初始化函数
{
   WriteCommand(0x80+0x00);//LCD1602字符型液晶显示器第一行第0个(从第零开始数)显示位
   WriteData(0x30+sethourshi);//0x30表示字符库的数字0,整个代码表示设时十位变量可显示0到9的数字。
   WriteData(0x30+sethourge);//0x30表示字符库的数字0,整个代码表示设时个位变量可显示0到9的数字。
   WriteData(0x3a);//0x3a表示字符库中冒号
   WriteData(0x30+setminutanshi);//0x30表示字符库的数字0,整个代码表示设分十位变量可显示0到9的数字。
   WriteData(0x30+setminutange);//0x30表示字符库的数字0,整个代码表示设分个位变量可显示0到9的数字。
   WriteData(0x3a);//0x3a表示字符库中冒号
   WriteData(0x30+setsecondshi);//0x30表示字符库的数字0,整个代码表示设秒十位位变量可显示0到9的数字。
   WriteData(0x30+setsecondge);//0x30表示字符库的数字0,整个代码表示设秒个位位变量可显示0到9的数字。 
  }
  void TimeBaoJing()//时间报警函数
{
   if(S2numflag==1||S3numflag==1)//判断增加键标志位变量是否为1或减少键标志位变量是否为1
  {  
	if(setsecondflag==1&&setminutanflag==0&&sethourflag==0&&setsecond>0&&TR0flag==1&&miaoflag==0)//判断设时秒钟标志位变量是否为1和设时分钟标志位变量是否为0和设时时钟标志位变量是否为0和设时秒钟是否大于0和定时器0标志位变量是否等于1和秒钟标志位变量置是否为0
   {
	 if(miao==setsecond)//判断走时秒钟是否等于设时秒钟
    { 
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
	}
    if(setminutanflag==1&&setsecondflag==0&&sethourflag==0&&setminutan>0&&TR0flag==1&&fenflag==0)//判断设时分钟标志位变量是否为1和设时秒钟标志位变量是否为0和设时时钟标志位变量是否为0和设时分钟是否大于0和定时器0标志位变量是否等于1和分钟标志位变量置是否为0
   {
   	 if(fen==setminutan)//判断走时分钟是否等于设时分钟
	{
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
    }
	if(sethourflag==1&&setsecondflag==0&&setminutanflag==0&&sethour>0&&TR0flag==1&&shiflag==0)//判断设时时钟标志位变量是否为1和设时秒钟标志位变量是否为0和设时分钟标志位变量是否为0设时时钟是否大于0和定时器0标志位变量是否等于1和时钟标志位变量置是否为0
   {
   	 if(shi==sethour)//判断走时时钟是否等于设时时钟
	{
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
    }
	if(setsecondflag==1&&setminutanflag==1&&setsecond>0&&setminutan>0&&TR0flag==1&&miaoflag==0&&fenflag==0)//判断设时秒钟标志位变量是否为1和设时分钟标志位变量是否为1和设时秒钟是否大于0和设时分钟是否大于0和定时器0标志位变量是否等于1和秒钟标志位变量置是否为0和分钟标志位变量是否为0
   {
	 if(miao==setsecond&&fen==setminutan)//判断走时秒钟和分钟是否等于设时秒钟和分钟
    { 
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
	}
	if(setsecondflag==1&&sethourflag==1&&setsecond>0&&sethour>0&&TR0flag==1&&miaoflag==0&&shiflag==0)//判断设时秒钟标志位变量是否为1和设时时钟标志位变量是否为1和设时秒钟是否大于0和设时时钟是否大于0和定时器0标志位变量是否等于1和秒钟标志位变量是否为0和时钟标志位变量是否为0
   {
	 if(miao==setsecond&&shi==sethour)//判断走时秒钟和时钟是否等于设时秒钟和时钟
    { 
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
	}
	if(setminutanflag==1&&sethourflag==1&&setminutan>0&&sethour>0&&TR0flag==1&&fenflag==0&&shiflag==0)//判断设时分钟标志位变量是否为1和设时时钟标志位变量是否为1和设时分钟是否大于0和设时时钟是否大于0和定时器0标志位变量是否等于1和分钟标志位变量是否为0和时钟标志位变量是否为0
   {
	 if(fen==setminutan&&shi==sethour)//判断走时分钟和时钟是否等于设时分钟和时钟
    { 
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
	}
	if(setsecondflag==1&&setminutanflag==1&&sethourflag==1&&setsecond>0&&setminutan>0&&sethour>0&&TR0flag==1&&miaoflag==0&&fenflag==0&&shiflag==0)//判断设时秒钟标志位变量是否为1和设时分钟标志位变量是否为1和设时时钟标志位变量是否为1和设时秒钟是否大于0和设时分钟是否大于0和设时时钟是否大于0和定时器0标志位变量是否等于1和秒钟标志位变量是否为0和分钟标志位变量是否为0和时钟标志位变量是否为0
   {
	 if(miao==setsecond&&fen==setminutan&&shi==sethour)//判断走时秒钟和分钟和时钟是否都等于设时秒钟和分钟和时钟
    { 
	  timebaojingflag=1;//时间报警标志位变量置1,进行时间报警。
	  TR0=0;//关定时器0
	 }
	}
   }
  }
  void TemperatrueBaoJing()//温度报警函数
{
   if(S2numflag==1||S3numflag==1)//判断增加键标志位变量是否为1或减少键标志位变量是否为1
  {  
	if(settemperatureflag==1)//判断设温标志位变量是否为1
   {
	 if(wendu-10>settemperature)//判断温度变量减10后是否大于设温变量,其中的10分别表示设温个位数1与设温小数位0,实际上表示1摄氏度,相当于温差报警温度,这么做的原因是因为设温数值和温度数值都带有小数,通过数值取整运算,把设温数值和温度数值换算成整数来计算温差,这样便于处理设温数值与温度数值的温差值。
    { 
	  temperatruebaojingflag=1;//温度报警标志位变量置1,进行温度报警。
	  TR0=0;//关定时器0
	 }
	}
	 if(wendu<10&&settemperatureflag==1)//判断温度变量是否小于10和设温标志位变量是否为1,其中的10分别表示设温个位数1与设温小数位0,实际上表示1摄氏度,相当于温差报警温度,这么做的原因是因为设温数值和温度数值都带有小数,通过数值取整运算,把设温数值和温度数值换算成整数来计算温差,这样便于处理设温数值与温度数值的温差值。
    {
	  temperatruebaojingflag=0;//温度报警标志位变量置0,不进行温度报警。
	  TR0=1;//开定时器0
     }	
   }
  }
  void main()//主函数
{
   LCD1602Init();//LCD1602字符型液晶显示器初始化函数
   Timer0Init();//定时器0初始化函数
   LCD1602Display();//LCD1602字符型液晶显示器显示函数
   DS18B20Init();//DS18B20初始化函数
   SetTimeInit();//设时初始化函数
   SetTemperatrueInit();//设温初始化函数	
   while(1)//死循环
  {
    SumKeyScan();//总按键扫描函数
	if(qitingflag==1)//判断启停标志位变量是否为1
   {
	 TimeBaoJing();//时间报警函数 
	 if(timebaojingflag==1)//判断时间报警标志位变量置是否为1
	{
	  FengNingQi_Alarm(80);//报警
	  settimedisplayflag=1;//设时显示标志位变量置1,限制操作设时按键扫描函数。
	  settemperaturedisplayflag=1;//设温显示标志位变量置1,限制操作设温按键扫描函数。
	  tiaotimedisplayflag=1;//调时显示标志位变量置1,限制操作调时按键扫描函数。
	 }
	 TemperatrueBaoJing();//温度报警函数
	 if(temperatruebaojingflag==1)//判断温度报警标志位变量是否为1
	{
	  FengNingQi_Alarm(80);//报警
	  settimedisplayflag=1;//设时显示标志位变量置1,限制操作设时按键扫描函数。
	  settemperaturedisplayflag=1;//设温显示标志位变量置1,限制操作设温按键扫描函数。
	  tiaotimedisplayflag=1;//调时显示标志位变量置1,限制操作调时按键扫描函数。
	  temperaturedisplayflag=1;//温度显示标志位变量置1,限制操作温度分解函数和温度显示函数。
	 }
	 if(settimedisplayflag==0)//判断设时显示标志位变量是否等于0
	{
	  SetTimeKeyScan();//设时按键扫描函数
	 }
	 if(settemperaturedisplayflag==0)//判断设温标志位变量是否等于0
    {	
      SetTemperatureKeyScan();//设温按键扫描函数
     }
	 if(tiaotimedisplayflag==0)//判断调时标志位变量是否等于0
    {
	  TiaoTimeKeyScan();//调时按键扫描函数
	 }
//	SetAlarmTemperatrueFenJie(alarmwendu);
	 if(lcd1602displaytimeflag==0)//判断液晶显示器显示时间标志位变量是否等于0
    {	
      if(miao<=60)//判断秒钟变量是否小于等于60
	  LCD1602DisplayTime(0x06,miao);//秒钟显示两位数分解函数
	  if(fen<=60)//判断分钟变量是否小于等于60
	  LCD1602DisplayTime(0x03,fen);//分钟显示两位数分解函数
	  if(shi<=24)//判断时钟变量是否小于等于24
	  LCD1602DisplayTime(0x00,shi);//时钟显示两位数分解函数
     }
	 if(temperaturedisplayflag==0)//判断温度显示标志位变量是否等于0
    {	 
	  TemperatureFenJie();//温度分解函数
	  TemperatureDisplay();//温度显示函数 
     }
    }
   }
  }

三、基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目Proteus软件仿真单片机外围电路

在这里插入图片描述

四、基于51单片机DS18B20测温LCD1602显示可设时设温调时的项目的操作功能描述

(1)、不修改时分秒个位十位数值,只是启动或停止计时的情况:如果第一次按下移位键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。如果第一次按下启停键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。

(2)、修改时分秒个位十位数值,再启动或停止计时的情况:要修改时分秒个位十位上的数值,再启动或停止计时,首先必须按下移位键,此时停止计时,通过点击移位键让LCD1602字符型液晶显示器光标移到时分秒相应个位十位数值上,利用点击增加键或减少键修改数值,修改完毕后,启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,停止计时可按下移位键或按下启停键,当按下移位键时,又可修改时分秒个位十位上的数值,再次启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,周而复始。

2019-12-20 12:30:07 CWQLTYH 阅读数 155
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目

一、前言

1、基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目包括用Keil软件编写单片机C语言程序和用Proteus软件仿真单片机外围电路

2、基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目构思

(1)、实现什么功能:LCD1602字符型液晶显示器先显示时分秒,在点击移位按键后,停止计时,LCD1602字符型液晶显示器光标闪烁,每次按下移位键,LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁,当LCD1602字符型液晶显示器的时分秒个位十位有闪烁后,可修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位上的数值,再通过移位按键或启停按键启动或停止计时。

(2)、如何实现功能:如何让LCD1602字符型液晶显示器先显示时分秒:采用定时器0工作方式1计时,计时得到的数值赋给LCD1602字符型液晶显示器显示时间两位数分解函数进行分解,分解得到的个位数值与十位数值用变量代替分别由LCD1602字符型液晶显示器写指令函数和LCD1602字符型液晶显示器写数据函数写入LCD1602字符型液晶显示器,通过LCD1602字符型液晶显示器显示出来。如何让LCD1602字符型液晶显示器的时分秒个位十位闪烁:采用按键扫描函数扫描,每次按下移位键(此时定时器0停止计时),执行LCD1602字符型液晶显示器光标闪烁指令和LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁的位置指令。如何修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位数值并在原计时基础上实现计时:当移位键按下后,定时器0停止计时,计时得到的数值采用两位数分解公式(如:shi=num/10,ge=num%10。)进行分解,分解得到的个位数值与十位数值用变量代替写入按键扫描函数,此时也要采用两位数合成公式(如:miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数(原因:时分秒的个位或十位显示位的数值是在原计时数值上分解得来,当时分秒的个位或十位显示位的数值发生变化后,原计时数值也要变化,否则启动定时器0计时后,LCD1602字符型液晶显示器显示的是原计时时间,而不是修改时分秒的个位或十位显示位的数值后的计时,因此要采用两位数合成公式(miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数。)。

二、基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目的Keil软件编写的单片机C语言程序

#include<reg52.h>//单片机头文件
#define uchar unsigned char//宏定义,用uchar表示unsigned char,叫无符号字符型数据类型,取值范围为:0到255。
#define uint unsigned int//宏定义,用uint表示unsigned int,叫无符号整数型数据类型,取值范围为:0到65535。 
sbit RS=P2^5;//位定义LCD1602字符型液晶显示器的数据/命令选择引脚                 
sbit RW=P2^6;//位定义LCD1602字符型液晶显示器的读写引脚                        
sbit EN=P2^7;//位定义LCD1602字符型液晶显示器的使能引脚   			  			  	
sbit qitingjian=P1^0;//位定义启停键
sbit zhengzhuanjian=P1^1;//位定义正转键
sbit fanzhuanjian=P1^2;//位定义反转键
sbit jiasujian=P1^3;//位定义加速键
sbit jiansujian=P1^4;//位定义减速键
sbit zhengzhuan=P2^0;//正转端口
sbit fanzhuan=P2^1;//反转端口
sbit zhuansuled=P2^2;//位定义转速指示灯 
sbit qitingled=P3^0;//位定义启停指示灯
sbit zhengzhuangled=P3^1;//位定义正转指示灯
sbit waibuzhongduanling=P3^2;//位定义外部中断0端口
sbit fanzhuangled=P3^3;//位定义反转指示灯
uint qian,bai,shi,ge,zhuansu;//数码管千位变量、百位变量、十位变量、个位变量以及转速变量
uint pwmshi,pwmge;//脉冲宽度调制十位变量、个位变量		  			   
uchar pwm,Timer0count,Timer1count,maichongcount,qitingnum,zhengzhuanflag,fanzhuanflag;//脉冲宽度调制变量、定时器0定时计数变量、定时器1定时计数变量、脉冲计数变量、启停键按下数次变量、正转标志位变量、反转标志位变量
uchar code table0[]={'z','h','a','n','k','o','n','g','b','i',':'};//占空比字符串数组
uchar code table1[]={'z','h','u','a','n','s','u',':'};//转速字符串数组 
uchar code table2[]={'r','p','m'};//每分钟圈字符串数组   
  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字符型液晶显示器写指令操作低电平
   P0=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字符型液晶显示器写数据操作低电平
   P0=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 LCD1602InitDisplay()//LCD1602初始化显示函数
{
   uchar j;
   WriteCommand(0x80+0x00);//LCD1602字符型液晶显示器第一行第一个位置显示
   for(j=0;j<11;j++)//有10个字符,要循环10次。
  {
    WriteData(table0[j]);////显示占空比字符串
    Delay(2);
   }
   WriteCommand(0x80+0x40);//LCD1602字符型液晶显示器第二行第一个位置显示
   for(j=0;j<8;j++)//有8个字符,要循环8次。
  { 
    WriteData(table1[j]);//显示转速字符串
    Delay(2);
   }
   WriteCommand(0x80+0x4c);//LCD1602字符型液晶显示器第二行第十三个位置显示
   for(j=0;j<3;j++)//有8个字符,要循环8次。
  { 
    WriteData(table2[j]);//显示每分钟圈字符串
    Delay(2);
   }
 }
  void LCD1602DisplaySpeed(uint qian,bai,shi,ge)//LCD1602显示四位数速度分解函数
{
   LCD1602InitDisplay();//LCD1602初始化显示函数
   WriteCommand(0x80+0x0b);//LCD1602第一行第十二位显示位
   WriteData(pwmshi+0x30);//0x30表示字符库的数字0,整个代码表示十位可显示0到9的数字。
   WriteData(pwmge+0x30);//0x30表示字符库的数字0,整个代码表示十位可显示0到9的数字。
   WriteCommand(0x80+0x48);//LCD1602第二行第九位显示位
   WriteData(qian+0x30);//0x30表示字符库的数字0,整个代码表示千位可显示0到9的数字。
   WriteData(bai+0x30);//0x30表示字符库的数字0,整个代码表示百位可显示0到9的数字。
   WriteData(shi+0x30);//0x30表示字符库的数字0,整个代码表示十位可显示0到9的数字。
   WriteData(ge+0x30);//0x30表示字符库的数字0,整个代码表示个位可显示0到9的数字。
 }
  void TimerInit()//定时器初始化函数
{
   TMOD=0x11;//设定定时器类型为定时器0和定时器1,工作模式都为模式1。
   TH0=(65536-10000)/256;//TH0重装初值为65536-10000=55536,即定时1000微妙,相当于10毫秒。
   TL0=(65536-10000)%256;//TL0重装初值为65536-10000=55536
   TH1=(65536-50000)/256;//TH1重装初值为65536-10000=55536,即定时50000微妙,相当于50毫秒。
   TL1=(65536-50000)%256;//TL1重装初值为65536-10000=55536
   EA=1;//全局中断允许
   EX0=1;//开外部中断0允许
   IT0=1;//设置外部中断0下降触发中断
   ET0=1;//打开定时器0中断允许
   TR0=1;//开定时器0       
   ET1=1;//打开定时器1中断允许
   TR1=1;//开定时器1
 }
//  void Timer0Init()//定时器0初始化函数
//{
//   TMOD=0x01;//设定定时器0工作模式为模式1
//   TH0=(65536-10000)/256;//TH0装初值
//   TL0=(65536-10000)%256;//TL0装初值
//   EA=1;//开启总中断
//   ET0=1;//开启定时器0中断开关
//   TR0=1;//启动定时器0
// }
//  void Timer1Init()//定时器0初始化函数
//{
//   TMOD=0x10;//设定定时器1工作模式为模式1
//   TH1=(65536-50000)/256;//TH1装初值
//   TL1=(65536-50000)%256;//TL1装初值
//   EA=1;//开启总中断
//   ET1=1;//开启定时器1中断开关
//   TR1=0;//关定时器1
// }
  void Timer0() interrupt 1//定时器/计数器0中断函数,用来产生PWM。 
{  
   TH0=(65536-10000)/256;//TH0重装初值为65536-10000=55536,即定时10000微妙,相当于10毫秒。
   TL0=(65536-10000)%256;//TL0重装初值为65536-10000=55536
   Timer0count++;//定时器0定时计数变量先赋值再自加 
   if(Timer0count==10)//产生PWM波周期为100ms
  {
    Timer0count=0;//定时器0定时计数变量等于0
   }
   if(qitingnum==1)//判断启停键是否第一次按下
  {     
    if(zhengzhuanflag==1)//判断正转标志位变量是否为1
   {
     if(Timer0count<pwm)//定时器0定时计数变量对比占空比       
    {                               
      zhengzhuan=0;//开正转端口
      fanzhuan=1;//关反转端口
	  zhuansuled=0;//开转速指示灯
     }
     else
    {
      zhengzhuan=1;//关正转端口
	  fanzhuan=1;//关反转端口
      zhuansuled=1;//关转速指示灯
     }   
    }
    if(fanzhuanflag==1)//判断反转标志位变量是否为1
   {
     if(Timer0count<pwm)//定时器0定时计数变量对比占空比       
    {                               
      fanzhuan=0;//开反转端口
	  zhengzhuan=1;//关正转端口
	  zhuansuled=0;//开转速指示灯
     }
     else
    {
   	  fanzhuan=1;//关反转端口
	  zhengzhuan=1;//关正转端口
	  zhuansuled=1;//关转速指示灯
     }   
    }
   }
  }
  void Timer1() interrupt 3//定时器1中断函数,用来显示转速。
{
   TH1=(65536-50000)/256;//TH1重装初值为65536-10000=55536,即定时50000微妙,相当于50毫秒。
   TL1=(65536-50000)%256;//TL1重装初值为65536-10000=55536
   Timer1count++;//定时器1中断次数先赋值再加
   if(Timer1count==20)//判断定时器0中断次数是否为20次,相当于1秒钟。
  {
	Timer1count=0;//定时器1中断次数归零
	EX0=0;//关外部中断0
	zhuansu=55*maichongcount/24;//电机转速=每分钟X脉冲计数变量/每转一圈需要的脉冲个数,即55*maichongcount/24,其中的55表示55秒,为什么不是一分钟60秒?由于Protues仿真电路图中的MOTOR-ENCODER仿真件存在误差,为了让MOTOR-ENCODER仿真件显示的转速达到数码管显示转速的效果,进行了一定秒数的修改,不过实际运用要以一分钟60秒为准,maichongcount为单片机从外部中断0端口处获取MOTOR-ENCODER仿真件旋转生产的脉冲计数变量,24为MOTOR-ENCODER仿真件每旋转一圈产生的脉冲个数。
    qian=zhuansu/1000;//数码管千位显示
	bai=zhuansu%1000/100;//数码管百位显示
    shi=zhuansu%100/10;//数码管十位显示
    ge=zhuansu%10;//数码管个位显示
    LCD1602DisplaySpeed(qian,bai,shi,ge);//LCD1602显示四位数速度分解函数
    maichongcount=0;//脉冲计数变量归零
    EX0=1;//开外部中断0
   }
  }
  void waibuzhongduanlingjishu() interrupt 0  using 1//外部中断0计数函数,用来计数外部脉冲。
{
   maichongcount++ ;//脉冲计数变量先赋值再自加
  }
  void KeyScan()//按键扫描函数 
{         
   if(qitingjian==0)//判断启停键是否按下
  {
   	Delay(1);//延时
	if(qitingjian==0)//再次判断启停键是否按下
   {
	 Delay(1);//延时
	 while(!qitingjian);//启停键释放
	 qitingnum++;//启停键按下数次变量先赋值再加加
	 qitingled=0;//开启停指示灯
	 if(qitingnum==2)//判断启停键按下数次变量是否为2
	{
	  qitingnum=0;//启停键按下数次变量归零
	  qitingled=1;//关启停指示灯
	  zhengzhuangled=1;//关正转指示灯
	  fanzhuangled=1;//关反转指示灯
	  zhuansuled=1;//关转速指示灯
	  zhengzhuan=1;//关正转端口
	  fanzhuan=1;//关反转端口
	  zhengzhuanflag=0;//正转标志位变量为0
	  fanzhuanflag=0;//反转标志位变量为0
	 }
	}
   }
   if(qitingnum==1)//判断启停键是否第一次按下
  {
  	if(zhengzhuanjian==0)//判断是否按下正转键
   {
   	 Delay(1);//延时
	 if(zhengzhuanjian==0)//再次判断是否按下正转
	{
	  Delay(1);//延时
	  while(!zhengzhuanjian)//正转键释放
      zhengzhuangled=0;//开正转指示灯
	  fanzhuangled=1;//关反转指示灯
	  zhengzhuanflag=1;//正转标志位变量为1
	  fanzhuanflag=0;//反转标志位变量为0
	 }
    }
  	if(fanzhuanjian==0)//判断是否按下反转键
   {
   	 Delay(1);//延时
	 if(fanzhuanjian==0)//再次判断是否按下反转键
	{
	  Delay(1);//延时
	  while(!fanzhuanjian)//反转键释放
	  zhengzhuangled=1;//关正转指示灯
	  fanzhuangled=0;//开反转指示灯
	  zhengzhuanflag=0;//正转标志位变量为0
	  fanzhuanflag=1;//反转标志位变量为1
	 }
    }
   }
   if(zhengzhuanflag==1||fanzhuanflag==1)//判断电机是否为正转或反转
  {
  	if(jiasujian==0)//判断是否按下加速键
   {
   	 Delay(1);//延时
	 if(jiasujian==0)//再次判断是否按下加速键
	{
	  Delay(1);//延时
	  while(!jiasujian);//加速键释放
	  if(pwm<10)//判断脉冲宽度调制变量是否小于10
	 {
	   pwm++;//脉冲宽度调制变量先赋值再加加
	   pwmshi=pwm/10;
	   pwmge=pwm%10;
	  }
	  if(pwm>=10)//判断脉冲宽度调制变量是否大于等于10
	  pwm=10;//脉冲宽度调制变量等于9     
	 }
    }
	if(jiansujian==0)//判断是否按下减速键
   {
   	 Delay(1);//延时
	 if(jiansujian==0)//再次判断是否按下减键
	{
	  Delay(1);//延时
	  while(!jiansujian);//减速键释放
   	  if(pwm>0)//判断脉冲宽度调制变量是否大于0
	 {    
       pwm--;//脉冲宽度调制变量先赋值再减减
	   pwmshi=pwm/10;
	   pwmge=pwm%10;
	  }  
	  if(pwm<=0)//判断脉冲宽度调制变量是否小于等于0
	  pwm=0;//脉冲宽度调制变量等于0 
	 }
    }
   }
  }	    	     
  void main()//主函数
{
//   Timer0Init();//定时器0初始化函数
//   Timer1Init();//定时器1初始化函数
   TimerInit();
   LCD1602Init();//LCD1602初始化函数
   while(1)//
 {
    KeyScan();//键盘扫描函数     
  }
 }  

三、基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目Proteus软件仿真单片机外围电路

在这里插入图片描述

四、基于51单片机脉冲宽度调制(即PWM)直流电机转速快慢以及霍尔测速的项目的操作功能描述

(1)、不修改时分秒个位十位数值,只是启动或停止计时的情况:如果第一次按下移位键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。如果第一次按下启停键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。

(2)、修改时分秒个位十位数值,再启动或停止计时的情况:要修改时分秒个位十位上的数值,再启动或停止计时,首先必须按下移位键,此时停止计时,通过点击移位键让LCD1602字符型液晶显示器光标移到时分秒相应个位十位数值上,利用点击增加键或减少键修改数值,修改完毕后,启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,停止计时可按下移位键或按下启停键,当按下移位键时,又可修改时分秒个位十位上的数值,再次启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,周而复始。

2017-08-31 09:56:40 csdn_newyk 阅读数 2021
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

/**************************************************************************************

              
程序功能:在8个数码管上显示时间(24小时制),包含时、分、秒各2位,共6位,时分秒之间
用短横隔开,可以使用按键对各位进行调时校准,被调整的那位所对应的数码管会闪烁,被调整的
位循环方向可以左移也可以右移,调整的数值可加可减。  
***************************************************************************************/


#include "reg52.h"
typedef unsigned int u16;  //对数据类型进行声明定义
typedef unsigned char u8;


#define GPIO_KEY P1


sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;


u8 KeyValue; //用来存放按键扫描读取到的键值


//预设时间各位数值,这里设置23:59:55是为了尽快观察进制变化是否正常
////u8 a=2;     //小时,十位
////u8 b=3;     //小时,个位
////u8 c=5; //分钟,十位
////u8 d=9; //分钟,个位
////u8 e=5; //秒,十位
////u8 f=5; //秒,个位


u16 smgwei[8]={2,3,10,5,9,10,5,5};//8位数码管对应的段码,10在smgduan数组中对应smgduan[10]=0x40,显示到数码管上是中间的一短横


u8 setwei=0; //调整时间各位的位置参数,默认为0,即不调整任何位。
u16 times[8];//循环次数累计,累计指令条数,粗略估算时间,控制被调整位闪烁频率。


u8 code smgduan[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,//数码管段选,显示0~9的值
0x40};//0x40数码管显示是短横


void delay(u16 i)  //延时子函数
{
while(i--);
}




void sub()      //调整时间数值,数值减小
{
switch(setwei)   //先判断调整时间中的哪一位,然后被选中位的数值自减
{ //减法可能越界,所以需要根据不同各位的进制来控制越界
case(1):smgwei[0]--;if(smgwei[0]==-1) smgwei[0]=2;break;
case(2):smgwei[1]--;if(smgwei[0]==0&&smgwei[1]==-1) 
{smgwei[1]=3;smgwei[0]=2;}
else if(smgwei[1]==-1)  
{smgwei[1]=9;smgwei[0]--; }
break;
case(3):;break;
case(4):smgwei[3]--;if(smgwei[3]==-1) {smgwei[3]=5;smgwei[1]--;}break;
case(5):smgwei[4]--;if(smgwei[4]==-1) {smgwei[4]=9;smgwei[3]--;}break;
case(6):;break;
case(7):smgwei[6]--;if(smgwei[6]==-1) {smgwei[6]=5;smgwei[4]--;}break;
case(8):smgwei[7]--;if(smgwei[7]==-1) {smgwei[7]=9;smgwei[6]--;}break;
}
}


void add()      //调整时间数值,数值增大
{
switch(setwei) //和减法类似,也是先判断被选中的位。再修改其值。
{ //不过加法的越界问题在main秒数递增进位过程中处理了
case(1):smgwei[0]++;break;
case(2):smgwei[1]++;break;
case(3):;break;
case(4):smgwei[3]++;break;
case(5):smgwei[4]++;break;
case(6):;break;
case(7):smgwei[6]++;break;
case(8):smgwei[7]++;break;
}
}


//4*4矩阵键盘按键扫描,因为需用到4个按键,所以让每一列的按键控制同一功能
void KEY_Scan()
{
char k=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
delay(1000);//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//测试列
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}


while((k<50)&&(GPIO_KEY!=0x0f)) //按键松手检测
{
delay(10000);
k++;
}


switch(KeyValue)
{ //被调整位的值也需要控制越界
case(0):setwei--;if(setwei==-1)  setwei=8; break;
case(1):setwei++;if(setwei==9) setwei=0;   break;
case(2):sub();break;
case(3):add();break;
}
}
}
}


void Timer0Init()
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}


//数码管动态显示函数
void show()   //修改后数码管显示函数
{
u8 j;
P2|=0x1c;   //8个数码管 ,使用for循环,轮流选通这8个数码管并传送不同的数据给P0
for (j=0;j<8;j++)
{ //同时根据条件,选择数码管常亮或者闪烁
P2+=4;
P0=(setwei==(j+1)&&times[j]>500)?0x00:smgduan[smgwei[j]];
times[j]++; 
if (times[j]>1000) times[j]=0;    
delay(10);P0=0x00;
}
}
// void show()   //修改前的数码管显示子函数
// {
// LSA=0;LSB=0;LSC=0;  
// P0=(setwei==1&&times[0]>500)?0x00:smgduan[a];
// times[0]++; 
// if (times[0]>1000) times[0]=0;    
// delay(10);P0=0x00;
// LSA=1;LSB=0;LSC=0;  
// P0=(setwei==2&&times[1]>500)?0x00:smgduan[b];
// times[1]++; 
// if (times[1]>1000) times[1]=0;
// delay(10);P0=0x00;
// LSA=0;LSB=1;LSC=0;   
// P0=0X40;
// delay(10);P0=0x00;
// LSA=1;LSB=1;LSC=0;  
// P0=(setwei==3&&times[2]>300)?0x00:smgduan[c];
// times[2]++; 
// if (times[2]>600) times[2]=0;
// delay(10);P0=0x00;  
// LSA=0;LSB=0;LSC=1;   
// P0=(setwei==4&&times[3]>300)?0x00:smgduan[d];
// times[3]++; 
// if (times[3]>600) times[3]=0;
// delay(10);P0=0x00;
// LSA=1;LSB=0;LSC=1;  
// P0=0X40;
// delay(10);P0=0x00;
// LSA=0;LSB=1;LSC=1;  
// P0=(setwei==5&&times[4]>100)?0x00:smgduan[e];
// times[4]++; 
// if (times[4]>200) times[4]=0;
// delay(10);P0=0x00;
// LSA=1;LSB=1;LSC=1;  
// P0=(setwei==6&&times[5]>100)?0x00:smgduan[f];
// times[5]++; 
// if (times[5]>200) times[5]=0;
// delay(10);P0=0x00;
// }


void main()
{
Timer0Init();  //定时器0初始化
while(1)
{ KEY_Scan(); //扫描是否有调时按键按下 
//由于秒数自加,需根据进制不同选择判断条件和对应操作
if(smgwei[7]==10) {smgwei[7]=0;smgwei[6]+=1;}
if(smgwei[6]==6) {smgwei[6]=0;smgwei[4]+=1;}
if(smgwei[4]==10) {smgwei[4]=0;smgwei[3]+=1;}
if(smgwei[3]==6) {smgwei[3]=0;smgwei[1]+=1;}
if(smgwei[1]==10) {smgwei[1]=0;smgwei[0]+=1;}
if((smgwei[0]*10+smgwei[1])>=24) {smgwei[0]=0;smgwei[1]=0;} 
show();
}
}


void Timer0() interrupt 1
{
static u16 i;
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
i++;
if(i==1000)
{
i=0;
smgwei[7]++;
}
}

c51时分秒

阅读数 234

没有更多推荐了,返回首页