【本文发布于https://blog.csdn.net/Stack_/article/details/132733884,未经许可不得转载,转载须注明出处】
找一张二叉树的图片,结合代码以及代码注释去理解。
#define DS18B20_PORT PORT5
#define DS18B20_PIN PIN2
#define DS18B20_NUM 5
#define DS18B20_PIN_MODE_IN(PORTx, PINx) //配置为输入
#define DS18B20_PIN_MODE_OUT(PORTx, PINx) //配置为开漏输出
#define DS18B20_PIN_GET(PORTx, PINx) PORT_GetBit(PORTx, PINx)
typedef struct {
uint8_t Online[DS18B20_NUM]; //是否在线
uint8_t Valid[DS18B20_NUM]; //温度值是否有效
int32_t Temperature[DS18B20_NUM]; //4位小数
uint8_t ROM_Code[DS18B20_NUM][8]; //64位rom code
} ds18b20_t;
extern ds18b20_t ds18b20_data;
void DS18B20_Init(void);
void DS18B20_Proc(void);
ds18b20_t ds18b20_data;
/**
* @brief
* @note
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
static bool DS18B20_Online_Check(PORT_TypeDef PORTx, PIN_TypeDef PINx)
{
uint32_t wait = 0;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
DELAY_US(10);
PORT_ClrBit(PORTx, PINx);
DELAY_US(700);
PORT_SetBit(PORTx, PINx);
DS18B20_PIN_MODE_IN(PORTx, PINx);
DELAY_US(30);
if (!DS18B20_PIN_GET(PORTx, PINx)) //有应答
{
UserTimer_Reset(&wait);
while (!DS18B20_PIN_GET(PORTx, PINx) && UserTimer_Read(&wait) < 2); //等待应答信号结束,最长等待1~2ms
if (DS18B20_PIN_GET(PORTx, PINx))
return true;
else
return false;
}
else
{
return false;
}
}
/**
* @brief
* @note
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
static void DS18B20_Write(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t val)
{
uint8_t i;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
for (i = 0; i < 8; i++)
{
PORT_SetBit(PORTx, PINx);
DELAY_US(4);
PORT_ClrBit(PORTx, PINx);
DELAY_US(1);
if (val & 0x01)
PORT_SetBit(PORTx, PINx);
else
PORT_ClrBit(PORTx, PINx);
DELAY_US(66);
val >>= 1;
}
PORT_SetBit(PORTx, PINx);
}
/**
* @brief 读2个bit
* @note
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
static uint8_t DS18B20_Read2Bit(PORT_TypeDef PORTx, PIN_TypeDef PINx)
{
uint8_t i;
uint8_t val = 0;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
for (i = 0; i < 2; i++)
{
val <<= 1;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
DELAY_US(4);
PORT_ClrBit(PORTx, PINx);
DELAY_US(1);
PORT_SetBit(PORTx, PINx);
DS18B20_PIN_MODE_IN(PORTx, PINx);
DELAY_US(5);
if (DS18B20_PIN_GET(PORTx, PINx))
val |= 0x01;
DELAY_US(60);
}
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
return val;
}
/**
* @brief
* @note
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
static void DS18B20_Write1Bit(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t val)
{
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
DELAY_US(4);
PORT_ClrBit(PORTx, PINx);
DELAY_US(1);
if (val & 0x01)
PORT_SetBit(PORTx, PINx);
else
PORT_ClrBit(PORTx, PINx);
DELAY_US(66);
PORT_SetBit(PORTx, PINx);
}
/**
* @brief 读N个字节
* @note
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
static void DS18B20_Read(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t *bytes_array, uint8_t n_bytes)
{
uint8_t i, j;
uint8_t val = 0;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
for (i = 0; i < n_bytes; i++)
{
for (j = 0; j < 8; j++)
{
val >>= 1;
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
DELAY_US(4);
PORT_ClrBit(PORTx, PINx);
DELAY_US(1);
PORT_SetBit(PORTx, PINx);
DS18B20_PIN_MODE_IN(PORTx, PINx);
DELAY_US(5);
if (DS18B20_PIN_GET(PORTx, PINx))
val |= 0x80;
DELAY_US(60);
}
bytes_array[i] = val;
}
DS18B20_PIN_MODE_OUT(PORTx, PINx);
PORT_SetBit(PORTx, PINx);
}
/**
* @brief 获取总线上各器件的ID
* @note 二叉树遍历获取ROM CODE
* @param None
* @retval None
* @author PWH
* @date 2023/2
*/
static void DS18B20_Search_ROMCode(void)
{
#define _00_OVER_ONE_DS18B20_BIT_DIFFERENT 0x00 //有超过1个的设备,且它们在这一位上的值有0也有1
#define _01_DS18B20_BITS_SAME_0 0x01 //可能只有一个,或者有多个且它们的这一位的值都为0
#define _10_DS18B20_BITS_SAME_1 0x02 //可能只有一个,或者有多个且它们的这一位的值都为1
#define _11_DS18B20_ALL_OFFLINE 0x03 //总线无响应,不存在设备
bool sta;
uint8_t bit_val, code_val;
uint8_t i, j;
uint8_t num = 0;
uint8_t stack_top[DS18B20_NUM], stack_top_cnt = 0; //记录栈顶(存在分叉的节点),一次遍历,最多有DS18B20_NUM-1次冲突
uint8_t deep; //记录当前深度
uint8_t node_choice[64]; //记录该分叉点选择的路线
uint8_t node_now;
memset(stack_top, 0, sizeof(stack_top));
memset(node_choice, 0, sizeof(node_choice));
sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
if (sta)
{
do {
DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xF0); //Search ROM 指令
node_now = deep = 0;
for (i = 0; i < 8; i++)
{
code_val = 0;
for (j = 0; j < 8; j++) //i * j = 64位rom code
{
code_val >>= 1;
bit_val = DS18B20_Read2Bit(DS18B20_PORT, DS18B20_PIN); //读取2bit(bit1为实际值,bit0为实际值的补码)
deep++; //每读一次,深度加一,深度1-64
switch (bit_val)
{
case _00_OVER_ONE_DS18B20_BIT_DIFFERENT: //冲突,分叉节点,选择一条未走过的路径
if (deep > stack_top[stack_top_cnt]) //当前冲突点深度大于记录的最新的冲突点,为新的冲突点,选择左边(0)路线
{
DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 0);
node_choice[deep - 1] = 0;
stack_top[++stack_top_cnt] = deep; //增加记录,记录最深/最新的一个冲突点(未走完2条路线的)
}
else if (deep < stack_top[stack_top_cnt]) //当前冲突点深度小于最深的冲突点,未到达上次记录的点,采用上次该点的值,选择上次在该点选择的路线
{
code_val |= (node_choice[deep - 1] << 7);
DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, node_choice[deep - 1]);
}
else //到达上次记录的最深的冲突点,选择新路线(1)
{
code_val |= 0x80;
DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 1);
node_choice[deep - 1] = 1;
stack_top_cnt--; //该分叉点的路线都走过了,减去该节点
}
break;
case _01_DS18B20_BITS_SAME_0:
DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 0); //无冲突,无节点 通知此位为非0的后续不要响应(实际不存在非0的)
node_choice[deep - 1] = 0;
break;
case _10_DS18B20_BITS_SAME_1:
DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 1); //无冲突,无节点 通知此位为非1的后续不要响应(实际不存在非1的)
code_val |= 0x80;
node_choice[deep - 1] = 1;
break;
case _11_DS18B20_ALL_OFFLINE:
break;
default:
break;
}
}
ds18b20_data.ROM_Code[num][i] = code_val;
}
ds18b20_data.Online[num] = 1;
printf("搜索ROM CODE %d : 0x", num);
for (i = 0; i < 8; i++)
{
printf("%.2x", ds18b20_data.ROM_Code[num][7 - i]);
}
printf("\r\n");
/*
[17:10:34.852] [ 7796][0000:00:07.795]#0 ROM CODE is : 0x6203139794034828
[17:10:34.882] [ 7822][0000:00:07.821]#1 ROM CODE is : 0xb9031397945fcf28
[17:10:34.884] [ 7848][0000:00:07.848]#2 ROM CODE is : 0x3103139794203428
[17:10:34.930] [ 7874][0000:00:07.874]#3 ROM CODE is : 0x3603029794140728
[17:10:34.962] [ 7900][0000:00:07.900]#4 ROM CODE is : 0xc70304979422c328
*/
num++;
} while (stack_top[stack_top_cnt] && num < DS18B20_NUM); //
}
else
{
printf("搜索ROM CODE无器件\r\n");
}
}
/**
* @brief
* @note main while调用
* @param None
* @retval None
* @author PWH
* @date 2022/10
*/
void DS18B20_Proc(void)
{
static uint32_t timer = 0;
static uint8_t Num = 0;
uint16_t temp;
int32_t temperature;
const uint16_t temper_decimal[16] = {0, 625, 1250, 1875, 2500, 3125, 3750, 4375, 5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375};
bool sta;
static uint8_t step = 0;
static uint32_t interval = 1000;
uint8_t i;
uint8_t array[8];
uint8_t *array_p = array + 7;
static bool f_search = false;
if (timer < TIMEOUT_1S * 3) //电源稳定后搜索
{
UserTimer_Reset(&timer);
return;
}
if (f_search == false)
{
f_search = true;
DS18B20_Search_ROMCode();
}
if (UserTimer_Read(&timer) > interval)
{
if (step == 0) //发转换命令,转换时间为750ms
{
sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
if (sta == true)
{
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xCC); //跳过ID读取
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0x44); //开始转换温度
}
else
{
printf("DS总线无应答\r\n");
}
}
else //读取温度
{
sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
if (sta == true)
{
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0x55); //匹配 ROM 指令
for (i = 0; i < 8; i++)
{
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, ds18b20_data.ROM_Code[Num][i]); //发送8字节rom code
}
DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xBE);
DS18B20_Read(DS18B20_PORT, DS18B20_PIN, array, 2);
temp = _bytes2short(array[1], array[0]);
if (temp & 0xf800)
{
temperature = ~(temp & 0x07ff) + 1;
temperature = (temperature >> 4) * 10000 + temper_decimal[temperature & 0x000f];
temperature = -temperature;
}
else
{
temperature = temp;
temperature = (temperature >> 4) * 10000 + temper_decimal[temperature & 0x000f];
}
if (temperature >= -550000 && temperature <= 1250000)
{
ds18b20_data.Temperature[Num] = temperature;
ds18b20_data.Valid[Num] = 1;
}
else
{
ds18b20_data.Valid[Num] = 0;
printf("#%d数据无效 - %d\r\n", Num, temperature);
}
}
else
{
printf("读取温度无应答\r\n");
}
}
if (++Num >= DS18B20_NUM || !ds18b20_data.Online[Num])
{
Num = 0;
UserTimer_Reset(&timer);
#if (0)
if (step)
{
printf("\r\n");
for (uint8_t j = 0; j < DS18B20_NUM; j++)
printf("#%d = %.3f℃, ", j + 1, (float)ds18b20_data.Temperature[j] / 10000);
printf("\r\n");
}
#endif
step = !step;
if (step) interval = 1000;
else interval = 500;
}
}
}
/**
* @brief 初始化
* @note
* @param None
* @retval None
* @author PWH
* @date 2023/2
*/
void DS18B20_Init(void)
{
DS18B20_PIN_INIT(DS18B20_PORT, DS18B20_PIN);
memset(ds18b20_data.Online, 0, sizeof(ds18b20_data));
}
文章来源:https://www.toymoban.com/news/detail-698116.html
待完善文字说明文章来源地址https://www.toymoban.com/news/detail-698116.html
到了这里,关于一个IO上挂接多个DS18B20的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!