?? ds18b20.c
字號:
#include "inc/config.h"
#define DQ_18B20 (1<<3) // PD3
#define DQ_TO_0() (DDRD |= DQ_18B20) // PD3='0'
#define DQ_TO_1() (DDRD &= ~DQ_18B20) // PD3='float'
#define DQ_status() (PIND & DQ_18B20) // read PD3 pin
/* 請認真檢查你的AVR微控制器的時鐘頻率! 特別注意:頻率
* 定義的單位是MHz! 并且請使用浮點數! 假如你的晶振是12MHz,
* 你應該寫成12.0000或12.0之類。
* 我的實驗電路的晶振是8.0000MHz
*/
#ifndef CPU_CRYSTAL
#define CPU_CRYSTAL (8.0000)
#endif
#define wait_us(us)\
_delay_loop_2((u16)((us)*CPU_CRYSTAL/4))
/*---------------- 函數原型聲明 ------------------*/
// 1個初始化模塊
void ds18b20_config(void); // 配置端口
// 3個基本模塊
inline BOOL ds18b20_reset(void); // 復位DS18B20
void ds18b20_write(u08 dat); // 寫字節到DS18B20
u08 ds18b20_read(void); // 讀字節從DS18B20
// 2個應用模塊
BOOL convert_T(void); // 啟動溫度轉換
u08 read_T(void); // 讀取轉換值
/*-------------------------------------------------------
* 配置(使能)AVR與DS18B20的接口
*/
void ds18b20_config(void)
{
DDRD &= ~DQ_18B20; // 輸入模式(上電時為高電平)
PORTD &= ~DQ_18B20; // 輸出鎖存器寫0,以后不再更改
}
/*-------------------------------------------------------
* 復位1-wire總線,并探測是否有溫度芯片DS18B20(TO-92
* 封裝)掛在總線上,有返回SUCC,沒有返回FAIL
*/
BOOL _ds18b20_reset(void)
{
BOOL bus_flag;
DQ_TO_0(); // 設置1-wire總線為低電平(占領總線)...
/* 現在延遲480us~960us, 與硬件密切相關,但應盡可能選小值(480us),
把抖動留給系統(比如在延遲期間發生中斷導致延遲變長)。
*/
wait_us(490); // 490us
cli(); // 下面這段時間要求比較嚴格,為保險起見,關中斷
DQ_TO_1(); // 設置1-wire總線為高電平(釋放總線)
/* 這個浮點數是由編譯器計算好的,而不是由你的MCU在運行時臨時計算的,
所以不會占用用戶MCU的時間,不必擔心(看看前面的宏你就可以確定了)
*/
wait_us(67.5); // 最佳時間: 60us+7.5us!(忙延時,只是一種策略)
// 探測總線上是否有器件
if(DQ_status()) bus_flag=FAIL; // 復位單總線但沒有發現有器件在線
else bus_flag=SUCC; // 復位單總線并發現有器件在線
sei(); // 退出臨界代碼區(開中斷)
/* 保證Master釋放總線的時間(不是說總線處于高電平的時間)不小于
480us即可,這一時間從讀總線狀態之前就開始了,所以這里把這個
時間計算在內。在Master釋放總線的前半段,也是被動器件聲明它
們在線之時。
*/
wait_us(490-67.5); // 490-67.5us
return(bus_flag);
}
/*--------------------------------------------------------
* 復位函數冗余處理
*/
inline BOOL ds18b20_reset(void)
{
u08 Cnt = 0;
while(!(_ds18b20_reset() == SUCC))
{
Cnt++;
if(Cnt > 3)
return FAIL ;
}
return SUCC ;
}
/*--------------------------------------------------------
* 寫命令或數據到溫度芯片DS18B20(發送一個字節)
*/
void ds18b20_write(u08 dat)
{
u08 count;
// 每個字節共8位,一次發一位
for(count=0; count<8; count++) {
cli(); // 保證絕對不會發生中斷!
DQ_TO_0(); // 設置1-wire總線為低電平
wait_us(2); // about 2us
if(dat&0x01) DQ_TO_1(); // 并串轉換,先低位后高位
else DQ_TO_0();
dat >>= 1; // 下一位做好準備
// 60us~120us(實際不能到120us, 因為其它語句也用時間了!)
wait_us(62); // 62us
DQ_TO_1();
sei(); // 恢復系統中斷
wait_us(2); // 2us
}
}
/*---------------------------------------------------------
* 從溫度芯片DS18B20讀配置或數據(接收一個字節)
*/
u08 ds18b20_read(void)
{
u08 count,dat;
dat = 0x00; // 數據接收準備
// 每個字節共8位,一次收一位
for(count=0; count<8; count++) {
cli(); // 保證絕對不會發生中斷!
// 從總線拉低到讀總線狀態,不能大于15us!
DQ_TO_0(); // 設置1-wire總線為低電平(拉低總線以同步)
wait_us(2); // 2us
DQ_TO_1(); // 設置1-wire總線為高電平(釋放總線)
wait_us(4); // 4us
dat >>= 1;
if(DQ_status()) dat|=0x80; // 讀取總線電平,先收低位再收高位
sei(); // 恢復系統中斷
wait_us(62); // 必須大于60us
}
return(dat);
}
/*-------------------------------------------------------
* 我的電路中只有一個器件DS18B20,所以不需要多個器件的ID
* 識別,跳過之后,啟動溫度轉換,但在啟動后,用戶應等待幾百個
* 毫秒,才能讀到這次的轉換值,這是DS18B20的數據手冊規定的。
* 因為溫度轉換是需要時間的嘛!(^_^)
*/
BOOL convert_is_succ = FALSE ;
BOOL convert_T(void)
{
if(ds18b20_reset()==SUCC) { // 如果復位成功
ds18b20_write(0xcc); // 跳過多器件識別
ds18b20_write(0x44); // 啟動溫度轉換
convert_is_succ = TRUE;
return TRUE ;
}
else
{
convert_is_succ = FALSE;
return FALSE ;
}
}
/*********************************************************************************************************
** 函數名稱: CRC8_Dallas
** 功能描述: DS18B20的CRC8校驗
** 輸 入: 需校驗的值
** 輸 出: 單字節CRC結果
** 全局變量: 無
** 調用模塊:
********************************************************************************************************/
u08 CRC8_Dallas(u08 Data,u08 CRC_Dallas)
{
u08 i;
u08 flag ;
CRC_Dallas^=Data;
for (i = 0; i < 8; i++)
{
flag = ( CRC_Dallas & (1<<0) );
CRC_Dallas >>= 1;
if (flag) CRC_Dallas ^= 0x8c; // b10001100 es la palabra del CRC (x8 + x5 + x4 + 1)
// 7..43..0 junto con el 1 aplicado a f.
}
return CRC_Dallas;
}
/*-------------------------------------------------------
* 讀取轉換后的溫度值
* 我假定DS18B20一定是正確的,所以沒有返回有關狀態。當你故意
* 把DS18B20從電路中拔下而能讓程序告訴你出錯時,你可以自己修
* 改這段代碼!
*/
u08 read_T(void)
{
u16 value = 0xee01;
u08 valueL;
u08 valueH;
u08 crc8;
u08 Cnt = 0;
if(convert_is_succ == FALSE)
{
return FALSE;
}
while(ds18b20_reset()==SUCC)
{ // 如果復位成功
ds18b20_write(0xcc); // 跳過多器件識別
ds18b20_write(0xbe); // 讀暫存器
valueL = ds18b20_read(); // 低字節
valueH = ds18b20_read(); // 高字節
value = ((uint16)valueH<<8) + valueL ;
crc8=CRC8_Dallas( valueL,0 );
crc8=CRC8_Dallas( valueH,crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
crc8=CRC8_Dallas( ds18b20_read(),crc8 );
if(crc8 == 0)
{
break;
}
else
{
Cnt++ ;
if(Cnt > 3)
{
value = 0xee02 ;
break;
}
}
}
Temperature = value *10/16;
if( (value & 0xff00) == 0xee00 )
{
return FALSE ;
}
else
{
return TRUE ;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -