MS5611气压传感器
模块来源
采购链接:
https://item.taobao.com/item.htm?spm=a230r.1.14.18.c2c52122lnx328&id=522572301522&ns=1&abbucket=19
资料下载链接:
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
移植过程
首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
查看资料
当PS引脚接高电平时,传感器属于IIC模式;当PS引脚接低电平时,传感器属于SPI模式;在原理图上,PS引脚通过上拉电阻接了高电平,故默认为IIC模式。
器件地址 = 0XEE
CSB的反补码 即CSB引脚接高电平时, 地址为 1110 110+(读写位)
CSB的反补码 即CSB引脚接低电平时, 地址为 1110 111+(读写位)
读取气压与温度的流程:开始-> 读取出厂校准值C1至C6 -> 读取气压D1和温度D2的原始数据 -> 将D2和C1C6带入公式求出dT和TEMP,其中TEMP为温度数据-> 将dT和C1至C6带入公式求出OFF、SENS和P,其中P为气压数据。
引脚选择
移植至工程
移植步骤中的导入.c和.h文件与上一节相同,只是将.c和.h文件更改为bsp_ms5611.c与bsp_ms5611.h。移植完成后面修改相关代码。
详细可见【TTP224触摸传感器】中的移植至工程目录。这里不再过多讲述。移植完成后面修改相关代码。
在文件bsp_ms5611.c中,编写如下代码
/********************************************************************************
* 文 件 名: bsp_ms5611.c
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年11月02日
* 功能介绍: 气压传感器MS5611的底层驱动
* 使用说明: 初始化的顺序:
MS5611_Reset();//器件复位
delay_1ms(300);//等待初始化完成;
MS5611_Read_PROM();//读取出厂校准值
while(1)
{
Get_pressure();//获取气压与温度
}
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#include "bsp_ms5611.h"
#include "bsp_usart.h"
#include "stdio.h"
#include "systick.h"
//出厂校准值
//Cal_C1_6[] = 厂家信息
//Cal_C1_6[] ~ Cal_C1_6[] = 校准值
//Cal_C1_6[] = 校准值的CRC校验
uint16_t Cal_C1_6[];
/******************************************************************
* 函 数 名 称:MS5611_GPIO_Init
* 函 数 说 明:MS5611的引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void MS5611_GPIO_Init(void)
{
/* 使能时钟 */
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);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_SCL,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,GPIO_SCL);
/* 配置SDA为输出模式 */
gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_SDA);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_SDA,GPIO_OTYPE_OD,GPIO_OSPEED_50MHZ,GPIO_SDA);
}
/******************************************************************
* 函 数 名 称: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[] = (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[] ={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_1ms(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_1ms(10);
IIC_Start();//起始信号
Send_Byte(0xee|1); //器件地址+读
if( I2C_WaitAck() == 1 )printf("D1 NACK -5\r\n");
buff[] = Read_Byte();
IIC_Send_Ack(0);
buff[] = Read_Byte();
IIC_Send_Ack(0);
buff[] = Read_Byte();
IIC_Send_Ack(1);
IIC_Stop();
dat = (((buff[]<<16) | ( buff[]<<8)) | buff[]);
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_1ms(10);
D2 = MS5611_Read_D1_D2(0x58);
dT = D2 - (Cal_C1_6[] * 256.0);
TEMP = 2000 + (((float)dT * Cal_C1_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[] * 65536.0 + Cal_C1_6[] * dT / 128;
SENS = (Cal_C1_6[] * 32768.0) + ((Cal_C1_6[] * 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
375
376
377
378
379
380
381
382
在文件bsp_ms5611.h中,编写如下代码
/********************************************************************************
* 文 件 名: bsp_ms5611.h
* 版 本 号: 初版
* 修改作者: LC
* 修改日期: 2023年11月02日
* 功能介绍:
******************************************************************************
* 开发板官网:www.lckfb.com
*********************************************************************************/
#ifndef _BSP_MS5611_H_
#define _BSP_MS5611_H_
#include "gd32e23x.h"
//端口移植
#define RCU_SDA RCU_GPIOA
#define PORT_SDA GPIOA
#define GPIO_SDA GPIO_PIN_2
#define RCU_SCL RCU_GPIOA
#define PORT_SCL GPIOA
#define GPIO_SCL GPIO_PIN_1
//设置SDA输出模式
#define SDA_OUT() gpio_mode_set(PORT_SDA,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_SDA)
//设置SDA输入模式
#define SDA_IN() gpio_mode_set(PORT_SDA,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP,GPIO_SDA)
//获取SDA引脚的电平变化
#define SDA_GET() gpio_input_bit_get(PORT_SDA,GPIO_SDA)
//SDA与SCL输出
#define SDA(x) gpio_bit_write(PORT_SDA,GPIO_SDA, (x?SET:RESET))
#define SCL(x) gpio_bit_write(PORT_SCL,GPIO_SCL, (x?SET: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
移植验证
在自己工程中的main主函数中,编写如下。
/******************************************************************************
* 测试硬件:立创开发板·GD32E230C8T6 使用主频72Mhz 晶振8Mhz
* 版 本 号: V1.0
* 修改作者: www.lckfb.com
* 修改日期: 2023年11月02日
* 功能介绍:
*****************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:【立创·GD32E230C8T6开发板】模块移植手册
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
******************************************************************************/
#include "gd32e23x.h"
#include "systick.h"
#include <stdio.h>
#include "bsp_usart.h"
#include "bsp_ms5611.h"
int main(void)
{
systick_config(); // 滴答定时器初始化
usart_gpio_config(9600U); // 串口0初始化
MS5611_GPIO_Init();
MS5611_Reset();//器件复位
delay_1ms(300);//等待初始化完成;
MS5611_Read_PROM();//读取出厂校准值
printf("start\r\n");
while(1)
{
//输出温度
printf("temp = %.0f℃\r\n",Get_TEMP() );
//输出气压
printf("pressure = %.2fHPa\r\n",Get_pressure() );
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
33
34
35
36
37
38
39
40
41
42
43
44
移植现象:每隔一秒测量一次温度和气压,并发送至串口0。