大家好!我自己動手做了一個數字溫度計。用的是STC12C2052AD單片機,而溫度傳感器用的是DS18B20,12M晶振,用C語言寫(移植)的程序,但是現在溫度可以測出來,只是顯示有時是對的,有是錯的。規律是:顯示正確溫度2-3秒,跳成850約一秒,然后又顯示正確溫度。對這個現象,我真是百思不得其解,如果是時序的問題,那為什么可以測得正確的溫度?
還有,資料上說STC12系列的單片機是不分頻的,那是不是說比如我用12M的晶振,那么執行一條指令的時間不再是1us,而是1/12 us?
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;
d3=0;
delayms(5);
d3=1;
P1=disdu;
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;
}
|