DS18B20多ROM搜索并读取温度

时间:2021-09-18 01:00:27

测试采用4个DS18B20挂在6m长得网线上面,使用的是5V供电,4.7K上拉,STM32驱动,

程序实现ROM搜索并分别读取每一个DS18B20的温度.




/*************************************************************************************************************
 * 文件名:		ds18b20.c
 * 功能:		STM32 DS18B20驱动
 * 作者:		cp1300@139.com
 * 创建时间:	2012年9月17日22:45
 * 最后修改时间:2012年9月17日
 * 详细:		需要延时函数支持
 * 			注意延时精度尽可能的高
 * 			读取的时候不要长时间的被中断,因为1wire对时间要求很严格
*************************************************************************************************************/
#include "system.h"
#include "delay.h"
#include "ds18b20.h"

//PC1
#define DS18B20_OUT		PBout(15)
#define DS18B20_IN		PBin(15)

//DS18B20使用的是GPIOE0
#define Set18b20IOout()		GPIOx_Init(GPIOB,BIT15,OUT_PP,SPEED_10M);	//设置DS18B20 IO为输出,
#define Set18b20IOin()		GPIOx_Init(GPIOB,BIT15,IN_IPU,0);			//设置DS18B20 IO为上拉输入,
#define Read18b20IO()		((DS18B20_IN) ? 1 : 0)						//读取DS18B20 IO
#define Write18b20IO(x)		(DS18B20_OUT = x)							//写DS18B20 IO








/*************************************************************************************************************************
*函数        :	bool DS18B20_Reset(void)
*功能        :	复位DS18B20
*参数        :	无
*返回        :	TRUE:成功;FALSE:失败
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20120917
*最后修改时间:	20120917
*说明        :无
*************************************************************************************************************************/
bool DS18B20_Reset(void)
{
	u8 i = 0;
	
	Set18b20IOout();		//主机端口推挽输出模式
	Write18b20IO(1);
	Delay_US(1);
	Write18b20IO(0);		//拉低总线480us~240us
	Delay_US(500); 			//>480US延时
	Write18b20IO(1);
	Delay_US(2);			//复位完成
	Set18b20IOin();			//主机端口浮空输入模式
	while(Read18b20IO())	//等待低电平应答信号
	{
		i ++;
		Delay_US(1);
		if(i > 100)
		{
			uart_printf("DS18B20 error!\r\n");
			return FALSE;	//等待超时,初始化失败,返回FALSE;
		}
	}
	Delay_US(250);			//跳过回复信号
	return TRUE;			//检测到DS18B20,并且初始化成功
}



/*************************************************************************************************************************
*函数        :	__inline u8 DS18B20_ReadBit(void)
*功能        :	读取DS18B20 1bit数据
*参数        :	无
*返回        :	数据,最低位有效
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20130402
*最后修改时间:	20130402
*说明        :无
*************************************************************************************************************************/
__inline u8 DS18B20_ReadBit(void)
{
	u8 data = 0;
	
	Set18b20IOout();	//主机端口推挽输出模式
	Write18b20IO(0);	//拉低总线10-15us
	Delay_US(12);
	Write18b20IO(1);	//释放总线
	Set18b20IOin();		//主机端口浮空输入模式
	Delay_US(10);
	if(Read18b20IO())	//读取数据,读取后大约延时40-45us
		data = 0x01;
	Delay_US(40);
	return data;
}


/*************************************************************************************************************************
*函数        :	u8 DS18B20_ReadData(void)
*功能        :	读取DS18B20数据
*参数        :	无
*返回        :	数据
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20120917
*最后修改时间:	20120917
*说明        :无
*************************************************************************************************************************/
u8 DS18B20_ReadData(void)
{
	u8 i,data = 0;
	
	for(i = 0;i < 8;i ++)
	{

		data >>= 1;
		if(DS18B20_ReadBit())
			data |= 0x80;
	}
	return data;
}


/*************************************************************************************************************************
*函数        :	__inline void DS18B20_WriteBit(u8 bit)
*功能        :	向DS18B20写一位数据
*参数        :	数据,只发送最低位
*返回        :	无
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20130402
*最后修改时间:	20130402
*说明        :无
*************************************************************************************************************************/
__inline void DS18B20_WriteBit(u8 bit)
{
	Set18b20IOout();	//主机端口推挽输出模式
   	Write18b20IO(0);		//拉低总线10-15us
	Delay_US(12);
	Write18b20IO(bit & 0x01);	//写入数据位,保持20-45us
	Delay_US(30);
	Write18b20IO(1);		//释放总线
	Delay_US(5);
}


/*************************************************************************************************************************
*函数        :	void DS18B20_WriteData(u8 data)
*功能        :	向DS18B20写数据
*参数        :	数据
*返回        :	无
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20120917
*最后修改时间:	20120917
*说明        :无
*************************************************************************************************************************/
void DS18B20_WriteData(u8 data)
{
	u8 i;
	
	for(i = 0;i < 8;i ++)
	{
		DS18B20_WriteBit(data);
		data >>= 1;
	}
}





/*************************************************************************************************************************
*函数        :	s16 DS18B20_ReadTemper(void)
*功能        :	读取DS18B20温度
*参数        :	无
*返回        :	温度值
*依赖	: 	底层宏定义
*作者        :	cp1300@139.com
*时间     :	20120917
*最后修改时间:	20120917
*说明        :温度值扩大了100倍,温度值是个有符号数.
*************************************************************************************************************************/
s16 DS18B20_ReadTemper(void)
{
	u8 th, tl;
	s16 data;
	
	if(DS18B20_Reset() == FALSE)	
	{
		return 0xffff;	//返回错误
	}

	DS18B20_WriteData(0xcc);	//跳过读序列号
	DS18B20_WriteData(0x44);	//启动温度转换
	DS18B20_Reset();
	DS18B20_WriteData(0xcc);	//跳过读序列号
	DS18B20_WriteData(0xbe);	//读取温度
	tl = DS18B20_ReadData();	//读取低八位
	th = DS18B20_ReadData(); 	//读取高八位
	data = th;
	data <<= 8;
	data |= tl;
	data *= 6.25;				//温度值扩大100倍,精确到2位小数
	
	return data;
}


/*************************************************************************************************************************
*函数        :	__inline u8 DS18B20_Read2Bit(void)
*功能        :	读取DS18B20 2bit数据
*参数        :	无
*返回        :	数据
*依赖		: 	底层宏定义
*作者        :	cp1300@139.com
*时间     	:	20120917
*最后修改时间:	20120917
*说明        :无
*************************************************************************************************************************/
u8 DS18B20_Read2Bit(void)
{
	u8 i,data = 0;
	
	for(i = 0;i < 2;i ++)
	{

		data <<= 1;
		if(DS18B20_ReadBit())
			data |= 1;
	}
	return data;
}









//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//以下代码为多DS18B20相关



#define MAXNUM 4 //定义最多有4个 DS18B20
/*************************************************************************************************************************
*函数        	:	u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num)
*功能        	:	搜索DS18B20 ROM
*参数        	:	pID:DS18B20 ID缓冲区指针
					Num:DS18B20数目,必须事先知道
*返回        	:	搜索到的DS18B20数目
*依赖			: 	底层宏定义
*作者        	:	cp1300@139.com
*时间     		:	2013-04-17
*最后修改时间	:	2013-04-17
*说明        	:	程序必须事先知道DS18B20数目,搜索的数目只会小于这个数目
					代码移植于互联网
*************************************************************************************************************************/
u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num)
{ 
	unsigned char k,l,chongtuwei,m,n;
	unsigned char zhan[(MAXNUM)];
	unsigned char ss[64];
	u8 num = 0;
	l=0;
	
	do
	{
		DS18B20_Reset();
		DS18B20_WriteData(0xf0);	
		for(m=0;m<8;m++)
		{
			unsigned char s=0;
			for(n=0;n<8;n++)
			{
				k=DS18B20_Read2Bit();//读两位数据
				k=k&0x03;
				s>>=1;
				if(k==0x01)//01读到的数据为0 写0 此位为0的器件响应
				{   		
					DS18B20_WriteBit (0);
	    			ss[(m*8+n)]=0;
				}
				else if(k==0x02)//读到的数据为1 写1 此位为1的器件响应
				{
					s=s|0x80;
					DS18B20_WriteBit (1);
					ss[(m*8+n)]=1;
				}
				else if(k==0x00)//读到的数据为00 有冲突位 判断冲突位 
				{				//如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
					chongtuwei=m*8+n+1;					
					if(chongtuwei>zhan[l])
					{						
						DS18B20_WriteBit (0);
						ss[(m*8+n)]=0;												
						zhan[++l]=chongtuwei;						
					}
					else if(chongtuwei<zhan[l])
					{
						s=s|((ss[(m*8+n)]&0x01)<<7);
						DS18B20_WriteBit (ss[(m*8+n)]);
					}
					else if(chongtuwei==zhan[l])
					{
						s=s|0x80;
						DS18B20_WriteBit (1);
						ss[(m*8+n)]=1;
						l=l-1;
					}
				}
				else
				{
					return num;	//搜索完成,//返回搜索到的个数
				}
			}
			pID[num][m]=s;		
		}
		num=num+1;
	}
	while(zhan[l]!=0&&(num<MAXNUM));	
	
	return num;		//返回搜索到的个数
}






/*************************************************************************************************************************
*函数        	:	s16 DS18B20_ReadDesignateTemper(u8 pID[8])
*功能        	:	读取指定ID的DS18B20温度
*参数        	:	pID:DS18B20 ID,必须事先知道,如果不知道请启动ROM搜索
*返回        	:	温度值
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2013-04-17
*最后修改时间	:	2013-04-17
*说明        	:	温度值扩大了100倍,温度值是个有符号数.
*************************************************************************************************************************/
s16 DS18B20_ReadDesignateTemper(u8 pID[8])
{
	u8 th, tl;
	s16 data;
	
	if(DS18B20_Reset() == FALSE)	
	{
		return 0xffff;				//返回错误
	}

	DS18B20_WriteData(0xcc);		//跳过读序列号
	DS18B20_WriteData(0x44);		//启动温度转换
	DS18B20_Reset();
	DS18B20_WriteData(0x55);		//发送序列号匹配命令
	for(data = 0;data < 8;data ++)	//发送8byte的序列号	
	{
	   DS18B20_WriteData(pID[data]);
	}
	Delay_US(10);
	DS18B20_WriteData(0xbe);	//读取温度
	tl = DS18B20_ReadData();	//读取低八位
	th = DS18B20_ReadData(); 	//读取高八位
	data = th;
	data <<= 8;
	data |= tl;
	data *= 6.25;				//温度值扩大100倍,精确到2位小数
	
	return data;
} 






#ifndef DS18B20_H_
#define DS18B20_H_

//DS18B20指令
typedef enum 
{
	SEARCH_ROM			=	0xf0,	//搜索ROM指令
	READ_ROM			=	0x33,	//读取ROM指令
	MATH_ROM			=	0x55,	//匹配ROM指令
	SKIP_ROM			=	0xcc,	//忽略ROM指令
	ALARM_SEARCH		=	0xec,	//报警索索指令
	CONVERT_T			=	0x44,	//温度转换指令
	WRITE_SCRATCHPAD	=	0x4e,	//写暂存器指令
	READ_SCRATCHPAD		=	0xbe,	//读取暂存器指令
	COPY_SCRATCHPAD		=	0x48,	//拷贝暂存器指令
	RECALL_E2			=	0xb8,	//召回EEPROM指令
	READ_POWER_SUPPLY	=	0xb4,	//读取电源模式指令
} DS18B20_CMD;



//DS18B20 ROM编码
typedef struct
{
 	u8	DS18B20_CODE;	//DS18B20单总线编码:0x19
	u8	SN_1;			//序列号第1字节
	u8	SN_2;			//序列号第2字节
	u8	SN_3;			//序列号第3字节
	u8	SN_4;			//序列号第4字节
	u8	SN_5;			//序列号第5字节
	u8	SN_6;			//序列号第6字节
	u8	crc8;			//CRC8校验码	
} DS18B20_ROM_CODE;	



#define DS18B20_Init()		(DeviceClockEnable(DEV_GPIOB,ENABLE))		//使能GPIOB时钟

s16 DS18B20_ReadTemper(void);	//读取DS18B20温度
void DS18B20_WriteData(u8 data);

u8 DS18B20_SearchROM(u8 (*pID)[8],u8 Num);	//搜索ROM;
s16 DS18B20_ReadDesignateTemper(u8 pID[8]);	//读取指定ID的DS18B20温度



#endif /*DS18B20_H_*/




#define DS18B20_NUM		4
u8 ID_Buff[DS18B20_NUM][8];
int main(void)
{
	OS_CPU_SR  cpu_sr;
	s16 temp;
	u8 buff[16];
	u8 i,j,num;

	SYSTEM_ClockInit(9);			//初始化系统时钟72MHz
	JTAG_Set(SWD_ENABLE);			//只开启SWD调试模式
	DevInit();


	uart_printf("start system ...\r\n\r\n");

	num = DS18B20_SearchROM(ID_Buff,DS18B20_NUM);
	uart_printf("总线上实际挂载DS18B20数量: %d\r\n",DS18B20_NUM);
	uart_printf("搜索到的DS18B20数量: %d\r\n",num);

	
	for(i = 0;i < num;i ++)
	{
		uart_printf("\r\n DS18B20 No%d ID: ",i);
		for(j = 0;j < 8;j ++)
		{
			uart_printf("%02X ",ID_Buff[i][j]);
		}
	}

	i = 0;
	while(1)
	{

		LED1 = ~LED1;
		Delay_MS(1000);
		temp = DS18B20_ReadDesignateTemper(ID_Buff[i ++]);
		uart_printf("\r\n DS18B20 No%d Temp:%d ",i,temp);
		if(i == 4)
		{
		 	i = 0;
			uart_printf("\r\n");
		}

	}
}



结果

DS18B20多ROM搜索并读取温度