由瑞士Sensirion推出的 SHT20数字温湿度传感器,基于领先世界的CMOSens ® 数字传感技术,具有极高的可靠性和卓越的长期稳定性。全量程标定,两线数字接口,可与单片机直接相连,大大缩短研发时间、简化外围电路并降低费用。此外,体积微小、响应迅速、低能耗、可浸没、抗干扰能力强、温湿一体,兼有露点测量,性价比高,使该产品能够适于多种场合的应用。
一、模块来源
二、规格参数
工作电压:2.1~3.6V
工作电流:0.1~1000uA
温度精度:±0.3℃
温度范围:-40~125℃
湿度范围:0~100 %RH
湿度精度:±3%RH
输出方式: IIC
管脚数量:4 Pin
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至开发板上【能够测量环境温湿度】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
开始传输后,随后先传输首字节包括I2C设备地址(7bit)和一个SDA方向位(R:1, W:0)。
一个时钟发送一个位,在第8个下降沿之后,通过拉低SDA引脚(ACK位 为0),只是传感器数据接收正常。在发出测量命令之后(‘1110’‘0011’代表温度测量,‘1110’‘0101’代表相对湿度测量 ,这种为主机模式),MCU必须等待测量完成。
主机模式:
测量过程中,SCL线被封锁(由传感器控制),在测量时,SHT2x将SCL拉低强制主机进入等待状态。当释放SCL线,表示传感器内部工作接收,可以继续进行数据传送
灰色的部分是传感器控制的,当传感器给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、引脚选择
VCC | 3V3 |
GND | GND |
SCL | PA2 |
SDA | PA3 |
3、代码编写
新建两个文件 bsp_sht20.c
和 bsp_sht20.h
,并且将头文件路径添加到编译器中。
在文件 bsp_sht20.c
和 bsp_sht20.h
中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef BSP_CODE_BSP_SHT20_H_
#define BSP_CODE_BSP_SHT20_H_
#include "gd32vw55x.h"
#include "systick.h"
#ifndef u8
#define u8 uint8_t
#endif
#ifndef u16
#define u16 uint16_t
#endif
#ifndef u32
#define u32 uint32_t
#endif
#ifndef delay_ms
#define delay_ms(x) delay_1ms(x)
#endif
#ifndef delay_us
#define delay_us(x) delay_1us(x)
#endif
#define Module_RCU_ENABLE() \
rcu_periph_clock_enable(Module_SCL_RCU); \
rcu_periph_clock_enable(Module_SDA_RCU);
#define Module_SCL_RCU RCU_GPIOA
#define Module_SCL_PORT GPIOA
#define Module_SCL_PIN GPIO_PIN_2 //SCL
#define Module_SDA_RCU RCU_GPIOA
#define Module_SDA_PORT GPIOA
#define Module_SDA_PIN GPIO_PIN_3 //SDA
//SDA输入模式
#define SDA_IN() \
gpio_mode_set(Module_SDA_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, Module_SDA_PIN);
//SDA输出模式
#define SDA_OUT() \
gpio_mode_set(Module_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, Module_SDA_PIN); \
gpio_output_options_set(Module_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, Module_SDA_PIN);
#define SCL(BIT) gpio_bit_write(Module_SCL_PORT, Module_SCL_PIN, BIT)
#define SDA(BIT) gpio_bit_write(Module_SDA_PORT, Module_SDA_PIN, BIT)
#define SDA_GET() gpio_input_bit_get(Module_SDA_PORT, Module_SDA_PIN)
#define SHT20_TEMP_REG_ADDR 0xF3 // 温度
#define SHT20_HUMI_REG_ADDR 0xF5 // 湿度
void SHT20_Init(void);
char SHT20_Read(uint8_t regaddr, float *sht20_value);
#endif /* BSP_CODE_BSP_SHT20_H_ */
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
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include "bsp_sht20.h"
#include "stdio.h"
/******************************************************************
* 函 数 名 称:IIC_Start
* 函 数 说 明:IIC起始信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Start(void)
{
SDA_OUT();
SCL(0);
SDA(1);
SCL(1);
delay_us(5);
SDA(0);
delay_us(5);
SCL(0);
delay_us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Stop
* 函 数 说 明:IIC停止信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_us(5);
SDA(1);
delay_us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Send_Ack
* 函 数 说 明:主机发送应答
* 函 数 形 参:0应答 1非应答
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Send_Ack(uint8_t ack)
{
SDA_OUT();
SCL(0);
SDA(0);
delay_us(5);
if(!ack) SDA(0);
else SDA(1);
SCL(1);
delay_us(5);
SCL(0);
SDA(1);
}
/******************************************************************
* 函 数 名 称:IIC_Wait_Ack
* 函 数 说 明:等待从机应答
* 函 数 形 参:无
* 函 数 返 回:1=无应答 0=有应答
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t IIC_Wait_Ack(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SDA_IN();
SDA(1);
delay_us(5);
SCL(1);
delay_us(5);
while( (SDA_GET()==1) && ( ack_flag ) )
{
ack_flag--;
delay_us(5);
}
if( ack_flag <= 0 )
{
IIC_Stop();
return 1;
}
else
{
SCL(0);
SDA_OUT();
}
return ack;
}
/******************************************************************
* 函 数 名 称:IIC_Write
* 函 数 说 明:IIC写一个字节
* 函 数 形 参:dat写入的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Write(uint8_t data)
{
int i = 0;
SDA_OUT();
SCL(0);//拉低时钟开始数据传输
for( i = 0; i < 8; i++ )
{
SDA( (data & 0x80) >> 7 );
delay_us(2);
data<<=1;
delay_us(6);
SCL(1);
delay_us(4);
SCL(0);
delay_us(4);
}
}
/******************************************************************
* 函 数 名 称:IIC_Read
* 函 数 说 明:IIC读1个字节
* 函 数 形 参:无
* 函 数 返 回:读出的1个字节数据
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t IIC_Read(void)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
SCL(0);
delay_us(5);
SCL(1);
delay_us(5);
receive<<=1;
if( SDA_GET() )
{
receive|=1;
}
delay_us(5);
}
return receive;
}
/******************************************************************
* 函 数 名 称:SHT20_Read
* 函 数 说 明:测量温湿度
* 函 数 形 参:regaddr寄存器地址 regaddr=0xF3测量温度 =0xF5测量湿度
* sht20_value数据地址
* 函 数 返 回:0成功,其他失败
* 作 者:LC
* 备 注:无
******************************************************************/
char SHT20_Read(uint8_t regaddr, float *sht20_value)
{
unsigned char data_H = 0;
unsigned char data_L = 0;
float temp = 0;
int timeOut = 1000;
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_us(10);
IIC_Start();
IIC_Write(0x80|1);
}while( IIC_Wait_Ack() == 1 && timeOut--);
if(!timeOut)
{
printf("SHT20_Read Failed!!\r\n");
return 1;
}
delay_us(20);
data_H = IIC_Read();
IIC_Send_Ack(0);
data_L = IIC_Read();
IIC_Send_Ack(1);
IIC_Stop();
if( regaddr == SHT20_TEMP_REG_ADDR ) // 温度
{
*sht20_value = (((uint16_t)data_H<<8)|data_L) / 65536.0 * 175.72 - 46.85;
}
if( regaddr == SHT20_HUMI_REG_ADDR ) // 湿度
{
*sht20_value = (((uint16_t)data_H<<8)|data_L) / 65536.0 * 125.0 - 6;
}
return 0;
}
/******************************************************************
* 函 数 名 称:SHT20_Init
* 函 数 说 明:SHT20 Sensor 初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void SHT20_Init(void)
{
Module_RCU_ENABLE();
//SCL引脚初始化
gpio_mode_set(Module_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, Module_SCL_PIN);
gpio_output_options_set(Module_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, Module_SCL_PIN);
//SDA引脚初始化
gpio_mode_set(Module_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, Module_SDA_PIN);
gpio_output_options_set(Module_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_25MHZ, Module_SDA_PIN);
SCL(1);
SDA(1);
delay_ms(100); // 等待传感器稳定
}
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
247
248
249
250
251
252
253
四、移植验证
在 src\main.c
中输入代码如下:
#include "gd32vw55x.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "gd32vw553h_eval.h"
#include "bsp_sht20.h"
/*!
\brief toggle the led every 500ms
\param[in] none
\param[out] none
\retval none
*/
void led_spark(void)
{
static __IO uint32_t timingdelaylocal = 0U;
if(timingdelaylocal) {
if(timingdelaylocal < 500U) {
gd_eval_led_on(LED1);
} else {
gd_eval_led_off(LED1);
}
timingdelaylocal--;
} else {
timingdelaylocal = 1000U;
}
}
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
#ifdef __FIRMWARE_VERSION_DEFINE
uint32_t fw_ver = 0;
#endif /* __FIRMWARE_VERSION_DEFINE */
/* configure systick */
systick_config();
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1);
/* initilize the LEDs, USART and key */
gd_eval_led_init(LED1);
gd_eval_com_init(EVAL_COM0);
gd_eval_key_init(KEY_TAMPER_WAKEUP, KEY_MODE_GPIO);
#ifdef __FIRMWARE_VERSION_DEFINE
fw_ver = gd32vw55x_firmware_version_get();
printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r\n\n");
printf("\r\n=== Welcome to use the LC-GD32VW553-HMQ6 development board ====\r\n\n");
printf("\r\n======================= www.lckfb.com =========================\r\n\n");
printf("\r\n======================= wiki.lckfb.com ========================\r\n\n");
printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\r\n");
/* print firmware version */
printf("\r\nGD32VW55X series firmware version: V%d.%d.%d", (uint8_t)(fw_ver >> 24), (uint8_t)(fw_ver >> 16), (uint8_t)(fw_ver >> 8));
#endif /* __FIRMWARE_VERSION_DEFINE */
/* print out the clock frequency of system, AHB, APB1 and APB2 */
printf("\r\nCK_SYS is %d\r\n", rcu_clock_freq_get(CK_SYS));
printf("\r\nCK_AHB is %d\r\n", rcu_clock_freq_get(CK_AHB));
printf("\r\nCK_APB1 is %d\r\n", rcu_clock_freq_get(CK_APB1));
printf("\r\nCK_APB2 is %d\r\n", rcu_clock_freq_get(CK_APB2));
SHT20_Init();
printf("\r\nSHT20 Sensor Init Successful\r\n");
while(1)
{
float Temperature = 0;
float Humidity = 0;
if(!SHT20_Read(SHT20_TEMP_REG_ADDR, &Temperature) &&
!SHT20_Read(SHT20_HUMI_REG_ADDR, &Humidity))
{
printf("\n");
printf("Temperature = %.2f*C\r\n", Temperature);
printf("Humidity = %.2f%%\r\n", Humidity);
}
delay_1ms(500);
}
}
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
编译烧录。
【代码下载】
- 跳转到
下载中心
去下载模块移植代码:【点击跳转🚀】