天天看點

驅動程式一:基于STM32自碼 DS18B20驅動程式

為了加深對于底層驅動開發的認識和了解,樓主決定自撸常見子產品,傳感器的驅動程式。-------立貼為證。

DS18B20是一款單總線可程式設計分辨率的數字溫度計,詳細内容可見中英文datasheet,筆者不在贅述。

很早就接觸到的溫度傳感器,也相信每一個曾學習過嵌入式開發的人都用過,筆者在STM32F4上自碼DS18B20驅動,有些小小心得:

1.初始化時序要注意,筆者親測,在MCU控制單總線為低電平240us即可(資料手冊上要求至少480us)釋放總線,等待60us後即可檢測到到DS18B20傳回的拉低單總線信号,此處,需注意至少應在此等待120us,否則可能會導緻溫度傳感器無法正常工作。

驅動程式一:基于STM32自碼 DS18B20驅動程式

2.初學者需注意時序,對于DS18B20的操作都必需經過三步:初始化,ROM指令(多為跳過指令0xCC),DS18B20功能指令。再次強調對其的每一個操作必須經過這三步,可閱讀code加深了解。

3.在讀取DS18B20時,注意順序,DS18B20先發送低位,在位元組讀取時應當注意。

4.初學者應嘗試實作對于DS18B20内部ROM的8位系列号(28H),和48位唯一序列号進行讀取,以及修改溫度傳感器内部EEPROM的過溫、低溫報警值。(可參考筆者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");
				
	}

}
//設定為主裝置寫總線,從裝置讀總線
void init_onewire_out( void )
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時鐘
	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);//初始化
}
//設定為主裝置讀取總線,從裝置寫總線
void init_onewire_in( void )
{
	
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時鐘
	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的位元組
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先發送地位到總線上
			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校驗為:%d\r\n",ds18b20_crc);
	
}
//開啟ds18b20溫度轉換
void tem_chage( void )
{
	init_ds18b20();
	ds18b20_write_byte(0xcc);		//忽略rom指令
	ds18b20_write_byte(0x44);	//開啟轉換
}

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);	//讀取溫度轉換值
	TL=ds18b20_read_byte();
	TH=ds18b20_read_byte();
	
	if(TH > 7) 		//通過判讀存儲器的高五位的0,1來判斷溫度的正負,
	{
		temp = 0;	//為負
		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);	//讀取溫度轉換值
	data = ds18b20_read_byte();
	data = ds18b20_read_byte();
	data_TH = ds18b20_read_byte();
	data_TL = ds18b20_read_byte();
	CONF =ds18b20_read_byte();
	printf("過溫報警的溫度為:%d℃\r\n",data_TH);
	printf("低溫報警的溫度為:%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;
	}
}
//設定溫度報警值和配置精度,TH過溫報警值(TH>0),TL低溫報警值(TL為負數 ),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);	//寫入暫存寄存器 ,過溫和低溫報警值
	ds18b20_write_byte(TH);	//寫入20°為過溫報警值
	ds18b20_write_byte(TL);	//寫入-20°為低溫報警值
	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();
}



           

筆者用序列槽助手得到結果如下:

驅動程式一:基于STM32自碼 DS18B20驅動程式

繼續閱讀