STM32的DS18B20单总线上挂载多路采集

DS18B20中文资料手册及程序代码下载链接:

https://pan.baidu.com/s/1IHSgMN9AQzW3L7jO3_PKlA

提取码:yhki  

DS18B20单总线上多路采集的关键在于读取ROM指令,通过ROM指令读取指定的DS18B20温度。

64 位(激)光刻只读存储器

每只DS18B20 都有一个唯一存储在ROM 中的64 位编码。最前面8 位是单线系列编码:28h。接着的48 位是一个唯一的序列号。最后8 位是以上56 位的CRC 编码。CRC的详细解释见CRC 发生器节。64位ROM和ROM操作控制区允许DS18B20作为单总线器件并按照详述于单总线系统节的单总线协议工作。

ROM 指令

一旦总线控制器探测到一个存在脉冲,它就发出一条ROM指令。如果总线上挂有多只DS18B20,这些指令将基于器件独有的64 位ROM 片序列码使得总线控制器选出特定要进行操作的器件。这些指令同样也可以使总线控制器识别有多少只,什么型号的器件挂在总线上,同样,它们也可以识别哪些器件已经符合报警条件。ROM指令有5条,都是8 位长度。总线控制器在发起一条DS18B20功能指令之前必须先发出一条ROM指令。ROM指令操作流程图见图11。

Search ROM [F0h] (搜索ROM 指令)

当系统上电初始化的时候,总线控制器必须通过识别总线上所有ROM片序列码去得到从机的数目和型号。总线控制器通过搜索ROM指令多次循环搜索ROM编码,以确认所有从机器件。如果总线上只有一只从机,那么可以用较为简单的读取ROM 指令(见下文)代替搜索ROM 指令。

READ ROM [33h] (读取ROM 指令)
只有在总线上存在单只DS18B20的时候才能使用这条命令。该命令允许总线控制器在不使用搜索ROM 指令的情况下读取从机的64 位片序列码。如果总线上有不止一只从机,当所有从机试图同时传送信号时就会发生数据冲突。

MATH ROM [55h] (匹配ROM 指令)
匹配ROM 指令,后跟64 位ROM 编码序列,让总线控制器在多点总线上定位一只特定的DS18B20。只有和64 位ROM 片序列码完全匹配的DS18B20 才能响应随后的存储器操作指令;所有和64位ROM片序列码不匹配的从机都将等待复位脉冲。

以下是STM32的DS18B20多路采集,时序代码和普通读单个的代码一致,添加了读取ID和读取多个DS18B20的程序。

核心代码如下:

  DS18B20.c文件代码:

#include "DS18B20.h"
#include "Delay.h"
#include "stdio.h" // printf用
 
#define DS18B20_GPIO_NUM				 GPIO_Pin_5
#define DS18B20_GPIO_X					GPIOC
#define RCC_APB2Periph_DS18B20_GPIO_X	RCC_APB2Periph_GPIOC
 
#define DS18B20_DQ_OUT_Low			GPIO_ResetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
#define DS18B20_DQ_OUT_High			GPIO_SetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
#define DS18B20_DQ_IN				GPIO_ReadInputDataBit(DS18B20_GPIO_X,DS18B20_GPIO_NUM) 
 
#define MaxSensorNum 8
unsigned char DS18B20_ID[MaxSensorNum][8];	// 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限
unsigned char DS18B20_SensorNum;			// 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)
 
// 配置DS18B20用到的I/O口
void DS18B20_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_DS18B20_GPIO_X, ENABLE);
	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
	GPIO_SetBits(DS18B20_GPIO_X, DS18B20_GPIO_NUM);
}
 
// 引脚输入
void DS18B20_Mode_IPU(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
}
 
// 引脚输出
void DS18B20_Mode_Out(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
 
}
 
// 复位,主机给从机发送复位脉冲
void DS18B20_Rst(void)
{
	DS18B20_Mode_Out();
	DS18B20_DQ_OUT_Low;		// 产生至少480us的低电平复位信号
	Delay_us(480);
	DS18B20_DQ_OUT_High;	// 在产生复位信号后,需将总线拉高
	Delay_us(15);
}
 
// 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲
u8 DS18B20_Answer_Check(void)
{
	u8 delay = 0;
	DS18B20_Mode_IPU(); // 主机设置为上拉输入
	// 等待应答脉冲(一个60~240us的低电平信号 )的到来
	// 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
	while (DS18B20_DQ_IN&&delay < 100)
	{
		delay++;
		Delay_us(1);
	}
	// 经过100us后,如果没有应答脉冲,退出函数
	if (delay >= 100)//Hu200
		return 1;
	else
		delay = 0;
	// 有应答脉冲,且存在时间不超过240us
	while (!DS18B20_DQ_IN&&delay < 240)
	{
		delay++;
		Delay_us(1);
	}
	if (delay >= 240)
		return 1;
	return 0;
}
 
// 从DS18B20读取1个位
u8 DS18B20_Read_Bit(void)
{
	u8 data;
	DS18B20_Mode_Out();
	DS18B20_DQ_OUT_Low; // 读时间的起始:必须由主机产生 >1us <15us 的低电平信号
	Delay_us(2);
	DS18B20_DQ_OUT_High;
	Delay_us(12);
	DS18B20_Mode_IPU();// 设置成输入,释放总线,由外部上拉电阻将总线拉高
	if (DS18B20_DQ_IN)
		data = 1;
	else
		data = 0;
	Delay_us(50);
	return data;
}
 
// 从DS18B20读取2个位
u8 DS18B20_Read_2Bit(void)//读二位 子程序
{
	u8 i;
	u8 dat = 0;
	for (i = 2; i > 0; i--)
	{
		dat = dat << 1;
		DS18B20_Mode_Out();
		DS18B20_DQ_OUT_Low;
		Delay_us(2);
		DS18B20_DQ_OUT_High;
		DS18B20_Mode_IPU();
		Delay_us(12);
		if (DS18B20_DQ_IN)	dat |= 0x01;
		Delay_us(50);
	}
	return dat;
}
 
// 从DS18B20读取1个字节
u8 DS18B20_Read_Byte(void)	// read one byte
{
	u8 i, j, dat;
	dat = 0;
	for (i = 0; i < 8; i++)
	{
		j = DS18B20_Read_Bit();
		dat = (dat) | (j << i);
	}
	return dat;
}
 
// 写1位到DS18B20
void DS18B20_Write_Bit(u8 dat)
{
	DS18B20_Mode_Out();
	if (dat)
	{
		DS18B20_DQ_OUT_Low;// Write 1
		Delay_us(2);
		DS18B20_DQ_OUT_High;
		Delay_us(60);
	}
	else
	{
		DS18B20_DQ_OUT_Low;// Write 0
		Delay_us(60);
		DS18B20_DQ_OUT_High;
		Delay_us(2);
	}
}
 
// 写1字节到DS18B20
void DS18B20_Write_Byte(u8 dat)
{
	u8 j;
	u8 testb;
	DS18B20_Mode_Out();
	for (j = 1; j <= 8; j++)
	{
		testb = dat & 0x01;
		dat = dat >> 1;
		if (testb)
		{
			DS18B20_DQ_OUT_Low;// 写1
			Delay_us(10);
			DS18B20_DQ_OUT_High;
			Delay_us(50);
		}
		else
		{
			DS18B20_DQ_OUT_Low;// 写0
			Delay_us(60);
			DS18B20_DQ_OUT_High;// 释放总线
			Delay_us(2);
		}
	}
}
 
//初始化DS18B20的IO口,同时检测DS的存在
u8 DS18B20_Init(void)
{
	DS18B20_GPIO_Config();
	DS18B20_Rst();
	return DS18B20_Answer_Check();
}
 
// 从ds18b20得到温度值,精度:0.1C,返回温度值(-550~1250),Temperature1返回浮点实际温度
float DS18B20_Get_Temp(u8 i)
{
	//u8 flag;
	u8 j;//匹配的字节
	u8 TL, TH;
	short Temperature;
	float Temperature1;
	DS18B20_Rst();
	DS18B20_Answer_Check();
	DS18B20_Write_Byte(0xcc);// skip rom
	DS18B20_Write_Byte(0x44);// convert
	DS18B20_Rst();
	DS18B20_Answer_Check();
 
	// DS18B20_Write_Byte(0xcc);// skip rom
	//匹配ID,i为形参
	DS18B20_Write_Byte(0x55);
	for (j = 0; j < 8; j++)
	{
		DS18B20_Write_Byte(DS18B20_ID[i][j]);
	}
 
	DS18B20_Write_Byte(0xbe);// convert
	TL = DS18B20_Read_Byte(); // LSB   
	TH = DS18B20_Read_Byte(); // MSB  
	if (TH & 0xfc)
	{
		//flag=1;
		Temperature = (TH << 8) | TL;
		Temperature1 = (~Temperature) + 1;
		Temperature1 *= 0.0625;
	}
	else
	{
		//flag=0;
		Temperature1 = ((TH << 8) | TL)*0.0625;
	}
	return Temperature1;
}
 
// 自动搜索ROM
void DS18B20_Search_Rom(void)
{
	u8 k, l, chongtuwei, m, n, num;
	u8 zhan[5];
	u8 ss[64];
	u8 tempp;
	l = 0;
	num = 0;
	do
	{
		DS18B20_Rst(); //注意:复位的延时不够
		Delay_us(480); //480、720
		DS18B20_Write_Byte(0xf0);
		for (m = 0; m < 8; m++)
		{
			u8 s = 0;
			for (n = 0; n < 8; n++)
			{
				k = DS18B20_Read_2Bit();//读两位数据
 
				k = k & 0x03;
				s >>= 1;
				if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应
				{
					DS18B20_Write_Bit(0);
					ss[(m * 8 + n)] = 0;
				}
				else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应
				{
					s = s | 0x80;
					DS18B20_Write_Bit(1);
					ss[(m * 8 + n)] = 1;
				}
				else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位
				{
					//如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
					chongtuwei = m * 8 + n + 1;
					if (chongtuwei > zhan[l])
					{
						DS18B20_Write_Bit(0);
						ss[(m * 8 + n)] = 0;
						zhan[++l] = chongtuwei;
					}
					else if (chongtuwei < zhan[l])
					{
						s = s | ((ss[(m * 8 + n)] & 0x01) << 7);
						DS18B20_Write_Bit(ss[(m * 8 + n)]);
					}
					else if (chongtuwei == zhan[l])
					{
						s = s | 0x80;
						DS18B20_Write_Bit(1);
						ss[(m * 8 + n)] = 1;
						l = l - 1;
					}
				}
				else
				{
					//没有搜索到
				}
			}
			tempp = s;
			DS18B20_ID[num][m] = tempp; // 保存搜索到的ID
		}
		num = num + 1;// 保存搜索到的个数
	} while (zhan[l] != 0 && (num < MaxSensorNum));
	DS18B20_SensorNum = num;
	//printf("DS18B20_SensorNum=%d\r\n",DS18B20_SensorNum);
}

DS18B20.h文件代码:

#ifndef __DS18B20_H
#define __DS18B20_H 
  
#include "stm32f10x.h"
 
u8 DS18B20_Init(void);
u8 DS18B20_Read_Byte(void);
u8 DS18B20_Read_Bit(void);
u8 DS18B20_Answer_Check(void);
void  DS18B20_GPIO_Config(void);
void  DS18B20_Mode_IPU(void);
void  DS18B20_Mode_Out(void);
void  DS18B20_Rst(void);
void  DS18B20_Search_Rom(void);
void  DS18B20_Write_Byte(u8 dat);
float DS18B20_Get_Temp(u8 i);
 
#endif

main.c文件代码:

#include "stm32f10x.h"
#include "stdio.h"
#include "string.h"//strlen、memset用到
#include "USART.h"
#include "Delay.h"
#include "DS18B20.h"
 
extern unsigned char DS18B20_ID[8][8];//检测到的传感器ID存数组
extern unsigned char DS18B20_SensorNum;
 
int main(void)
{
	u8 num=0;
	USART1_init(9600);
	while(DS18B20_Init())//初始化DS18B20,兼检测18B20
	{
		printf("DS18B20 Check Failed!\r\n");  
	}
	printf("DS18B20 Ready!\r\n");
	while(1)
	{	  
		DS18B20_Search_Rom();
		printf("DS18B20_SensorNum:%d\r\n",DS18B20_SensorNum);
	  for(num=0;num<DS18B20_SensorNum;num++)
		{
			printf("ID:%02x%02x%02x%02x%02x%02x%02x%02x TM:%.2f\r\n",DS18B20_ID[num][0],DS18B20_ID[num][1],DS18B20_ID[num][2],DS18B20_ID[num][3],DS18B20_ID[num][4],DS18B20_ID[num][5],DS18B20_ID[num][6],DS18B20_ID[num][7],DS18B20_Get_Temp(num));
		}
		printf("\r\n");
		Delay_s(2);
	}	
}

运行结果如图:

猜你喜欢

转载自blog.csdn.net/u012166958/article/details/84872480