基于51单片机LCD1602温度显示时钟
要在1602上显示时间和温度先要了解1602是如何显示的。详情可以参考我之前的文章基于51单片机1602显示 ;时间显示可以用时钟芯片DS1302,但是此次我没使用,接着使用定时中断写可以参考之前我的文章基于51单片机定时,数码管显示时间,温度检测由于使用51单片机使用DS18B20方便一点因为DS18B20传递的直接是数字量单片机可以直接识别,如果使用热敏电阻还要进行模数转换而且温度测量精度也不高。
整体设计思路
按照系统设计的需求,初步确定系统由电源模块、时钟模块、显示模块、键盘接口模块、温度测量模块和闹钟模块共六个模块组成,其中电源模块采用5V电源对单片机供电,温度模块采用DS18B20温度传感器对当前环境温度进行采集,利用按键对当前时间节点进行校正,采用定时器T0对电子时钟的时间进行计数操作,采用1602显示器对当前时间和当前环境温度进行显示,利用蜂鸣器对所设定时间节点进行发声操作,系统设计框图如图所示。
时间显示模块
此次时间显示相对与数码管显示那次 我修改了一下加入了按键可以修改时间到当前时间而不是从0开始。
先对1602的第一行进行输入显示时间初始数组写入,然后将中断开启,每1秒记1次并判断一下秒时分,将其与时间初始数组地址联系一块,这样时间就随中断计时的改变一直改变。改变时间也是对初始时间数组改变,时间调节函数对按键进行扫描,看有无按键按下,对应按键按下,中断停止通过其余按键扫描,对初始数组标志位地址改变实现加减。通过闹钟函数对计入数字次数进行扫描,看是否到达预定次数,即可模拟实现闹钟的功能。
1602初始化我就不写了(看前面文章)直接开始关键点时间数组导入,和改变时间显示。
定时器中断记时还是老操作了:
void init_t0(){//中断初始化
TMOD=0X01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
void timer0()interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
time++;
}
void tem(){
if(time==20){
time=0;
miao++;
if(miao==60){
miao=0;
fen++;
if(fen==60){
fen=0;
shi++;
if(shi==24){
shi=0;
}
write_sfm(0,shi);//调用分离十位个位函数分离后送到1602对应位置显示
}
write_sfm(3,fen);
}
write_sfm(6,miao);
}
//可以内部设置闹钟直接判断
if(miao==10&&fen == 00&&shi == 00){
bz=0;
delay_ms(1000);
bz=1;
}
}
时间显示重点
时间规格写好了,怎么才能将shi,fen,miao,这几个变量写入1602,之前的数码管是将数码管显示数字编码写成一个数组,计时器写好后对10取整取余 分离十位个位判段数组下标然后传递给数码管显示。对余1602也可以采取类似的办法,将十位个位分离后送到对应1602显示位置,显示位置与下面送入1602时间初始数组有关
void write_sfm(uchar add,uchar date)
{
uchar s,g;
s=date/10;
g=date%10;
write_com(0x80+add);//这里写命令写数据参考前面1602显示文章
write_date(0x30+s);
write_date(0x30+g);
}
uchar code time_0[]="00:00:00";
for(i=0;i<8;i++){
write_date(time_0[i]);
delay_ms(1);
}
改变时间我是这样写的:判断按键1按下然后中断停止,而后直接寻址,然后判断按键2按下加一按键3按下减一,按键1再按下可以再寻址,时分秒按完就恢复。
void key_g(){
if(k0==0){//判断按键1按下了吗
delay_ms(10);
if(k0==0){
while(!k0);
num++;
if(num==1){//最开始光标在秒那
TR0=0;
write_com(0x0f);
write_com(0x80+7);
}
if(num==2){//再按一次光表在分那
write_com(0x80+4);
}
if(num==3){
write_com(0x80+1);
}
if(num==4){
num=0;
TR0=1;
write_com(0x0c);
}
}
}
if(k1==0) //改变光标所在位置的数字+1
{
delay_ms(10);
if(k1==0)
{
while(!k1);
if(num==1){
miao++;
if(miao==60)miao=0;
write_sfm(6,miao);
write_com(0x80+7);
}
if(num==2){
fen++;
if(fen==60)fen=0;
write_sfm(3,fen);
write_com(0x80+4);
}
if(num==3){
shi++;
if(shi==24)shi=0;
write_sfm(0,shi);
write_com(0x80+1);
}
}
}
if(k2==0) //改变光标所在位置的数字-1
{
delay_ms(10);
if(k2==0){
while(!k2);
if(num==1){
miao--;
if(miao==-1)
miao=59;
write_sfm(6,miao);
write_com(0x80+7);
}
if(num==2){
fen--;
if(fen==-1)fen=59;
write_sfm(3,fen);
write_com(0x80+4);
}
if(num==3){
shi--;
if(shi==-1)shi=23;
write_sfm(0,shi);
write_com(0x80+1);
}
}
}
}
直接在主函数里调用这些函数(注意顺序,初始化都要在前面)
温度显示函数调用详情参考基于51单片机DS18B20测温
void main(){
uint i;
write_init();//1602初始化
init_t0();//开启定时器初始化
for(i=0;i<8;i++){
write_date(time_0[i]);
delay_ms(1);
}
while(1){
tem();
key_g();
LcdDisplay(Ds18b20ReadTemp());
if(Ds18b20ReadTemp()==20.0){
bz=0;
delay_ms(1000);
bz=1;
}
if(Ds18b20ReadTemp()==-015.0){
bz=0;
delay_ms(10000);
bz=1;
}
}
}
仿真效果如图: