使用GD32303C-EVAL开发板和MPL3115A2模块测量气压或高度数据,两者间使用硬件I2C进行通讯。

一开始发现I2C读写异常,EXMC模块时钟使能就会导致I2C读取失败。通过逐步排查与调试验证,最终确认问题为PB7引脚使用冲突,EXMC模块与I2C均使用了开发板的PB7引脚。通过对I2C0功能的引脚remap配置,已经将问题解决。

那么下面就进入到了MPL3115A2模块的配置和使用了。

下面是焊接前后的模块实物图。

下面是所使用的GD32303C-EVAL开发板实物图。

由于前面已经调通了I2C硬件驱动,这里开始编写MPL3115A2模块初始化程序。

首先查看MPL3115A2的芯片手册,确认使用过程。

找到MPL3115A2的内部寄存器列表,查看需要使用的内容。

这里可以看到,0x01-0x05寄存器是保存测量结果的,其中0x01-0x03是保存气压值或高度值的,0x04和0x05是保存温度值的。

MPL3115有两种工作模式,气压计模式和高度计模式,在不同的工作模式下,0x01-0x03寄存器中保存的值是不同的,分别跟对应的工作模式匹配。就是说无论工作在什么模式,读取结果都是同样的寄存器地址。

0x00寄存器是状态寄存器。这个地址有点特别,在不同的数据模式下指向不同的寄存器地址。

MPL3115除了具有单次采样结果存储的模式之外,还具有FIFO功能,在开启FIFO数据模式的情况下,芯片可以保存最多32组数据,每组数据都包括气压值/高度值和温度值(5字节数据)。

在这个数据模式下,0x00地址指向的是0x0D寄存器,即I2C读取0x00地址的值,实际上读取的是0x0D寄存器(当然,直接读取0x0D寄存器也是可以的),这个寄存器是FIFO系统状态寄存器,可以查询有没有发生FIFO数据溢出事件以及FIFO数据有没有存储到设定数量。

在这个模式下,读取数据也不是0x01-0x05寄存器读取了。为了方便循环读取,可以始终读取0x01寄存器的值,读取到的值会轮流按照“气压值/高度值高字节→中字节→低字节→温度高字节→低字节→下一组值的气压/高度值高字节”的形式一直循环读取,直到读取完毕所有FIFO数据的值。而且按照I2C通讯连续读取时寄存器地址自增模式进行匹配,0x01寄存器地址在这个模式下的自增地址还是0x01,即按照I2C总线通讯模式进行连续读取,寄存器地址选择为0x01,一直读取,会一直读到0x01地址的值,直到读取完所有数据。

而如果没有开启FIFO数据模式,0x00寄存器地址指向的是0x06寄存器,这个寄存器也是状态寄存器,这个寄存器可以查看有没有出现数据覆盖以及当前数据有没有准备好。

由于没有启用FIFO数据模式,这个模式下只能保存一组数据(气压值/高度值和温度值,共5字节),分别存放在0x01-0x05寄存器里,读取时直接连续读取5字节即可。如果一直循环读取,读完0x05寄存器之后寄存器指针会自动再次定位到0x00寄存器,再次进行一轮读取,但是由于这时候下一组采样数据还没有准备好,因此读出来的值无效(应该为0,不过没有验证)。

工作模式大概说了一下,继续查看如何配置工作模式。首先使用最简单的模式:不启用FIFO数据的连续采样模式。

可以看到,控制寄存器有5个,分别查看每个寄存器的介绍,发现只要控制第一个控制寄存器0x26即可完成初步使用。

这个寄存器可以配置芯片工作在气压计模式或高度计模式,可以配置过采样次数,可以配置芯片的待机模式和激活模式。

通过描述来看,直接将SBYB位置1即可使芯片进入激活模式,开始进行采样。

于是初始化函数如下(气压计模式,过采样设置为最大128,增加数据稳定性):

init8_t MPL_Init(void){uint8_t reg_data, get_data;reg_data = 0x39;eeprom_byte_write(& reg_data, CTRL_REG1_ADDR);eeprom_buffer_read(&get_data, CTRL_REG1_ADDR, 1);if(get_data==reg_data){return 0;}else{return -1;}}

其中CTRL_REG1_ADDR为0x26。

同时编写结果读取函数(刚开始只是把结果读取出来,至于数值转换等读取成功之后再处理):

int8_t MPL_Result_Read(void){uint8_t status;uint8_t data_buf[5];eeprom_buffer_read(&status, DATA_STATUS_ADDR, 1);if((status & 0x08) == 0){return -1;}eeprom_buffer_read(data_buf, DATA_START_ADDR, 5);return 0;}

其中DATA_STATUS_ADDR为0x00,而DATA_START_ADDR为0x01。

编译、烧录、运行,结果发现读取DATA_STATUS_ADDR始终为0。好吧,继续找问题。

单步调试运行,发现控制寄存器写入成功了,但是读取状态寄存器确实为0,那么久确认问题不是出在I2C读写上。

继续看手册,同时网上找一下例程(例程放到附件里)。

通过对比网上找的例程,发现多了一个寄存器的操作:0x13寄存器。查看手册,发现这个是数据更新状态置位允许寄存器,就是说这个寄存器可以配置允许哪些情况产生事件更新标志。

原来问题在这里。这个寄存器配置了允许,数据采样完成后才会在状态寄存器里产生标志位。

OK!了解了。然后按照例程里的模式,对控制寄存器进行写入,并增加了读取验证过程,同时增加了气压计/高度计模式选择控制,避免来回切换工作模式都要改动初始化函数。并在运行完成之后显示初始化结果。

void MPL_Init(uint8_t mode){uint8_t i, mode_data,reg_data, get_data=0;if(mode==0){mode_data = 0x38;}else{mode_data = 0xB8;}reg_data = mode_data;eeprom_byte_write(& reg_data, CTRL_REG1_ADDR);eeprom_buffer_read(&get_data, CTRL_REG1_ADDR, 1);if(get_data!=reg_data){MPL_ERR_Display();return;}reg_data = 0x07;eeprom_byte_write(& reg_data, PT_DATA_CFG_ADDR);eeprom_buffer_read(&get_data, PT_DATA_CFG_ADDR, 1);if(get_data!=reg_data){MPL_ERR_Display();return;}reg_data = mode_data + 1;eeprom_byte_write(& reg_data, CTRL_REG1_ADDR);eeprom_buffer_read(&get_data, CTRL_REG1_ADDR, 1);if(get_data!=reg_data){MPL_ERR_Display();return;}MPL_OK_Display();}

再次编译、烧录、运行,这次果然读取到状态和数据了。

下面就是数据格式转换了,这个相对简单,按照手册上的说明对数据进行位移和拼接处理,即可得到正确的结果。这里为了显示方便,直接将整数部分和小数部分分别存储,然后拼接显示在TFT屏幕上的。

int8_t MPL_Result_Read(void){uint8_t status;uint8_t data_buf[5];eeprom_buffer_read(&status, DATA_STATUS_ADDR, 1);if((status & 0x08) == 0){return -1;}eeprom_buffer_read(data_buf, DATA_START_ADDR, 5);height_integer = (uint32_t)data_buf[0]*0x100 + (uint32_t)data_buf[1];height_decimal = (data_buf[2]>>4) * 625;temp_integer = data_buf[3];temp_decimal = (data_buf[4]>>4) * 625;pressure_value = (uint32_t)data_buf[0]*0x400 + (uint32_t)data_buf[1]*0x04 + (data_buf[2]>>6);return 0;}

这里将高度计模式和气压计模式两种模式下的转换关系都保存了下来,当然,同一模式下肯定有一组转换结果是错误的,但是只使用正确的结果就可以了,防止每次切换模式都去修改代码,毕竟调试阶段经常变换模式是很正常的。同时这里将气压计模式的小数位直接丢弃了(精度不够)。

下面是高度计模式的运行结果示意,分别显示高度值和温度值。

然后开始运行,同时查看测量结果的变化是否符合预期。

初步观察,发现测量结果会有波动,但是波动值范围在±0.3m范围内,符合预期情况。

由于我是在4楼办公,于是准备逐层下到1楼,再上到4楼,来查看测量结果的变化。

实验结果如下:一开始在4楼时高度约16m,下到3楼高度约12.5m,下到2楼高度约7m,下到1楼高度约2.5m,再上到2楼高度约7m,上到3楼高度约12m,上到4楼高度约15.5m。

通过初步测试,剔除掉绝对误差后,发现基本可以测量出楼层高度。

但是在办公室一直运行时发现一个问题,测量值一直在漂移,一两个小时测量结果就能漂移10m左右,而温度的变化很小,不应该引起这么大的漂移。以为是没有配置好芯片工作模式,于是继续查资料,找例程。同时对接淘宝卖家,问下有没有技术支持或者例程代码之类的。

最终卖家发过来一个例程代码包,C++语言编写的,不过大致看一下配置过程还是OK的。(例程见附件)

多方对比之下,发现我的配置流程和读取流程没有问题,就是这么用的。

那么是什么原因导致的测量结果漂移呢?

为了确认漂移的情况,我对程序增加了结果上传功能,通过串口实时将测量结果上传到电脑上,通过串口助手接收保存数据。

然后进行长时间的采样、数据保存,并对采集到的数据按照时间进行图表绘制,确认其变化趋势。

可以看出,温度的变化(右侧的附坐标轴)很小,基本上在25.5-27.5度之间变化,而高度值在整个过程中(约13小时)从23m左右最终下降到0m附近。可以看出其瞬时值还是相对比较准的(趋势线不是特别粗),那是什么原因导致了长时间的测量值漂移这么大呢?

这时候我想到了一个问题,一天之内大气压是稳定的么?毕竟大气是气体,整体包裹在地球外部,并没有一个特定的容器去限制它,而且天气、风、云等等也可能影响到大气压。于是我去搜了一下,大气压在一天之内有没有变化。

结果搜到一个“气压日变化”的词条,里面说了大气在一天之内的变化规律。

气压日变化
气压日变化的特点是在一天中有一个最高值和一个次高值,一个最低值和一个次低值。最高值出现在9 ~10时,次高值出现在21~22时;最低值出现在15~16时,次低值出现在3~4时。

气压的日变化在低纬度地区比较明显。气压日振幅(一日中最高值与最低值之差,又称为日较差)随纬度的增高而减小。在低纬地区,平均日振幅可达3~4百帕,到纬度50度附近日振幅不足1 百帕了。不同纬度上气压日变化的情况,在我国中纬度地区气压日振幅为1~2.5百帕,在低纬地区为2.5~4百帕,而在西藏高原东部边缘的山谷中气压的日振幅有时可达6. 5百帕。

对照这个说明,可以看到大气压在一天之内变化几百帕是正常的,换算成高度的话差不多有几十米,因此测到的漂移应该是正常的。

为了验证这个结果,我继续进行长时间连续数据采集,采集够24小时的测量结果(早上上班前约7点50分测量到第二天早上上班前),得到的趋势图如下:

可以从趋势图中看出,高度值在上午9时-10时左右最低,在下午16时左右最高,这刚好对应了上面词条里说的气压最高值出现在9-10时,最低值出现在15-16时(气压越高海拔越低)。而较小的波峰波谷也基本上能对应词条里的次低值和次高值时段。

因此基本确认了长时间的测量结果漂移实际上是大气压的真实变化,而不是芯片测量不准确。

至此,问题基本解决,测量结果也符合预期,后期加上数据修正和基准补偿之后,可以相对准确的获取当前的高度值。

注:代码里配置寄存器时eeprom_byte_write(& reg_data, CTRL_REG1_ADDR);这里&和reg_data中间不应该有空格的,但是不加空格的话论坛会显示®_data。这个只能在这里做一个说明。

代码见原文。
---------------------
作者:blust5
链接:https://bbs.21ic.com/icview-3301492-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

【技术分享】MPL3115A2模块测量气压与海拔高度相关推荐

  1. 技术分享:印制插头侧面包镍金加工工艺研究

    1.前 言 随着通讯领域的发展,光模块产品的使用环境越来越复杂,采用传统闪金+印制插头硬金加工的PCB因为印制插头与焊盘侧面为蚀刻后残留的铜面,不能通过客户的较为严格的盐雾测试,因此客户提出了侧面包裹 ...

  2. android4 设置栈大小,【技术分享】Android内核漏洞利用技术实战:环境搭建栈溢出实战...

    [技术分享]Android内核漏洞利用技术实战:环境搭建&栈溢出实战 2017-08-14 16:22:02 阅读:0次 预估稿费:300RMB 投稿方式:发送邮件至linwei#360.cn ...

  3. SAP技术专家Jerry的技术分享微信群 - 2021年1月14日更新 - 还剩27个名额

    SAP技术专家Jerry的技术分享微信群 2020年10月19日才创建的微信群,里面会不定期分享我的工作感受和对SAP技术发展方向的个人看法,欢迎扫码加入. 加入群后请将自己的昵称改成如下格式: &l ...

  4. 技术分享 | 混合云模式下SaaS端前端最佳实践

    导读:集成开放平台采用的是混合云部署架构,包含两个大的组件,管理控制台和引擎.管理控制台是SaaS的,部署在公有云,按租户隔离.引擎部署在客户私有云.一套SaaS版的管理控制台如何适配不同客户的引擎, ...

  5. 技术分享 | CodeReview主要Review什么?

    源宝导读:Code Review, 意即代码审查,是指一种有意识和系统的召集其他程序员来检查彼此的代码是否有错误的地方. 在敏捷团队中推行CodeReview, 可以帮助团队快速成长.本文将分享在&q ...

  6. 技术分享|单元测试推广与实战-在全新的DDD架构上进行单元测试

    源宝导读:单元测试是伴随软件工程出现和发展的,怎么做大家可能各有见解.本文介绍了单元测试中的反模式,强调了可测试性的重要性,并以 DDD 架构项目的迭代进程作为示例,演示了单元测试的组织过程,展示了单 ...

  7. 【华为云技术分享】三大前端技术(React,Vue,Angular)探密(下)

    [华为云技术分享]三大前端技术(React,Vue,Angular)探密(上) [Angular] Angular(通常被称为 "Angular 2+"或 "Angula ...

  8. 技术分享——机房搬迁工作步骤及方案详解

    技术分享--机房搬迁工作步骤及方案详解 随着企业.单位的不断深入发展,现有的涉及办公.生产场所已经不能满足,新的厂房及办公大楼逐渐筹建,那么机房搬迁或机房改建服务应运而生,而机房搬迁作为一项非常重要的 ...

  9. 尤雨溪 6 月 4 日的 Vue 技术分享

    尤大于 6 月 4 日,在深圳某科技公司做了一次 Vue 相关的技术分享.这里我讲 PPT 分享给大家. 线下聚会:https://events.vuejs.or Vue 团队成员简介:https:/ ...

最新文章

  1. 参数控制c语言代码走向,C语言可变参数完全解读
  2. C++文件流操作备忘录
  3. gatsby_如何使用Gatsby和MDX从头开始构建编码博客
  4. go高性能tcp服务器,在Go中构建并发TCP服务器
  5. 还对Angel平台一知半解?腾讯专家为你指点迷津!
  6. mysql一个表中多个字段对应另一个表的id如何查询?
  7. python 流写入文件_Python数据流写入文件
  8. 人脸对齐(五)--ESR算法
  9. 【HDU-5246】超级赛亚ACMer(贪心)
  10. 我把SpringBoot的banner换成了美女,老板说工作不饱和,建议安排加班...
  11. 输出滑动窗口最大值(双端队列)
  12. 解锁网易云音乐客户端变灰歌曲的详细教程
  13. 【6G】算力网络技术白皮书整理
  14. pageHelper.startPage(m,n)的用法
  15. Arduino通过串口透传ESP 13板与java程序交互
  16. AI实战:文本自动摘要简述
  17. 【android】几种模拟按键、屏幕点击的方法
  18. 服务器机箱装系统蓝屏,电脑安装系统,容易出现蓝屏、死机等5大问题,装机达人给你支招...
  19. VSCode下载慢的问题解决
  20. GEE学习笔记:在Google Earth Engine(GEE)中批量下载Sentinel-2影像

热门文章

  1. git删除本地分支和线上分支
  2. 【00】-迟来的毕设进度记录-【素材、场景搭建(一)】
  3. 红米K30至尊纪念版和红米K30参数对比哪个好
  4. 12306火车票查询api调用文档
  5. Android布局measure,android  OnMeasure()深入理解(总结)
  6. python socketio 服务器编程
  7. VNPY使用记录(二) -- 模拟盘接入
  8. 微信小程序案例——简易前端与云数据库的使用
  9. mybatis通过注解使用动态sql
  10. android 字体粗体_10多种免费的粗体和粗体字体使您的设计更加生动