1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
注:该程序基于普中科技C51 V2.2开发板设计,库函数和硬件资料均来自普中科技,侵删。main.c大部分为原创,如有雷同,纯属巧合。
名称:C51万年历。 硬件:以C51芯片为核心,LCD1602作为显示,DS18B20获取温度信息,按键设置。 软件:可以显示年、月、日、周、时、分、秒以及当前温度。 指标: 自动完成平年闰年判断(体现在2月份的天数变化); 其他不同月份对应的天数不同; 温度显示精度为0.01℃; 四个按键:K1进入设置模式,K2选择设置项,K3增加,K4减少。 硬件原理图:可以参考普中科技资料自行设计最小系统板。 main.c代码: /******************************************************************************* * 实验名称 :万年历 * 实验效果 :LCD1602显示万年历,按K1进入时钟设置,按K2选择设置的年月日周时分秒,按K3选择设置+1,按K4选择设置-1 *******************************************************************************/ #include #include "lcd.h" #include "ds1302.h" #include "temp.h" ***it K1 = P3 ^ 0; //设置/完成设置 ***it K2 = P3 ^ 1; //切换设置位 ***it K3 = P3 ^ 2; //+ ***it K4 = P3 ^ 3; //— void EnterTimeSet(); void ExitTimeSet(); void IncSetTime(); void DecSetTime(); void RefreshSetShow(); void RightShiftTimeSet(); unsigned char KeyScan(); //不支持连按 void KeyAction(); void Delay10ms(void); //误差 0us void LcdDisplay(); void LcdDisplay_temp(int temp); unsigned char flag, year; unsigned char SetPlace = 9; unsigned char keynum = 5; /******************************************************************************* * 函数名 : main * 函数功能 : 主函数 *******************************************************************************/ void main() { LcdInit(); Ds1302Init(); LcdWriteCom(0x8D); //写地址 80表示初始地址 LcdWriteData('A'); LcdWriteData('u'); LcdWriteData('t'); while (1) { keynum = KeyScan(); //按键扫描 //判断平年闰年 if ((2000 + TIME[0]) % 400 == 0) year = 0; else if ((2000 + TIME[0]) % 4 == 0 && (2000 + TIME[0]) % 100 != 0) year = 0; else year = 1; KeyAction(); if (SetPlace == 9) { Ds1302ReadTime(); LcdDisplay(); LcdWriteCom(0x40 + 0x8F); //写地址 80表示初始地址 LcdWriteData('C'); LcdDisplay_temp(Ds18b20ReadTemp()); } } } /******************************************************************************* * 函数名 : LcdDisplay_temp() * 函数功能 : 温度显示函数 *******************************************************************************/ void LcdDisplay_temp(int temp) //lcd显示 { unsigned char datas[] = {0, 0, 0, 0}; //定义数组 float tp; if (temp < 0) //当温度值为负数 { LcdWriteCom(0x40 + 0x89); //写地址 80表示初始地址 LcdWriteData('-'); //显示负 //因为读取的温度是实际温度的补码,所以减1,再取反求出原码 temp = temp - 1; temp = ~temp; tp = temp; temp = tp * 0.0625 * 100 + 0.5; //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算由?.5,还是在小数点后面。 } else { LcdWriteCom(0x40 + 0x89); //写地址 80表示初始地址 LcdWriteData('+'); //显示正 tp = temp; //因为数据处理有小数点所以将温度赋给一个浮点型变量 //如果温度是正的那么,那么正数的原码就是补码它本身 temp = tp * 0.0625 * 100 + 0.5; //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点 //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就 //算加上0.5,还是在小数点后面。 } datas[0] = temp % 10000 / 1000; datas[1] = temp % 1000 / 100; datas[2] = temp % 100 / 10; datas[3] = temp % 10; LcdWriteCom(0x40 + 0x8A); //写地址 80表示初始地址 LcdWriteData('0' + datas[0]); //十位 LcdWriteCom(0x40 + 0x8B); //写地址 80表示初始地址 LcdWriteData('0' + datas[1]); //个位 LcdWriteCom(0x40 + 0x8C); //写地址 80表示初始地址 LcdWriteData('.'); //显示 ‘.’ LcdWriteCom(0x40 + 0x8D); //写地址 80表示初始地址 LcdWriteData('0' + datas[2]); //显示小数点 LcdWriteCom(0x40 + 0x8E); //写地址 80表示初始地址 LcdWriteData('0' + datas[3]); //显示小数点 } /******************************************************************************* * 函数名 : LcdDisplay() * 函数功能 : 显示函数 *******************************************************************************/ void LcdDisplay() { LcdWriteCom(0x80 + 0x40); LcdWriteData('0' + TIME[4] / 16); //时 LcdWriteData('0' + (TIME[4] & 0x0f)); LcdWriteData(':'); LcdWriteData('0' + TIME[5] / 16); //分 LcdWriteData('0' + (TIME[5] & 0x0f)); LcdWriteData(':'); LcdWriteData('0' + TIME[6] / 16); //秒 LcdWriteData('0' + (TIME[6] & 0x0f)); LcdWriteCom(0x80); LcdWriteData('2'); LcdWriteData('0'); LcdWriteData('0' + TIME[0] / 16); //年 LcdWriteData('0' + (TIME[0] & 0x0f)); LcdWriteData('-'); LcdWriteData('0' + TIME[1] / 16); //月 LcdWriteData('0' + (TIME[1] & 0x0f)); LcdWriteData('-'); LcdWriteData('0' + TIME[2] / 16); //日 LcdWriteData('0' + (TIME[2] & 0x0f)); LcdWriteCom(0x8B); LcdWriteData('0' + (TIME[3] & 0x07)); //星期 } /******************************************************************************* * 函数名 : Delay10ms * 函数功能 : 延时函数,延时10ms * 输入 : 无 * 输出 : 无 *******************************************************************************/ void Delay10ms(void) //误差 0us { unsigned char a, b, c; for (c = 1; c > 0; c--) for (b = 38; b > 0; b--) for (a = 130; a > 0; a--) ; } /******************************************************************************* * * 时间设置相关函数 * *******************************************************************************/ /* 进入时间设置状态 */ void EnterTimeSet() { LcdWriteCom(0x8D); //写地址 80表示初始地址 LcdWriteData('S'); LcdWriteData('e'); LcdWriteData('t'); SetPlace = 0; //把设置索引设置为0,即可进入设置状态 RefreshSetShow(); //刷新光标位置 LcdOpenCursor(); //打开光标闪烁效果 } /* 退出时间设置状态*/ void ExitTimeSet() { LcdWriteCom(0x8D); //写地址 80表示初始地址 LcdWriteData('A'); LcdWriteData('u'); LcdWriteData('t'); SetPlace = 9; //把设置索引设置为9,即可退出设置状态 LcdCloseCursor(); //关闭光标显示 Ds1302Init(); LcdWriteCom(0x40 + 0x8F); //写地址 80表示初始地址 LcdWriteData('C'); LcdDisplay_temp(Ds18b20ReadTemp()); } /* 递增当前设置位的值 */ void IncSetTime() { TIME[SetPlace]++; if ((TIME[SetPlace] & 0x0f) > 9) //换成BCD码 { TIME[SetPlace] = TIME[SetPlace] + 6; } if ((TIME[SetPlace] >= 0x9A) && (SetPlace == 0)) //年只能到2099 { TIME[SetPlace] = 0; } if ((TIME[SetPlace] >= 0x13) && (SetPlace == 1)) //月只能到12 { TIME[SetPlace] = 1; } //不同月份的天数不同: if (TIME[1] == 1 || TIME[1] == 3 || TIME[1] == 5 || TIME[1] == 7 || TIME[1] == 8 || TIME[1] == 10 || TIME[1] == 12) //月份为大 { if((TIME[SetPlace] >= 0x32) && (SetPlace == 2)) //日只能到31 { TIME[SetPlace] = 1; } } if (TIME[1] == 4 || TIME[1] == 6 || TIME[1] == 9 || TIME[1] == 11) //月份为小 { if ((TIME[SetPlace] >= 0x31) && (SetPlace == 2)) //日只能到30 { TIME[SetPlace] = 1; } } if ((TIME[1] == 2) && (SetPlace == 2)) //月份为2月 { if ((TIME[SetPlace] >= 0x30) && (year == 0)) //闰年日只能到29 { TIME[SetPlace] = 1; } if ((TIME[SetPlace] >= 0x29) && (year == 1)) //平年日只能到28 { TIME[SetPlace] = 1; } } if ((TIME[SetPlace] >= 0x08) && (SetPlace == 3)) //周只能到7 { TIME[SetPlace] = 1; } if ((TIME[SetPlace] >= 0x24) && (SetPlace == 4)) //时只能到23 { TIME[SetPlace] = 0; } if ((TIME[SetPlace] >= 0x60) && (SetPlace == 5)) //分只能到60 { TIME[SetPlace] = 0; } if ((TIME[SetPlace] >= 0x60) && (SetPlace == 6)) //秒只能到60 { TIME[SetPlace] = 0; } LcdDisplay(); //刷新时间显示 RefreshSetShow(); //刷新光标显示 } /* 递减当前设置位的值 */ void DecSetTime() { TIME[SetPlace]--; if ((TIME[SetPlace] & 0xf0) < 0x00) //换成BCD码 { TIME[SetPlace] = TIME[SetPlace] - 0x10; } if ((TIME[SetPlace] & 0x0f) > 9) //换成BCD码 { TIME[SetPlace] = TIME[SetPlace] - 6; } if (('0' +(TIME[0]/16)=='?') && (SetPlace == 0)) //年只能到2099 { TIME[SetPlace] = 0x99; } if ((TIME[SetPlace] <= 0x00) && (SetPlace == 1)) //月只能到12 { TIME[SetPlace] = 0x12; } //不同月份的天数不同: if (TIME[1] == 1 || TIME[1] == 3 || TIME[1] == 5 || TIME[1] == 7 || TIME[1] == 8 || TIME[1] == 10 || TIME[1] == 12) //月份为大 { if((TIME[SetPlace] <= 0x00) && (SetPlace == 2)) //日只能到31 { TIME[SetPlace] = 0x31; } } if (TIME[1] == 4 || TIME[1] == 6 || TIME[1] == 9 || TIME[1] == 11) //月份为小 { if((TIME[SetPlace] <= 0x00) && (SetPlace == 2)) //日只能到31 { TIME[SetPlace] = 0x30; } } if ((TIME[1] == 2) && (SetPlace == 2)) //月份为2月 { if ((TIME[SetPlace] <= 0x00) && (year == 0)) //闰年日只能到29 { TIME[SetPlace] = 0x29; } if ((TIME[SetPlace] <= 0x00) && (year == 1)) //平年日只能到28 { TIME[SetPlace] = 0x28; } } if ((TIME[SetPlace] <= 0x00) && (SetPlace == 3)) //周只能到7 { TIME[SetPlace] = 0x07; } if (('0' +(TIME[4] / 16)=='?') && (SetPlace == 4)) //时只能到23 { TIME[SetPlace] = 0x23; } if (('0' +(TIME[5] / 16)=='?') && (SetPlace == 5)) //分只能到60 { TIME[SetPlace] = 0x59; } if (('0' +(TIME[6] / 16)=='?') && (SetPlace == 6)) //秒只能到60 { TIME[SetPlace] = 0x59; } LcdDisplay(); //刷新时间显示 RefreshSetShow(); //刷新光标显示 } /* 刷新当前设置位的光标指示 */ void RefreshSetShow() { switch (SetPlace) { case 0: LcdSetCursor(3, 0); //年 break; case 1: LcdSetCursor(6, 0); //月 break; case 2: LcdSetCursor(9, 0); //日 break; case 3: LcdSetCursor(11, 0); //周 break; case 4: LcdSetCursor(1, 1); //时 break; case 5: LcdSetCursor(4, 1); //分 break; case 6: LcdSetCursor(7, 1); //秒 break; default: break; } } /* 右移时间设置位 */ void RightShiftTimeSet() { if (SetPlace != 9) { if (SetPlace < 6) SetPlace++; else SetPlace = 0; RefreshSetShow(); } } /******************************************************************************* * * 按键相关函数 * *******************************************************************************/ unsigned char KeyScan() //不支持连按 { static unsigned char key_up = 1; if (key_up && (K1 == 0 || K2 == 0 || K3 == 0 || K4 == 0)) { Delay10ms(); key_up = 0; if (K1 == 0) return 1; else if (K2 == 0) return 2; else if (K3 == 0) return 3; else if (K4 == 0) return 4; }else if(K1==1&&K2==1&&K3==1&&K4==1)key_up=1; return 0; } void KeyAction() { switch (keynum) { case 1: if (SetPlace == 9) //不处于设置状态时,进入设置状态 { EnterTimeSet(); } else //已处于设置状态时,保存时间并退出设置状态 { ExitTimeSet(); } break; case 2: RightShiftTimeSet(); break; case 3: IncSetTime(); break; case 4: DecSetTime(); break; default: break; } } 实物图: 补充:类似程序网上有很多例程,但是大多并不完善(不是没有平年闰年判断,就是设置项只能加不能减,要么就是设置项顺序紊乱),因而产生了自己做一个比较完善的万年历C51程序的想法。由于本人还是高校学生,水平有限,若有HXD有发现BUG或者有更优秀的程序设计,欢迎指正交流。 |
|
|
|
只有小组成员才能发言,加入小组>>
2548 浏览 0 评论
1144浏览 2评论
744浏览 1评论
498浏览 0评论
262浏览 0评论
424浏览 0评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 09:58 , Processed in 1.330229 second(s), Total 77, Slave 59 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号