3年前做的一个小东西,今晚偶尔兴起,改了下程序:1、可以测量并显示负温度
2、出错时错误码显示
3、数码管显示多余0去掉
原理图如下:
PCB图如下:
程序如下:
/*
程序功能:测量温度(DS18B20),数码管动态显示
硬件平台:STC89C52(12M)
软件平台: Keil 3
端口分配:P1位选,P3段选,DQ=P1^4
作者: Mr Lee
修改日期:2012.11.30
*/
#include
#define uint unsigned int
#define uchar unsigned char
#define uint unsigned int
#define uchar unsigned char
//管脚定义
#define wei P1
#define duan P3
sbit DQ=P1^4; //数据传输线接单片机的相应的引脚
//数码管段码位码定义
uint ww[]={0xf7,0xfb,0xfd,0xfe,0xf7,0xfb,0xfd,0xfe,0xf7,0xfb};
uchar dot[]={0x40,0x7c,0x09,0x03,0x26,0x12,0x10,0x47,0x00,0x02};//0-9共阳,带小数点
char nodot[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82};//0-9共阳,不带小数点
char code_func[]={0x98,0xbd,0xbf};//E,r,-
//定义全局变量
unsigned char tempL=0; //临时变量低位
unsigned char tempH=0; //临时变量高位
float temperature; //温度值
uchar flag_fu=0; //温度正负值标志位
/****************************************************************************
函数功能:延时子程序
入口参数:k
出口参数:
****************************************************************************/
void delay_ms(uint z)
{
uint x,y;
for(x=11;x>0;x--)
for(y=z;y>0;y--);
}
void delay(unsigned int k)
{
unsigned int n;
n=0;
while(n < k)
{n++;}
return;
}
/****************************************************************************
函数功能:DS18B20初始化子程序
入口参数:
出口参数:
****************************************************************************/
Init_DS18B20(void)
{
unsigned char x=0;
DQ=1; //DQ先置高
delay(8); //延时
DQ=0; //发送复位脉冲
delay(85); //延时(>480ms)
DQ=1; //拉高数据线
delay(14); //等待(15~60ms)
}
/****************************************************************************
函数功能:向DS18B20读一字节数据
入口参数:
出口参数:dat
****************************************************************************/
ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat=0;
for (i=8;i>0;i--)
{
DQ=1;
delay(1);
DQ=0;
dat>>=1;
DQ=1;
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}
/****************************************************************************
函数功能:向DS18B20写一字节数据
入口参数:dat
出口参数:
****************************************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for(i=8;i>0;i--)
{
DQ=0;
DQ=dat&0x01;
delay(5);
DQ=1;
dat>>=1;
}
delay(4);
}
/****************************************************************************
函数功能:向DS18B20读温度值
入口参数:
出口参数:temperature
****************************************************************************/
float ReadTemperature(void)
{
int temp_int;
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳过读序列号的操作
WriteOneChar(0x44); //启动温度转换
delay(125); //转换需要一点时间,延时
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳过读序列号的操作
WriteOneChar(0xbe); //读温度寄存器(头两个值分别为温度的低位和高位)
tempL=ReadOneChar(); //读出温度的低位LSB
tempH=ReadOneChar(); //读出温度的高位MSB
temp_int=(tempH<<8) + tempL;
//如果温度小于0
if(temp_int&0x8000)
{
temp_int=~temp_int;
temp_int+=1;
flag_fu=1;
}
else
{
flag_fu=0;
}
//温度转换,把高低位做相应的运算转化为实际温度
temperature=temp_int*0.0625;
delay(200);
return(temperature);
}
void display(float temperature )
{
int temp_shi;
int temp_ge;
int temp_dot;
temperature=ReadTemperature();
//测量温度不在范围内,表示错误
if((temperature < 0) || (temperature>150))
///if(temperature==85)
//if(1)
{
wei=ww[3];//错误码,左至右第一个数码管
duan=code_func[0];//"E"
delay_ms(45);
wei=ww[2];//错误码,左至右第二个数码管
duan=code_func[1];//"r"
delay_ms(45);
wei=ww[1];//左至右第三个数码管
duan=code_func[1];//"r" `111111
delay_ms(45);
wei=ww[0];//错误码数码,左至右第四个数码管(最右边)
duan=nodot[7];
delay_ms(45);
}
else
{
//temperature-=12;
temp_shi=(int)(temperature/10);
temp_ge=((((int)temperature)%100)%10);
temp_dot=((int)(temperature*10))%10;
if(temperature>=10)
{
wei=ww[3];
if(flag_fu==1)
{
//负温度显示
duan=code_func[2];//"-"
}
else
{
//关闭该数码管
duan=0xff;
}
delay_ms(60);
wei=ww[2];//十位,左至右第二个数码管
duan=nodot[temp_shi];
delay_ms(60);
wei=ww[1];//个位,左至右第三个数码管
duan=dot[temp_ge];
delay_ms(60);
wei=ww[0];//小数位,左至右第四个数码管(最右边)
duan=nodot[temp_dot];
}
else//温度绝对值在10以内
{
wei=ww[3];
duan=0xff;//关闭第1个数码管
delay_ms(60);
wei=ww[2];//
if(flag_fu==1)
{
duan=code_func[2];//"-"
}
delay_ms(60);
wei=ww[1];//个位,左至右第三个数码管
duan=dot[temp_ge];
delay_ms(60);
wei=ww[0];//小数位,左至右第四个数码管(最右边)
duan=nodot[temp_dot];
//delay_ms(10);
}
}
}
void main()
{
float i;
//init();
while(1)
{
display(i);
//delay(500);
}
}
效果图如下:
程序进过最后修正,做了如下修改:
1、用定时器0周期扫描数码管,取代之前的延时函数,使显示十分稳定,看不到数码管在晃动。
数码管的扫描显示是在定时器中断中做的。
2、在主循环中偶尔读取温度传感器值并计算。
3、温度测量范围在-55到100之间。(负温度部分通过打火机充气瓶对其喷气降温测试过)
4、定时器扫描周期和主循环测量周期都是经过反复测试过的,现在值是最稳定的。
5、定时器中断做了优化,提高效率。否则会影响显示效果。
程序如下:
/*
程序功能:测量温度(DS18B20),数码管动态显示
硬件平台:STC89C52(12M)
软件平台: Keil 3
端口分配:P1位选,P3段选,DQ=P1^4
作者: Mr Lee
修改日期:2012.11.30
最后修改:2012.12.8
*/
#include
#define uint unsigned int
#define uchar unsigned char
#define uint unsigned int
#define uchar unsigned char
#define LZ_TEMP_DEBUG 0
//管脚定义
#define wei P1
#define duan P3
sbit DQ=P1^4; //数据传输线接单片机的相应的引脚
//定时器扫描数码管时间间隔:4ms
#define DISTIME_DELAY 4000
#define F_READ_TEMP 300
//数码管段码位码定义
char ww[]={0xf7,0xfb,0xfd,0xfe};
uchar dot[]={0x40,0x7c,0x09,0x03,0x26,0x12,0x10,0x47,0x00,0x02};//0-9共阳,带小数点
char nodot[]={0xc0,0xfc,0x89,0x83,0xa6,0x92,0x90,0xc7,0x80,0x82};//0-9共阳,不带小数点
char code_func[]={0x98,0xbd,0xbf,0xd8};//E,r,-,C
//定义全局变量(温度值相关变量)
unsigned char tempL=0; //临时变量低位
unsigned char tempH=0; //临时变量高位
float temperature; //温度值
uchar flag_fu=0; //温度正负值标志位
//数码管显示相关变量
uchar temp_shi;
uchar temp_ge;
uchar temp_dot;
uchar flag_dis_temp=0;
int flag_read_temp=0;
void display(void);
/****************************************************************************
函数功能:延时子程序
入口参数:k
出口参数:
****************************************************************************/
void delay_ms(uint z)
{
uint x,y;
for(x=11;x>0;x--)
for(y=z;y>0;y--);
}
void delay(unsigned int k)
{
unsigned int n;
n=0;
while(n < k)
{n++;}
return;
}
/****************************************************************************
函数功能:DS18B20初始化子程序
入口参数:
出口参数:
****************************************************************************/
Init_DS18B20(void)
{
unsigned char x=0;
DQ=1; //DQ先置高
delay(8); //延时
DQ=0; //发送复位脉冲
delay(85); //延时(>480ms)
DQ=1; //拉高数据线
delay(14); //等待(15~60ms)
}
/****************************************************************************
函数功能:向DS18B20读一字节数据
入口参数:
出口参数:dat
****************************************************************************/
ReadOneChar(void)
{
unsigned char i=0;
unsigned char dat=0;
for (i=8;i>0;i--)
{
DQ=1;
delay(1);
DQ=0;
dat>>=1;
DQ=1;
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}
/****************************************************************************
函数功能:向DS18B20写一字节数据
入口参数:dat
出口参数:
****************************************************************************/
WriteOneChar(unsigned char dat)
{
unsigned char i=0;
for(i=8;i>0;i--)
{
DQ=0;
DQ=dat&0x01;
delay(5);
DQ=1;
dat>>=1;
}
delay(4);
}
/****************************************************************************
函数功能:向DS18B20读温度值
入口参数:
出口参数:temperature
****************************************************************************/
float ReadTemperature(void)
{
int temp_int;
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳过读序列号的操作
WriteOneChar(0x44); //启动温度转换
delay(125); //转换需要一点时间,延时
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳过读序列号的操作
WriteOneChar(0xbe); //读温度寄存器(头两个值分别为温度的低位和高位)
tempL=ReadOneChar(); //读出温度的低位LSB
tempH=ReadOneChar(); //读出温度的高位MSB
temp_int=(tempH<<8) + tempL;
//如果温度小于0
if(temp_int&0x8000)
{
temp_int=~temp_int;
temp_int+=1;
flag_fu=1;
}
else
{
flag_fu=0;
}
//温度转换,把高低位做相应的运算转化为实际温度
temperature=temp_int*0.0625;
//delay(200);
return(temperature);
}
void dis_temp_error(void)
{
switch(flag_dis_temp)
{
case 1:
{
wei=ww[3];//错误码,左至右第一个数码管
duan=code_func[0];//"E"
}break;
case 2:
{
wei=ww[2];//错误码,左至右第二个数码管
duan=code_func[1];//"r"
}break;
case 3:
{
wei=ww[1];//左至右第三个数码管
duan=code_func[1];//"r" `111111
}break;
case 4:
{
wei=ww[0];//错误码数码,左至右第四个数码管(最右边)
duan=nodot[7];
}break;
}
}
void dis_temp_large10(void)
{
switch(flag_dis_temp)
{
case 1:
{
wei=ww[3];
if(flag_fu==1)
{
//负温度显示
duan=code_func[2];//"-"
}
else
{
//关闭该数码管
duan=0xff;
}
}break;
case 2:
{
wei=ww[2];//十位,左至右第二个数码管
duan=nodot[temp_shi];
}break;
case 3:
{
wei=ww[1];//个位,左至右第三个数码管
duan=dot[temp_ge];
}break;
case 4:
{
wei=ww[0];//小数位,左至右第四个数码管(最右边)
duan=nodot[temp_dot];
}break;
}
}
void dis_temp_small10()
{
switch(flag_dis_temp)
{
case 1:
{
wei=ww[3];
duan=0xff;//关闭第1个数码管
}break;
case 2:
{
wei=ww[2];//
if(flag_fu==1)
{
duan=code_func[2];//"-"
}
else
{
duan=0xff;
}
}break;
case 3:
{
wei=ww[1];//个位,左至右第三个数码管
duan=dot[temp_ge];
}break;
case 4:
{
wei=ww[0];//小数位,左至右第四个数码管(最右边)
duan=nodot[temp_dot];
}break;
}
}
void display(void)
{
//测量温度不在范围内,表示错误
if((temperature < 0) || (temperature>150))
///if(temperature==85)
//if(1)
{
dis_temp_error();
}
else
{
if(temperature>=10)
{
dis_temp_large10();
}
else//温度绝对值在10以内
{
dis_temp_small10();
}
}
}
void timer0_init(void)
{
//TMOD=0x01;//选定时器0,工作方式1,16位计数模式
TMOD|=0x01;
TH0=(65535-DISTIME_DELAY)/255;//设置初始值
TL0=(65535-DISTIME_DELAY)%255;
EA=1;//打开总中断
ET0=1;//打开定时器0中断
TR0=1;//定时器零开始计数
}
void main()
{
unsigned char flag_calc=0;
timer0_init();
while(1)
{
if(flag_read_temp<2 )
{
temperature=ReadTemperature();
#if LZ_TEMP_DEBUG==1
temperature=1.3;
flag_fu=1;
#endif
flag_calc=1;
}
if(flag_calc==1)
{
{
temp_shi=(int)(temperature/10);
temp_ge=(((int)temperature))%10;
temp_dot=((int)(temperature*10))%10;
flag_calc=0;
}
}
}
}
void timer0() interrupt 1
{
TH0=0xf0; //(65535-4000)/255;
TL0=0x5f; //(65535-4000)%255;
//数码管显示标识量
flag_dis_temp++;
//读取温度传感器标识量
flag_read_temp++;
if(flag_read_temp>=F_READ_TEMP)
{
flag_read_temp=0;
}
if(flag_dis_temp>=5)
flag_dis_temp=1;
display();
}