大家好!我自己动手做了一个数字温度计。用的是STC12C2052AD
单片机,而温度传感器用的是DS18B20,12M晶振,用C语言写(移植)的程序,但是现在温度可以测出来,只是显示有时是对的,有是错的。规律是:显示正确温度2-3秒,跳成850约一秒,然后又显示正确温度。对这个现象,我真是百思不得其解,如果是时序的问题,那为什么可以测得正确的温度?
还有,资料上说STC12系列的单片机是不分频的,那是不是说比如我用12M的晶振,那么执行一条指令的时间不再是1us,而是1/12 us?还是要通过反汇编再查stc的指令表得知?
DS18B20是数字传感器,读出的是一个16bit的数据,前5bit表示符号,中间八位表示温度的整数部分,我是把中间8位取出来,然后用分离出百、十、个位,送到数码管显示,刚开始用定时器中断扫描数码管,但因这个传感器对时序要求很严格,便改用了软件延时,可是用定时器与用软件延时效果是一样的都是对错对错循还。
是不是在读的时候时序错了呢?读的数据刚好错位了?如果在每次读温度前对它进行读忙呢?是否可以解决?
以下是我的程序,请
论坛高手多多指点,在下感激不尽!
(程序可以显示正确的温度,只是会跳动)
#include <reg2051.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
void ow_reset(void);
void delay(uint t);
void write_byte(uchar val);
uint read_temp();
uchar read_byte(void);
work_temp(uint tem);
void chuli(uchar wd);
void delayms(uint ms);
void displays();
uchar wei=0;
uint temp=0;
uchar wendu=0;
uchar b,s,g,x; //百位,十位,个位,小数
sbit d4=P3^2; //位选信号端
sbit d3=P3^4;
sbit d2=P3^3;
sbit d1=P3^5;
sbit DQ=P3^7; //接传感 器
uchar code disdu[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf}; //段选列表
//共阳LED段码表 "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "不亮" "-"
uchar data temp_data[2]={0x00,0x00}; //读出温度暂放
uchar code ditab[16]=
{0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09}; //小数部分直接查表
void main()
{
ow_reset();
write_byte(0xcc); //Skip ROM
write_byte(0x44); //发转换命令
while(1)
{
work_temp(read_temp());
displays();
}
}
void ow_reset(void) //复位
{
char presence=1;
while(presence)
{
while(presence)
{
DQ=1;_nop_();_nop_();//从高拉倒低
DQ=0;
delay(50); //550 us
DQ=1;
delay(6); //66 us
presence=DQ; //presence=0 复位成功,继续下一步
}
delay(45); //延时500 us
presence=~DQ;
}
DQ=1; //拉高电平
}
/****************DS18B20写命令函数************************/
//向1-WIRE 总线上写1个字节
void write_byte(uchar val)
{
uchar i;
for(i=8;i>0;i--)
{
DQ=1;_nop_();_nop_(); //从高拉倒低
DQ=0;_nop_();_nop_();_nop_();_nop_(); //5 us
DQ=val&0x01; //最低位移出
delay(6); //66 us
val=val/2; //右移1位
}
DQ=1;
delay(1);
}
/****************DS18B20读1字节函数************************/
//从总线上取1个字节
uchar read_byte(void)
{
uchar i;
uchar value=0;
for(i=8;i>0;i--)
{
DQ=1;_nop_();_nop_();
value>>=1;
DQ=0;_nop_();_nop_();_nop_();_nop_(); //4 us
DQ=1;_nop_();_nop_();_nop_();_nop_(); //4 us
if(DQ)value|=0x80;
delay(6); //66 us
}
DQ=1;
return(value);
}
uint read_temp()
{
ow_reset(); //总线复位
delay(200);
write_byte(0xcc); //发命令
write_byte(0x44); //发转换命令
ow_reset();
delay(1);
write_byte(0xcc); //发命令
write_byte(0xbe);
temp_data[0]=read_byte(); //读温度值的第字节
delay(3);
temp_data[1]=read_byte(); //读温度值的高字节
temp=temp_data[1];
temp<<=8;
temp=temp|temp_data[0]; // 两字节合成一个整型变量。
return(temp); //返回温度值
}
/****************温度数据处理函数************************/
//二进制高字节的低半字节和低字节的高半字节组成一字节,这个
//字节的二进制转换为十进制后,就是温度值的百、十、个位值,而剩
//下的低字节的低半字节转化成十进制后,就是温度值的小数部分
/********************************************************/
work_temp(uint tem)
{
uchar n=0;
if(tem>6348) // 温度值正负判断
{
tem=65536-tem;
n=1;
}
x=tem&0x0f; // 取小数部分的值
wendu=tem>>4; // 取中间八位,即整数部分的值
chuli(wendu);
if(n)
b=0x0b; //负温度时最高位显示"-"
}
void delay(uint t)
{ t=t*12; //stc12系列单片机不分频,乘以8-12时,延时约10us
for (;t>0;t--);
}
void delayms(uint ms)
{
ms=120*2*ms; //取这个参数显示比较稳定(数码管不闪烁,也有较高亮度)
for(;ms>0;ms--)
;
}
void displays() //显示温度
{
P1=disdu[ditab[x]];
d1=0;
delayms(5);
d1=1;
P1=disdu[g];
P1^7=0; //点亮小数点
d2=0;
delayms(5);
d2=1;
P1=disdu[s];
d3=0;
delayms(5);
d3=1;
P1=disdu[b];
d4=0;
delayms(5);
d4=1;
}
void chuli(uchar wd) //处埋温度数据
{
b=wd/100;
s=wd%100/10;
g=wd%100%10;
if(b==0)
b=10;
if(s==0)
s=10;
}
刚才在弄定时器的数码管动态扫描,加上18b20之后怎么的都不好用,看了你的话茅塞顿开啊,18b20不实时转换就什么问题都没有了,太感谢了
一周热门 更多>