STM32F1与STM32CubeIDE编程实例-DS18B20温度传感器驱动

DS18B20温度传感器驱动

文章目录

1、DS18B20介绍

DS18B20 是一种温度传感器,它提供 9 位到 12 位的温度读数。 该传感器的通信可以通过单线总线(One-Wire,1-Wire)协议完成,该协议使用一条数据线与内部微处理器进行通信。

本文将介绍如何在STM32CubeIDE中驱动DS18B20。

由于DS18B20的数据通信方式为One-Wire,请参考前面与One-Wire总线相关文章:

在前面的文章中,对DS18B20作为详细的介绍,请参考:

2、DS18B20配置

DS18B20引脚配置如下:

在这里插入图片描述

One-Wire总线时序延时使用DWT实现,请参考前面文章:

3、DS18B20驱动实现

1)基本定义

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
// ds18b20.h
#ifndef \_DS18B20\_H
#define \_DS18B20\_H

#include "onewire/onewire.h"

// DS18B20配置
#define \_DS18B20\_MAX\_SENSORS 4
#define \_DS18B20\_GPIO DS18B20\_GPIO\_Port
#define \_DS18B20\_PIN DS18B20\_Pin

//#define \_DS18B20\_USE\_CRC

//
// DS18B20传感器定义
//
typedef struct
{
uint8\_t Address[8];
float Temperature;
uint8\_t ValidDataFlag;
} Ds18b20Sensor_t;


#define DS18B20\_FAMILY\_CODE 0x28

#define DS18B20\_CMD\_ALARMSEARCH 0xEC
#define DS18B20\_CMD\_CONVERTTEMP 0x44

#define DS18B20\_STEP\_12BIT 0.0625
#define DS18B20\_STEP\_11BIT 0.125
#define DS18B20\_STEP\_10BIT 0.25
#define DS18B20\_STEP\_9BIT 0.5

#define DS18B20\_RESOLUTION\_R1 6 // 分辨率位 R1
#define DS18B20\_RESOLUTION\_R0 5 // 分辨率位 R0

#ifdef \_DS18B20\_USE\_CRC
#define DS18B20\_DATA\_LEN 9
#else
#define DS18B20\_DATA\_LEN 5
#endif

// DS18B20分辨率
typedef enum {
DS18B20_Resolution_9bits = 9,
DS18B20_Resolution_10bits = 10,
DS18B20_Resolution_11bits = 11,
DS18B20_Resolution_12bits = 12
} DS18B20_Resolution_t;

// DS18B20初始化
void DS18B20\_Init(DS18B20_Resolution_t resolution);
// DS18B20设置
uint8\_t DS18B20\_GetResolution(uint8\_t number); // Get the sensor resolution
uint8\_t DS18B20\_SetResolution(uint8\_t number, DS18B20_Resolution_t resolution); // Set the sensor resolution
// 启动单个传感器转换
uint8\_t DS18B20\_Start(uint8\_t number);
// 启动所有传感器转换
void DS18B20\_StartAll(void);
// 读取单个传感器
uint8\_t DS18B20\_Read(uint8\_t number, float\* destination);
// 读取所有传感器
void DS18B20\_ReadAll(void);
// 检查ROM地址是否为DS18B20系列
uint8\_t DS18B20\_Is(uint8\_t\* ROM);
// 检查所有传感器是否转换完成
uint8\_t DS18B20\_AllDone(void);
// 从“number”位置获取传感器的 ROM
void DS18B20\_GetROM(uint8\_t number, uint8\_t\* ROM);
// 将 ROM 写入传感器表中的“number”位置
void DS18B20\_WriteROM(uint8\_t number, uint8\_t\* ROM);
// 查询连接数量
uint8\_t DS18B20\_Quantity(void);
// 查询当前温度值,如果读取的数据无效,则返回 0
uint8\_t DS18B20\_GetTemperature(uint8\_t number, float\* destination);
#endif

2)DS18B20初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void DS18B20\_Init(DS18B20_Resolution_t resolution)
{
uint8\_t next = 0, i = 0, j;
OneWire\_Init(&OneWire, DS18B20_GPIO_Port, DS18B20_Pin); // 初始化One-Wire总线

next = OneWire\_First(&OneWire); // 查询第一个设备
// 查询总线上所有设备
while(next)
{
TempSensorCount++;
OneWire\_GetFullROM(&OneWire, (uint8\_t\*)&ds18b20[i++].Address); // 获取下一个传感器的ROM
next = OneWire\_Next(&OneWire);
if(TempSensorCount >= _DS18B20_MAX_SENSORS) // 不允许超过设置的最大值的传感器
break;
}

for(j = 0; j < i; j++)
{
DS18B20\_SetResolution(j, resolution); // 设置分辨率

DS18B20\_StartAll(); // 启动所有传感器转换
}
}

3)DS18B20启动

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
// 启动指定传感器
uint8\_t DS18B20\_Start(uint8\_t number)
{
if( number >= TempSensorCount) // 大于最大限制数量,无效
return 0;

if (!DS18B20\_Is((uint8\_t\*)&ds18b20[number].Address)) // 检查传感器是否为DS18B20系列
return 0;

OneWire\_Reset(&OneWire); // 重置One-Wire总线
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)ds18b20[number].Address); // 通过ROM查询设备
OneWire\_WriteByte(&OneWire, DS18B20_CMD_CONVERTTEMP); // 向总线发送开始转换命令

return 1;
}

//
// 启动所有传感器
//
void DS18B20\_StartAll()
{
OneWire\_Reset(&OneWire); // 重置总线
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_SKIPROM); // Skip ROM 命令
OneWire\_WriteByte(&OneWire, DS18B20_CMD_CONVERTTEMP); // 启动所有设备转换
}

4)DS18B20数据读写

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
//
// 启动所有传感器
//
void DS18B20\_StartAll()
{
OneWire\_Reset(&OneWire); // 重置总线
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_SKIPROM); // Skip ROM 命令
OneWire\_WriteByte(&OneWire, DS18B20_CMD_CONVERTTEMP); // 启动所有设备转换
}

//
// 读取单个传感器
//
uint8\_t DS18B20\_Read(uint8\_t number, float \*destination)
{
if( number >= TempSensorCount) // 超过最大限制数量,无效
return 0;

uint16\_t temperature;
uint8\_t resolution;
float result;
uint8\_t i = 0;
uint8\_t data[DS18B20_DATA_LEN];
#ifdef \_DS18B20\_USE\_CRC
uint8\_t crc;

#endif


if (!DS18B20\_Is((uint8\_t\*)&ds18b20[number].Address)) // 检查是否为DS18B20系列传感器
return 0;

if (!OneWire\_ReadBit(&OneWire)) // 检查总线是否释放
return 0; // 转换未完成,表示总线处于忙状态

OneWire\_Reset(&OneWire); // 重置总线
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)&ds18b20[number].Address); // 通过ROM选择传感器
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_RSCRATCHPAD); // 发送数据读取命令

for (i = 0; i < DS18B20_DATA_LEN; i++) // 读取暂存器数据
data[i] = OneWire\_ReadByte(&OneWire);

#ifdef \_DS18B20\_USE\_CRC
crc = OneWire\_CRC8(data, 8); // CRC计算

if (crc != data[8])
return 0; // CRC无效
#endif
temperature = data[0] | (data[1] << 8); // 16位温度数据

OneWire\_Reset(&OneWire); //重置总线

resolution = ((data[4] & 0x60) >> 5) + 9; // 传感器的分辨率来自暂存器的字节 4

switch (resolution) // 由于分辨率检查正确的值
{
case DS18B20_Resolution_9bits:
result = temperature\*(float)DS18B20_STEP_9BIT;
break;
case DS18B20_Resolution_10bits:
result = temperature\*(float)DS18B20_STEP_10BIT;
break;
case DS18B20_Resolution_11bits:
result = temperature\*(float)DS18B20_STEP_11BIT;
break;
case DS18B20_Resolution_12bits:
result = temperature\*(float)DS18B20_STEP_12BIT;
break;
default:
result = 0xFF;
}

\*destination = result;

return 1; // 温度值有效
}


5)DS18B20转换分辨率查询与设置

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
uint8\_t DS18B20\_GetResolution(uint8\_t number)
{
if( number >= TempSensorCount)
return 0;

uint8\_t conf;

if (!DS18B20\_Is((uint8\_t\*)&ds18b20[number].Address))
return 0;

OneWire\_Reset(&OneWire); // 重置总线
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)&ds18b20[number].Address); // 通过ROM查询设备
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_RSCRATCHPAD); // 发送读取暂存器命令

OneWire\_ReadByte(&OneWire);
OneWire\_ReadByte(&OneWire);
OneWire\_ReadByte(&OneWire);
OneWire\_ReadByte(&OneWire);

conf = OneWire\_ReadByte(&OneWire); // 寄存器 5 是带分辨率的配置寄存器
conf &= 0x60; // 屏蔽两个分辨率位
conf >>= 5; // 向左移动
conf += 9; // 获取分辨率位数的结果

return conf;
}

uint8\_t DS18B20\_SetResolution(uint8\_t number, DS18B20_Resolution_t resolution)
{
if( number >= TempSensorCount)
return 0;

uint8\_t th, tl, conf;
if (!DS18B20\_Is((uint8\_t\*)&ds18b20[number].Address))
return 0;

OneWire\_Reset(&OneWire); // 重置总线
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)&ds18b20[number].Address); // 通过ROM查询设备
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_RSCRATCHPAD); //发送读取暂存器命令

OneWire\_ReadByte(&OneWire);
OneWire\_ReadByte(&OneWire);

th = OneWire\_ReadByte(&OneWire); // 从温度警报字节开始写入暂存器
tl = OneWire\_ReadByte(&OneWire);
conf = OneWire\_ReadByte(&OneWire);

if (resolution == DS18B20_Resolution_9bits) // 分辨率设置
{
conf &= ~(1 << DS18B20_RESOLUTION_R1);
conf &= ~(1 << DS18B20_RESOLUTION_R0);
}
else if (resolution == DS18B20_Resolution_10bits)
{
conf &= ~(1 << DS18B20_RESOLUTION_R1);
conf |= 1 << DS18B20_RESOLUTION_R0;
}
else if (resolution == DS18B20_Resolution_11bits)
{
conf |= 1 << DS18B20_RESOLUTION_R1;
conf &= ~(1 << DS18B20_RESOLUTION_R0);
}
else if (resolution == DS18B20_Resolution_12bits)
{
conf |= 1 << DS18B20_RESOLUTION_R1;
conf |= 1 << DS18B20_RESOLUTION_R0;
}

OneWire\_Reset(&OneWire); // 重置总线
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)&ds18b20[number].Address);
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_WSCRATCHPAD);

OneWire\_WriteByte(&OneWire, th); // 将 3 个字节写入暂存器
OneWire\_WriteByte(&OneWire, tl);
OneWire\_WriteByte(&OneWire, conf);

OneWire\_Reset(&OneWire); // Reset the bus
OneWire\_SelectWithPointer(&OneWire, (uint8\_t\*)&ds18b20[number].Address);
OneWire\_WriteByte(&OneWire, ONEWIRE_CMD_CPYSCRATCHPAD); // 将暂存器复制到 EEPROM

return 1;
}

uint8\_t DS18B20\_Is(uint8\_t\* ROM)
{
if (\*ROM == DS18B20_FAMILY_CODE) //检查是否为DS18B20传感器
return 1;
return 0;
}

uint8\_t DS18B20\_AllDone(void)
{
return OneWire\_ReadBit(&OneWire); // 检查所有设备转换是否完成
}

void DS18B20\_ReadAll(void)
{
uint8\_t i;

if (DS18B20\_AllDone())
{
for(i = 0; i < TempSensorCount; i++)
{
ds18b20[i].ValidDataFlag = 0;

if (DS18B20\_Is((uint8\_t\*)&ds18b20[i].Address))
{
ds18b20[i].ValidDataFlag = DS18B20\_Read(i, &ds18b20[i].Temperature);
}
}
}
}

void DS18B20\_GetROM(uint8\_t number, uint8\_t\* ROM)
{
if( number >= TempSensorCount)
number = TempSensorCount;

uint8\_t i;

for(i = 0; i < 8; i++)
ROM[i] = ds18b20[number].Address[i];
}

void DS18B20\_WriteROM(uint8\_t number, uint8\_t\* ROM)
{
if( number >= TempSensorCount)
return;

uint8\_t i;

for(i = 0; i < 8; i++)
ds18b20[number].Address[i] = ROM[i];
}

uint8\_t DS18B20\_Quantity(void)
{
return TempSensorCount;
}

6)温度读取

1
2
3
4
5
6
7
8
9
10
uint8\_t DS18B20\_GetTemperature(uint8\_t number, float\* destination)
{
if(!ds18b20[number].ValidDataFlag)
return 0;

\*destination = ds18b20[number].Temperature;
return 1;

}

4、主程序

main.c文件中添加如下代码:

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
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include "onewire/onewire.h"
#include "ds18b20/ds18b20.h"
#include "dwt/dwt\_delay.h"
#include <stdio.h>

/\* USER CODE END Includes \*/

/\* Private typedef -----------------------------------------------------------\*/
/\* USER CODE BEGIN PTD \*/
float temperature;
/\* USER CODE END PTD \*/

int main(void)
{
/\* USER CODE BEGIN 1 \*/

/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_USART1\_UART\_Init();
/\* USER CODE BEGIN 2 \*/
printf("\*\*\*\*DS18B20\*\*\*\*\r\n");
dwt\_init();
DS18B20\_Init(DS18B20_Resolution_12bits);
HAL\_GPIO\_WritePin(DS18B20_GPIO_Port, DS18B20_Pin, 0);
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
DS18B20\_ReadAll();
HAL\_GPIO\_WritePin(TEST_GPIO_Port, TEST_Pin, 1);
DS18B20\_StartAll();
HAL\_GPIO\_WritePin(TEST_GPIO_Port, TEST_Pin, 0);
uint8\_t ROM_tmp[8];
uint8\_t i;
for (i = 0; i < DS18B20\_Quantity(); i++) {
if (DS18B20\_GetTemperature(i, &temperature)) {
DS18B20\_GetROM(i, ROM_tmp);

printf("%d. ROM: %X%X%X%X%X%X%X%X Temp: %f\n\r", i, ROM_tmp[0],
ROM_tmp[1], ROM_tmp[2], ROM_tmp[3], ROM_tmp[4],
ROM_tmp[5], ROM_tmp[6], ROM_tmp[7], temperature);
}
}

HAL\_Delay(1000);
HAL\_GPIO\_TogglePin(LED_GPIO_Port, LED_Pin);
}
/\* USER CODE END 3 \*/
}

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/125271066