2.24 SHT20 温湿度传感器
由瑞士 Sensirion 推出的 SHT20 数字温湿度传感器,基于领先世界的 CMOSens ® 数字传感技术,具有极高的可靠性和卓越的长期稳定性。全量程标定,两线数字接口,可与单片机直接相连,大大缩短研发时间、简化外围电路并降低费用。此外,体积微小、响应迅速、低能耗、可浸没、抗干扰能力强、温湿一体,兼有露点测量,性价比高,使该产品能够适于多种场合的应用。
2.24.1 模块来源
采购链接: SHT20 温湿度传感器模块/数字型温湿度测量模块 I2C 通讯小体积模块 资料下载链接: https://pan.baidu.com/s/1HrQkwECvGgQSHvt_RNdLdA
**图 2.24.1-1 产品实物展示**2.24.2 规格参数
**工作电压:**2.1~3.6V **工作电流:**0.1~1000uA 温度精度:±0.3℃ 温度范围:-40~125℃ **湿度范围:**0~100 %RH 湿度精度:±3%RH **输出方式: ****IIC** 管脚数量:4 Pin 文件 2.24.2-1 产品规格书
2.24.3 移植过程
我们的目标是在梁山派 GD32F470 上能够测量环境温湿。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.24.3.1 查看资料
开始传输后,随后先传输首字节包括 I2C 设备地址(7bit)和一个 SDA 方向位(R:1, W:0)。
一个时钟发送一个位,在第 8 个下降沿之后,通过拉低 SDA 引脚(ACK 位 为 0),只是传感器数据接收正常。在发出测量命令之后(‘1110’‘0011’代表温度测量,‘1110’‘0101’代表相对湿度测量 ,这种为主机模式),MCU 必须等待测量完成。
灰色的部分是传感器控制的,当传感器给 MCU 返回数据时,每返回一个字节,MCU 要返回一个 ACK 信号,当接收完毕之后,返回一个 NACK 并接着传输停止时序(P)。
注:校验和可以不需要,不需要则就在数据接收完之后返回 NACK
② 非主机模式:测量过程中,SCL 线是开发状态,可进行其它通信,可以在总线上处理其它 I2C 总线通信任务。
当 MCU 要对传感器状态进行查询时,先发起一个开始信号,在发送从机地址和 SDA 方向位(写),此时从机匹配地址成功,则发送 ACK 信号,并开始测量。如果传感器完成了测量过程,并且发送 ASK 信号,那么 MCU 就可以读取相关数据。如果测量没有完成,传感器发送 NACK 信号,此时 MCU 必须重新发送启动传输时序,直至测量完成,MCU 读取数据。
注意:测量的数据,温度和湿度均为两个字节。而且无论哪一种传输模式,测量的最大分辨率最大是 14bit,数据的第二个字节 SDA 上最后两位是用来标记相关状态信息。其中 bit1 表示测量类型(0 是温度,1 是湿度)
灰色的区域是传感器控制的,如果不需要校验和,那么在接收完两个字节的数据之后就 MCU 直接发出 NACK 信号再接着发出停止时序(P),则结束通信。
通常测量的最长时间取决于测量类型和分辨率.
在计算 MCU 通信时间时,测量温度选择最长测量时间是 85ms,而测量相对湿度选择最长的时间是 29ms。
传感器内部设置的默认分辨率为相对湿度 12 位和温度 14 位。SDA 的输出数据被转换成两个字节的数据包,高字节 MSB 在前(左对齐)。每个字节后面都跟随一个应答位。两个状态位,即 LSB 的后两位在进行物理计算前须置 0。
计算湿度:其中 SRH 表示我们读取到的湿度原始数据。
计算温度:其中 ST 表示我们读取到的温度原始数据。
2.24.3.2 引脚选择
######### SHT20 | ######### 立创·梁山派 | ######### 接线图 |
---|
2.24.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与上一节相同,只是将.c 和.h 文件更改为 bsp_sht20.c 与 bsp_sht20.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_sht20.c 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_sht20.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年04月27日
* 功能介绍:
******************************************************************************
* 注意事项:
*********************************************************************************/
#include "bsp_sht20.h"
#include "systick.h"
#include "stdio.h"
/******************************************************************
* 函 数 名 称:SHT20_GPIO_Init
* 函 数 说 明:对IIC引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:
******************************************************************/
void SHT20_GPIO_Init(void)
{
//打开SDA与SCL的引脚时钟
rcu_periph_clock_enable(RCU_SCL);
rcu_periph_clock_enable(RCU_SDA);
//设置SCL引脚模式为上拉输出
gpio_mode_set(PORT_SCL, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SCL);
//设置引脚为开漏模式,翻转速度2MHz
gpio_output_options_set(PORT_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_SCL);
//设置引脚输出高电平SCL等待信号
gpio_bit_write(PORT_SCL, GPIO_SCL, SET);
//设置SDA引脚
gpio_mode_set(PORT_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SDA);
gpio_output_options_set(PORT_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_SDA);
gpio_bit_write(PORT_SDA, GPIO_SDA, SET);
}
/******************************************************************
* 函 数 名 称:IIC_Start
* 函 数 说 明:IIC起始信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Start(void)
{
SDA_OUT();
SDA(1);
delay_1us(5);
SCL(1);
delay_1us(5);
SDA(0);
delay_1us(5);
SCL(0);
delay_1us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Stop
* 函 数 说 明:IIC停止信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_1us(5);
SDA(1);
delay_1us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Send_Ack
* 函 数 说 明:主机发送应答
* 函 数 形 参:0应答 1非应答
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Send_Ack(unsigned char ack)
{
SDA_OUT();
SCL(0);
SDA(0);
delay_1us(5);
if(!ack) SDA(0);
else SDA(1);
SCL(1);
delay_1us(5);
SCL(0);
SDA(1);
}
/******************************************************************
* 函 数 名 称:IIC_Wait_Ack
* 函 数 说 明:等待从机应答
* 函 数 形 参:无
* 函 数 返 回:1=无应答 0=有应答
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char IIC_Wait_Ack(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SDA_IN();
SDA(1);
delay_1us(5);
SCL(1);
delay_1us(5);
while( (GETSDA()==1) && ( ack_flag ) )
{
ack_flag--;
delay_1us(5);
}
if( ack_flag <= 0 )
{
IIC_Stop();
return 1;
}
else
{
SCL(0);
SDA_OUT();
}
return ack;
}
/******************************************************************
* 函 数 名 称:IIC_Write
* 函 数 说 明:IIC写一个字节
* 函 数 形 参:dat写入的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Write(unsigned char dat)
{
int i = 0;
SDA_OUT();
SCL(0);//拉低时钟开始数据传输
for( i = 0; i < 8; i++ )
{
SDA( (dat & 0x80) >> 7 );
__nop();
__nop();
__nop();
dat<<=1;
delay_1us(6);
SCL(1);
delay_1us(4);
SCL(0);
delay_1us(4);
}
}
/******************************************************************
* 函 数 名 称:IIC_Read
* 函 数 说 明:IIC读1个字节
* 函 数 形 参:无
* 函 数 返 回:读出的1个字节数据
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char IIC_Read(void)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
SCL(0);
delay_1us(5);
SCL(1);
delay_1us(5);
receive<<=1;
if( GETSDA() )
{
receive|=1;
}
delay_1us(5);
}
return receive;
}
/******************************************************************
* 函 数 名 称:SHT20_Read
* 函 数 说 明:测量温湿度
* 函 数 形 参:regaddr寄存器地址 regaddr=0xf3测量温度 =0x35测量湿度
* 函 数 返 回:regaddr=0xf3时返回温度,regaddr=0xf5时返回湿度
* 作 者:LC
* 备 注:无
******************************************************************/
float SHT20_Read(unsigned char regaddr)
{
unsigned char data_H = 0;
unsigned char data_L = 0;
float temp = 0;
IIC_Start();
IIC_Write(0x80|0);
if( IIC_Wait_Ack() == 1 ) printf("error -1\r\n");
IIC_Write(regaddr);
if( IIC_Wait_Ack() == 1 ) printf("error -2\r\n");
do{
delay_1us(10);
IIC_Start();
IIC_Write(0x80|1);
}while( IIC_Wait_Ack() == 1 );
delay_1us(20);
data_H = IIC_Read();
IIC_Send_Ack(0);
data_L = IIC_Read();
IIC_Send_Ack(1);
IIC_Stop();
if( regaddr == 0xf3 )
{
temp = ((data_H<<8)|data_L) / 65536.0 * 175.72 - 46.85;
}
if( regaddr == 0xf5 )
{
temp = ((data_H<<8)|data_L) / 65536.0 * 125.0 - 6;
}
return temp;
}
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
在文件 bsp_sht20.h 中,编写如下代码。
/********************************************************************************
* 文 件 名: bsp_sht20.h
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年04月27日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#ifndef _BSP_SHT20_H_
#define _BSP_SHT20_H_
#include "gd32f4xx.h"
#define RCU_SCL RCU_GPIOA
#define PORT_SCL GPIOA
#define GPIO_SCL GPIO_PIN_5
#define RCU_SDA RCU_GPIOA
#define PORT_SDA GPIOA
#define GPIO_SDA GPIO_PIN_6
#define SDA_IN() {gpio_mode_set(PORT_SDA, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_SDA);} //SDA输入模式
#define SDA_OUT() {gpio_mode_set(PORT_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SDA);} //SDA输出模式
#define SCL(BIT) gpio_bit_write( PORT_SCL, GPIO_SCL, BIT?SET:RESET)
#define SDA(BIT) gpio_bit_write( PORT_SDA, GPIO_SDA, BIT?SET:RESET)
#define GETSDA() gpio_input_bit_get( PORT_SDA, GPIO_SDA)
void SHT20_GPIO_Init(void);
float SHT20_Read(unsigned char regaddr);
#endif
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
2.24.4 移植验证
在自己工程中的 main 主函数中,编写如下。
/********************************************************************************
* 文 件 名: main.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2022年04月27日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "bsp_sht20.h"
int main(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 优先级分组
systick_config(); //滴答定时器初始化 1ms
usart_gpio_config(115200);
SHT20_GPIO_Init();
delay_1ms(1000);
printf("demo start\r\n");
while(1)
{
printf("temperature = %.2f ℃\r\n",SHT20_Read(0xf3));
printf("humidity = %.2f %%RH\r\n",SHT20_Read(0xf5));
delay_1ms(1000);
}
}
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
移植现象:每隔一秒测量一次温湿度,并发送至串口 0。
移植成功示例,见文件 2.24.4-1 。
文件 2.24.4-1 移植成功示例