① ds18b20 如何讀取數據
1、首先雙擊電腦中的proteus軟體,然後點擊左側的「P」按鈕,如圖。
② 單片機 C51中關於18B20讀出數據的處理
t = b; t <<= 8; t = t | a;
這三句話相當於:t=b<<8+a; 由於a,b,t都是unsigned int 型,也就是16位的 ,這樣是可以的。其目的就是將兩個溫度值寄存器合成一個,方便處理。
上面的程序採用的是12位精度的,此時最小解析度為0.0625°。下面是是溫度操作過程 ,我在旁邊幫你注釋了。
a = ReadOneChar(); //讀取LSB,溫度值低位位元組
b = ReadOneChar(); //讀取MSB,溫度值高位位元組
t = b;
t <<= 8;
t = t | a; //最終結果是t = b*(2^8) + a;
tt = t * 0.0625; //總的溫度值,解析度是0.0625
t = tt * 10 + 0.5; //放大10倍輸出並四捨五入
a = t / 100; //十位
b = t / 10 - a * 10; //個位
c = t - a * 100 - b * 10; //小數位
小數會有一定的誤差,最好用查找表的方式,可取多位小數更准確。
③ 單片機中12Mhz晶振的,讀取18B20的數據需要多久
是這樣的,18B20的時序是有嚴格要求的,這是沒有辦法的事情,6ms屬於正常的時間,短一點的話,可以寫到4ms,但是這不是解決問題的關鍵,如果你程序有改動,還有可能的把時間加長。
所以,根本的解決辦法是,你操作18B20放在正常的程序中,而數碼管的顯示驅動,放在定時器中斷里時行,中斷固定3--5ms,這樣就互不影響了,其實在大工程中,數碼管的顯示驅動都是放大定時器里進行的。
④ 關於STM32讀18B20的問題
18b20是單數據線傳輸的,所以需要一位一位的接收,另外先接收的是低位,所以每次接收到數據就與data的最高位進行或運算(這樣不會修改data的其他位),接收完一位後,就要把數據data向右移一位,這樣data的最高位就空餘出來了,可以繼續接收,如此循環
比如
0000 0000 B
接收到1
進行或運算
1000 0000B
之後右移
0100 0000B
有接收到一個1
或運算
1100 0000B
如此循環
或運算可以很好的進行位操作而不影響其他的位,因為最先接收到的是低位所以選擇了右移,同理如果銜接受到的是高位則用左移。
⑤ 單片機用AT89S52,使用的溫度感測器是18B20,可以測量並存儲當前溫度,使用I2C匯流排協議
這是我用51編寫的,希望對你有幫助
//調用一次讀取溫度,所有點的溫度值就都保存到數組中了,對這個數組就可以隨意操作了
//實現多點采樣,一個18b20佔用一個I/O口,同樣是採用輪詢的方式采樣,不過這里只有讀取數據時是採用輪詢的,
//寫數據是同時進行的,直到發送溫度轉換指令,這就節省的很多時間,也就是輪詢一次只需要等待原來的一次的轉換時間,
//讀取和原來獨立是一樣。(即同時轉換,輪流讀取)
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*********************************************************************************/
// 18b20子程序
/*********************************************************************************/
/************************ROM操作命令代碼:
讀取ROM 0x33
匹配ROM 0x55 發送該命令後,接著發送64位ID編號,之後就可以直接發送操作命令,這時只有匹配的才做出響應。
搜索ROM 0xf0
跳過ROM 0xCC
告警搜索指令 0xec
*************************RAM操作命令代碼:
溫度轉換 0xbe
讀取暫存器 0xbe
寫入暫存器 0x4e 發出向內部RAM 3、4位元組寫上下限溫度數據命令 區分於寫功能(用來寫入所有指令的)
復制RAM到EEPROM 0x48 對RAM中第3、4位元組的操作
恢復EEPROM到RAM 0xb8
讀取供電方式 0xb4 寄生供電時18b20發回「0」,外接電源供電發回「1」。
**********************************************************************************/
/*********************************************************************************/
#define port P2 //定義18b20埠
sbit buzzer=P1^3; //蜂鳴器埠
unsigned char account; //定義全局變數
/**************************改變埠采樣點用的數組*********************************/
unsigned char change[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f} ;
unsigned char change2[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80} ;
/*********************************************************************************/
/**************************溫度存儲用數組*****************************************/
unsigned char save_temp[8]={0};
/*********************************************************************************/
//164顯示程序
/*********************************************************************************/
unsigned char sheet[]={0x11,0x7D,0x23,0x29,0x4D,0x89,0x81,0x3D,0x01,0x09};
sbit disp_data=P1^0;
sbit disp_clk=P1^1;
void disp_164(unsigned int x)
{
unsigned char i,j=4,k;
while(j--)
{
k=sheet[x%10];
for(i=0;i<8;i++)
{
if(k&0x01)disp_data=1;
else disp_data=0;
disp_clk=0;disp_clk=1;disp_clk=0;
k=k>>1;
}
x/=10;
}
}
/*********************************************************************************/
//18b20初始化
/*********************************************************************************/
void Init18B20(void)
{
unsigned char qq=0;
port=0; //DQ=0;
qq=250;while(qq)qq--; //Delay15(33);//至少延時480us
port=0xff; //DQ=1;
qq=75;while(qq)qq--; //Delay15(10);//至少延時100us
//if(DQ==1) return 0; //初始化失敗
// else return 1;
//DQ=1; Delay15(18);
}
/*********************************************************************************/
//18b20讀取一個位元組
/*********************************************************************************/
unsigned char Read18B20(void)
{
unsigned char i,temp,qq=0;
for(i=0;i<8;i++)
{
temp=temp>>1;
port&=change[account]; //DQ=0;
qq++; //_nop_();
port=0xff; //DQ=1;
qq=2;while(qq)qq--; //_nop_();_nop_();_nop_();_nop_();
if(port&change2[account]/*DQ==1*/)
{temp=temp|0x80;}
else
{temp=temp&0x7f;}
qq=15;while(qq)qq--; //Delay15(3);
port=0xff; //DQ=1;
}
return (temp);
}
/*********************************************************************************/
//18b20寫一個位元組
/*********************************************************************************/
void Write18B20(unsigned char temp)
{
unsigned char i,qq=0;
for(i=0;i<8;i++)
{
port=0; //port&=change[account];//DQ=0;
qq=7;while(qq)qq--; //Delay15(1);
if(temp&0x01)port=0xff; //DQ=ch&0x01;
else port=0; //port&=change[account];
qq=22;while(qq)qq--; //Delay15(3);
port=0xff; //DQ=1;
temp=temp>>1;
qq++; //_nop_();
}
}
/*********************************************************************************/
//讀取溫度值
/*********************************************************************************/
void get_temp()
{
unsigned char qq=0;
unsigned int TemH,TemL,temp,save=0,kk=0;
Init18B20();
Write18B20(0xCC); //跳過ROM
qq++; // _nop_();
Write18B20(0x44); //發送溫度轉換指令
qq=100;while(qq)qq--; //Delay10ms(25);//等待1s轉換
Init18B20();
Write18B20(0xCC); //跳過ROM
Write18B20(0xBE); //發送溫度轉換指令
for(account=0;account<8;account++)//設定采樣點的數量
{
TemL=Read18B20(); //讀低位溫度值
TemH=Read18B20(); //讀高位溫度值
//Delay10ms(2);
temp=(TemH<<4)|(TemL>>4);
if(save_temp[account]!=temp)
save_temp[account]=temp; //只有當前采樣值和前一次不同時才保存
}
//return(TemH);
}
/*********************************************************************************/
/*********************************************************************************/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************/
// 矩陣鍵盤
/***************************************************************************************/
/******************************************/////****************************************/
/*****需要修改的參數*****/
/******************************************/////****************************************/
sbit horizontal1=P3^2; sbit vertical1=P1^7;
sbit horizontal2=P3^3; sbit vertical2=P1^6;
sbit horizontal3=P3^4; sbit vertical3=P1^0;
sbit horizontal4=P3^5; sbit vertical4=P2^3;
sbit horizontal5=P0^3; sbit vertical5=P2^4;
sbit horizontal6=P0^5; sbit vertical6=P2^5;
sbit horizontal7=P0^6; sbit vertical7=P2^6;
sbit horizontal8=P0^7; sbit vertical8=P2^7;
#define HANG 4
#define LIE 1
//sbit buzzer=P1^3;
#define vertical_check vertical1//&vertical2 //只有列數變化時要進行修改
unsigned char code key_tab[HANG][LIE]={1,
2,
3,
4
};
/******************************************/////****************************************/
/******************************************/////****************************************/
/***************************************************************************************/
/***************************************************************************************/
void key_init()
{
horizontal1=1; vertical1=1;
horizontal2=1; //vertical2=1;
horizontal3=1; //vertical3=1;
horizontal4=1; //vertical4=1;
//horizontal5=1; vertical5=1;
//horizontal6=1; vertical6=1;
//horizontal7=1; vertical7=1;
//horizontal8=1; vertical8=1;
}
/***************************************************************************************/
/***************************************************************************************/
void key_check()
{
horizontal1=0; vertical1=1;
horizontal2=0; //vertical2=1;
horizontal3=0; //vertical3=1;
horizontal4=0; //vertical4=1;
//horizontal5=0; vertical5=1;
//horizontal6=0; vertical6=1;
//horizontal7=0; vertical7=1;
//horizontal8=0; vertical8=1;
}
/**************************************************************************************/
/**************************************************************************************/
unsigned char get_vertical()
{
unsigned char temp=LIE, vertical_temp=0;
if(vertical1)
{
//P0=0x0f;
vertical_temp++;
if(--temp==0)goto eend;
if(vertical2)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical3)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical4)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical5)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical6)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical7)
{
vertical_temp++;
if(--temp==0)goto eend;
if(vertical8)
{
goto eend;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
}
else goto eend ;
eend: ;
return(vertical_temp);
}
/***************************************************************************************/
/***************************************************************************************/
unsigned char get_key()
{
unsigned char horizontal=0,vertical=0,key_resault;
unsigned char delay1,delay2,temp;
key_init();
key_check();
if(vertical_check) goto key_over; //判斷是否有按鍵按下,有按鍵按下時vertical_check為0,沒有按鍵按下時vertical_check不為0
buzzer=0;
delay1=250;
while(delay1){delay1--;delay2=4;while(delay2)delay2--;} //延時5ms
buzzer=1;
key_init();
key_check();
if(vertical_check) goto key_over;
key_init();
for(temp=0;temp<HANG;temp++)
{
switch(temp)
{
case 0:{horizontal1=0;vertical=get_vertical();break;} //判斷第1行是否有按鍵按下
case 1:{horizontal2=0;vertical=get_vertical();break;} //判斷第2行是否有按鍵按下
case 2:{horizontal3=0;vertical=get_vertical();break;} //判斷第3行是否有按鍵按下
case 3:{horizontal4=0;vertical=get_vertical();break;} //判斷第4行是否有按鍵按下
case 4:{horizontal5=0;vertical=get_vertical();break;} //判斷第5行是否有按鍵按下
case 5:{horizontal6=0;vertical=get_vertical();break;} //判斷第6行是否有按鍵按下
case 6:{horizontal7=0;vertical=get_vertical();break;} //判斷第7行是否有按鍵按下
case 7:{horizontal8=0;vertical=get_vertical();break;} //判斷第8行是否有按鍵按下
default:break;
}
if(vertical==LIE) // 該行沒有檢測到按鍵按下,進行下一行
{
horizontal++;
}
else //檢測到該行有按鍵按下,就要跳出不再檢測了
{
key_resault=key_tab[horizontal][vertical]; goto key_over;
}
}
key_over:
return(key_resault);
}
/***************************************************************************************/
main()
{
unsigned char i=0,temp;
unsigned int kk=0;
while(1)
{
// for(j=0;j<6;j++) //設置要顯示的采樣點的數量
{
get_temp(); //調用一次讀取溫度,所有點的溫度值就都保存到數組中了,接下來就可以隨意的顯示了
/*i++;
if(i!=50) goto tiaozhuan; //相當於延時
{
i=0;
P0=change[j]; //LED指示采樣點的位置
buzzer=0; //蜂蜜器提示
kk=5000;
while(kk)kk--;
buzzer=1;
//disp_164(save_temp[j]);
} */
}
temp=get_key();
disp_164(save_temp[temp]);
}
}
⑥ 單片機18b20的資料
DS18B20一線匯流排數字式感測器的原理與使用
________________________________________
DS18B20、 DS1822 「一線匯流排」數字化溫度感測器是DALLAS最新單線數字溫度感測器, 同DS1820一樣,DS18B20也 支持「一線匯流排」介面,測量溫度范圍為 -55°C~+125°C,在-10~+85°C范圍內,精度為±0.5°C。DS1822的精度較差為± 2°C 。現場溫度直接以「一線匯流排」的數字方式傳輸,大大提高了系統的抗干擾性。適合於惡劣環境的現場溫度測量,與前一代產品不同,新的產品支持3V~5.5V的電壓范圍,使系統設計更靈活、方便。而且新一代產品更便宜,體積更小。
DS18B20可以程序設定9~12位的解析度,精度為±0.5°C。可選更小的封裝方式,更寬的電壓適用范圍。解析度設定,及用戶設定的報警溫度存儲在EEPROM中,掉電後依然保存。DS18B20的性能是新一代產品中最好的!性能價格比也非常出色! DS1822與 DS18B20軟體兼容,是DS18B20的簡化版本。省略了存儲用戶定義報警溫度、解析度參數的EEPROM,精度降低為±2°C,適用於對性能要求不高,成本控制嚴格的應用,是經濟型產品。 繼「一線匯流排」的早期產品後,DS1820開辟了溫度感測器技術的新概念。DS18B20和DS1822使電壓、特性及封裝有更多的選擇,讓我們可以構建適合自己的經濟的測溫系統。
DS18B20的內部結構
DS18B20內部結構主要由四部分組成:64位光刻ROM、溫度感測器、非揮發的溫度報警觸發器TH和TL、配置寄存器。DS18B20的管腳排列如下:
15元/只
DQ為數字信號輸入/輸出端;GND為電源地;VDD為外接供電電源輸入端(在寄生電源接線方式時接地)。
光刻ROM中的64位序列號是出廠前被光刻好的,它可以看作是該DS18B20的地址序列碼。64位光刻ROM的排列是:開始8位(28H)是產品類型標號,接著的48位是該DS18B20自身的序列號,最後8位是前面56位的循環冗餘校驗碼(CRC=X8+X5+X4+1)。光刻ROM的作用是使每一個DS18B20都各不相同,這樣就可以實現一根匯流排上掛接多個DS18B20的目的。
DS18B20中的溫度感測器可完成對溫度的測量,以12位轉化為例:用16位符號擴展的二進制補碼讀數形式提供,以0.0625℃/LSB形式表達,其中S為符號位。
這是12位轉化後得到的12位數據,存儲在18B20的兩個8比特的RAM中,二進制中的前面5位是符號位,如果測得的溫度大於0,這5位為0,只要將測到的數值乘於0.0625即可得到實際溫度;如果溫度小於0,這5位為1,測到的數值需要取反加1再乘於0.0625即可得到實際溫度。
例如+125℃的數字輸出為07D0H,+25.0625℃的數字輸出為0191H,-25.0625℃的數字輸出為FF6FH,-55℃的數字輸出為FC90H。
DS18B20溫度感測器的存儲器
DS18B20溫度感測器的內部存儲器包括一個高速暫存RAM和一個非易失性的可電擦除的E2RAM,後者存放高溫度和低溫度觸發器TH、TL和結構寄存器。
暫存存儲器包含了8個連續位元組,前兩個位元組是測得的溫度信息,第一個位元組的內容是溫度的低八位,第二個位元組是溫度的高八位。第三個和第四個位元組是TH、TL的易失性拷貝,第五個位元組是結構寄存器的易失性拷貝,這三個位元組的內容在每一次上電復位時被刷新。第六、七、八個位元組用於內部計算。第九個位元組是冗餘檢驗位元組。
該位元組各位的意義如下:
TM R1 R0 1 1 1 1 1
低五位一直都是1 ,TM是測試模式位,用於設置DS18B20在工作模式還是在測試模式。在DS18B20出廠時該位被設置為0,用戶不要去改動。R1和R0用來設置解析度,如下表所示:(DS18B20出廠時被設置為12位)
解析度設置表:
R1 R0 解析度 溫度最大轉換時間
0 0 9位 93.75ms
0 1 10位 187.5ms
1 0 11位 375ms
1 1 12位 750ms
根據DS18B20的通訊協議,主機控制DS18B20完成溫度轉換必須經過三個步驟:每一次讀寫之前都要對DS18B20進行復位,復位成功後發送一條ROM指令,最後發送RAM指令,這樣才能對DS18B20進行預定的操作。復位要求主CPU將數據線下拉500微秒,然後釋放,DS18B20收到信號後等待16~60微秒左右,後發出60~240微秒的存在低脈沖,主CPU收到此信號表示復位成功。
DS1820使用中注意事項
DS1820雖然具有測溫系統簡單、測溫精度高、連接方便、佔用口線少等優點,但在實際應用中也應注意以下幾方面的問題:
(1)較小的硬體開銷需要相對復雜的軟體進行補償,由於DS1820與微處理器間採用串列數據傳送,因此,在對DS1820進行讀寫編程時,必須嚴格的保證讀寫時序,否則將無法讀取測溫結果。在使用PL/M、C等高級語言進行系統程序設計時,對DS1820操作部分最好採用匯編語言實現。
(2)在DS1820的有關資料中均未提及單匯流排上所掛DS1820數量問題,容易使人誤認為可以掛任意多個DS1820,在實際應用中並非如此。當單匯流排上所掛DS1820超過8個時,就需要解決微處理器的匯流排驅動問題,這一點在進行多點測溫系統設計時要加以注意。
(3)連接DS1820的匯流排電纜是有長度限制的。試驗中,當採用普通信號電纜傳輸長度超過50m時,讀取的測溫數據將發生錯誤。當將匯流排電纜改為雙絞線帶屏蔽電纜時,正常通訊距離可達150m,當採用每米絞合次數更多的雙絞線帶屏蔽電纜時,正常通訊距離進一步加長。這種情況主要是由匯流排分布電容使信號波形產生畸變造成的。因此,在用DS1820進行長距離測溫系統設計時要充分考慮匯流排分布電容和阻抗匹配問題。
(4)在DS1820測溫程序設計中,向DS1820發出溫度轉換命令後,程序總要等待DS1820的返回信號,一旦某個DS1820接觸不好或斷線,當程序讀該DS1820時,將沒有返回信號,程序進入死循環。這一點在進行DS1820硬體連接和軟體設計時也要給予一定的重視。
測溫電纜線建議採用屏蔽4芯雙絞線,其中一對線接地線與信號線,另一組接VCC和地線,屏蔽層在源端單點接地。
本站實驗板實驗程序:
;這是關於DS18B20的讀寫程序,數據腳P2.2,晶振12MHZ
;溫度感測器18B20匯編程序,採用器件默認的12位轉化,最大轉化時間750微秒
;可以將檢測到的溫度直接顯示到AT89C51開發實驗板的兩個數碼管上
;顯示溫度00到99度,很准確哦~~無需校正!
ORG 0000H
;單片機內存分配申明!
TEMPER_L EQU 29H;用於保存讀出溫度的低8位
TEMPER_H EQU 28H;用於保存讀出溫度的高8位
FLAG1 EQU 38H;是否檢測到DS18B20標志位
a_bit equ 20h ;數碼管個位數存放內存位置
b_bit equ 21h ;數碼管十位數存放內存位置
MAIN:
LCALL GET_TEMPER;調用讀溫度子程序
;進行溫度顯示,這里我們考慮用網站提供的兩位數碼管來顯示溫度
;顯示範圍00到99度,顯示精度為1度
;因為12位轉化時每一位的精度為0.0625度,我們不要求顯示小數所以可以拋棄29H的低4位
;將28H中的低4位移入29H中的高4位,這樣獲得一個新位元組,這個位元組就是實際測量獲得的溫度
MOV A,29H
MOV C,40H;將28H中的最低位移入C
RRC A
MOV C,41H
RRC A
MOV C,42H
RRC A
MOV C,43H
RRC A
MOV 29H,A
LCALL DISPLAY;調用數碼管顯示子程序
CPL P1.0
AJMP MAIN
; 這是DS18B20復位初始化子程序
INIT_1820:
SETB P3.5
NOP
CLR P3.5
;主機發出延時537微秒的復位低脈沖
MOV R1,#3
TSR1:MOV R0,#107
DJNZ R0,$
DJNZ R1,TSR1
SETB P3.5;然後拉高數據線
NOP
NOP
NOP
MOV R0,#25H
TSR2:
JNB P3.5,TSR3;等待DS18B20回應
DJNZ R0,TSR2
LJMP TSR4 ; 延時
TSR3:
SETB FLAG1 ; 置標志位,表示DS1820存在
CLR P1.7;檢查到DS18B20就點亮P1.7LED
LJMP TSR5
TSR4:
CLR FLAG1 ; 清標志位,表示DS1820不存在
CLR P1.1;點亮P1。1腳LED表示溫度感測器通信失敗
LJMP TSR7
TSR5:
MOV R0,#117
TSR6:
DJNZ R0,TSR6 ; 時序要求延時一段時間
TSR7:
SETB P3.5
RET
; 讀出轉換後的溫度值
GET_TEMPER:
SETB P3.5
LCALL INIT_1820;先復位DS18B20
JB FLAG1,TSS2
CLR P1.2
RET ; 判斷DS1820是否存在?若DS18B20不存在則返回
TSS2:
CLR P1.3;DS18B20已經被檢測到!!!!!!!!!!!!!!!!!!
MOV A,#0CCH ; 跳過ROM匹配
LCALL WRITE_1820
MOV A,#44H ; 發出溫度轉換命令
LCALL WRITE_1820
;這里通過調用顯示子程序實現延時一段時間,等待AD轉換結束,12位的話750微秒
LCALL DISPLAY
LCALL INIT_1820;准備讀溫度前先復位
MOV A,#0CCH ; 跳過ROM匹配
LCALL WRITE_1820
MOV A,#0BEH ; 發出讀溫度命令
LCALL WRITE_1820
LCALL READ_18200; 將讀出的溫度數據保存到35H/36H
CLR P1.4
RET
;寫DS18B20的子程序(有具體的時序要求)
WRITE_1820:
MOV R2,#8;一共8位數據
CLR C
WR1:
CLR P3.5
MOV R3,#6
DJNZ R3,$
RRC A
MOV P3.5,C
MOV R3,#23
DJNZ R3,$
SETB P3.5
NOP
DJNZ R2,WR1
SETB P3.5
RET
; 讀DS18B20的程序,從DS18B20中讀出兩個位元組的溫度數據
READ_18200:
MOV R4,#2 ; 將溫度高位和低位從DS18B20中讀出
MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
MOV R2,#8;數據一共有8位
RE01:
CLR C
SETB P3.5
NOP
NOP
CLR P3.5
NOP
NOP
NOP
SETB P3.5
MOV R3,#9
RE10:
DJNZ R3,RE10
MOV C,P3.5
MOV R3,#23
RE20:
DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
DEC R1
DJNZ R4,RE00
RET
;顯示子程序
display: mov a,29H;將29H中的十六進制數轉換成10進制
mov b,#10 ;10進制/10=10進制
div ab
mov b_bit,a ;十位在a
mov a_bit,b ;個位在b
mov dptr,#numtab ;指定查表啟始地址
mov r0,#4
dpl1: mov r1,#250 ;顯示1000次
dplop: mov a,a_bit ;取個位數
MOVC A,@A+DPTR ;查個位數的7段代碼
mov p0,a ;送出個位的7段代碼
clr p2.0 ;開個位顯示
acall d1ms ;顯示1ms
setb p2.0
mov a,b_bit ;取十位數
MOVC A,@A+DPTR ;查十位數的7段代碼
mov p0,a ;送出十位的7段代碼
clr p2.1 ;開十位顯示
acall d1ms ;顯示1ms
setb p2.1
djnz r1,dplop ;100次沒完循環
djnz r0,dpl1 ;4個100次沒完循環
ret
;1MS延時(按12MHZ算)
D1MS: MOV R7,#80
DJNZ R7,$
RET
;實驗板上的7段數碼管0~9數字的共陰顯示代碼
numtab: DB 0F3H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
end
以下是第二種採集和處理程序供網友參考
;溫度感測器18B20匯編程序,採用器件默認的12位轉化,最大轉化時間750微秒
;將溫度數據通過串口發送出去,波特率2400
;本程序專為AT89C51實驗開發板編寫.適合12晶振
;本程序經過驗證,可以顯示溫度+/-和兩位整數溫度和兩位小數溫度數據
DOT EQU 30H
ZHENGSHU EQU 31H
FLAG1 EQU 38H ;是否檢測到DS18B20的標志位
;定義溫度數據
DIS_1 EQU 32H ;符號
DIS_2 EQU 33H ;十位
DIS_3 EQU 34H ;個位
DIS_4 EQU 35H ;小數點後第一位
DIS_5 EQU 36H ;小數點後第二位
WDDATA BIT P2.2 ;定義DS18B20的數據腳為P2.2埠
ORG 0000H
;以下為主程序進行CPU中斷方式設置
CLR EA ;關閉總中斷
MOV SCON,#50H ;設置成串口1方式
MOV TMOD,#20H ;波特率發生器T1工作在模式2上
MOV TH1,#0F3H ;預置初值(按照波特率2400BPS預置初值)
MOV TL1,#0F3H ;預置初值(按照波特率2400BPS預置初值)
SETB TR1 ;啟動定時器T1
;以上完成串口2400通訊初始化設置
;-------------------------
; 主程序
;-------------------------
MAIN:
LCALL INIT_1820 ;調用復位DS18B20子程序
MAIN1:
LCALL GET_TEMPER;調用讀溫度子程序
LCALL FORMULA ;通過公式計算,小數點後顯示兩位
LCALL BCD
LCALL DISPLAY ;調用串口顯示子程序
LCALL DELAY500 ;延時0.5秒
LCALL DELAY500 ;延時0.5秒
LCALL DELAY500 ;延時0.5秒
AJMP MAIN1
;-------------------------
; DS18B20復位初始化程序
;-------------------------
INIT_1820:
SETB WDDATA
NOP
CLR WDDATA
;主機發出延時540微秒的復位低脈沖
MOV R0,#36
LCALL DELAY
SETB WDDATA;然後拉高數據線
NOP
NOP
MOV R0,#36
TSR2:
JNB WDDATA,TSR3;等待DS18B20回應
DJNZ R0,TSR2
LJMP TSR4 ; 延時
TSR3:
SETB FLAG1 ; 置標志位,表示DS1820存在
LJMP TSR5
TSR4:
CLR FLAG1 ; 清標志位,表示DS1820不存在
LJMP TSR7
TSR5:
MOV R0,#06BH
TSR6:
DJNZ R0,TSR6 ;復位成功!時序要求延時一段時間
TSR7:
SETB WDDATA
RET
;-------------------
; 讀出轉換後的溫度值
;-------------------
GET_TEMPER:
SETB WDDATA ; 定時入口
LCALL INIT_1820 ;先復位DS18B20
JB FLAG1,TSS2
RET ; 判斷DS1820是否存在?若DS18B20不存在則返回
TSS2:
MOV A,#0CCH ; 跳過ROM匹配
LCALL WRITE_1820
MOV A,#44H ; 發出溫度轉換命令
LCALL WRITE_1820
MOV R0,#50 ;等待AD轉換結束,12位的話750微秒.
LCALL DELAY
LCALL INIT_1820 ;准備讀溫度前先復位
MOV A,#0CCH ; 跳過ROM匹配
LCALL WRITE_1820
MOV A,#0BEH ; 發出讀溫度命令
LCALL WRITE_1820
LCALL READ_18200; 將讀出的九個位元組數據保存到60H-68H
RET
;----------------------------------
;寫DS18B20的子程序(有具體的時序要求)
;----------------------------------
WRITE_1820:
MOV R2,#8 ;一共8位數據
CLR C
WR1:
CLR WDDATA
MOV R3,#6
DJNZ R3,$
RRC A
MOV WDDATA,C
MOV R3,#24
DJNZ R3,$
SETB WDDATA
NOP
DJNZ R2,WR1
SETB WDDATA
RET
;--------------------------------------------------
; 讀DS18B20的程序,從DS18B20中讀出九個位元組的數據
;--------------------------------------------------
READ_18200:
MOV R4,#9
MOV R1,#60H ; 存入60H開始的九個單元
RE00:
MOV R2,#8
RE01:
CLR C
SETB WDDATA
NOP
NOP
CLR WDDATA
NOP
NOP
NOP
SETB WDDATA
MOV R3,#09
RE10:
DJNZ R3,RE10
MOV C,WDDATA
MOV R3,#23
RE20:
DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
INC R1
DJNZ R4,RE00
RET
;------------------------
;溫度計運算元程序
;------------------------
FORMULA: ; 按公式:T實際=(T整數-0.25)+( M每度-M剩餘)/ M每度
;計算出實際溫度,整數部分和小數部分分別存於ZHENGSHU單元和DOT單元
;將61H中的低4位移入60H中的高4位,得到溫度的整數部分,並存於ZHENGSHU單元
MOV 29H,61H
MOV A,60H
MOV C,48H
RRC A
MOV C,49H
RRC A
MOV C,4AH
RRC A
MOV C,4BH
RRC A
MOV ZHENGSHU,A
; ( M每度-M剩餘)/ M每度,小數值存於A中
MOV A,67h
SUBB A,66h
MOV B,#64H
MUL AB
MOV R4,B
MOV R5,A
MOV R7,67H
LCALL DIV457
MOV A,R3
;再減去0.25,實際應用中減去25
SUBB A,#19H
MOV DOT,A ;小數部分存於DOT中
MOV A,ZHENGSHU
SUBB A,#00H ;整數部分減去來自小數部分的借位
MOV ZHENGSHU,A
MOV C,4BH
JNC ZHENG ;是否為負數
CPL A
INC A
MOV DIS_1,#2DH ; 零度以下時,第一位顯示"-"號
MOV ZHENGSHU,A
ZHENG:
MOV DIS_1,#2BH ; 零度以上時,第一位顯示"+"號
RET
;------------------------
;雙位元組除以單位元組子程序
;------------------------
DIV457: CLR C
MOV A,R4
SUBB A,R7
JC DV50
SETB OV ;商溢出
RET
DV50: MOV R6,#8 ;求平均值(R4R5/R7-→R3)
DV51: MOV A,R5
RLC A
MOV R5,A
MOV A,R4
RLC A
MOV R4,A
MOV F0,C
CLR C
SUBB A,R7
ANL C,/F0
JC DV52
MOV R4,A
DV52: CPL C
MOV A,R3
RLC A
MOV R3,A
DJNZ R6,DV51
MOV A,R4 ;四捨五入
ADD A,R4
JC DV53
SUBB A,R7
JC DV54
DV53: INC R3
DV54: CLR OV
RET
;---------------------
;轉換成非壓縮的BCD碼
;---------------------
BCD: MOV A,ZHENGSHU
MOV B,#0AH
DIV AB
ORL A,#00110000B ;轉換成ASCII碼
MOV DIS_2,A
MOV DIS_3,B
MOV A,DIS_3
ORL A,#00110000B ;轉換成ASCII碼
mov DIS_3,A
MOV A,DOT
MOV B,#0AH
DIV AB
ORL A,#00110000B ;轉換成ASCII碼
MOV DIS_4,A
MOV DIS_5,B
MOV A,DIS_5
ORL A,#00110000B ;轉換成ASCII碼
mov DIS_5,A
RET
;----------------------
;串口顯示數據子程序
;----------------------
DISPLAY:
CLR TI
MOV A,DIS_1
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示+/-
CLR TI
MOV A,DIS_2
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示整數第一位
CLR TI
MOV A,DIS_3
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示整數第二位
CLR TI
MOV A,#2EH
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示小數點
CLR TI
MOV A,DIS_4
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示小數第一位
CLR TI
MOV A,DIS_5
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示小數第一位
CLR TI
MOV A,#0DH;換行
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示
CLR TI
MOV A,#0AH;換行
MOV SBUF,A
JNB TI,$ ;發送給PC,通過串口調試助手顯示
RET
;----------------------
;延時子程序
;----------------------
;為保證DS18B20的嚴格I/O時序,需要做較精確的延時
;在DS18B20操作中,用到的延時有15 μs,90 μs,270 μs,540 μs
;因這些延時均為15 μs的整數倍,因此可編寫一個DELAY15(n)函數
DELAY: ;11.05962M晶振
LOOP: MOV R1,#06H
LOOP1: DJNZ R1,LOOP1
DJNZ R0,LOOP
RET
;500毫秒延時子程序,佔用R4、R5
DELAY500:MOV R4,#248
DA222:MOV R5,#248
DJNZ R5,$
DJNZ R4,DA222
RET
END