MS5611 气压传感器
模块来源
采购链接:
GY-63 MS5611-01BA03 气压传感器 高度传感器模块
资料下载链接:
https://pan.baidu.com/s/1QOrpiggCE6mBpqabJXUufg
提取码:c2pp
规格参数
工作电压: 1.8~3.6V
工作电流: 0.25~23uA
温度精度: 0.8℃
温度范围: -40~85℃
气压范围: 10~1200 mbar
气压精度: 1.5 mbar
输出方式: IIC
管脚数量: 3 Pin
移植过程
我们的目标是在天空星 STM32F407 上能够测量环境气压。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
查看资料
当 PS 引脚接高电平时,传感器属于 IIC 模式;当 PS 引脚接低电平时,传感器属于 SPI 模式;在原理图上,PS 引脚通过上拉电阻接了高电平,故默认为 IIC 模式。
器件地址 = 0XEE
CSB 的反补码 即 CSB 引脚接高电平时, 地址为 1110 110+(读写位)
CSB 的反补码 即 CSB 引脚接低电平时, 地址为 1110 111+(读写位)
bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 1 | 1 | CSB | 读写位 |
读取气压与温度的流程:开始-> 读取出厂校准值 C1 至 C6 -> 读取气压 D1 和温度 D2 的原始数据 -> 将 D2 和 C1C6 带入公式求出 dT 和 TEMP,其中 TEMP 为温度数据-> 将 dT 和 C1 至 C6 带入公式求出 OFF、SENS 和 P,其中 P 为气压数据。
引脚选择
移植至工程
移植步骤中的导入.c 和.h 文件与第二章的第 1 小节【DHT11 温湿度传感器】相同,只是将.c 和.h 文件更改为 bsp_ms5611.c 与 bsp_ms5611.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件 bsp_ms5611.c 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-19 LCKFB-LP first version
*/
#include "bsp_ms5611.h"
#include "stdio.h"
#include "board.h"
//出厂校准值
//Cal_C1_6[0] = 厂家信息
//Cal_C1_6[1] ~ Cal_C1_6[6] = 校准值
//Cal_C1_6[7] = 校准值的CRC校验
uint16_t Cal_C1_6[8];
/******************************************************************
* 函 数 名 称:MS5611_GPIO_Init
* 函 数 说 明:MS5611的引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void MS5611_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_MS5611, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_SDA|GPIO_SCL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PORT_MS5611, &GPIO_InitStructure);
GPIO_SetBits(PORT_MS5611, GPIO_SDA|GPIO_SCL);
}
/******************************************************************
* 函 数 名 称:IIC_Start
* 函 数 说 明:IIC起始时序
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Start(void)
{
SDA_OUT();
SDA(1);
delay_us(5);
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(unsigned char 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);
}
/******************************************************************
* 函 数 名 称:I2C_WaitAck
* 函 数 说 明:等待从机应答
* 函 数 形 参:无
* 函 数 返 回:0有应答 1超时无应答
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char I2C_WaitAck(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SCL(0);
SDA(1);
SDA_IN();
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;
}
/******************************************************************
* 函 数 名 称:Send_Byte
* 函 数 说 明:写入一个字节
* 函 数 形 参:dat要写人的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void Send_Byte(uint8_t dat)
{
int i = 0;
SDA_OUT();
SCL(0);//拉低时钟开始数据传输
for( i = 0; i < 8; i++ )
{
SDA( (dat & 0x80) >> 7 );
delay_us(1);
SCL(1);
delay_us(5);
SCL(0);
delay_us(5);
dat<<=1;
}
}
/******************************************************************
* 函 数 名 称:Read_Byte
* 函 数 说 明:IIC读时序
* 函 数 形 参:无
* 函 数 返 回:读到的数据
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char Read_Byte(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);
}
SCL(0);
return receive;
}
/**********************************************************
* 函 数 名 称:MS5611_Reset
* 函 数 功 能:MS5611的复位
* 传 入 参 数:无
* 函 数 返 回:0=复位成功 1=器件地址错误 2=命令无应答
* 作 者:LC
* 备 注:无
**********************************************************/
char MS5611_Reset(void)
{
IIC_Start();//起始信号
Send_Byte(0xee|0); //器件地址+写
if( I2C_WaitAck() == 1 )return 1;
Send_Byte(0x1e); //复位命令
if( I2C_WaitAck() == 1 )return 2;
IIC_Stop();
return 0;
}
//C1-C6 16位 6个地址 每一个地址16位
/**********************************************************
* 函 数 名 称:MS5611_Read_PROM
* 函 数 功 能:读取出厂校准值
* 传 入 参 数:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
**********************************************************/
void MS5611_Read_PROM(void)
{
uint8_t data_H=0,data_L=0;
uint8_t i = 0;
for( i = 0; i < 8; i++ )
{
IIC_Start();//起始信号
Send_Byte(0xee|0); //器件地址+写
I2C_WaitAck();
Send_Byte( 0xA0 + i * 2 ); //寄存器地址
I2C_WaitAck();
IIC_Stop();
delay_us(200);
IIC_Start();//起始信号
Send_Byte(0xee|1); //器件地址+读
I2C_WaitAck();
data_H = Read_Byte();//读取的数据高8位
IIC_Send_Ack(0);
data_L = Read_Byte();//读取的数据低8位
IIC_Send_Ack(1);
IIC_Stop();
//保存出厂校准数据
Cal_C1_6[i] = (data_H<<8) | data_L;
}
}
/**********************************************************
* 函 数 名 称:MS5611_Read_D1_D2
* 函 数 功 能:读取气压D1和温度D2的初始数据
* 传 入 参 数:regaddr=0x48或0x58
* 函 数 返 回:返回读取后整合为24位的数据
* 作 者:LC
* 备 注:
* regaddr= 0x48 读取D1数据(OSR=4096)
* regaddr= 0x58 读取D2数据(OSR=4096)
**********************************************************/
uint32_t MS5611_Read_D1_D2(uint8_t regaddr)
{
uint32_t dat = 0;
uint8_t buff[3] ={0};
IIC_Start();//起始信号
Send_Byte(0xee|0); //器件地址+写
if( I2C_WaitAck() == 1 )printf("D1 NACK -1\r\n");
Send_Byte(regaddr); //OSR = 4096
if( I2C_WaitAck() == 1 )printf("D1 NACK -2\r\n");
IIC_Stop();
delay_ms(10);
IIC_Start();//起始信号
Send_Byte(0xee|0); //器件地址+写
if( I2C_WaitAck() == 1 )printf("D1 NACK -3\r\n");
Send_Byte(0X00);
if( I2C_WaitAck() == 1 )printf("D1 NACK -4\r\n");
IIC_Stop();
delay_ms(10);
IIC_Start();//起始信号
Send_Byte(0xee|1); //器件地址+读
if( I2C_WaitAck() == 1 )printf("D1 NACK -5\r\n");
buff[0] = Read_Byte();
IIC_Send_Ack(0);
buff[1] = Read_Byte();
IIC_Send_Ack(0);
buff[2] = Read_Byte();
IIC_Send_Ack(1);
IIC_Stop();
dat = (((buff[0]<<16) | ( buff[1]<<8)) | buff[2]);
return dat;
}
uint32_t D1 = 0, D2 = 0, dT = 0;
/**********************************************************
* 函 数 名 称:Get_TEMP
* 函 数 功 能:换算温度
* 传 入 参 数:无
* 函 数 返 回:没有小数点后的温度数据
* 作 者:LC
* 备 注:无
**********************************************************/
float Get_TEMP(void)
{
float dat = 0;
long long TEMP = 0;
D1 = MS5611_Read_D1_D2(0x48);
delay_ms(10);
D2 = MS5611_Read_D1_D2(0x58);
delay_ms(10);
dT = D2 - (Cal_C1_6[5] * 256.0);
TEMP = 2000 + (((float)dT * Cal_C1_6[6]) / 8388608.0);
// printf("temp = %lld%lld.%lld%lld\r\n",TEMP/1000, TEMP/100%10,TEMP/10%10,TEMP%10);
//没有小数的温度
dat = (((TEMP/1000)*10) + (TEMP/100%10)) ;
return dat;
}
/**********************************************************
* 函 数 名 称:Get_pressure
* 函 数 功 能:换算气压数据
* 传 入 参 数:无
* 函 数 返 回:返回气压,单位(HPa)
* 作 者:LC
* 备 注:无
**********************************************************/
float Get_pressure(void)
{
long long SENS = 0;
long long P =0;
long long OFF = 0;
Get_TEMP();
OFF = Cal_C1_6[2] * 65536.0 + Cal_C1_6[4] * dT / 128;
SENS = (Cal_C1_6[1] * 32768.0) + ((Cal_C1_6[3] * dT ) / 256.0);
P = (D1 * SENS / 2097152.0 - OFF) / 32768.0;
return (P/100.0);
}
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
在文件 bsp_sht10.h 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-19 LCKFB-LP first version
*/
#ifndef _BSP_MS5611_H_
#define _BSP_MS5611_H_
#include "stm32f4xx.h"
//端口移植
#define RCC_MS5611 RCC_AHB1Periph_GPIOA
#define PORT_MS5611 GPIOA
#define GPIO_SDA GPIO_Pin_2
#define GPIO_SCL GPIO_Pin_1
//设置SDA输出模式
#define SDA_OUT() { \
GPIO_InitTypeDef GPIO_InitStructure; \
GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; \
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; \
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; \
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
GPIO_Init(PORT_MS5611, &GPIO_InitStructure); \
}
//设置SDA输入模式
#define SDA_IN() { \
GPIO_InitTypeDef GPIO_InitStructure; \
GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; \
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; \
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; \
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
GPIO_Init(PORT_MS5611, &GPIO_InitStructure); \
}
//获取SDA引脚的电平变化
#define SDA_GET() GPIO_ReadInputDataBit(PORT_MS5611, GPIO_SDA)
//SDA与SCL输出
#define SDA(x) GPIO_WriteBit(PORT_MS5611, GPIO_SDA, (x?Bit_SET:Bit_RESET) )
#define SCL(x) GPIO_WriteBit(PORT_MS5611, GPIO_SCL, (x?Bit_SET:Bit_RESET) )
void MS5611_GPIO_Init(void);
char MS5611_Reset(void);
void MS5611_Read_PROM(void);
float Get_TEMP(void);
float Get_pressure(void);
#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
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
移植验证
在自己工程中的 main 主函数中,编写如下。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-19 LCKFB-LP first version
*/
#include "board.h"
#include "bsp_uart.h"
#include <stdio.h>
#include "bsp_ms5611.h"
int main(void)
{
board_init();
uart1_init(115200U);
MS5611_GPIO_Init();
MS5611_Reset();//器件复位
delay_ms(300);//等待初始化完成;
MS5611_Read_PROM();//读取出厂校准值
printf("start\r\n");
while(1)
{
//输出温度
printf("温度 = %.0f℃\r\n",Get_TEMP() );
//输出气压
printf("气压 = %.2fHPa\r\n",Get_pressure() );
printf("\n");
delay_ms(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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
移植现象:每隔一秒左右测量一次温度和气压。
代码下载
链接在开发板介绍
章节的离线资料下载!!