简介
我们知道多个DS18B20的DQ线是可以被挂在一起的, 也就是一根线上可以访问不同的DS18B20而不会造成数据错乱, 怎么做到的,其实数据手册都有说到, 就是靠64-bit ROM code 进行识别, 也可以理解成Serial Number进行识别, 因为主要差异还是在Serial Number上面;
电路图
两个DS18B20连接到一起
实现步骤
创建项目
基于 上一篇 普中STM32-PZ6806L开发板(HAL库函数实现-温度传感器DS18B20)
添加用户代码
获取DS18B20的Serial Number信息, 然后记录下来, 用于向指定DS18B20获取温度值
typedef struct
{
uint8_t familyCode;
uint8_t sns[6];
uint8_t crc;
} SENSOR_DS18B20_SerialNumberInfo;
SENSOR_DS18B20_SerialNumberInfo SENSOR_DS18B20_GetSN(void)
{
SENSOR_DS18B20_SerialNumberInfo info;
uint8_t recvs[8] = { 0 };
SENSOR_DS18B20_Reset ();
HAL_Delay (1);
SENSOR_DS18B20_Write (0x33); // read rom
HAL_Delay (1);
// 1 byte -> family code
// 2 ~ 7 byte -> serial number
// 8 byte -> CRC8
recvs[0] = SENSOR_DS18B20_Read(); // family code
info.familyCode = recvs[0];
for (int i = 0; i < 6; ++i) // serial number
{
recvs[i+1] = SENSOR_DS18B20_Read();
info.sns[i] = recvs[i+1];
}
recvs[7] = SENSOR_DS18B20_Read(); // CRC8
info.crc = recvs[7];
if (SENSOR_DS18B20_CRC8(recvs, 7) != recvs[7]) // CRC8 检查
{
info.familyCode = 0;
memset(info.sns, 0, sizeof(info.sns)/sizeof(uint8_t));
info.crc = 0;
return info; // CRC校验不一致
}
return info;
}
实现流程参考pdf
实现代码
/* 两个DS18B20设备 */
#include <stdio.h>
#include <string.h>
/* DS18B20, 提前读取出来的SN&familyCode&CRC码 */
SENSOR_DS18B20_SerialNumberInfo ds18b20_infos[] =
{
{ 0x28, { 0x2E, 0x7C, 0x04, 0x05, 0x00, 0x00 }, 0xCC },
{ 0x28, { 0x2F, 0x7D, 0x10, 0x02, 0x01, 0x00 }, 0xBE }
};
/* 引脚重新设置为输入 */
static void SENSOR_DS18B20_SetPinInput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
/* 引脚重新设置为输出 */
static void SENSOR_DS18B20_SetPinOutput(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_Pin;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
/*
SENSOR_DS18B20_Reset :
初始化,也是复位, 每次发送指令前的动作
0 : 初始化失败
1 : 初始化成功
*/
static uint8_t SENSOR_DS18B20_Reset(void)
{
uint8_t res = 0;
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN); // 引脚输出模式
HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0); // 拉低引脚
delay_us (480); // 参考初始化时序图, 延时480us
SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN); // set the pin as input
delay_us (60); // 15~60us等待DS18B20回复信息, 多等20us避免检测不到
if ( !HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN) )
res = 1; // 检测到低电平, DS18B20有响应
else
res = 0;
delay_us (420); // 等待DS18B20结束响应
return res;
}
/* 写流程 */
void SENSOR_DS18B20_Write(uint8_t data)
{
/*
按位写, 根据时序图, 按照写的 高电平的时序 和 低电平的时序进行延时
*/
for (int i = 0; i < 8; ++i)
{
if ((data & (1<<i))!=0) // 写1
{
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 0); // 拉低
delay_us (2); // 低电平保持时间
SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN); // 输入
delay_us (60); // 等待
}
else // 写0
{
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0); // 拉低
delay_us (60); // 等待60us
SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN); // 输入
}
}
}
/* 读流程 */
uint8_t SENSOR_DS18B20_Read (void)
{
uint8_t value = 0;
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
for (int i=0;i<8;i++)
{
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, 0); // 拉低
delay_us(2); // 拉低电平等待时间
SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);
if (HAL_GPIO_ReadPin (DS18B20_PORT, DS18B20_PIN))
{
value |= 1<<i;
}
delay_us (60); // DS18B20数据响应时间
}
return value;
}
/* 计算CRC码 */
uint8_t SENSOR_DS18B20_CRC8(uint8_t *dats, uint8_t len)
{
uint8_t i, dat, crc, fb, st_byt;
st_byt = 0;
crc = 0;
do {
dat = dats[st_byt];
for (i = 0; i < 8; i++)
{
fb = crc ^ dat;
fb &= 1;
crc >>= 1;
dat >>= 1;
if (fb == 1)
crc ^= 0x8c;
}
st_byt++;
} while (st_byt < len);
return crc;
}
/* 获取Serial Number&CRC&family Code */
SENSOR_DS18B20_SerialNumberInfo SENSOR_DS18B20_GetSN(void)
{
SENSOR_DS18B20_SerialNumberInfo info;
uint8_t recvs[8] = { 0 };
SENSOR_DS18B20_Reset ();
HAL_Delay (1);
SENSOR_DS18B20_Write (0x33); // read rom
HAL_Delay (1);
// 1 byte -> family code
// 2 ~ 7 byte -> serial number
// 8 byte -> CRC8
recvs[0] = SENSOR_DS18B20_Read(); // family code
info.familyCode = recvs[0];
for (int i = 0; i < 6; ++i) // serial number
{
recvs[i+1] = SENSOR_DS18B20_Read();
info.sns[i] = recvs[i+1];
}
recvs[7] = SENSOR_DS18B20_Read(); // CRC8
info.crc = recvs[7];
if (SENSOR_DS18B20_CRC8(recvs, 7) != recvs[7]) // CRC8 检查
{
info.familyCode = 0;
memset(info.sns, 0, sizeof(info.sns)/sizeof(uint8_t));
info.crc = 0;
return info; // CRC校验不一致
}
return info;
}
/* 写Serial Number&CRC&family Code */
void SENSOR_DS18B20_WriteID(uint8_t index)
{
uint8_t id_data[8];
id_data[0] = ds18b20_infos[index].familyCode;
id_data[7] = ds18b20_infos[index].crc;
for ( int i = 1; i < 7; ++i )
{
id_data[i] = ds18b20_infos[index].sns[i-1];
}
SENSOR_DS18B20_Reset ();
SENSOR_DS18B20_Write (0x55); // skip ROM; //Match ROM [55h]
for ( int i = 0; i < 8; i++ )
{
SENSOR_DS18B20_Write(id_data[i]);
}
}
/* 等待电平被拉高 */
void SENSOR_DS18B20_WaitForHigh(uint32_t time)
{
SENSOR_DS18B20_SetPinInput(DS18B20_PORT, DS18B20_PIN);
delay_us(time);
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9) == 0);
SENSOR_DS18B20_SetPinOutput(DS18B20_PORT, DS18B20_PIN);
}
/* 将读取值转化成温度值 */
float SENSOR_DS18B20_ValueToTemperature(uint8_t lsb, uint8_t msb)
{
uint16_t temp = 0;
temp = (msb << 8) + lsb;
if((temp&0xf800)==0xf800) // 符号位判定是否负数
{
temp=(~temp)+1; // 补码转原码
return temp*(-0.0625); //12bit 增量值
}
else
{
return temp*0.0625; //12bit 增量值
}
}
/* 通过serial number数据获取温度 */
float SENSOR_DS18B20_GetTemperatureByID(uint8_t ds18b20_index)
{
uint8_t recv_data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 9 Bytes
uint8_t ds18b20_num = sizeof(ds18b20_infos) / sizeof(SENSOR_DS18B20_SerialNumberInfo);
uint16_t temp = 0;
if ( ds18b20_index >= ds18b20_num )
return 0; // 不存在此设备
SENSOR_DS18B20_Reset ();
HAL_Delay (1);
SENSOR_DS18B20_WriteID(ds18b20_index);
SENSOR_DS18B20_Write(0x44);//Convert Temperature [44h]
SENSOR_DS18B20_WaitForHigh(20);
SENSOR_DS18B20_Reset ();
SENSOR_DS18B20_WriteID(ds18b20_index);
SENSOR_DS18B20_Write(0xBE);//Read Scratchpad [BEh]
for (uint8_t i = 0; i < 9; i++)
{
recv_data[i] = SENSOR_DS18B20_Read();
}
return SENSOR_DS18B20_ValueToTemperature(recv_data[0], recv_data[1]);
}
代码
无需下载, 代码上面基本都提供了
Note:
支持你的DS18B20, 你需要修改, 改成你的DS18B20的信息
SENSOR_DS18B20_SerialNumberInfo ds18b20_infos[] =
{
{ 0x28, { 0x2E, 0x7C, 0x04, 0x05, 0x00, 0x00 }, 0xCC },
{ 0x28, { 0x2F, 0x7D, 0x10, 0x02, 0x01, 0x00 }, 0xBE }
};