• STM32——一线协议之DS18B20温度采样


    一、DS18B20传感器介绍

    在这里插入图片描述
    每个DS18B20出厂的时候都烧录了一个唯一的64为产品序列号在ROM中。ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个传感器。

    1、DS18B20一线协议

    所有的单总线器件都要求用严格的信号时序,以保证数据的完整性。DS18B20共有6种信号类型:复位脉冲、应答脉冲、写0/1、读0/1。所有的这些信号除了应答信号。都由主机发出同步信号,并且所有发送的命令和数据都是字节的低位在前(LSB)。

    (1)复位脉冲和应答脉冲

    单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时15 ~ 60us,并进入接收模式(Rx)。接着DS18B20模块拉低总线60 ~ 240us,以产生低电平应答脉冲,若产生了低电平应答脉冲,再延时240us。
    在这里插入图片描述

    (2)写时序

    写时序包括写0时序和写1时序。所有写时序至少要60us,且在两次独立的写时序之间至少要1us的恢复时间,两种写时序均起始于拉低总线。

    写0时序:主机输出低电平,延时60us,然后释放总线2us;
    写1时序:主机输出低电平,延时2us,然后再释放总线,延时60us。

    从机在总线拉低30us后,读取电平。若为低电平,表示写0,若为高电平,表示写1。

    在这里插入图片描述

    (2)读时序

    单总线器件仅在主机发出读时序时,才向主机传数据,主机发出读数据命令后,必须马上产生读时序,一遍从机能够传输数据。所有的读时序至少需要60us,且两次独立的读时序之间至少需要1us的恢复时间。

    当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持1us,然后总线被释放。DS18B20通过拉高或拉低总线来传输“1”或“0”。当逻辑“0”结束后,总线被释放,通过上拉电阻回到上升状态,从DS18B20输出的数据在读时序的下降沿出现后15us内有效6.因此,总线控制器在读时序开始后必须停止把I/O口驱动为低电平,以读取I/O状态。

    在这里插入图片描述

    2.DS18B20工作流程

    先进行温度转换,再进行温度读取;
    温度转换:初始化 -> 跳过ROM -> 温度转换
    温度读取:初始化 -> 跳过ROM -> 读寄存器 -> 读低八位 -> 读高八位

    (1)初始化

    单总线上的所有通信都是以初始化序列开始,主机发出初始化信号后等待从设备的应答信号,以确认从设备是否能正常工作。

    (2)ROM操作命令

    总线主机检测到DS18B20存在之后,便可以发出ROM操作命令,这些命令如下。但是我们一般不关心ROM中的16位产品序列号,通常会发送0xCC跳过ROM的相关操作。
    在这里插入图片描述

    (3)存储器操作命令

    接下来发送相应的高速暂存存储器命令,命令表如下。其中0x44命令通知DS18B20传感器开始进行温度变换(温度采样),而0xBE命令则将开始读出DS18B20的采样值。
    在这里插入图片描述

    (4)数据处理

    DS18B20的高速暂存存储器由9个字节组成。当执行温度转换命令(0x44)后,经转换的温度以二字节补码形式存于高速暂存存储器的前两个字节。
    在这里插入图片描述
    如果我们只关心温度值的话,则只需读前两个字节就可以了。其中Byte[0]为温度值得低字节,而Byte[1]为温度值得高字节。这16位数据的格式如下:
    在这里插入图片描述
    其中BIT[3:0]为温度值的小数部分,而BIT[10:4]为温度值的整数部分,BIT[15:11]为符号位,如果为0表示温度为正值,如果为-1则表示温度为负值。

    二、DS18B20温度采样实现

    1、硬件连接

    DS18B20传感器工作电压为3~5.5V,本人将DS18B20的I/O口接到开发板的GPIO管脚PA5上,其实任意一个GPIO管脚都可以的,只需修改一下代码即可(后面说)。

    2、代码实现

    ds18b20.h

    /*
     * ds18b20.h
     *
     *  Created on: 2022年6月28日
     *      Author: 28980
     */
    
    #ifndef INC_DS18B20_H_
    #define INC_DS18B20_H_
    #include "main.h"
    
    uint8_t DS18B20_Reset(void);//初始化复位及应答
    
    void DS18B20_Writte_Byte(uint8_t byte);//写一个字节
    
    uint8_t DS18B20_Read_Bit(void);//读一个位
    
    uint8_t DS18B20_Read_Byte(void);//读一个字节
    
    uint8_t DS18B20_SampleData(float *temperature);//温度采样
    
    #endif /* INC_DS18B20_H_ */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    ds18b20.c

    /*
     * ds18b20.c
     *
     *  Created on: 2022年6月28日
     *      Author: 28980
     */
    
    
    #include "ds18b20.h"
    
    typedef struct w1_gpio_S
    {
    	GPIO_TypeDef	*group;
    	uint16_t		pin;
    }w1_gpio_s;
    
    static w1_gpio_s W1DS =
    {
    	.group = GPIOA,
    	.pin = GPIO_PIN_5,
    };
    
    #define W1DS_Input()	\
    {\
    	GPIO_InitTypeDef GPIO_InitStruct = {0};\
     	GPIO_InitStruct.Pin = W1DS.pin;\
     	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\
     	GPIO_InitStruct.Pull = GPIO_PULLUP;\
     	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
     	HAL_GPIO_Init(W1DS.group, &GPIO_InitStruct);\
    }
    
    
    #define W1DS_Output()	\
    {\
    	GPIO_InitTypeDef GPIO_InitStruct = {0};\
     	GPIO_InitStruct.Pin = W1DS.pin;\
     	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
     	GPIO_InitStruct.Pull = GPIO_NOPULL;\
     	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;\
     	HAL_GPIO_Init(W1DS.group, &GPIO_InitStruct);\
    }
    
    #define W1DS_Write(x)	HAL_GPIO_WritePin(W1DS.group, W1DS.pin,\
    		(x==1)?GPIO_PIN_SET : GPIO_PIN_RESET)
    
    #define W1DQ_Read()	HAL_GPIO_ReadPin(W1DS.group, W1DS.pin)
    
    uint8_t DS18B20_Reset(void)
    {
    	uint8_t retry = 0;
    	uint8_t rv;
    
    	W1DS_Output();
    	W1DS_Write(1);
    	delay_us(2);
    
    	W1DS_Write(0);
    	delay_us(480);
    
    	W1DS_Write(1);
    	delay_us(60);
    
    	W1DS_Input();
    	while(W1DQ_Read() && retry < 240)
    	{
    		retry++;
    		delay_us(1);
    	}
    
    	if(retry >= 240)
    	{
    		rv = 1;
    	}
    
    	delay_us(240);
    
    	W1DS_Output();
    	W1DS_Write(1);
    	delay_us(240);
    
    	return rv;
    
    }
    
    
    void DS18B20_Writte_Byte(uint8_t byte)
    {
    	uint8_t i;
    
    	W1DS_Output();
    
    	for(i = 0; i< 8; i++)
    	{
    		if(byte & 0x01)
    		{
    			W1DS_Write(0);
    			delay_us(2);
    
    			W1DS_Write(1);
    			delay_us(60);
    		}
    		else
    		{
    			W1DS_Write(0);
    			delay_us(80);
    
    			W1DS_Write(1);
    			delay_us(2);
    		}
    
    		byte >>= 1;
    		delay_us(2);
    	}
    }
    
    
    uint8_t DS18B20_Read_Bit(void)
    {
    	uint8_t rv = 0;
    
    	W1DS_Output();
    	W1DS_Write(0);
    	delay_us(2);
    	W1DS_Write(1);
    	delay_us(2);
    
    	W1DS_Input();
    
    	if(W1DQ_Read())
    	{
    		rv = 1;
    	}
    
    	delay_us(60);
    	W1DS_Output();
    	W1DS_Write(1);
    
    	return rv;
    }
    
    
    uint8_t DS18B20_Read_Byte(void)
    {
    	uint8_t bit;
    	uint8_t i, Byte = 0;
    
    	for(i = 0; i < 8; i++)
    	{
    		bit = DS18B20_Read_Bit();
    		printf("read bit:%d\r\n", bit);
    		if(bit)
    		{
    			Byte |= (1 << i);
    		}
    		delay_us(2);
    	}
    	printf("Byte:%d\r\n", Byte);
    	return Byte;
    }
    
    uint8_t DS18B20_Start_Convet(void)
    {
    	if(DS18B20_Reset())
    	{
    		printf("Initialization failed!\r\n");
    		return -1;
    	}
    
    	DS18B20_Writte_Byte(0xCC);
    
    	DS18B20_Writte_Byte(0x44);
    
    	return 0;
    }
    
    uint8_t DS18B20_SampleData(float *temperature)
    {
    	uint8_t Byte[2];
    	uint8_t sign;
    	uint16_t temp;
    
    	if(!temperature)
    		return -1;
    
    	if(DS18B20_Start_Convet())
    	{
    			printf("Convet Temperature failed!\r\n");
    			return -2;
    	}
    
    	if(DS18B20_Reset())
    	{
    		printf("Initialization failed!\r\n");
    		return -3;
    	}
    
    	DS18B20_Writte_Byte(0xCC);
    	DS18B20_Writte_Byte(0xBE);
    
    	Byte[0] = DS18B20_Read_Byte();
    	Byte[1] = DS18B20_Read_Byte();
    
    	printf("Byte[0]:%d\r\n", Byte[0]);
    	printf("Byte[1]:%d\r\n", Byte[1]);
    
    	if(Byte[1] > 7)
    	{
    		sign = 0;
    		temp = ~(Byte[1]<<8 | Byte[0]) + 1;
    	}
    	else
    	{
    		sign = 1;
    		temp = Byte[1]<<8 | Byte[0];
    	}
    
    
    	*temperature = (temp>>4) + (temp & 0x0F) * 0.0625;
    	if(!sign)
    	{
    		*temperature = - *temperature;
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226

    main.c

    while(1)
    {
    	  if(DS18B20_SampleData(&temperature) < 0)
    	  {
    		  printf("ERROR:DS18B20 Sample Data failure\r\n");
    	  }
    	  else
    	  {
    		  printf("DS18B20 Sample Temperature:%.3f\r\n", temperature);
    	  }
    	  HAL_Delay(3000);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    个人总结

    在写之前借鉴了一下别人的代码,然后自己看datasheet自己写了代码,出现了不少错,其中有一个隐藏而致命的,让我找了很久,就是写一个字节最后的移位这,byte >>= 1;和读一个字节Byte |= (1 << i);这,少写了一个等号,也算是一个小坑吧,另外在写驱动的时候,一定先看懂数据手册的时序图,和一些对存储器的操作。

  • 相关阅读:
    接入HMS Core应用内支付服务过程中一些常见问题总结
    D. Binary String To Subsequences
    [Python]Django模型(Model)
    独立产品灵感周刊 DecoHack #031 - 用 AI 给黑白照片上色哪家好?
    基于深度学习的苹果叶片病害检测系统(含UI界面、yolov8、Python代码、数据集)
    基于JavaSwing开发小区物业信息房屋出租管理系统 课程设计 大作业
    laravel自定义日志保存文件加上日期
    推荐 NestJs 官方教程
    20221026,开启DevOps之路。冲击最大的是项目上或者功能的英文名词。现在记录如下
    华为被迫开源,从认知到落地SpringBoot企业级实战手册(完整版)
  • 原文地址:https://blog.csdn.net/weixin_45880057/article/details/125494537