一、前言
繼上次發(fā)布的光照傳感器講解,這次繼續(xù)講一些簡單的適合大學(xué)生學(xué)習(xí)使用的傳感器。這次要講的是一款溫度傳感器,想要完整代碼工程的,可以在文章末尾的鏈接下載。
二、芯片介紹
1、簡介
DS18B20是一款數(shù)字型溫度傳感器,這款傳感器已經(jīng)有長的歷史了,驅(qū)動方式簡單,很適合初學(xué)者使用,具體的我就不多說了,很多人應(yīng)該都是知道這個(gè)傳感器的。
2、引腳定義
引腳 | 名稱 | 說明 |
---|---|---|
1 | GND | 供電電源負(fù)極 |
2 | DQ | 數(shù)據(jù)輸入輸出引腳(和單片機(jī)IO口相連的時(shí)候一定要接上拉電阻) |
3 | VCC | 供電電源正極 |
3、通訊方式
DS18B20用的是單總線方式,單片機(jī)給DQ引腳輸出一定規(guī)則的時(shí)序信號即可配置和驅(qū)動DS18B20,同樣的,單片機(jī)按照時(shí)序接收DS18B20發(fā)送的數(shù)據(jù)即可得到溫度數(shù)據(jù)。
4、工作原理
DS18B20通過傳感電路把溫度轉(zhuǎn)換成對應(yīng)的電壓信息,然后轉(zhuǎn)換成數(shù)字信號,再把溫度相關(guān)的數(shù)據(jù)存到自身的寄存器里面,單片機(jī)去讀取這些數(shù)據(jù),就可以知道當(dāng)前的溫度了。簡單的說就是把模擬信號轉(zhuǎn)換成數(shù)字信號,然后把這些數(shù)據(jù)存起來交給單片機(jī),大概的原理是這樣,如果你想繼續(xù)深入了解,可以去找一下相關(guān)的文章,關(guān)于這方面的介紹有很多。
三、編程講解
1、DS18B20驅(qū)動程序
//單片機(jī)只需要用一個(gè)普通的IO口和DS18B20的DQ引腳相連,然后控制這個(gè)IO口輸出高低電平即可
//復(fù)位DS18B20
//作用:復(fù)位
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //把單片機(jī)的IO口配置為輸出
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us,這個(gè)時(shí)間是根據(jù)DS18B20本身的規(guī)則定的,可以在數(shù)據(jù)手冊找到相關(guān)介紹
DS18B20_DQ_OUT=1; //拉高DQ
delay_us(15); //15US
}
//等待DS18B20的回應(yīng)
//作用:檢查單片機(jī)和DS18B20的通訊是否正常
//返回1:未檢測到DS18B20的存在(可能是DQ引腳沒有上拉電阻,通訊的時(shí)序不對,芯片損壞等原因)
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();//把IO口配置為輸入,目的是為了接收DS18B20發(fā)過來的數(shù)據(jù)
while (DS18B20_DQ_IN&&retry<200)//如果IO口是低電平,則是正常的,否則一直進(jìn)while循環(huán)
{
retry++;
delay_us(1);
};
if(retry>=200)
{//通訊有誤,返回1
return 1;
}
else
{//正常
retry=0;
}
while (!DS18B20_DQ_IN&&retry<240)//繼續(xù)讀取電平,如果IO口是高電平,則是正常的
{
retry++;
delay_us(1);
};
if(retry>=240)
{//通訊有誤,返回1
return 1;
}
return 0;//通訊正常,返回0
}
//從DS18B20讀取一個(gè)位
//作用:讀取一個(gè)位數(shù)據(jù),重復(fù)調(diào)用該函數(shù)可以把溫濕度數(shù)據(jù)讀出來
//返回值:1/0
u8 DS18B20_Read_Bit(void) // read one bit
{
u8 data;
DS18B20_IO_OUT();//單片機(jī)輸出一個(gè)由低到高的上升沿脈沖給DS18B20
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();//把IO口配置為輸入,讀取電平
delay_us(12);
if(DS18B20_DQ_IN)//如果是高電平,則DS18B20輸出的數(shù)據(jù)是'1',否則為'0'
data=1;
else
data=0;
delay_us(50);
return data;
}
//從DS18B20讀取一個(gè)字節(jié)
//作用:連續(xù)讀8個(gè)位,并合成一個(gè)字節(jié)數(shù)據(jù)
//返回值:讀到的數(shù)據(jù)
u8 DS18B20_Read_Byte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();//連續(xù)調(diào)用8次
dat=(j<<7)|(dat>>1);//每次讀取到1個(gè)位的數(shù)據(jù)后左移1位,讀取完8個(gè)位的數(shù)據(jù)之后就可以合成1個(gè)字節(jié)了
}
return dat;//返回合成的1字節(jié)數(shù)據(jù)
}
//寫一個(gè)字節(jié)到DS18B20
//作用:寫數(shù)據(jù)到DS18B20,調(diào)用這個(gè)函數(shù)可以發(fā)送指令控制DS18B20
//dat:要寫入的字節(jié)
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;//把傳進(jìn)來的這個(gè)數(shù)據(jù)的最高位提取出來
dat=dat>>1;//dat的數(shù)據(jù)左移1位,作用是把次高位移到最高位
if (testb) //如果最高位數(shù)據(jù)為'1'
{
DS18B20_DQ_OUT=0;// Write 1
delay_us(2);
DS18B20_DQ_OUT=1;//輸出60us高電平,相當(dāng)于告訴DS18B20要傳的數(shù)據(jù)是'1'
delay_us(60);
}
else //如果最高位數(shù)據(jù)為'0'
{
DS18B20_DQ_OUT=0;//輸出60us低電平,相當(dāng)于告訴DS18B20要傳的數(shù)據(jù)是'0'
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//開始溫度轉(zhuǎn)換
//作用:從DS18B20中讀取溫度數(shù)據(jù)
void DS18B20_Start(void)// ds1820 start convert
{
DS18B20_Rst();//復(fù)位
DS18B20_Check();//檢查單片機(jī)和DS18B20的通訊是否正常
DS18B20_Write_Byte(0xcc);//尋址總線上的所有從設(shè)備,詳細(xì)說明可以參考數(shù)據(jù)手冊ROM COMMANDS
DS18B20_Write_Byte(0x44);//0x44命令為啟動溫度轉(zhuǎn)換命令,詳細(xì)說明可以參考數(shù)據(jù)手冊ROM COMMANDS
}
//初始化DS18B20的IO口DQ 同時(shí)檢測DS18B20的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA口時(shí)鐘
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0); //輸出1
DS18B20_Rst();//復(fù)位
return DS18B20_Check();
}
//從ds18b20得到溫度值
//精度:0.1C
//返回值:溫度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
//DS18B20_Start (); //開始采集溫度
DS18B20_Rst();//復(fù)位
DS18B20_Check();//檢查單片機(jī)和DS18B20通訊是否正常
DS18B20_Write_Byte(0xcc);//尋址總線上的所有從設(shè)備,詳細(xì)說明可以參考數(shù)據(jù)手冊ROM COMMANDS
DS18B20_Write_Byte(0xbe);//0x44命令為啟動溫度轉(zhuǎn)換命令,詳細(xì)說明可以參考數(shù)據(jù)手冊ROM COMMANDS
TL=DS18B20_Read_Byte(); //讀取數(shù)據(jù)低字節(jié)
TH=DS18B20_Read_Byte(); //讀取數(shù)據(jù)高字節(jié)
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//溫度為負(fù)
}
else
{
temp=1;//溫度為正
}
tem=TH;//獲得高字節(jié)數(shù)據(jù)
tem<<=8;//高字節(jié)位左移8位
tem+=TL;//左移的高8位加上低8位合成一個(gè)16位數(shù)據(jù)
tem=(float)tem*0.625;//從DS18B20讀取到的2個(gè)字節(jié)的數(shù)據(jù)還不是溫度值,需要轉(zhuǎn)換,轉(zhuǎn)換公式參考數(shù)據(jù)手冊
if(temp)
{
return tem; //返回溫度值
}
else
{
return -tem;
}
}
2、main函數(shù)
int main()
{
short temperature;
uart_init(115200); //串口初始化為115200
LED_Init(); //初始化與LED連接的硬件接口
OLED_Init(); //OLED初始化
OLED_Clear(); //OLED清屏
while(DS18B20_Init()) //DS18B20初始化
{
OLED_ShowString(50,2,"error",12);//DS18B20通訊有問題
}
while(1)
{
//讀取溫度
temperature=DS18B20_Get_Temp();
if(temperature<0)//溫度低于0
{
OLED_ShowString(50,4,"-",16); //顯示負(fù)號
temperature=-temperature; //轉(zhuǎn)為正數(shù)
}
else //溫度大于0
{
OLED_ShowString(50,4," ",16); //不顯示負(fù)號,也不顯示正號
}
OLED_ShowCHinese(0,4,0);//顯示中文字體“溫”
OLED_ShowCHinese(16,4,1);//顯示中文字體“度”
OLED_ShowString(32,4,":",16);
OLED_ShowNum(60,4,temperature/10,2,16); //顯示整數(shù)部分
OLED_ShowString(80,4,".",16);
OLED_ShowNum(88,4,temperature%10,1,16); //顯示小數(shù)部分
OLED_ShowCHinese(100,4,9);//顯示“℃”
}
好了,關(guān)于這個(gè)傳感器的介紹就到這里吧。
鏈接:https://pan.baidu.com/s/1pIcwctU0q1EWM7975JWrnQ ,提取碼:bbhc
創(chuàng)作不易,希望你們尊重別人的勞動,點(diǎn)贊+關(guān)注支持一下吧,謝謝大家了,博主也會繼續(xù)寫更多的大學(xué)生專欄,如果你們還有什么問題,可以評論留言或者私信給我