自己做的
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
Proteus仿真是用8.1版本的
单片机源程序如下:
- /*
- * 万年历
- */
- #include "main.h" //包含头文件main.h
- #include "LCD.h" //包含头文件LCD.h
- #include "DS1302.h" //包含头文件DS1302.h
- #include "word.h" //包含头文件word.h
- #include "lunar_calendar.h" //包含头文件lunar_calendar.h
- #include "buzz.h" //包含头文件buzz.h
- TIME time, tmp_time; //时间变量
- ALARM alarm; //时间变量
- bit Alarm_flag=0; //时间变量
- bit Clock_flag=0; //时间变量
- bit flag=0; //时间变量
- sbit DQ=P2^6; //DS18B20 pin 温度传感器引脚
- //-----------------18B20-----------------------
- unsigned char L_18B20,H_18B20,zhengshu,shangwen,xiawen; //温度用变量
- unsigned int fg=0,xiaoshu_a; //温度用变量
- //-----------------18B20----------------------
- //-------------音乐-----------------------------
- uint8 code SONG_TONE[]= //音乐数据
- {
- 212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,129,169,190,119,119,126,159,142,159,0
- };
- uint8 code SONG_LONG[]=//
- {
- 9,3,12,12,12,24,9,3,12,12,12,24,9,3,12,12,12,12,12,9,3,12,12,12,24,0
- };
- //------------------------------------------------------------
- void delay(uint16 n)//延时us级
- {
- while (n--);
- }
- //************************************************************************/
- // 函数: LCD_Delay()
- // 描述: 延时t ms函数
- // 参数: t
- // 返回: 无
- // 备注: 11.0592MHZ t=1延时时间约1ms
- // 版本: 2011/01/01 First version
- //************************************************************************/
- void Delay_nms(unsigned int t)
- {
- unsigned int i,j;
- for(i=0;i<t;i++) //循环t次
- for(j=0;j<113;j++) //循环113次 每次约3us
- ;
- }
- /////////////////////////////////////////////////
- //-----------播放音乐----------------------------
- void PlayMusic()
- {
- uint16 i =0,j,k;
- while(SONG_LONG[i]!=0||SONG_TONE[i]!=0)
- {
- for(j=0;j<SONG_LONG[i]*20;j++) //读取数据
- {
- BEEP = ~BEEP; //蜂鸣器取反
- for(k=0;k<SONG_TONE[i]/3;k++); //读取数据
- }
- Delay_nms(10); //延时10ms
- i++; //累加1
- }
- BEEP =1; //关闭蜂鸣器
- }
- /////////////////////////////////////////////////
- /*------DS18B20------*/
- void delay_18B20(unsigned int i)
- {
- while(i--);
- }
- /*DS18B20的复位脉冲 主机通过拉低单总线至少480us以产生复位脉冲
- 然后主机释放单总线并进入接收模式 此时单总线电平被拉高
- DS18B20检测到上升沿后 延时15~60us,拉低总线60~240us产生应答脉冲 */
- void Init_DS18B20(void)
- {
- unsigned char x=0;
- DQ = 1; //DQ复位
- delay_18B20(8); //稍做延时
- DQ = 0; //单片机将DQ拉低
- delay_18B20(80); //精确延时 大于 480us
- DQ = 1; //拉高总线
- delay_18B20(14); //延时
- x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
- delay_18B20(20); //延时
- }
- /*写时隙 主机在写1时隙向DS18B20写入1,在写0时隙向DS18B20写入0
- 所有写时隙至少需要60us,且在两次写时隙之间至少需要1us的恢复时间
- 两种写时隙均以主机拉低总线开始
- 产生写1时隙:主机拉低总线后,必须在15us内释放总线,由上拉电阻拉回至高电平
- 产生写0时隙:主机拉低总线后,必须整个时隙保持低电平 */
- void WriteOneChar(unsigned char dat)
- {
- unsigned char i=0;
- for (i=8; i>0; i--)//循环8次
- {
- DQ = 0; //DQ输出0
- DQ = dat&0x01;
- delay_18B20(5); //延时
- DQ = 1; //DQ输出1
- dat>>=1; //右移位
- }
- }
-
- /*所有读时隙至少60us 且两次独立的读时隙之间至少需要1us的恢复时间
- 每次读时隙由主机发起,拉低总线至少1us。
- 若传1,则保持总线高电平;若发送0,则拉低总线
- 传0时DS18B20在该时隙结束时释放总线,再拉回高电平状态,主机必须在读时隙开始后的15us内释放总线,并保持采样总线状态 */
- unsigned char ReadOneChar(void)
- {
- unsigned char i=0;
- unsigned char dat = 0;
- for (i=8;i>0;i--)
- {
- DQ = 0; // 给脉冲信号
- dat>>=1; //移位
- DQ = 1; // 给脉冲信号
- if(DQ) //如果DQ=1,执行下面的语句
- dat|=0x80;
- delay_18B20(4);//延时
- }
- return(dat); //返回数据
- }
-
- void read_18B20(void)
- {
- Init_DS18B20();
- WriteOneChar(0xCC); // 跳过读序号列号的操作
- WriteOneChar(0x44); // 启动温度转换
- delay_18B20(100); // this message is wery important
- Init_DS18B20(); //初始化DS18B20
- WriteOneChar(0xCC); //跳过读序号列号的操作
- WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
- delay_18B20(100); //延时
- L_18B20=ReadOneChar(); //读取低八位数据
- H_18B20=ReadOneChar(); //读取高八位数据
- zhengshu=L_18B20/16+H_18B20*16; //整数部分
- xiaoshu_a=(L_18B20&0x0f)*10/16; //小数第一位
- }
- //------------------DS18B20---------------------
- /////////////////////////////////////////////////
- /*
- * 按键扫描
- */
- int8 scan_key(void)
- {
- int8 val=-1; //初始化键值为-1
- if (KeyIn1 == 0) //判断=0?有无按键按键
- {
- val = 1; //键值=1
- while (KeyIn1 == 0); //等待按键释放
- }
- else if (KeyIn2 == 0) //判断=0?有无按键按键
- {
- val = 2; //键值=2
- while (KeyIn2 == 0);//等待按键释放
- }
- else if (KeyIn3 == 0) //判断=0?有无按键按键
- {
- val = 3; //键值=3
- while (KeyIn3 == 0);//等待按键释放
- }
- //if (val > 0)
- //buzzer_sound();
- return val; //返回键值
- }
- /*
- * 主界面框架
- */
- void main_frame(void)
- {
- play32(80, 2, 10); //显示数
- play32(32, 2, 10); //显示数
- play8(16, 0, S_xie);//显示斜线
- play8(40, 0, S_xie);//显示斜线
- // play8(96, 0, RH);
- // play8(120, 0, S_percent);
- play8(120, 6, S_du);//显示度
- }
- /*
- * 主界面
- */
- void main_show(bit refresh)
- {
- uint8 lunar[2];
- if (refresh)
- read_time((uint8 *)&time);// 读时间函数// 时间
- if (refresh || (time.sec != tmp_time.sec)) // 秒更新
- {
- tmp_time.sec = time.sec; //读取秒数据
- play8_num(104, 6,zhengshu); //温度显示
- play32_num(96, 2, time.sec); //显示秒
- }
- if (refresh)
- main_frame();//刷新界面
- if (refresh || (time.min != tmp_time.min)) // 分更新
- {
- if (!refresh)
- flag = 0;
- tmp_time.min = time.min;//读取分
- play32_num(48, 2, time.min); //显示分
- }
- if (refresh || (time.hour != tmp_time.hour)) // 时更新
- {
- if ((!refresh)&&(Clock_flag))
- alarm_sound();
- tmp_time.hour = time.hour; //读取时
- play32_num(0, 2, time.hour); //显示时
- }
- if (refresh || (time.day != tmp_time.day)) //日更新
- {
- tmp_time.day = time.day; //读取日
- play8_num(48, 0, time.day); //显示日
- // 农历
- turn_lunar_calendar(&time, lunar);
- play_lunar_calendar(0, 6, lunar[0], lunar[1]);
- }
- if (refresh || (time.week != tmp_time.week)) // 周更新
- {
- tmp_time.week = time.week; //读取周
- play_week(68, 0, time.week); //显示周
- }
- if (refresh || (time.mon != tmp_time.mon)) // 月更新
- {
- tmp_time.mon = time.mon; //读取月
- play8_num(24, 0, time.mon); //显示月
- // 农历
- turn_lunar_calendar(&time, lunar); //转换农历月
- play_lunar_calendar(0, 6, lunar[0], lunar[1]); //显示农历月
- }
- if (refresh || (time.year != tmp_time.year)) // 年更新
- {
- tmp_time.year = time.year; //读取年数据
- play8_num(0, 0, time.year); //显示年
- // 农历
- turn_lunar_calendar(&time, lunar); //转换农历年
- play_lunar_calendar(0, 6, lunar[0], lunar[1]); //显示农历年
- }
-
- }
- /*
- * 主机界面设置
- */
- void main_set(void)
- {
- int8 key_val, state=1; //变量
- play32_num(96, 2|0x80, time.sec); //显示秒
- while (1)
- { key_val = scan_key();//键盘扫描
- if (key_val == 1) // 设置
- {
- if (state >= 7)
- state = 0;
- else
- state++; //位置状态加1
- set_time((uint8 *)&time); //设置时间
- main_show(1); //显示主界面
- switch (state)
- { case 0: set_time((uint8 *)&time); break;//设置时间
- case 1: play32_num(96, 2|0x80, time.sec); break;//显示秒
- case 2: play32_num(48, 2|0x80, time.min); break;//显示分
- case 3: play32_num(0, 2|0x80, time.hour); break;//显示时
- case 4: play_week(68, 0|0x80, time.week); break;//显示周
- case 5: play8_num(48, 0|0x80, time.day); break; //显示日
- case 6: play8_num(24, 0|0x80, time.mon); break; //显示月
- case 7: play8_num(0, 0|0x80, time.year); break; //显示年
- default: break; //退出循环
- }
- }
- else if (key_val > 1)//按键值大于1
- {
- if (state == 1)//位置1设置秒
- {
- if (key_val == 3)//加按下?
- time.sec++;//秒加1
- else
- time.sec--; //秒减1
- if (time.sec >= 60)
- time.sec = 0;
- else if (time.sec < 0)
- time.sec = 59;
- play32_num(96, 2|0x80, time.sec);//显示秒
- }
- else if (state == 2) //位置2设置分
- {
- if (key_val == 3) //加按下?
- time.min++; //加1
- else
- time.min--; //减1
- if (time.min >= 60)
- time.min = 0;
- else if (time.min < 0)
- time.min = 59;
- play32_num(48, 2|0x80, time.min);//显示分
- }
- else if (state == 3) //位置3设置时
- { if (key_val == 3) //加按下?
- time.hour++; //加1
- else
- time.hour--; //减1
- if (time.hour >= 24)
- time.hour = 0;
- else if (time.hour < 0)
- time.hour = 23;
- play32_num(0, 2|0x80, time.hour);//显示时
- }
- else if (state == 4) //位置4设置周
- { if (key_val == 3) //加按下?
- time.week++; //加1
- else
- time.week--; //减1
- if (time.week >= 8)
- time.week = 1;
- else if (time.week < 1)
- time.week = 7;
- play_week(68, 0|0x80, time.week);//显示周
- }
- else if (state == 5)//位置5设置日
- {
- if (key_val == 3) //加按下?
- time.day++; //加1
- else
- time.day--; //减1
- if (time.day >= 32)
- time.day = 1;
- else if (time.day < 1)
- time.day = 31;
- play8_num(48, 0|0x80, time.day);//显示日
- }
- else if (state == 6) //位置6设置月
- {
- if (key_val == 3) //加按下?
- time.mon++; //加1
- else
- time.mon--; //减1
- if (time.mon >= 13)
- time.mon = 1;
- else if (time.mon < 1)
- time.mon = 12;
- play8_num(24, 0|0x80, time.mon);//显示月
- }
- else if (state == 7) //位置7设置年
- {
- if (key_val == 3) //加按下?
- time.year++; //加1
- else
- time.year--; //减1
- if (time.year >= 100)
- time.year = 0; //0年
- else if (time.year < 0)
- time.year = 99; //99年
- play8_num(0, 0|0x80, time.year);//显示年
- }
- else
- {
- break; //退出循环
- }
- }
- if (state == 0)
- break; //退出循环
- }
- }
- /*
- * 闹钟界面显示
- */
- void alarm_show(void)
- {
- int8 key_val, state=1;
- uint32 t=0;
- play16(0, 0, nao); //显示 闹
- play16(16, 0, zhong); //钟
- play16(32, 0, maohao); //冒号:
- if (Alarm_flag)
- play16(48, 0, kai); //开
- else
- play16(48, 0, guan);//关
- play32_num(32, 2, alarm.hour); //时
- play32(64, 2, 10); //冒号
- play32_num(80, 2, alarm.min); //分
- play16(0, 6, zheng); //显示 整
- play16(16, 6, dian); //显示 点
- play16(32, 6, bao); //显示 报
- play16(48, 6, shi); //显示 时
- play16(64, 6, maohao); //显示 冒号
- if (Clock_flag)
- play16(80, 6, kai); //显示 开
- else
- play16(80, 6, guan); //显示 关
- for (t=0; t<30000; t++)
- { key_val = scan_key(); //键盘扫描 获取键值
- if (key_val > 1) //判断数据
- break;
- else if (key_val == 1) //判断数据
- {
- if (Alarm_flag)
- play16(48, 0|0x80, kai);//显示 开
- else
- play16(48, 0|0x80, guan);//关
- while (1)
- { key_val = scan_key();//键盘扫描 获取键值
- if (key_val == 1) // 完成设置
- {
- if (state >= 4) //判断数据
- state = 0;
- else
- state++;
- if (Alarm_flag)
- play16(48, 0, kai); //显示 开
- else
- play16(48, 0, guan); //显示 关
- play32_num(32, 2, alarm.hour); //闹钟 时 显示
- play32_num(80, 2, alarm.min); //闹钟 分 显示
- if (Clock_flag)
- play16(80, 6, kai); //显示 开
- else
- play16(80, 6, guan); //显示 关
- switch (state) //判断数据
- {
- case 1:
- if (Alarm_flag)//判断数据
- play16(48, 0|0x80, kai); //显示 开
- else
- play16(48, 0|0x80, guan); //显示 关
- break;
- case 2:
- play32_num(80, 2|0x80, alarm.min);//闹钟 分 显示
- break;
- case 3:
- play32_num(32, 2|0x80, alarm.hour);//闹钟 时 显示
- break;
- case 4:
- if (Clock_flag)//判断数据
- play16(80, 6|0x80, kai);//显示 开
- else
- play16(80, 6|0x80, guan);//显示 关
- break;
- default: break;
- }
- }
- else if (key_val > 1)//判断数据
- {
- if (state == 1)//判断数据
- {
- Alarm_flag = ~Alarm_flag;
- if (Alarm_flag)
- play16(48, 0|0x80, kai);//显示 开
- else
- play16(48, 0|0x80, guan);//显示 关
- }
- else if (state == 2)//判断数据
- {
- if (key_val == 3)//判断数据
- alarm.min++;//加1
- else
- alarm.min--;//减1
- if (alarm.min >= 60)//判断数据
- alarm.min = 0;
- else if (alarm.min < 0)//判断数据
- alarm.min = 59;
- play32_num(80, 2|0x80, alarm.min);//闹钟 分 显示
- }
- else if (state == 3)//判断数据
- {
- if (key_val == 3)//判断数据
- alarm.hour++;//加1
- else
- alarm.hour--;//减1
- if (alarm.hour >= 24)//判断数据
- alarm.hour = 0;
- else if (alarm.hour < 0)//判断数据
- alarm.hour = 23;
- play32_num(32, 2|0x80, alarm.hour);//闹钟 时 显示
- }
- else if (state == 4) //判断数据
- {
- Clock_flag = ~Clock_flag;
- if (Clock_flag) //判断数据
- play16(80, 6|0x80, kai);//显示 开
- else
- play16(80, 6|0x80, guan);//显示 关
- }
- else
- {
- break; //退出
- }
- }
- if (state == 0) //状态为0退出
- break; //状态为0退出
- }
- if (state == 0) //状态为0退出
- break; //状态为0退出
- }
- }
- }
- main()
- {
- uint8 key_val;
- read_18B20(); //初始DS18B20
- Delay_nms(1000);//延时1S,等待18B20工作正常
- LCD_init(); //初始化液晶
- clear12864(); //清屏幕
- main_frame(); //显示主界面框架
- main_show(1); //刷新1次
- read_18B20(); //读温度
- play8_num(104, 6,zhengshu); //显示温度
- while(1)
- {
- key_val = scan_key();
- if (key_val == 1) //K1?
- {
- main_set(); //设置主界面
- }
- else if (key_val == 2) //K2?
- {
- clear12864(); //清屏幕
- alarm_show(); //闹钟画面
- clear12864(); //清屏幕
- main_show(1); //主界面
- }
- else if (key_val == 3) //K3?
- {
- clear12864(); //清屏幕
- alarm_show(); //闹钟画面
- clear12864(); //清屏幕
- main_show(1); //主界面
- }
- else
- {
- read_time((uint8 *)&time); //读取时间
- main_show(0); //显示主界面
- if((time.sec%2)==0){read_18B20();} //每隔2S采集一次
- }
-
- // 闹钟
- if (Alarm_flag)//如果闹钟标志有 执行下面的
- {
- if ((flag == 0) && (alarm.hour == time.hour) && (alarm.min == time.min))//判断条件是否满足
- {
- flag = 1;
- clear12864(); //清屏幕
- alarm_show(); //闹钟
- PlayMusic(); //播放音乐
- PlayMusic(); //播放音乐
- clear12864(); //清屏幕
- main_show(1); //显示主界面
- }
- }
- }
- }
复制代码
所有资料51hei附件下载:
万年历.7z
(3.13 MB, 下载次数: 46)
|