Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1966709
  • 博文数量: 356
  • 博客积分: 8284
  • 博客等级: 中将
  • 技术积分: 4580
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-15 20:25
个人简介

天行健,君子以自强不息

文章分类

全部博文(356)

文章存档

2018年(1)

2016年(4)

2015年(13)

2014年(14)

2013年(2)

2012年(25)

2011年(43)

2010年(65)

2009年(189)

分类: C/C++

2012-11-30 22:26:47

3年前做的一个小东西,今晚偶尔兴起,改了下程序:
1、可以测量并显示负温度
2、出错时错误码显示
3、数码管显示多余0去掉
原理图如下:
PCB图如下:
程序如下:
/*
程序功能:测量温度(DS18B20),数码管动态显示
硬件平台:STC89C52(12M)
软件平台: Keil 3
端口分配:P1位选,P3段选,DQ=P1^4
作者:    Mr Lee
修改日期:2012.11.30

*/
#include
#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
#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();

}
 

阅读(7693) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~