一、题目:
![](https://img-blog.csdnimg.cn/img_convert/dd07b7030fe51ebec6b43f1acf4dff00.png)
二、存在BUG的代码:
DS18B20代码:
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include "reg52.h"
#define u8 unsigned char
#define u16 unsigned int
sbit DQ = P3^7;
u16 rd_temperature();
void Convert_T();
#endif
#include "onewire.h"
//
void Delay_OneWire(unsigned int t)
{
while(t--);
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
1void Convert_T()
{
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
}
u16 rd_temperature()
{
u8 LSB,LMB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
LMB = Read_DS18B20();
return LSB | (LMB<<8);
}
DS1302代码
#ifndef __DS1302_H
#define __DS1302_H
#include <reg52.h>
#include <intrins.h>
sbit SCK = P2^5;
sbit SDA = P2^6;
sbit RST = P2^7;
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
#endif
#include "ds1302.h"
//
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
主函数:
#include "reg52.h"
#include "stdio.h"
#include "onewire.h"
#include "ds1302.h"
#define u8 unsigned char
#define u16 unsigned int
#define set_mode 1 //参数设置模式
#define timer_mode 2 //时钟显示模式
#define temper_mode 3 //温度显示模式
sbit L1 = P2^0;
code unsigned char shownum[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
//数码管
u8 COD[8],PSI,COT[10];
u16 seg_delay;
u8 display_re;
//按键
u16 key_delay;
u8 key_now,key_old;
//DS1302
u16 count_500ms = 0;
u8 ds1302_time[3];
//DS18B20
u8 GAT_time=1;
u8 t_num=0,temper[10];
u8 count_1s;
//其他
u8 mode = set_mode;
//LED
u8 l_sign;
void Timer0_Init(void);
void SEG_Proc();
void SEG_Set();
void Key_Proc();
void DS1302_Init(u8 hour,u8 minute,u8 second);
void main()
{
Timer0_Init();
SEG_Set();
while(1)
{
Key_Proc();
SEG_Proc();
}
}
/*********数码管*************/
/*
将字符串转化成数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0,j=0;
for(i=0;i<8;i++,j++)
{
switch(input[j])
{
case '0': output[i] = shownum[0]; break;
case '1': output[i] = shownum[1]; break;
case '2': output[i] = shownum[2]; break;
case '3': output[i] = shownum[3]; break;
case '4': output[i] = shownum[4]; break;
case '5': output[i] = shownum[5]; break;
case '6': output[i] = shownum[6]; break;
case '7': output[i] = shownum[7]; break;
case '8': output[i] = shownum[8]; break;
case '9': output[i] = shownum[9]; break;
case '-': output[i] = 0x40; break;
case ' ': output[i] = 0x00; break;
default: output[i] = 0x00;
}
if(input[j+1] == '.')
{
output[i] |= 0x80;
j++;
}
}
}
/*
数码管显示函数
P22,P23,P24协助译码器控制位选,其中P22为最低位
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消影
P0 = 0x00;
// //位选
P2 = P2 & 0xe3 | (PSI<<2);
//段选
P0 = COD;
}
/*
参数设置界面
*/
void SEG_Set()
{
sprintf(COT," -%02u",(u16)GAT_time);
SEG_TSL(COT,COD);
}
/*
时钟显示界面
*/
void SEG_Timer1()
{
u8 TSL_time[3]={0},i=0;
for(i=0;i<3;i++)
TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
sprintf(COT,"%02u-%02u-%02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
SEG_TSL(COT,COD);
}
void SEG_Timer2()
{
u8 TSL_time[3]={0},i=0;
for(i=0;i<3;i++)
TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
sprintf(COT,"%02u %02u %02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
SEG_TSL(COT,COD);
}
/*
温度显示界面
*/
void SEG_Temper()
{
sprintf(COT,"-%02u -%02u",(u16)t_num,(u16)temper[t_num]);
SEG_TSL(COT,COD);
}
/***************定时器***************************/
void Timer0_Init(void) //1毫秒@12MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
//开启中断
EA = 1;
ET0 = 1;
}
void Timer0_IT() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(seg_delay++ == 500) seg_delay = 0;
if(key_delay++ == 17) key_delay = 0;
SEG_Show(COD[PSI],PSI);
if(PSI++ == 7)PSI = 0;
}
/**********************独立按键******************/
/*
独立按键按键检测
K4-K7
*/
u8 D_key()
{
u8 i=0;
for(i=0;i<4;i++)
{
if((P3 & (0x01<<i)) == 0)
return i+4;
}
return 0;
}
/*********************DS1302**********************/
/*
初始化DS1302的时间
*/
void DS1302_Init(u8 hour,u8 minute,u8 second)
{
Write_Ds1302_Byte(0x80,((second/10)<<4) | second%10);
Write_Ds1302_Byte(0x82,((minute/10)<<4) | minute%10);
Write_Ds1302_Byte(0x84,((hour/10)<<4) | hour%10);
}
/*
读取DS1302的时间
*/
void DS1302_Read(u8 *ds_time)
{
u8 i=0;
for(i=0;i<3;i++)
{
ds_time[i] = Read_Ds1302_Byte(0x81+i*2);
}
}
/*******************DS18B20******************************/
/*
读取DS18B20的温度
*/
void Temper_Read()
{
Convert_T();
temper[t_num] = rd_temperature()*0.0625;
t_num++;
}
/************************************************/
/*
数码管功能
*/
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
if((mode == set_mode) && display_re)
{
SEG_Set();
display_re = 0;
}
if(mode == timer_mode )
{
if(count_500ms == 2)
{
DS1302_Read(ds1302_time);
SEG_Timer2();
Temper_Read();
}
if(count_500ms == 4)
{
DS1302_Read(ds1302_time);
SEG_Timer1();
Temper_Read();
count_500ms = 0;
}
if(t_num == 10)
{
mode = temper_mode;
display_re = 1;
t_num = 0;
l_sign = 1;
}
count_500ms++;
}
if(mode == temper_mode)
{
if(display_re)
{
display_re = 0;
SEG_Temper();
}
if(l_sign)
{
L1 = !L1;
}
}
}
/*
按键功能
*/
void Key_Proc()
{
u8 key_down=0;
static u8 s_sign=2;
if(key_delay)return;
key_delay = 1;
key_now = D_key();
key_down = key_now & (key_now ^ key_old);
key_old = key_now;
if(mode == set_mode)
{
if(key_down == 4)
{
switch(s_sign)
{
case 1:GAT_time = 1;break;
case 2:GAT_time = 5;break;
case 3:GAT_time = 30;break;
case 4:GAT_time = 60;break;
}
if(s_sign++ == 4)s_sign = 1;
display_re = 1;//刷新数码管
}
if(key_down == 5)
{
mode = timer_mode;
DS1302_Init(23,59,50);
DS1302_Read(ds1302_time);
SEG_Timer1();
}
}
if(mode == temper_mode)
{
if(key_down == 6)
{
t_num++;
display_re = 1;
if(t_num == 10)t_num = 0;
l_sign = 0;
}
if(key_down == 7)
{
mode = set_mode;
display_re = 1;
}
}
}
三、存在的问题:
1.第一个温度显示异常
![](https://img-blog.csdnimg.cn/img_convert/8a0617772131a739ee070827a48fd4f6.jpeg)
(1)尝试在一开始做一次读操作,验证是否是第一次读操作的问题——仍然是85,证明不是读操作的问题,应该是读出的数据没有存到数组中
解决问题:DS18B20温度转换需要时间,所以我们要把转化温度和读取温度的操作分开,每一秒都转化温度,选择性读取其中的温度。
![](https://img-blog.csdnimg.cn/img_convert/c9d294911caba6dfb0aa13a35f124543.png)
四、修改后的主函数:
#include "reg52.h"
#include "stdio.h"
#include "onewire.h"
#include "ds1302.h"
#define u8 unsigned char
#define u16 unsigned int
#define set_mode 1 //参数设置模式
#define timer_mode 2 //时钟显示模式
#define temper_mode 3 //温度显示模式
sbit L1 = P2^0;
code unsigned char shownum[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40};
//数码管
u8 COD[8],PSI,COT[10];
u16 seg_delay;
u8 display_re;
//按键
u16 key_delay;
u8 key_now,key_old;
//DS1302
u16 count_500ms = 0;
u8 ds1302_time[3];
//DS18B20
u8 GAT_time=1;
u8 t_num=0,temper[10];
u8 count_1s;
//其他
u8 mode = set_mode;
//LED
u8 l_sign;
void Timer0_Init(void);
void SEG_Proc();
void SEG_Set();
void Key_Proc();
void DS1302_Init(u8 hour,u8 minute,u8 second);
void main()
{
Timer0_Init();
SEG_Set();
while(1)
{
Key_Proc();
SEG_Proc();
}
}
/*********数码管*************/
/*
将字符串转化成数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i=0,j=0;
for(i=0;i<8;i++,j++)
{
switch(input[j])
{
case '0': output[i] = shownum[0]; break;
case '1': output[i] = shownum[1]; break;
case '2': output[i] = shownum[2]; break;
case '3': output[i] = shownum[3]; break;
case '4': output[i] = shownum[4]; break;
case '5': output[i] = shownum[5]; break;
case '6': output[i] = shownum[6]; break;
case '7': output[i] = shownum[7]; break;
case '8': output[i] = shownum[8]; break;
case '9': output[i] = shownum[9]; break;
case '-': output[i] = 0x40; break;
case ' ': output[i] = 0x00; break;
default: output[i] = 0x00;
}
if(input[j+1] == '.')
{
output[i] |= 0x80;
j++;
}
}
}
/*
数码管显示函数
P22,P23,P24协助译码器控制位选,其中P22为最低位
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消影
P0 = 0x00;
// //位选
P2 = P2 & 0xe3 | (PSI<<2);
//段选
P0 = COD;
}
/*
参数设置界面
*/
void SEG_Set()
{
sprintf(COT," -%02u",(u16)GAT_time);
SEG_TSL(COT,COD);
}
/*
时钟显示界面
*/
void SEG_Timer1()
{
u8 TSL_time[3]={0},i=0;
for(i=0;i<3;i++)
TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
sprintf(COT,"%02u-%02u-%02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
SEG_TSL(COT,COD);
}
void SEG_Timer2()
{
u8 TSL_time[3]={0},i=0;
for(i=0;i<3;i++)
TSL_time[i] = (ds1302_time[i]>>4)*10+(ds1302_time[i]&0x0f);
sprintf(COT,"%02u %02u %02u",(u16)TSL_time[2],(u16)TSL_time[1],(u16)TSL_time[0]);
SEG_TSL(COT,COD);
}
/*
温度显示界面
*/
void SEG_Temper()
{
sprintf(COT,"-%02u -%02u",(u16)t_num,(u16)temper[t_num]);
SEG_TSL(COT,COD);
}
/***************定时器***************************/
void Timer0_Init(void) //1毫秒@12MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
//开启中断
EA = 1;
ET0 = 1;
}
void Timer0_IT() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(seg_delay++ == 500) seg_delay = 0;
if(key_delay++ == 17) key_delay = 0;
SEG_Show(COD[PSI],PSI);
if(PSI++ == 7)PSI = 0;
}
/**********************独立按键******************/
/*
独立按键按键检测
K4-K7
*/
u8 D_key()
{
u8 i=0;
for(i=0;i<4;i++)
{
if((P3 & (0x01<<i)) == 0)
return i+4;
}
return 0;
}
/*********************DS1302**********************/
/*
初始化DS1302的时间
*/
void DS1302_Init(u8 hour,u8 minute,u8 second)
{
Write_Ds1302_Byte(0x80,((second/10)<<4) | second%10);
Write_Ds1302_Byte(0x82,((minute/10)<<4) | minute%10);
Write_Ds1302_Byte(0x84,((hour/10)<<4) | hour%10);
}
/*
读取DS1302的时间
*/
void DS1302_Read(u8 *ds_time)
{
u8 i=0;
for(i=0;i<3;i++)
{
ds_time[i] = Read_Ds1302_Byte(0x81+i*2);
}
}
/*******************DS18B20******************************/
/*
读取DS18B20的温度
*/
void Temper_Read()
{
temper[t_num] = rd_temperature()*0.0625;
t_num++;
}
/************************************************/
/*
数码管功能
*/
void SEG_Proc()
{
if(seg_delay)return;
seg_delay = 1;
if((mode == set_mode) && display_re)
{
SEG_Set();
display_re = 0;
}
if(mode == timer_mode )
{
if(count_500ms == 2)
{
DS1302_Read(ds1302_time);
SEG_Timer2();
count_1s++;
Convert_T();
}
if(count_500ms == 4)
{
DS1302_Read(ds1302_time);
SEG_Timer1();
count_1s++;
count_500ms = 0;
Convert_T();
}
if(count_1s == GAT_time)
{
count_1s = 0;
Temper_Read();
}
if(t_num == 10)
{
mode = temper_mode;
display_re = 1;
t_num = 0;
l_sign = 1;
}
count_500ms++;
}
if(mode == temper_mode)
{
if(display_re)
{
display_re = 0;
SEG_Temper();
}
if(l_sign)
{
L1 = !L1;
}
}
}
/*
按键功能
*/
void Key_Proc()
{
u8 key_down=0;
static u8 s_sign=2;
if(key_delay)return;
key_delay = 1;
key_now = D_key();
key_down = key_now & (key_now ^ key_old);
key_old = key_now;
if(mode == set_mode)
{
if(key_down == 4)
{
switch(s_sign)
{
case 1:GAT_time = 1;break;
case 2:GAT_time = 5;break;
case 3:GAT_time = 30;break;
case 4:GAT_time = 60;break;
}
if(s_sign++ == 4)s_sign = 1;
display_re = 1;//刷新数码管
}
if(key_down == 5)
{
mode = timer_mode;
DS1302_Init(23,59,50);
DS1302_Read(ds1302_time);
SEG_Timer1();
Convert_T();
}
}
if(mode == temper_mode)
{
if(key_down == 6)
{
t_num++;
display_re = 1;
if(t_num == 10)t_num = 0;
l_sign = 0;
}
if(key_down == 7)
{
mode = set_mode;
display_re = 1;
}
}
}