51单片机万年历

来源:互联网 发布:教育培训网络推广方案 编辑:程序博客网 时间:2024/05/21 07:53


功能:万年历 闹钟 温度采集 

误差:亲测24小时误差小于10s

<pre name="code" class="cpp">/*************************************************** *文件名称:main.c *功能说明:1.主函数运行 *  2.定时器中断0,1运行 *  3.提供系统状态标志变量SysSt *  系统晶振:11.0592MHz *  创建日期:2015.2.20 *软件版本:v1.0 */ #include<reg52.h> #include".\\SCR\\display.h" #include".\\SCR\\keyscan.h" #include".\\SCR\\Time.h" #include".\\SCR\\Temperature.h" #include".\\SCR\\music.h" #include".\\SCR\\hostPC.h" #define uchar unsigned char #define uint unsigned int volatile unsigned char SysSt; //系统状态 unsigned char RecvPC = 0;//接收上位机数据  sbit speaker = P0^4; //蜂鸣器 void IniSys(void);//系统初始化函数 void InitTimer(void);//定时器初始化函数 void DelaySys(void);//系统上电延时函数 void main(void) {IniSys();//系统初始化DelaySys();//上电延时 for( ;; ){    mnKeySer();/* 按键服务函数 */ mnLed_Drive();/* 数码管显示服务函数 */ mnAlarmSer();/* 闹钟服务函数 */MnDS18B20();/* 温度采集函数 */mnRecvPC();     /* 上位机数据处理函数 */  } }/******************* * 系统初始化函数 */ void IniSys(void) {SysSt = 0x00;//初始系统状态30 先显示10s温度    InitTimer();//初始化定时器中断0IniKey();//按键相关初始化InitClock();//时间相关初始化InitDisplay();//数码管显示文件下变量初始化Init18B20();//DS18B20初始化 } /******************** * 定时器初始化函数 */ void InitTimer(void) {TMOD   = 0x11;  //T0,T1方式1T2MOD |= 0x00;//定时器2工作模式寄存器 部分头文件中没有添加 sfr T2MOD  = 0xC9;T2CON  = 0x30; //定时器2控制寄存器SCON   = 0x50;  //串口中断工作模式1RCAP2H = 0xff; //定时器2自动装载的初值RCAP2L = 0xdc;TH0 = 0xEE;  //T0定时器11.0592M 定时5msTL0 = 0x00;TH1 = 0xFC;  //T1定时器11.0592M 定时1ms    TL1 = 0x66;TH2 = 0xff; //定时器2产生9600波特率初值TL2 = 0xdc;    ES  = 1; //打开串口中断ET1 = 1; //定时器1允许   ET0 = 1; //定时器0允许TR0 = 1; //定时器0打开TR1 = 1; //定时器1打开TR2 = 1; //定时器2打开EA  = 1; }/***************** * 定时器0中断 */ void Timer0() interrupt 1 {TH0 = 0xEE; //11.0592M 定时5ms  无误差TL0 = 0x00;flagReLed ++;//数码管显示刷新计时器ptKeyScan();//按键扫描函数ptTemperatureDrive();//温度显示pub_MsClock ++;//作为时钟毫秒基准sgUglyClock();//计时函数(为保证精度) }/********************* * 系统上电延时函数 */ void Timer1(void) interrupt 3//定时器1{    TR1 = 0; speaker = !speaker; TH1 = timer1h; TL1 = timer1l; TR1 = 1;}/**************** * 串口中断 */ void Isr(void) interrupt 4{while (RI){   RI = 0;RecvPC = SBUF;AlarmRing = 0;//接收到数据闹钟响标志位置位SBUF = RecvPC;//将数据返回,做调试用while( !TI );TI = 0;}}/******************** * 系统上电延时函数 */ void DelaySys(void) {unsigned char i,j;for( i=0; i<200; i++ )for( j=0; j<210; j++ ); }
/*************************************************** *文件名称:display.c *功能说明:1.提供日期显示驱动 *  2.提供时间显示驱动 *  3.提供温度显示驱动 *  4.提供闹钟显示驱动 *硬件说明:采用四个八段数码管,段选占用P1口,位选占用P0^4~P0^7 *  系统晶振:11.0592MHz *  创建日期:2015.2.20 *软件版本:v1.0 */ #include".\\SCR\\Time.h" #include".\\SCR\\Temperature.h" #define uchar unsigned char #define uint unsigned int #define PortSeg P1 //段码口 #define PortBit P0 //位码口 #define DATEROL_LEVEL 70 //日期滚动速度  sfr P0 = 0x80; //声明P0口 该声明在<reg51.h> 中也有 sfr P1 = 0x90; //声明P1口 extern volatile uchar SysSt; //系统状态 unsigned char  TempCnt2 = 0; /*日期滚动显示计算中间变量,声明在这里是为了     外部引用,在按键函数中,每一次状态切换需要改变重新从0开始计数 ,避免每一切换到日期显示从原来位置开始滚动    ,而是重新开始滚动 */ volatile unsigned char flagReLed; //数码管显示刷新标志位 unsigned char code SegCode[13] = //段码 /// 0    1    2     3   4    5    6    7    8    9   -  空    度数符号  {0xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xBF,0xff,0x9c}; unsigned char code BitCode[4] =  //位码  {0xFE,0xFD,0xFB,0xF7}; unsigned char DisBuffer[4] = {1,2,3,4}; //显示缓冲区 void InitDisplay(void)          //本文件下变量初始化 {   flagReLed = 0; }/******************************* * 说明:数据送缓冲区函数, * 参数分别对应缓冲器的每一位 */ void DataToBuffer( const unsigned char Data_1, const unsigned char Data_2,const unsigned char Data_3,     const unsigned char Data_4 ) { DisBuffer[0] = Data_1;DisBuffer[1] = Data_2;DisBuffer[2] = Data_3;DisBuffer[3] = Data_4; }/********************* * 闹钟数码管驱动 */ void AlarmLedDrive(void)             // { static unsigned char counter = 0;if( flagReLed>=1 ){//每5ms刷新显示一次,起延时作用PortBit |= 0xff;//关闭显示。消除其它段泛光switch( SysSt ){case 0x20:if( counter==1 )//闹钟时秒间隔长亮            PortSeg = SegCode[DisBuffer[counter]]&0x7f;else if( (counter==3) && (AlarmMark==0) ) //闹钟关闭则最后一位小数点长亮PortSeg = SegCode[DisBuffer[counter]]&0x7f;            else if( (counter==3) && (AlarmMark==1) && ((pub_MsClock%50)<25) ) //闹钟启动最后一位小数点狂闪烁PortSeg = SegCode[DisBuffer[counter]]&0x7f;else if( (counter==3) && (AlarmMark==1) && ((pub_MsClock%50)>=25) )PortSeg = SegCode[DisBuffer[counter]];else PortSeg = SegCode[DisBuffer[counter]];//送段码break;case 0x21:if( counter==1 )//分钟调整闪烁            PortSeg = SegCode[DisBuffer[counter]]&0x7f;            else if( ( (counter==2)||(counter==3) ) && ( pub_MsClock<100 ) )PortSeg = 0xFF;else PortSeg = SegCode[DisBuffer[counter]];//送段码break;case 0x22:if( (counter==1) && !(pub_MsClock<100) )            PortSeg = SegCode[DisBuffer[counter]]&0x7f;else if( (counter==1) && (pub_MsClock<100) )PortSeg = 0x7F;            else if( (counter==0) && ( pub_MsClock<100 ) )PortSeg = 0xFF;else PortSeg = SegCode[DisBuffer[counter]];//送段码break;default : break;}PortBit = BitCode[counter];//送位码  if( ++counter > 3){counter = 0;}    flagReLed = 0;DataToBuffer(AlarmHour/10,AlarmHour%10,AlarmMinute/10,AlarmMinute%10);//时间数据送缓冲区} }/********************* * 日期数码管驱动 */ void DateLedDrive(void) // { static unsigned char counter = 0,TempCnt1 = 0; static unsigned char dataTempbuf[14] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13};//同时存储年月日和分割线if( flagReLed>=1 ){//每5ms刷新显示一次,起延时作用PortBit |= 0xff;//关闭显示。消除其它段泛光PortSeg = SegCode[DisBuffer[counter]];PortBit = BitCode[counter];//送位码if( ++counter > 3){counter = 0;}    flagReLed = 0; //数码管刷新dataTempbuf[0] = 11;//11参数数码管不显示dataTempbuf[1] = 11;dataTempbuf[2] = 11;dataTempbuf[3] = 11;dataTempbuf[4] = pub_TimeObj.YearH/10;dataTempbuf[5] = pub_TimeObj.YearH%10;dataTempbuf[6] = pub_TimeObj.YearL/10;dataTempbuf[7] = pub_TimeObj.YearL%10;dataTempbuf[8] = 10;  //分割线dataTempbuf[9] = pub_TimeObj.Month/10;dataTempbuf[10] = pub_TimeObj.Month%10;dataTempbuf[11] = 10;  //分割线dataTempbuf[12] = pub_TimeObj.Day/10;dataTempbuf[13] = pub_TimeObj.Day%10;if( ++TempCnt1>=DATEROL_LEVEL ){TempCnt1 = 0;if(++TempCnt2>=151)TempCnt2 = 0;}switch( SysSt ){//判断显示状态case 0x10: DataToBuffer(dataTempbuf[TempCnt2%14],dataTempbuf[(TempCnt2+1)%14],dataTempbuf[(TempCnt2+2)%14],dataTempbuf[(TempCnt2+3)%14]);    break;case 0x11: if( pub_MsClock<100 )DataToBuffer( pub_TimeObj.YearH/10,pub_TimeObj.YearH%10,pub_TimeObj.YearL/10,pub_TimeObj.YearL%10 );else DataToBuffer( 11,11,11,11 ) ;//闪烁中的全不显示break;case 0x12: if( pub_MsClock<100 )DataToBuffer( pub_TimeObj.Month/10,pub_TimeObj.Month%10,10,11 );   else DataToBuffer( 11,11,10,11 );   break;case 0x13: if( pub_MsClock<100 )DataToBuffer( 11,10,pub_TimeObj.Day/10,pub_TimeObj.Day%10 );   else DataToBuffer( 11,10,11,11 );   break;}} }/********************* * 时间显示驱动 */ void TimeLedDrive(void) // { static unsigned char counter = 0;if( flagReLed>=1 ){//每5ms刷新显示一次,起延时作用PortBit |= 0xff;//关闭显示。消除其它段泛光switch( SysSt ){case 0x00:if( (counter==1)&&(pub_MsClock<100) )//秒闪烁            PortSeg = SegCode[DisBuffer[counter]]&0x7f;            else PortSeg = SegCode[DisBuffer[counter]];//送段码break;case 0x01:if( counter==1 )//分钟调整闪烁            PortSeg = SegCode[DisBuffer[counter]]&0x7f;            else if( ( (counter==2)||(counter==3) ) && ( pub_MsClock<100 ) )PortSeg = 0xFF;else PortSeg = SegCode[DisBuffer[counter]];//送段码break;case 0x02:if( (counter==1) && !(pub_MsClock<100) )            PortSeg = SegCode[DisBuffer[counter]]&0x7f;else if( (counter==1) && (pub_MsClock<100) )PortSeg = 0x7F;            else if( (counter==0) && ( pub_MsClock<100 ) )PortSeg = 0xFF;else PortSeg = SegCode[DisBuffer[counter]];//送段码break;default : break;}PortBit = BitCode[counter];//送位码  if( ++counter > 3){counter = 0;}    flagReLed = 0;  DataToBuffer(pub_TimeObj.Hour/10,pub_TimeObj.Hour%10,pub_TimeObj.Minute/10,pub_TimeObj.Minute%10);//时间数据送缓冲区} }/******************************************************** * 由于温度采集耗时间,所以该函数放在ptTemperatureDrive * 函数中由中断服务程序执行 */ void ptTemperatureDrive(void)//温度显示函数 {static unsigned char counter = 0;if( SysSt==0x30 ){PortBit |= 0xff;//关闭显示。消除其它段泛光if( counter==1 )//小数点    PortSeg = SegCode[DisBuffer[counter]]&0x7f;else PortSeg = SegCode[DisBuffer[counter]];//送段码PortBit = BitCode[counter];//送位码  if( ++counter > 3){counter = 0;} DataToBuffer(IntgerM,IntgerL,DecimalH,12);//温度数据送缓冲区} }/********************* * 数码管驱动调度 */ void mnLed_Drive(void) //数码管驱动 { unsigned char SysStH = SysSt & 0xF0;//提取主状态switch( SysStH ){   case 0x00: TimeLedDrive(); break;//时间显示  case 0x10: DateLedDrive(); break;//日期显示  case 0x20: AlarmLedDrive(); break;//闹钟显示  case 0x30: break; //状态3的显示在中断里      default : TimeLedDrive(); break; } }

/*************************************************** *文件名称:display.h */ #ifndef __DISPLAY_H__ #define __DISPLAY_H__ extern unsigned char code SegCode[];//段码定义 extern unsigned char code BitCode[];//位码定义 #define PortSeg P1 //段码口 #define PortBit P0 //位码口 extern volatile unsigned char flagReLed; //数码管显示刷新标志位,位于中断里 extern void InitDisplay(void);//本文件下变量初始化 extern void DataToBuffer( const unsigned char Data_1,    const unsigned char Data_2,   const unsigned char Data_3,    const unsigned char Data_4);//数据送缓冲区函数  extern  void mnLed_Drive(void); //数码管驱动 extern  void ptTemperatureDrive(void);//温度显示函数 #endif //__DISPLAY_H__*/

/*************************************************** *文件名称:keysacn.c *功能说明:1.产生S1按键长,短按 *  2.产生S2按键驱动 *      3.产生S3按键驱动 *硬件说明:S1按键占用P2^7,S2按键占用P2^6,S3按键占用P^5 *  系统晶振:11.0592MHz *  创建日期:2015.2.20 *软件版本:v1.0 */ #include<reg52.h> #include".\\SCR\\Time.h"  #define uchar unsigned char #define uint unsigned int #define S1LONG_LEVEL 160 //S1长按确定时间 #define S1SHORT_LEVEL 22 //S1短按确定时间 #define S_NORMAL_LEVEL 22 //普通按键确定时间 #define BUZZER_LEVEL 80 //每一次按键蜂鸣器响时间 #define SYSST_KEEPTIME 2000 //系统非00状态保持时间,1为5ms秒(估计值) /*  *位定义按键 */ sbit  ioKeyS1 = P2^7; //状态切换键 sbit  ioKeyS2 = P2^6; //向上调整按键 sbit  ioKeyS3 = P2^5; //向下调整按键  sbit  Buzzer  = P0^4;//蜂鸣器 extern volatile uchar SysSt; //系统状态 extern unsigned char  TempCnt2; volatile unsigned char S1Long = 0, //S1长按确定标志位            S1Short = 0;//S1短按确定标志位 volatile unsigned int KeyS1Cnt, //按键1计数器                       KeyS2Cnt, //按键2计数器                       KeyS3Cnt; //按键3计数器  unsigned int SysStKeepTimeCnt = 0;//系统状态保持计数器/****************************** * 长时间无操作系统状态切换为00 */ void SysKeepTime(void) { if( (ioKeyS1!=0) && (ioKeyS2!=0) && (ioKeyS3!=0) ){//判断有无按键操作 if( SysSt!=0x00 ){if( ++SysStKeepTimeCnt>=SYSST_KEEPTIME ){SysStKeepTimeCnt = 0;SysSt = 0x00;}}}else SysStKeepTimeCnt = 0; }/********************************** * 按键扫描函数,由定时器中断0调用 */ void ptKeyScan(void) { static BuzzerCnt = 0;//蜂鸣器延时计数器    static uchar S1Pass = 0;/* * 按键上一刻是否按下标志位,防止连续触发      * 如果连续按下不管按多长时间长按都只可能发生一次 * 该变量在按键按下后置位,松开后清零 */ if( ioKeyS1==0 ){if( S1Pass==0 )KeyS1Cnt ++; //防抖计数器if( KeyS1Cnt>=S1LONG_LEVEL ){  //判断是否达到长按时间S1Long = 1;KeyS1Cnt = 0;S1Pass = 1; //达到长按时间后连续按标志位置位,防止一直处罚长按}}else {S1Pass = 0;  //连续按标志位清零if( KeyS1Cnt>S1SHORT_LEVEL ){S1Short = 1;KeyS1Cnt = 0;}}if( ioKeyS2==0 ){  //S2计数器KeyS2Cnt ++;//防抖计数器}if( ioKeyS3==0 ){ //S3计数器KeyS3Cnt ++; //防抖计数器 }/* * 按键响 */if( (ioKeyS1==0) || (ioKeyS2==0) || (ioKeyS3==0) ){BuzzerCnt ++;if( BuzzerCnt<BUZZER_LEVEL ){Buzzer = 0;}else  Buzzer = 1;}else BuzzerCnt = 0;SysKeepTime();//无操作状态切回函数 }/******************* * S1长按服务函数 * 从状态切换 */ void S1LongSer(void) { switch( SysSt ){case 0x00 : SysSt = 0x01;break;case 0x01 : SysSt = 0x02;break;case 0x02 : SysSt = 0x00;break;case 0x10 : SysSt = 0x11;break;case 0x11 : SysSt = 0x12;break;case 0x12 : SysSt = 0x13;break;case 0x13 : SysSt = 0x10;TempCnt2 = 0;//日期滚动重新开始,而不从原来位置开始break;case 0x20 : SysSt = 0x21;break;case 0x21 : SysSt = 0x22;break;case 0x22 : SysSt = 0x20;break;case 0x30 : break; //温度显示状态default : SysSt = 0x00; break;} }/***************** * S1短按服务函数 * 主状态切换 */ void S1ShortSer(void) {  switch( SysSt ){ //状态切换  case 0x00: SysSt = 0x10;TempCnt2 = 0;//日期滚动重新开始,而不从原来位置开始   break;  case 0x01: SysSt = 0x00; break;  case 0x02: SysSt = 0x00; break;  case 0x10: SysSt = 0x20; break;  case 0x11: SysSt = 0x10; TempCnt2 = 0;//日期滚动重新开始,而不从原来位置开始   break;  case 0x12: SysSt = 0x10; TempCnt2 = 0;//日期滚动重新开始,而不从原来位置开始   break;  case 0x13: SysSt = 0x10; TempCnt2 = 0;//日期滚动重新开始,而不从原来位置开始    break;  case 0x20: SysSt = 0x30; break;  case 0x21: SysSt = 0x20; break;    case 0x22: SysSt = 0x20; break;  case 0x30: SysSt = 0x00; break;    default : SysSt = 0x00; break; } }/******************* * S2按键服务函数 * 向上调节数据 */ void S2Ser(void) { switch(SysSt){case 0x01:if( ++pub_TimeObj.Minute>=60 )pub_TimeObj.Minute = 0;  AlarmRing = 1;//允许闹钟响标志位置位  break;case 0x02:if( ++pub_TimeObj.Hour>=24 )pub_TimeObj.Hour = 0;  AlarmRing = 1;//允许闹钟响标志位置位  break;case 0x11:if( ++pub_TimeObj.YearL>=100 ){pub_TimeObj.YearL = 0;pub_TimeObj.YearH++;}JudLeapYear( pub_TimeObj.YearH,pub_TimeObj.YearL );//调整完年需要计算一次平润年if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==0) &&(pub_TimeObj.Day>28))  pub_TimeObj.Day = 28;//防止在原来闰年2月29或其它月份天数大于29的情况下发生调整错误  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==1) &&(pub_TimeObj.Day>29))  pub_TimeObj.Day = 29;//防止在原来其它月份天数大于29的情况下发生调整错误break;case 0x12:if( ++pub_TimeObj.Month>=13 )pub_TimeObj.Month = 1;  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==0) &&(pub_TimeObj.Day>28))  pub_TimeObj.Day = 28;//防止在原来闰年2月29或其它月份天数大于29的情况下发生调整错误  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==1) &&(pub_TimeObj.Day>29))  pub_TimeObj.Day = 29;//防止在原来其它月份天数大于29的情况下发生调整错误  break;case 0x13:if( (++pub_TimeObj.Day) >= (JudMouth(pub_TimeObj.Month)+1) ){pub_TimeObj.Day = 1;}break;case 0x20:AlarmMark = 1;//闹钟开break;case 0x21:if( ++AlarmMinute>=60 )//闹钟分向上调整AlarmMinute = 0;break;case 0x22:if( ++AlarmHour>=24 ) //闹钟时向上调整AlarmHour = 0;break;default: break;} }/****************** * S3按键服务函数 * 向下调节数据 */ void S3Ser(void) { switch(SysSt){case 0x01:if( (pub_TimeObj.Minute--)==0 )pub_TimeObj.Minute = 59;  AlarmRing = 1;//允许闹钟响标志位置位  break;case 0x02:if( (pub_TimeObj.Hour--)==0 )pub_TimeObj.Hour = 23;  AlarmRing = 1;//允许闹钟响标志位置位  break;case 0x11:if( (pub_TimeObj.YearL--)==0 ){pub_TimeObj.YearL = 99;pub_TimeObj.YearH--;}JudLeapYear( pub_TimeObj.YearH,pub_TimeObj.YearL );//调整完年需要计算一次平润年  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==0) &&(pub_TimeObj.Day>28))  pub_TimeObj.Day = 28;//防止在原来闰年2月29或其它月份天数大于29的情况下发生调整错误  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==1) &&(pub_TimeObj.Day>29))  pub_TimeObj.Day = 29;//防止在原来其它月份天数大于29的情况下发生调整错误break;case 0x12:if( (pub_TimeObj.Month--)==1 )pub_TimeObj.Month = 12;  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==0) &&(pub_TimeObj.Day>28))  pub_TimeObj.Day = 28;//防止在原来闰年2月29或其它月份天数大于29的情况下发生调整错误  if( (pub_TimeObj.Month==2) && (pub_TimeObj.LeapYear==1) &&(pub_TimeObj.Day>29))  pub_TimeObj.Day = 29;//防止在原来其它月份天数大于29的情况下发生调整错误break;case 0x13:if( (pub_TimeObj.Day--)==1 ){pub_TimeObj.Day = JudMouth(pub_TimeObj.Month);}break;case 0x20:AlarmMark = 0;//闹钟关break;case 0x21:if( (AlarmMinute--)==0 ) //闹钟分向下调整AlarmMinute = 59;break;case 0x22:if( (AlarmHour--)==0 ) //闹钟时向下调整AlarmHour = 23;break;default: break;} }/***************** * 按键S1服务函数 */ void keyserS1Ser(void) { if( S1Long==1 ){//如果长按确定标志位置位则S1发生长按事件S1Long = 0;//标志位清零 /* * s1长按服务函数  */CloseAlarming();//如果闹钟正在响 ,则关闭S1LongSer(); }else if ( S1Short==1 ){//如果短按确定标志位置位则S1发生长按事件     S1Short = 0;//标志位清零/*   * s1短按服务 */CloseAlarming();//如果闹钟正在响 ,则关闭S1ShortSer(); } }/***************** * 按键S2服务函数 */ void keyserS2Ser(void) {  if( KeyS2Cnt>=S_NORMAL_LEVEL ){//防抖时间  KeyS2Cnt = 0;/* * s2服务函数  */ CloseAlarming();//如果闹钟正在响 ,则关闭 S2Ser(); } }/***************** * 按键S3服务函数 */ void keyserS3Ser(void) {  if( KeyS3Cnt>=S_NORMAL_LEVEL ){ //防抖  KeyS3Cnt = 0;/* *  s3服务函数   */CloseAlarming();//如果闹钟正在响 ,则关闭 S3Ser(); } }/******************* * 初始化 */ void IniKey(void) { ioKeyS1 = 1;  // 按键初始化ioKeyS2 = 1;ioKeyS3 = 1;    KeyS1Cnt = 0;    KeyS2Cnt = 0;    KeyS3Cnt = 0;Buzzer = 1;//蜂鸣器初始化 } /***************** * 按键服务函数 */ void mnKeySer(void) {  keyserS1Ser();//按键s1判断服务函数 keyserS2Ser();//按键s2判断服务函数 keyserS3Ser();//按键s3判断服务函数 }

 /*************************** * 文件名称:keysacn.h * 说明:pt前缀函数由定时器中断调用 *mn前缀函数由主函数调用 */ #ifndef __KEYSCAN_H__ #define __KEYSCAN_H__ extern volatile unsigned int KeyS1Cnt; //按键1计数器 extern volatile unsigned int KeyS2Cnt; //按键2计数器 extern volatile unsigned int KeyS3Cnt; //按键3计数器 extern void ptKeyScan(void);  //按键扫描函数 extern void IniKey(void) ;    //按键相关初始化 extern void mnKeySer(void);   //按键服务函数 extern void S1LongSer(void);  //调整状态切换服务函数 extern void S1ShortSer(void); //显示状态切换服务函数 extern void S2Ser(void);      //向上调节函数 extern void S3Ser(void);      //向下调节函数 #endif //__KEYSCAN_H__*/

/*************************************************** *文件名称:Time.c *功能说明:1.提供系统年,月,日,时,分,秒,计时 *  2.提供系统闹钟 *硬件说明:以中断5ms提供时间基准 *  系统晶振:11.0592MHz *  创建日期:2015.2.20 *软件版本:v1.0 */  #include".\\SCR\\music.h" #include<reg51.h>  /********************************* * 说明:type前缀为声明的新类型 * */ typedef struct TimeBox{ unsigned char Hour,  Minute,  Sec;unsigned char YearL,//年低位  YearH;// 年高位unsigned char Month,  Day;unsigned char LeapYear;//润年标志位 1为闰年,0为平年 }type_TimeBox; volatile unsigned int pub_MsClock; //时钟毫秒元变量 type_TimeBox pub_TimeObj;//定义一个时间类型变量 unsigned char AlarmHour; //闹钟时 unsigned char AlarmMinute;//闹钟分 unsigned char AlarmMark;//闹钟启动标志位,值为1时启动/*  *允许闹钟响是用来在闹钟响的时候任意按键关闭闹钟响  */ unsigned char  AlarmRing;  //闹钟响标志位,1表示允许闹钟响 unsigned char  Alarming; //闹钟正在响标志位 1位闹钟正在响  sbit  Buzzer = P0^4;//蜂鸣器/*********************** * 判断是否闰年, *  */ void JudLeapYear( const unsigned char YearH,const unsigned char YearL ) { unsigned int Year;Year = YearH*100 + YearL; if( ( ( (Year%4)==0 )&& (Year%100!=0) ) || ((Year%400)==0) )   pub_TimeObj.LeapYear = 1; //闰年置1else pub_TimeObj.LeapYear = 0; //平年置0 }/********************* * 判断月份的天数 */ unsigned char JudMouth( const unsigned char Month ) {   JudLeapYear( pub_TimeObj.YearH,pub_TimeObj.YearL );//重载判断一次润平年   switch( Month ){       case 1  : return 31;  case 3  : return 31;  case 5  : return 31;  case 7  : return 31;  case 8  : return 31;  case 10 : return 31;  case 12 : return 31;  case 4  : return 30;  case 6  : return 30;  case 9  : return 30;  case 11 : return 30;  case 2 : if( pub_TimeObj.LeapYear==1 )  return 29;//   else return 28;// default : return 0;   } }/******************** * 计时函数 */ void sgUglyClock(void) { static unsigned  int CorrectCnt = 0; //秒基校准参考计时器  if( pub_MsClock>=200 ){ //一秒到pub_MsClock = 0;//ms标志位清零if( (++CorrectCnt)>=122 ){//校准变量达到122秒基加1   一天误差小于10sCorrectCnt = 0;pub_TimeObj.Sec ++; }if( (++pub_TimeObj.Sec) >= 60 ){ //秒变量加1pub_TimeObj.Sec = 0;//秒变量清零AlarmRing = 1;//允许闹钟响标志位置位if( (++pub_TimeObj.Minute) >= 60 ){//分变量加1pub_TimeObj.Minute = 0;//分变量清零if( (++pub_TimeObj.Hour) >= 24 ){//时变量加1pub_TimeObj.Hour = 0;//时变量清零/* * 根据月份判断天数增加的最大值 */if( (++pub_TimeObj.Day) >= (JudMouth(pub_TimeObj.Month)+1) ){pub_TimeObj.Day = 0;if( (++pub_TimeObj.Month)>=13 ){//月份增加pub_TimeObj.Month = 0;if( (++pub_TimeObj.YearL)>=100 ){pub_TimeObj.YearL = 0;pub_TimeObj.YearH ++; JudLeapYear( pub_TimeObj.YearH,pub_TimeObj.YearL );//判断一次润平年}}}    }}}} }/******************** * 时间相关初始化函数 */ void InitClock(void)//colock 文件内变量初始化 {pub_TimeObj.Hour = 11;//时pub_TimeObj.Minute =39; //分pub_TimeObj.Sec = 0;   //秒pub_TimeObj.YearH = 20; //年高位pub_TimeObj.YearL = 4; //年高位pub_TimeObj.Month = 1; //月pub_TimeObj.Day = 24;  //日pub_TimeObj.LeapYear = 0; //润年标志位 1为闰年,0为平年AlarmHour = 11; //闹钟时    AlarmMinute = 40;//闹钟分    AlarmMark = 1;//闹钟启动标志位,值为1时启动AlarmRing = 1; //允许闹钟响Alarming = 0; //闹钟没在响pub_MsClock = 0;JudLeapYear( pub_TimeObj.YearH,pub_TimeObj.YearL );//初始化计算平润年 }/******************** * 闹钟服务函数 */ void mnAlarmSer(void) { ///// 允许闹钟响 ////////// 闹钟开启 ////////////// 时匹配 ///////////////////////////// 分匹配 /////////// if( (AlarmRing==1) && (AlarmMark==1) && (pub_TimeObj.Hour==AlarmHour) && (pub_TimeObj.Minute==AlarmMinute) ){ /*   * 闹钟处理服务函数     */ TR1 = 1;singMusic();Alarming = 1; //闹钟正在响}else {TR1 = 0;Alarming = 0;//闹钟没在响} } void CloseAlarming(void) {   if( Alarming==1 )//闹钟正在响  AlarmRing = 0;//关闭闹钟允许响标志位 }

#ifndef __TIME_H__/*************************************************** *文件名称:Time.h */ #define __TIME_H__//#pragma once //////////////// 时间类型结构体外部声明 ///////////////////// extern struct TimeBox  { unsigned char Hour,  Minute,  Sec;unsigned char YearL,//年低位  YearH;// 年高位unsigned char Month,  Day;unsigned char LeapYear;//闰年标志位 }; typedef struct TimeBox type_TimeBox;/////////////////////////////////////////////////////////// extern type_TimeBox pub_TimeObj; //时间类型变量外部声明 extern volatile unsigned int pub_MsClock;//每毫秒+1变量 extern void InitClock(void);//clock文件初始化 extern void sgUglyClock(void);//计时函数 extern unsigned char JudMouth( const unsigned char Month );//判断对应月份的天数 extern void JudLeapYear( const unsigned char YearH,const unsigned char YearL );//判断平润年 extern void mnAlarmSer(void);//闹钟服务函数 extern void CloseAlarming(void);//关闭正在响的闹钟 extern unsigned char AlarmHour; //闹钟时 extern unsigned char AlarmMinute;//闹钟分 extern unsigned char AlarmMark;//闹钟启动标志位,值为1时启动 extern unsigned char AlarmRing;    //闹钟允许响标志位,该标志位用来闹钟响时任意按键停止闹钟响 extern unsigned char Alarming; //闹钟正在响标志位 1位闹钟正在响#endif //__TIME__

//文件名称:(FILE7)DS18B20驱动文件//功能说明:读出温度数据,并转换为BCD码。//本驱动只针对单总线上挂一只DS18B20的情况。//硬件描述:数据口P3^4,上拉4.7K电阻,未采用寄生电源供电//使用晶体:12M晶体//创建日期:2009-03-03//软件版本:v 1.0     //================================================================== #include".\\SCR\\display.h" #include <reg51.h> #include <intrins.h>  #define uchar unsigned char #define uint  unsigned int//=====================常量========================================= #defineSkipROM0xcc//跳过ROM指令 #defineTempCvt0x44//温度转化命令 #defineReadTemp0xbe//读温度命令 sbitDQ18B20 =  P3^3;//数据口//=====================变量========================================= uintdataTempReg;//温度值 bitbdataNPflag;//正负标志 uchardataIntgerH;//BCD码表示 uchardataIntgerM; uchardataIntgerL; uchardataDecimalH; uchardataDecimalMH; uchardataDecimalML; uchardataDecimalL; extern volatile uchar SysSt; //系统状态//小数部分转换表 uintcodeTempTab[] = { 0x0000,0x0625,0x1250,0x1875,   0x2500,0x3125,0x3750,0x4375,   0x5000,0x5625,0x6250,0x6875,   0x7500,0x8125,0x8750,0x9375};//==================================================================//函 数 名: _nNOP_()//功能描述: 短延时函数//输入参数: i//输出参数:无//设 计 者://创建日期:2009-03-03//================================================================== void_nNOP_(uint i) {for(;i>0;i--){_nop_();} }//==================================================================//函 数 名: Init18B20()//功能描述: 18B20初始化函数//输入参数: 无//输出参数:Init18B20()//设 计 者://创建日期:2009-03-03//================================================================== bitInit18B20(void) {DQ18B20 = 0;//数据线拉低EA = 0; //关中断,防止中断服务程序打乱操作DS18B20的时序_nNOP_(80);//延时480usDQ18B20 = 1;//数据线拉高_nNOP_(7);//延时25usEA = 1;if(DQ18B20==1){DQ18B20 = 1;//数据线拉高return(0);//初始化失败返回0}else{EA = 0;_nNOP_(240);//延时240usEA = 1;DQ18B20 = 1;//数据线拉高return(1);//初始化成功返回1}EA = 1;  //开中断 }//==================================================================//函 数 名: Write18B20()//功能描述: 18B20写数据函数//输入参数: Data//输出参数:无//设 计 者://创建日期:2009-03-03//================================================================== voidWrite18B20(ucharData) {uchardatai;EA = 0;    for (i=8; i>0; i--)   {  DQ18B20 = 0;     DQ18B20 = Data&0x01;      EA = 0;//关中断     _nNOP_(10);    // EA = 1; //开中断     DQ18B20 = 1;     Data>>=1;   }    EA = 1; }//==================================================================//函 数 名: Read18B20()//功能描述: 读18B20两字节数据函数//输入参数: 无//输出参数:TempReg[]//设 计 者://创建日期:2009-03-03//================================================================== ucharRead18B20(void) {uchardata i=0;uchardata Data = 0;EA = 0;//关中断for (i=8;i>0;i--){   DQ18B20 = 0; //给脉冲信号    Data>>=1;    DQ18B20 = 1; //给脉冲信号    if(DQ18B20)    Data|=0x80;    EA = 0;//关中断     _nNOP_(10);     //EA = 1; //开中断}EA = 1; //开中断   return(Data); }//==================================================================//函 数 名: GetTemp()//功能描述: 得到温度数据函数//输入参数: 无//输出参数://设 计 者://创建日期:2009-03-03//================================================================== voidGetTemp(void) {uchar dataTempL,TempH;if(Init18B20()==0);//初始化不成功则继续初始化Write18B20(SkipROM );//发出跳过ROM指令Write18B20(TempCvt );//发出温度转化命令EA = 0;_nNOP_(80);//延时800usEA = 1;if(Init18B20()==0);//初始化不成功则继续初始化Write18B20(SkipROM );//发出跳过ROM指令Write18B20( ReadTemp);//发出读温度命令TempL = Read18B20();//调用读程序,读出两字节TempH = Read18B20();TempReg = TempH;TempReg = TempReg<<8;TempReg = TempReg|TempL;if((TempReg&0x800)!=0x800)NPflag = 0;//正温度else{TempReg = ~TempReg+1;//负温度NPflag = 1;} }//==================================================================//函 数 名: DataCovt()//功能描述: 将读出的温度数据拆分为整数和小数部分,并转为ASIC码//输入参数: 无//输出参数://设 计 者://创建日期:2009-03-03//================================================================== voidDataCovt(void)//11位有效位 {uchar dataRwk1,Rwk2;uint  dataRwk3;Rwk1 = (TempReg&0x07f0)>>4;//  ssss,s|xxx,xxxx,|xxxxRwk2 = TempReg&0x000f;//  符号位| 整数    | 小数  (整数部分-55--125,为7位)IntgerH = Rwk1/100;//整数部分IntgerM = Rwk1%100/10;IntgerL = Rwk1%10;Rwk3 = TempTab[Rwk2];DecimalL  = Rwk3&0x000f;//小数部分DecimalML = (Rwk3&0x00f0)>>4;DecimalMH = (Rwk3&0x0f00)>>8;DecimalH  = (Rwk3&0xf000)>>12; }//==================================================================//函 数 名: MnDS18B20()//功能描述: DS18B20驱动函数//输入参数: 无//输出参数:无//设 计 者://创建日期:2009-03-03//================================================================== void    MnDS18B20(void) {    static unsigned int hCnt = 0;//采集周期计数器    static unsigned char initFlag = 0;        if( hCnt>=6000 )    {        hCnt = 0;        if( SysSt==0x30 )        {            if( initFlag==0 )            {                Init18B20();                        //初始化                initFlag = 1;            }            GetTemp();                            //温度采集            DataCovt();                            //采集值变换为BCD码        }else initFlag = 0;    }else hCnt ++; }

/*************************************************** *文件名称:Temperature.h */ #ifndef __TEMPERATURE_H__ #define __TEMPERATURE_H__//=======================变量定义================================== externunsigned chardataIntgerM; externunsigned chardataIntgerL; externunsigned chardataDecimalH; externunsigned chardataDecimalMH;//=======================调用函数=================================== extern  bit Init18B20(void);//初始化 extern  voidMnDS18B20(void); #endif //__TEMPERATURE__

/*************************************************** *文件名称:music.c *功能说明:播放世上只有妈妈好音乐,音乐可以根据音符更改,更改时注意调整系统音符长度 *硬件说明:蜂鸣器占用P0^4,实际上音乐播放由定时器中断完成,本系统音乐播放由定时器中断1完成  *  系统晶振:11.0592MHz *  创建日期:2015.2.20 *软件版本:v1.0 */ #include <reg51.h> #include".\\SCR\\Time.h" #define musicSpeed 800 //音乐播放速度 #define musicLong  100  //音乐长度 unsigned char timer1h = 0, //定时器初值高位  timer1l = 0, //定时器初值低位  通过改变定时器初值来调整音阶  time = 0;  //音乐播放速度计时        //世上只有妈妈好数据表 code unsigned char sszymmh[]={        6,2,3,      5,2,1,      3,2,2, 5,2,2, 1,3,2, 6,2,1, 5,2,1,                                      6,2,4,      3,2,2,      5,2,1, 6,2,1, 5,2,2, 3,2,2, 1,2,1,                                      6,1,1,      5,2,1,      3,2,1, 2,2,4, 2,2,3, 3,2,1, 5,2,2,                                      5,2,1,      6,2,1,      3,2,2, 2,2,2, 1,2,4, 5,2,3, 3,2,1,                                      2,2,1,      1,2,1,      6,1,1, 1,2,1, 5,1,6, 0,0,0                                       };       // 音阶频率表 高八位 code unsigned char FREQH[]={                                0xF2,0xF3,0xF5,0xF5,0xF6,0xF7,0xF8,                                 0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,0xFC, //1,2,3,4,5,6,7,8,i                                0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,                                0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF,                               } ;         // 音阶频率表 低八位 code unsigned char FREQL[]={                                 0x42,0xC1,0x17,0xB6,0xD0,0xD1,0xB6,                                 0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,0x8F, //1,2,3,4,5,6,7,8,i                                 0xEE,0x44, 0x6B,0xB4,0xF4,0x2D,                                  0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16,                                };/******************* * 音乐播放函数 */ void singMusic(void) { static unsigned char k = 0, i = 0; static unsigned long int t = 0;       if( ++t>time*musicSpeed){//根据音节决定延时时间,musicSpeed由调试决定     t = 0;   i=i+3;       if( i>musicLong )        //音乐数组长度 ,唱完从头再来   i = 0;  k=sszymmh[i]+7*sszymmh[i+1]-1;      timer1h=FREQH[k];      timer1l=FREQL[k];      time=sszymmh[i+2];    }                 } 

/*************************************************** *文件名称:music.h */ #ifndef __MUSIC_H__ #define __MUSIC_H__ extern unsigned char timer1h ,   timer1l ,          time; extern  void mnMusic(void);//闹钟响音乐函数 extern  void singMusic(void); #endif //__MUSIC__

/********************************** * 文件名称:hostPC.c * 说明:波特率 9600 */ #include".\\SCR\\keyscan.h" #include".\\SCR\\Time.h" #include<reg52.h> #define BEENTIME 300                    //每次接收到数据蜂鸣器响时间 extern unsigned int SysStKeepTimeCnt;   //系统状态保持计数器 extern unsigned char RecvPC;            //接收上位机数据 sbit speaker = P0^4;                    //蜂鸣器/******************* * 串口数据处理函数 */ void mnRecvPC(void) { static unsigned int beenCnt = 0;     //蜂鸣器响时间计数器 switch( RecvPC ){case 0x31: S1ShortSer();         //显示状态切换   beenCnt = BEENTIME; //接收到数据蜂鸣器响时间   SysStKeepTimeCnt = 0; //阻止系统自动切回00   break;  case 0x32: S1LongSer();   beenCnt = BEENTIME;   SysStKeepTimeCnt = 0; //阻止系统自动切回00   break;                //数据调节状态切换case 0x33: S2Ser();   beenCnt = BEENTIME;   SysStKeepTimeCnt = 0; //阻止系统自动切回00   break;                //向上调节case 0x34: S3Ser();           beenCnt = BEENTIME;   SysStKeepTimeCnt = 0; //阻止系统自动切回00   break;             //向下调节default :  break;}RecvPC = 0;                         //数据接收区清零if ( beenCnt!=0 ){                    //蜂鸣器响延时beenCnt --; speaker = 0;}else speaker = 1; }

/*************************************************** *文件名称:hostPC.h */ #ifndef __HOSTPC_H__ #define __HOSTPC_H__  extern void mnRecvPC(void); #endif //__HOSTPC__



0 0
原创粉丝点击