|
//******************************************************************************
// 用于河北北方學院宣化教學部2015級單片機課程實驗的
// 單線數字溫度傳感器DS18B20的C51驅動代碼
//
// 代碼沿革
// 創建: 2015年4月1日
// 修改: 2015年4月4日,代碼優化
// 2015年4月9日,注釋
// 版權聲明
// 1.版權擁有者是河北北方學院宣化教學部2005級單片機課程全體學生及該課程任課
// 教師.
// 2.任何團體或個人均可無條件使用本代碼, 但版權擁有者不對由此引起的任何直接
// 或間接后果負擔任何法律責任
// 3.一旦部分或全部使用本代碼,則必須在源程序文檔中無條件包含本版權聲明
//******************************************************************************
#include "DS18b20.h"
#include "reg52.h"
//******************************************************************************
// DS18B20復位和初始化函數: DS18B20_Reset(void)
// 功能: 8051發出時間長度>=480us的低電平到數據線,然后拉高數據線維持15~60us
// 輸入: 無
// 輸出: DS18B20被復位
// 返回: 無
//******************************************************************************
void DS18B20_Reset(void)
{
uchar i;
DQ = 0; //拉低數據線DQ
i = 80; //使用12MHz晶體時用80,根據晶體頻率按比例增減i的值
while(i--); //軟件延時,"while(i--);"的反匯編代碼單次循環消耗6us,80*6us=480us
DQ = 1;
i = 5; //使用12MHz晶體時用5,根據晶體頻率按比例增減
while(i--); //軟件延時,"while(i--);"的反匯編代碼單次循環消耗6us,5*6us=30us
}
//******************************************************************************
// 讀取一位數據函數: bit bitread(void)
// 功能: 51發長3us的低電平到數據線, 然后拉高數據線7us,再讀回數據線,最后由軟件延
// 時消耗掉60us位時間的剩余部分.
// 輸入: 無
// 輸出: 無
// 返回: 位值
//******************************************************************************
bit bitread(void)
{
uchar i;
bit dat;
DQ = 0; //拉低數據線DQ
i++; //模擬1~15us的延時,反匯編顯示實際延時3us
DQ = 1; //拉高數據線DQ
i++; i++; //適當延時,反匯編顯示實際延時7us
dat = DQ; //至此,DS18B20會在DQ上給出位值,讀回此位值
i = 8; //從DQ拉低至此,反匯編顯示已耗時13us, 60us-13us=47us約=48us
while(i--); //軟件延時,"while(i--);"的反匯編代碼單次循環消耗6us,8*6us=48us
return(dat); //返回位值
}
//******************************************************************************
// 讀取一個字節數據函數: uchar byteread(void)
// 功能: 通過8次調用讀取一位函數, 從DS18B20讀回一個字節值,注意先讀的是最低位
// 輸入: 無
// 輸出: 無
// 返回: 字節值
//******************************************************************************
uchar byteread(void)
{
uchar i, j, dat;
dat = 0;
for(i=1; i<=8; i++)
{
j = bitread(); //順序讀8個位
dat >>= 1;
dat |= (j<<7); //組裝成一個字節
}
return(dat); //返回字節值
}
//******************************************************************************
// 寫一個字節數據或命令函數: bytewrite(uchar dat)
// 功能: 寫一個字節數據或命令到DS18B20中
// 輸入: dat是準備寫入DS18B20的一個命令字節或數據字節
// 輸出: 命令字節或數據字節被寫入DS18B20中
// 返回: 無
// 按位寫入: 位值1寫法:在DQ上發 1~ 15us低電平后跟高電平,應使位時間>=60us
// 位值0寫法:在DQ上發60~120us低電平后跟高電平,應使位時間>=60us
// 注意:延時時間的統計計算需要瀏覽反匯編代碼
//******************************************************************************
void bytewrite(uchar dat)
{
uchar i, j;
for(j=0; j<8; j++)
{
if(dat&0x01) //如果當前位的值為1,發1~15us低電平后跟高電平到數據線DQ
{
DQ = 0; //拉低數據線DQ
DQ = 0; //延時1us
DQ = 0; //到此共延時2us, 1us<2us<15us
DQ = 1; //拉高數據線DQ
i = 7; //自DQ拉低后到此語句執行完畢共耗時4us
while(i--); //每次循環耗時8us,7*8us=56us, 56us+4us=60us
}
else //如果當前位的值為0,發60~120us低電平后跟高電平到數據線DQ
{
DQ = 0; //拉低數據線DQ
i = 8; while(i--); //延時約65us, 60us<65us<120us
DQ =1; //拉高數據線DQ
DQ =1; //延時1us
DQ =1; //延時2us
}
dat = dat>>1; //右移,準備下一個位
}
}
//******************************************************************************
// 溫度轉換啟動函數: uchar DS18B20_Start(void)
// 功能: 復位DS18B20并檢測其是否在位,若在位則啟動溫度轉換
// 輸入: 無
// 輸出: 若DS18B20在位,啟動溫度轉換過程
// 返回: 0啟動失敗,1啟動成功
//******************************************************************************
uchar DS18B20_Start(void)
{
uchar i = 10;
DS18B20_Reset(); //復位DS18B20,返回時DQ已拉高,DS18B20最多60us后發在位脈沖
while((DQ==1) && //等待DS18B20在數據線DQ上發低電平在位脈沖
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i遞減到0之前檢測到DQ被拉低,說明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脈沖發完(持續60~120us)
bytewrite(0xcc); //寫"跳過ROM檢測命令"到DS18B20
bytewrite(0x44); //寫"開始溫度轉換命令"到DS18B20
return 1;
}
return 0;
}
//******************************************************************************
// 讀取溫度值函數: DS18B20_Tempread(void)
// 輸入: 無
// 輸出: 無
// 返回: 補碼表示的攝氏溫度值,有符號整型數,若DS18B20異常則返回0x7fff
//******************************************************************************
int DS18B20_Tempread(void)
{
uchar a, b, i = 10;
DS18B20_Reset(); //復位DS18B20,返回時DQ已拉高,DS18B20最多60us后發在位脈沖
while((DQ==1) && //等待DS18B20在數據線DQ上發低電平在位脈沖
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i遞減到0之前檢測到DQ被拉低,說明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脈沖發完(持續60~120us)
bytewrite(0xcc); //寫"跳過ROM檢測命令"到DS18B20
bytewrite(0xbe); //寫"連續讀9個寄存器命令"到DS18B20
a = byteread(); //讀第一個寄存器(溫度值低字節)
b = byteread(); //讀第二個寄存器(溫度值高字節)
; //其余7個寄存器不讀
return (a + (b*256)); //溫度值組裝成一個16位字
}
return 0x7fff; //最高五位正常情況下是值相同的符號位,現為01111,表明DS18B20異常
}
//******************************************************************************
// 配置函數: void DS18B20_Set(uchar v_reg2, v_reg3, v_reg4)
// 配置DS18B20的高溫閥值寄存器,低溫閥值寄存器,分辨率設置寄存器
// 輸入: v_reg2 高溫閥值寄存器的值
// v_reg3 低溫閥值寄存器的值
// v_reg4 分辨率設置寄存器的值
// 輸出: 若DS18B20在位,指定的三個寄存器被配置好
// 返回: 無
//******************************************************************************
void DS18B20_Set(uchar v_reg2, v_reg3, v_reg4)
{
uchar i = 10;
DS18B20_Reset(); //復位DS18B20,返回時DQ已拉高,DS18B20最多60us后發在位脈沖
while((DQ==1) && //等待DS18B20在數據線DQ上發低電平在位脈沖
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i遞減到0之前檢測到DQ被拉低,說明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脈沖發完(持續60~120us)
v_reg4 |= 0x80; //保證最高位TM=1
bytewrite(0xcc); //寫"跳過ROM檢測命令"到DS18B20
bytewrite(0x4e); //寫"連續寫9個寄存器命令"到DS18B20
bytewrite(0x00); //寫第一個寄存器(溫度值低字節,寫無意義,給0)
bytewrite(0x00); //寫第二個寄存器(溫度值高字節,寫無意義,給0)
bytewrite(v_reg2); //寫第三個寄存器(高溫閥值)
bytewrite(v_reg3); //寫第四個寄存器(低溫閥值)
bytewrite(v_reg4); //寫第五個寄存器(分辨率)
; //其余4個寄存器不寫
}
}
//******************************************************************************
//讀取64位ROM
//******************************************************************************
uchar sn[8];
void DS18B20_Readrom(void)
{
uchar i = 10;
DS18B20_Reset(); //復位DS18B20,返回時DQ已拉高,DS18B20最多60us后發在位脈沖
while((DQ==1) && //等待DS18B20在數據線DQ上發低電平在位脈沖
(i--)); //最多等待80us(80us>60us)
if(i!=0) //在i遞減到0之前檢測到DQ被拉低,說明DS18B20在位
{
while(DQ==0); //等待DS18B20把她的在位脈沖發完(持續60~120us)
bytewrite(0x33);
for(i=0; i<8; i++)
sn[ i] = byteread();
}
}
|
|