基于STM32平台的BMP180测试(模拟IIC)

来源:互联网 发布:python 捕捉ctrl c 编辑:程序博客网 时间:2024/06/15 21:35

1.测试描述:

使用模拟IIC,从BMP180中获取ID号、温度值、气压值以及计算海拔高度。

2.测试准备:

硬件平台:原子战舰V3开发板
测试工具:逻辑分析仪、串口调试工具


3.数据手册解读:

(1) 首先是多个字节的读取时序图,从这里也可以看出BMP180芯片的地址+写信号是0xEE,地址+读信号为0xEF,当然手册前面也有提到过,有兴趣的可以自己去查看一下手册。

这里写图片描述

(2) 然后本人测试时默认使用的是下图画横线部分的部分,也就是气压这块使用的是低功耗模式。OSS的值要注意,因为后期的计算需要这个,并且读取UT值时也要做对应的处理。

这里写图片描述

(3) 下图就是手册里给出的利用BMP180里的参数计算气压和温度的流程图。特别注意流程里的OSS,由于本测试使用的OSS = 0,所以在实际代码中省去了这一部分。

这里写图片描述

4.测试代码:

由于本工程是直接使用原子战舰的标准例程-库函数版本\实验23 IIC实验源码改过来的,所以模拟IIC部分使用的原子这块的代码。BMP180部分由本人编写。
(1) 首先是BMP180.C的代码片

#include "bmp180.h"#include "delay.h"#include "math.h"//存储BMP180数据的结构_bmp180 bmp180;//BMP180初始化//对使用的IIC端口进行初始化void BMP_Init(void){    IIC_Init();}//写一个数据到BMP180void BMP_WriteOneByte(uint8_t WriteAddr,uint8_t DataToWrite){    IIC_Start();    IIC_Send_Byte(0xEE);    IIC_Wait_Ack();    IIC_Send_Byte(WriteAddr);    IIC_Wait_Ack();    IIC_Send_Byte(DataToWrite);    IIC_Wait_Ack();    IIC_Stop();}//从BMP180读一个字节数据uint8_t BMP_ReadOneByte(uint8_t ReadAddr){    uint8_t data = 0;    IIC_Start();    IIC_Send_Byte(0xEE);    IIC_Wait_Ack();    IIC_Send_Byte(ReadAddr);    IIC_Wait_Ack();    IIC_Start();    IIC_Send_Byte(0xEF);    IIC_Wait_Ack();    data = IIC_Read_Byte(1);    IIC_Stop();    return data;}//从BMP180读一个16位的数据short BMP_ReadTwoByte(uint8_t ReadAddr){    short data;    uint8_t msb,lsb;    IIC_Start();    IIC_Send_Byte(0xEE);    IIC_Wait_Ack();    IIC_Send_Byte(ReadAddr);    IIC_Wait_Ack();    IIC_Start();    IIC_Send_Byte(0xEF);    IIC_Wait_Ack();    msb = IIC_Read_Byte(1);    lsb = IIC_Read_Byte(0);    IIC_Stop();    data = msb*256 + lsb;    return data;}//从BMP180的获取计算参数void BMP_ReadCalibrationData(void){    bmp180.AC1 = BMP_ReadTwoByte(0xAA);    bmp180.AC2 = BMP_ReadTwoByte(0xAC);    bmp180.AC3 = BMP_ReadTwoByte(0xAE);    bmp180.AC4 = BMP_ReadTwoByte(0xB0);    bmp180.AC5 = BMP_ReadTwoByte(0xB2);    bmp180.AC6 = BMP_ReadTwoByte(0xB4);    bmp180.B1  = BMP_ReadTwoByte(0xB6);    bmp180.B2  = BMP_ReadTwoByte(0xB8);    bmp180.MB  = BMP_ReadTwoByte(0xBA);    bmp180.MC  = BMP_ReadTwoByte(0xBC);    bmp180.MD  = BMP_ReadTwoByte(0xBE);}//从BMP180读取未修正的温度long BMP_Read_UT(void){    long temp = 0;    BMP_WriteOneByte(0xF4,0x2E);    delay_ms(5);    temp = (long)BMP_ReadTwoByte(0xF6);    return temp;}//从BMP180读取未修正的大气压long BMP_Read_UP(void){    long pressure = 0;    BMP_WriteOneByte(0xF4,0x34);    delay_ms(5);    pressure = (long)BMP_ReadTwoByte(0xF6);    //pressure = pressure + BMP_ReadOneByte(0xf8);    pressure &= 0x0000FFFF;    return pressure;}//用获取的参数对温度和大气压进行修正,并计算海拔void BMP_UncompemstatedToTrue(void){    bmp180.UT = BMP_Read_UT();//第一次读取错误    bmp180.UT = BMP_Read_UT();//进行第二次读取修正参数    bmp180.UP = BMP_Read_UP();    bmp180.X1 = ((bmp180.UT - bmp180.AC6) * bmp180.AC5) >> 15;    bmp180.X2 = (((long)bmp180.MC) << 11) / (bmp180.X1 + bmp180.MD);    bmp180.B5 = bmp180.X1 + bmp180.X2;    bmp180.Temp  = (bmp180.B5 + 8) >> 4;    bmp180.B6 = bmp180.B5 - 4000;    bmp180.X1 = ((long)bmp180.B2 * (bmp180.B6 * bmp180.B6 >> 12)) >> 11;    bmp180.X2 = ((long)bmp180.AC2) * bmp180.B6 >> 11;    bmp180.X3 = bmp180.X1 + bmp180.X2;    bmp180.B3 = ((((long)bmp180.AC1) * 4 + bmp180.X3) + 2) /4;    bmp180.X1 = ((long)bmp180.AC3) * bmp180.B6 >> 13;    bmp180.X2 = (((long)bmp180.B1) *(bmp180.B6*bmp180.B6 >> 12)) >>16;    bmp180.X3 = ((bmp180.X1 + bmp180.X2) + 2) >> 2;    bmp180.B4 = ((long)bmp180.AC4) * (unsigned long)(bmp180.X3 + 32768) >> 15;    bmp180.B7 = ((unsigned long)bmp180.UP - bmp180.B3) * 50000;    if(bmp180.B7 < 0x80000000)    {        bmp180.p = (bmp180.B7 * 2) / bmp180.B4;         }    else    {        bmp180.p = (bmp180.B7 / bmp180.B4) * 2;    }    bmp180.X1 = (bmp180.p >> 8) * (bmp180.p >>8);    bmp180.X1 = (((long)bmp180.X1) * 3038) >> 16;    bmp180.X2 = (-7357 * bmp180.p) >> 16;    bmp180.p = bmp180.p + ((bmp180.X1 + bmp180.X2 + 3791) >> 4);    bmp180.altitude = 44330 * (1-pow(((bmp180.p) / 101325.0),(1.0/5.255)));  }

(2) 然后是BMP180.H部分

#ifndef _BMP180_H_#define _BMP180_H_#include "myiic.h"typedef struct __BMP180{    short AC1;    short AC2;    short AC3;    unsigned short AC4;    unsigned short AC5;    unsigned short AC6;    short B1;    short B2;    short MB;    short MC;    short MD;    long UT;    long UP;    long X1;    long X2;    long X3;    long B3;    unsigned long B4;    long B5;    long B6;    long B7;    long p;    long Temp;    float altitude;}_bmp180;extern _bmp180 bmp180;void BMP_Init(void);uint8_t BMP_ReadOneByte(uint8_t ReadAddr);void BMP_WriteOneByte(uint8_t WriteAddr,uint8_t DataToWrite);short BMP_ReadTwoByte(uint8_t ReadAddr);void BMP_ReadCalibrationData(void);long BMP_Read_UT(void);long BMP_Read_UP(void);void BMP_UncompemstatedToTrue(void);#endif

由于是测试,所以将所有的参数都建了一个结构体,方便DEBUG时通过WATCH窗口查看,实际使用当中可以将一些非必要的参数做成临时变量。

5.测试时遇到的问题:

在BMP_UncompemstatedToTrue函数中,开头时首先读取UT和UP的值。开始时两者都只是读取一次,测算时发现UT值并未正确读出,为0,从而导致算出来的实际温度值在-71度左右,海拔在2500多米。通过逻辑分析仪监测,发现在第一次读取数据时,模拟IIC部分发出的数据是错误的。如下图画线处所示:
这里写图片描述
但是从图中可以看出,后面部分是正常的。针对这个现象我对延时、底层驱动模块都做了改变和测试,没有任何的改观。所以后面将UT值读取两次,就是为了消除这个错误,这也是一个折中的办法。经修改后实测读取正常。

6.测试结果:

这里写图片描述

本人在上海,平均海拔在4m的样子,温度值基本一致。由于海拔、温度、气压三者之间的联系,所以该气压也大致可以认定为测算出的实际大气压。

7.测试源码:

链接:http://pan.baidu.com/s/1gfH2SXd 密码:zr7g