找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6729|回复: 10
收起左侧

单片机时钟温度计小制作

  [复制链接]
ID:83710 发表于 2015-6-24 22:14 | 显示全部楼层 |阅读模式
     最近利用DS1302与DS18B20做了一个能显示当前时间、日期、温度的东西。有三个按键,正常运行时显示当前的时间,利用按键2、3可以切换到日期与温度。按下按键1进入设置时间状态,在设置时间状态利用按键2、3可调整时间与日期。调整好后不进行任何操作6秒退出设置状态。
实物图:
显示当前时间:(11时:24分:47秒)


显示当前日期:(09年:01月:15日)

显示当前温度:(17.2度)


源程序:
#include <reg51.h>
#include<intrins.h>
sbit dq = P0^0;//定义P0.0为DS18B20的数据线
sbit t_rst=P0^2;//DS1302数据线
sbit t_clk=P0^4;
sbit t_io=P0^3;
sbit P2_0=P2^0;//按键
sbit P2_1=P2^1;
sbit P2_2=P2^2;
sbit P3_0=P3^0;//显示
sbit P3_1=P3^1;
sbit P3_2=P3^2;
sbit P3_3=P3^3;
sbit P3_4=P3^4;
sbit P3_5=P3^5;
sbit P3_6=P3^6;
sbit P3_7=P3^7;
void delay(unsigned char i);//定义延时函数
bit init_18b20();//定义DS18B20初始化复位函数
void w_18b20(unsigned char dat);//定义写DS18B20函数
unsigned char r_18b20();//定义读DS18B20函数
void GetTem(void);//定义获得温度函数
void Temdisp(void);//温度显示函数
void in_1302(unsigned char tdat);//定义写一个字节到DS1302函数
unsigned char out_1302(void);//定义从DS1302读一个字节函数
void w_1302(unsigned char ucAddr, unsigned char ucDa);//定义写DS1302函数
void set1302(void);//设置时间
void get1302(void);//读取时间
void timedisp(void);//时间显示函数
void datedisp(void);//日期显示函数
void setbom(void);
unsigned char TemL;//温度低位
unsigned char TemH;//温度高位
unsigned char Tem1;//转换后温度个位
unsigned char Tem2;//转换后温度十位
unsigned char Led[4];
unsigned char dis[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//不带点的0~9
unsigned char dis1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//带点的0~9
bit TempS;//温度符号位
unsigned int ms;
unsigned char time[7]={0x00,0x24,0x11,0x15,0x01,0x04,0x09};

main()
{
set1302();
while(1)
{
  if(!P2_1){get1302();datedisp();}
  if(!P2_2){GetTem();Temdisp();}
  if(P2_1 && P2_2){ get1302();timedisp();}
  
  if(!P2_0)
  {
   TMOD=0x01; EA=1;ET0=1;TH0=0xFC;TL0=0x66;
   while(!P2_0);delay(255);delay(255);delay(255);
   setbom();
  }
}
}
void delay (unsigned char i) //延时程序,12M晶振下延时为:(2i+3)us ,i=0~255
{
while (--i);
}
bit init_18b20() //初始化,init_18b20=0初始化成功,init_18b20=1初始化失败,可能18b20不存在
{
bit SS;
dq=1;
_nop_();
dq=0;
delay(255);
dq=1;
delay(34);
SS=dq;
delay(120);
return (SS);
}
void w_18b20(unsigned char dat) //写一个字节到18b20
{
unsigned char i=0;
for(i=8;i>0;i--)
{
  dq=0;
  delay(5);
  dq=dat&0x01;
  delay(22);//延时
  dq=1;
  dat>>=1;
}
}
unsigned char r_18b20()//从18b20读一个字节
{
unsigned char i=0;
unsigned char dat=0;
for(i=8;i>0;i--)
{
  dq=0;
  dat>>=1;
  dq=1;
  delay(6);
  if(dq) dat|=0x80;
  delay(22);
}
return(dat);
}

void GetTem() //获得温度函数
{
bit SS;
unsigned char A;
unsigned long Tem;//温度变量
unsigned char TemLH;//低位温度高位
unsigned char TemLL;//低位温度低位
do SS=init_18b20();while(SS);//初始化DS18B20,检测是否存在,存在继续
w_18b20(0xCC);//跳过ROM匹配
w_18b20(0x44);//开始温度转换
do//等待温度转换完成
{
dq=0;
_nop_();
_nop_();
_nop_();
dq=1;
delay(6);
SS=dq;
delay(22);
Temdisp();
}
while (!SS);//温度转换完成后继续

init_18b20();//复位
w_18b20(0xCC);//跳过ROM匹配
w_18b20(0xBE);//读取温度值
TemL=r_18b20();//低位
TemH=r_18b20();//高位
if (TemH&0x80)//把读取的温度值进行转换,并存进Led[]中
{
  TemH=~TemH;
  TemL=(~TemL)+1;
  TempS=1;
  Led[0]=0x40;//显示负号
}
else TempS=0;

TemLH=TemL>>4;
TemLL=TemL&0x0F;
Tem=(TemH*16 + TemLH + TemLL*0.0625)*10000;
A=Tem/100000;
Led[1]=dis[A];
Tem=Tem%100000;
A=Tem/10000;
Led[2]=dis1[A];
Tem=Tem%10000;
A=Tem/1000;
Led[3]=dis[A];
}
void Temdisp()//温度显示函数,符号位(为负号显示),十位(为0不显示,个位(带小数点),小数位
{
if (TempS==1)//温度为负则显示负号,否则不显示
{
  if (Led[1]!=0x3f)
  {
   P1=Led[0];
   P3_5=0;
   delay(255);
   P3_5=1;
  }
  else
  {
   P1=Led[0];
   P3_4=0;
   delay(255);
   P3_4=1;
  }
}
if (Led[1]!=0x3f)//十位不为零则显示,否则不显示
{
  P1=Led[1];
  P3_4=0;
  delay(255);
  P3_4=1;
}
P1=Led[2];//个位
P3_3=0;
delay(255);
P3_3=1;
P1=Led[3];//小数位
P3_2=0;
delay(255);
P3_2=1;
}
void in_1302(unsigned char tdat) //写一个字节到DS1302
{
unsigned char i;
for(i=8;i>0;i--)
{
  t_io=tdat&0x01;
  _nop_();
  t_clk=1;
  _nop_();
  t_clk=0;
  tdat>>=1;
}
}
unsigned char out_1302(void) //从DS1302读一个字节
{
unsigned char i;
unsigned char tdat;
for(i=8;i>0;i--)
{
  tdat>>=1;
  if(t_io){tdat=tdat|0x80;}
  t_clk=1;
  _nop_();
  t_clk=0;
}
return(tdat);
}

void w_1302(unsigned char ucAddr, unsigned char ucDa) //往DS1302写入数据,先写地址,后写命令/数据
{
t_rst = 0;
t_clk = 0;
t_rst = 1;
in_1302(ucAddr); /* 地址,命令 */
in_1302(ucDa); /* 写1Byte数据*/
t_clk = 1;
t_rst =0;
}
unsigned char r_1302(unsigned char ucAddr)//从DS1302读出数据,先写地址,后读命令/数据
{
unsigned char ucDa;
t_rst = 0;
t_clk = 0;
t_rst = 1;
in_1302(ucAddr); /* 地址,命令 */
ucDa = out_1302(); /* 读1Byte数据 */
t_clk = 1;
t_rst =0;
return(ucDa);
}
void set1302(void)
{
unsigned char i;
unsigned char ucAddr = 0x80;
w_1302(0x8e,0x00); /* 控制命令,WP=0,写操作?*/
for(i =0;i<7;i++)
{
  w_1302(ucAddr,time[ i]); /* 秒 分 时 日 月 星期 年 */
  ucAddr +=2;
}
w_1302(0x8e,0x80); /* 控制命令,WP=1,写保护?*/
}
void get1302(void)
{
unsigned char i;
unsigned char ucAddr = 0x81;
for (i=0;i<7;i++)
{
  time = r_1302(ucAddr);/*格式为: 秒 分 时 日 月 星期 年 */
  ucAddr += 2;
}
}
void timedisp(void)
{
unsigned char m;unsigned char n;
m=time[0]>>4;n=time[0]&0x0f;//显示秒
P1=dis[m];
P3_3=0;
delay(255);delay(255);delay(255);delay(255);
P3_3=1;
P1=dis1[n];
P3_2=0;
delay(255);delay(255);delay(255);delay(255);
P3_2=1;

m=time[1]>>4;n=time[1]&0x0f;//显示分
P1=dis[m];
P3_5=0;
delay(255);delay(255);delay(255);delay(255);
P3_5=1;
P1=dis1[n];
P3_4=0;
delay(255);delay(255);delay(255);delay(255);
P3_4=1;
m=time[2]>>4;n=time[2]&0x0f;//显示时
P1=dis[m];
P3_7=0;
delay(255);delay(255);delay(255);delay(255);
P3_7=1;
P1=dis1[n];
P3_6=0;
delay(255);delay(255);delay(255);delay(255);
P3_6=1;
}
void datedisp(void)
{
unsigned char m;unsigned char n;
m=time[3]>>4;n=time[3]&0x0f;//显示日
P1=dis[m];
P3_3=0;
delay(255);delay(255);delay(255);delay(255);
P3_3=1;
P1=dis1[n];
P3_2=0;
delay(255);delay(255);delay(255);delay(255);
P3_2=1;

m=time[4]>>4;n=time[4]&0x0f;//显示月
P1=dis[m];
P3_5=0;
delay(255);delay(255);delay(255);delay(255);
P3_5=1;
P1=dis1[n];
P3_4=0;
delay(255);delay(255);delay(255);delay(255);
P3_4=1;
m=time[6]>>4;n=time[6]&0x0f;//显示年
P1=dis[m];
P3_7=0;
delay(255);delay(255);delay(255);delay(255);
P3_7=1;
P1=dis1[n];
P3_6=0;
delay(255);delay(255);delay(255);delay(255);
P3_6=1;
}
void setbom(void)
{
unsigned char i,m,n;
TR0=1;
while(ms<6000)
{
  if(!P2_0)
  {
   i++;ms=0;
   if(i==5) {i=6;}
   if(i==7) {i=0;}
   while(!P2_0);
   delay(255);delay(255);delay(255);
   ms=0;
  }
  if(!P2_1)
  {
   m=time>>4; n=time&0x0f;
   if(n!=9) n=n+1;
   else{m=m+1;n=0;}
   time=(m<<4)|n;
   while(!P2_1);
   delay(255);delay(255);delay(255);
   ms=0;
  }
  if(!P2_2)
  {
   m=time>>4; n=time&0x0f;
   if(m!=0 && n==0) {n=9;m=m-1;}
   else if(n!=0) {n=n-1;}
   time=(m<<4)|n;
   while(!P2_2);
   delay(255);delay(255);delay(255);
   ms=0;
  }
  
  if (time[0]==0x60)time[0]=0x00;
  if (time[1]==0x60)time[1]=0x00;
  if (time[2]==0x24)time[2]=0x00;
  if (time[3]==0x32)time[3]=0x00;
  if (time[4]==0x13)time[4]=0x00;
  if (time[6]==0x99)time[6]=0x00;
  set1302();
  if(i<3){get1302();timedisp();}
  else {get1302();datedisp();}
}
TR0=0;
ms=0;
}
void time0() interrupt 1 //定时器0中断
{
TR0=0;
TH0=0xFC;TL0=0x66;
ms++;
TR0=1;
}


回复

使用道具 举报

ID:62973 发表于 2015-6-25 17:04 | 显示全部楼层
精度如何;误差率多少!
回复

使用道具 举报

ID:61954 发表于 2015-6-26 07:48 | 显示全部楼层
晶振多少MHZ?上原理图啊
回复

使用道具 举报

ID:19947 发表于 2015-8-21 13:42 | 显示全部楼层
是个沃,楼主你发下原理图吗,我们小辈学习学习!
回复

使用道具 举报

ID:19947 发表于 2015-9-5 21:29 | 显示全部楼层
程序中晶振已经提示了,可是,1302需不需要电池供电?
回复

使用道具 举报

ID:1 发表于 2015-9-6 13:26 来自手机 | 显示全部楼层
wxgzf 发表于 2015-9-5 21:29
程序中晶振已经提示了,可是,1302需不需要电池供电?

晶振需要电池,不然无法断电保存时间。
回复

使用道具 举报

ID:258202 发表于 2017-12-6 15:37 | 显示全部楼层
大神,厉害了
回复

使用道具 举报

ID:256736 发表于 2017-12-6 17:36 | 显示全部楼层
这个不错啊,能有原理图就好了,初学者的好制作。
回复

使用道具 举报

ID:275642 发表于 2018-1-17 18:49 | 显示全部楼层
我是初学者,也想要原理图,谢谢!
回复

使用道具 举报

ID:257136 发表于 2018-2-8 14:07 | 显示全部楼层
应该弄个时间日期温度自动轮流显示的。我刚自己做了个时钟,想实现时间日期温度轮流显示,可是试了好多办法都不行,还是只能显示时间。
回复

使用道具 举报

ID:286600 发表于 2018-3-5 09:52 | 显示全部楼层
chen19890708 发表于 2018-2-8 14:07
应该弄个时间日期温度自动轮流显示的。我刚自己做了个时钟,想实现时间日期温度轮流显示,可是试了好多办法 ...

这很容易,设一个标志位,0--显时间,1--显温度,在走时程序中隔几秒取反一次该位。这是我用过的方法。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表