為了加深對于底層驅(qū)動開發(fā)的認(rèn)識和理解,樓主決定自擼常見模塊,傳感器的驅(qū)動程序。-------立貼為證。 DS18B20是一款單總線可編程分辨率的數(shù)字溫度計(jì),詳細(xì)內(nèi)容可見中英文datasheet,筆者不在贅述。 很早就接觸到的溫度傳感器,也相信每一個(gè)曾學(xué)習(xí)過嵌入式開發(fā)的人都用過,筆者在STM32F4上自碼DS18B20驅(qū)動,有些小小心得: 1.初始化時(shí)序要注意,筆者親測,在MCU控制單總線為低電平240us即可(數(shù)據(jù)手冊上要求至少480us)釋放總線,等待60us后即可檢測到到DS18B20返回的拉低單總線信號,此處,需注意至少應(yīng)在此等待120us,否則可能會導(dǎo)致溫度傳感器無法正常工作。 2.初學(xué)者需注意時(shí)序,對于DS18B20的操作都必需經(jīng)過三步:初始化,ROM命令(多為跳過指令0xCC),DS18B20功能命令。再次強(qiáng)調(diào)對其的每一個(gè)操作必須經(jīng)過這三步,可閱讀code加深理解。 3.在讀取DS18B20時(shí),注意順序,DS18B20先發(fā)送低位,在字節(jié)讀取時(shí)應(yīng)當(dāng)注意。 4.初學(xué)者應(yīng)嘗試實(shí)現(xiàn)對于DS18B20內(nèi)部ROM的8位系列號(28H),和48位唯一序列號進(jìn)行讀取,以及修改溫度傳感器內(nèi)部EEPROM的過溫、低溫報(bào)警值。(可參考筆者code)
廢話不多說,上碼:
- #include <ds18b20.h>
- #include "delay.h"
- #include "usart.h"
-
- //ds18b20初始化
- void init_ds18b20( void )
- {
- init_onewire_out();
- GPIO_ResetBits(GPIOG,GPIO_Pin_9);
- delay_us(480);
- init_onewire_in();
- delay_us(60);
- if( !DQ_In)
- {
- delay_us(120);
-
- }
- }
- //ds18b20 檢測
- void chack_ds18b20( void )
- {
- init_onewire_out();
- GPIO_ResetBits(GPIOG,GPIO_Pin_9);
- delay_us(240);
- init_onewire_in();
- delay_us(60);
- if( !DQ_In)
- {
- delay_us(80);
- if( !DQ_In )
- printf("檢測到DS18B20!\r\n");
-
- }
-
- }
- //設(shè)置為主設(shè)備寫總線,從設(shè)備讀總線
- void init_onewire_out( void )
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時(shí)鐘
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通輸出模式
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽輸出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
- }
- //設(shè)置為主設(shè)備讀取總線,從設(shè)備寫總線
- void init_onewire_in( void )
- {
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時(shí)鐘
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通輸入模式
- // GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽輸出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
- GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
- }
-
- void ds18b20_write_byte( u8 data )
- {
- u8 i;
- u8 j=0;
- init_onewire_out();
- for(i=0;i<8;i++)
- {
- j=data & 0x01;
- if(j)
- {
- DQ_Out=0; //寫1
- delay_us(15);
- DQ_Out=1;
- delay_us(60);
-
- }
- else
- {
- DQ_Out=0; //寫0
- delay_us(60);
- DQ_Out=1;
- delay_us(1);
- }
- data = data>>1;
- }
- }
- //讀取DS18B20 的一位
- u8 ds18b20_read_bit( void )
- {
- u8 bit;
- init_onewire_out();
- DQ_Out=0;
- delay_us(2);
- DQ_Out=1;
- init_onewire_in();
- delay_us(12);
- if(DQ_In)
- bit=1;
- else
- bit=0;
- delay_us(50);
- return bit;
- }
- //讀ds18b20的字節(jié)
- u8 ds18b20_read_byte ( void )
- {
- u8 data=0;
- u8 i;
- u8 j=0;
- for(i=0;i<8;i++)
- {
- j=ds18b20_read_bit();
- if(j) //注意順序即可,ds18b20先發(fā)送地位到總線上
- j=j<<i;
- data |=j;
-
- }
- return data;
- }
- //獲取ds18b20的系列碼和48位唯一序列號
- void ds18b20_read_rom_number()
- {
- u32 number=0;
- u8 data,i,serial_num,ds18b20_crc;
- init_ds18b20();
- ds18b20_write_byte(0x33);
- serial_num = ds18b20_read_byte();
- for(i=0;i<6;i++)
- {
- data = ds18b20_read_byte();
- number |= data;
- number = number<<8;
- }
- ds18b20_crc = ds18b20_read_byte();
-
- printf("系列號是:%d\r\n",serial_num);
- printf("序列號是:%d\r\n",number);
- printf("CRC校驗(yàn)為:%d\r\n",ds18b20_crc);
-
- }
- //開啟ds18b20溫度轉(zhuǎn)換
- void tem_chage( void )
- {
- init_ds18b20();
- ds18b20_write_byte(0xcc); //忽略rom指令
- ds18b20_write_byte(0x44); //開啟轉(zhuǎn)換
- }
-
- short get_temp( void )
- {
- int temp=0;
- u8 i,TH,TL;
- short tem;
-
- tem_chage();
- delay_us(10);
- init_ds18b20();
- ds18b20_write_byte(0xcc); //忽略rom指令
- ds18b20_write_byte(0xbe); //讀取溫度轉(zhuǎn)換值
- TL=ds18b20_read_byte();
- TH=ds18b20_read_byte();
-
- if(TH > 7) //通過判讀存儲器的高五位的0,1來判斷溫度的正負(fù),
- {
- temp = 0; //為負(fù)
- TH =~TH;
- TL =~TL;
- }
- else
- temp = 1; //為正
- tem = TH;
- tem =tem<<8;
- tem =tem+TL;
- tem = (double)tem * 0.625;
- if(temp)
- return tem;
- else
- return -tem;
-
- }
- void ds18b20_return_TH_TL_CONF( void )
- {
- char data,data_TH,data_TL,CONF;
- init_ds18b20();
- ds18b20_write_byte(0xcc); //忽略rom指令
- ds18b20_write_byte(0xbe); //讀取溫度轉(zhuǎn)換值
- data = ds18b20_read_byte();
- data = ds18b20_read_byte();
- data_TH = ds18b20_read_byte();
- data_TL = ds18b20_read_byte();
- CONF =ds18b20_read_byte();
- printf("過溫報(bào)警的溫度為:%d℃\r\n",data_TH);
- printf("低溫報(bào)警的溫度為:%d℃\r\n",-(data_TL-128));
- CONF &=0x60 ;
- CONF =CONF>>5;
- switch (CONF) {
- case 0:
- printf("ds18b20的測量精度為9位,精度為0.5℃\r\n");
- break;
- case 1:
- printf("ds18b20的測量精度為10位,精度為0.25℃\r\n");
- break;
- case 2:
- printf("ds18b20的測量精度為11位,精度為0.125℃\r\n");
- break;
- case 3:
- printf("ds18b20的測量精度為12位,精度為0.0625℃\r\n");
- break;
- default:
- printf("error!!\r\n");
- break;
- }
- }
- //設(shè)置溫度報(bào)警值和配置精度,TH過溫報(bào)警值(TH>0),TL低溫報(bào)警值(TL為負(fù)數(shù) ),mode配置模式0,1,2,3
- //mode=0 精度為9位 00011111 dat=31
- //mode=1 精度為10位 00111111 dat=63
- //mode=2 精度為11位 01011111 dat=95
- //mode=3 精度為12位 01111111 dat =127
- void ds18b20_write_TH_TL_CONF(u8 TH,u8 TL,u8 mode)
- {
- u8 dat;
- switch (mode){
- case 0:
- dat=31;
- break;
- case 1:
- dat=63;
- break;
- case 2:
- dat=95;
- break;
- case 3:
- dat=127;
- break;
- default:
- printf("mode error!!\r\n");
- dat=127;
- break;
- }
- TL=TL+128;
- init_ds18b20();
- ds18b20_write_byte(0xcc); //忽略rom指令
- ds18b20_write_byte(0x4e); //寫入暫存寄存器 ,過溫和低溫報(bào)警值
- ds18b20_write_byte(TH); //寫入20°為過溫報(bào)警值
- ds18b20_write_byte(TL); //寫入-20°為低溫報(bào)警值
- ds18b20_write_byte(dat); //寫入精度
- init_ds18b20();
- ds18b20_write_byte(0xcc); //忽略rom指令
- ds18b20_write_byte(0x48); //將寫入的暫存寄存器拷入EEPROM
- }
- void ds18b20_chack_self( void )
- {
- chack_ds18b20();
- ds18b20_read_rom_number();
- ds18b20_return_TH_TL_CONF();
- }
復(fù)制代碼
筆者用串口助手得到結(jié)果如下: 
|