STM32F103VCT6驱动气压计芯片BMP180

2019-07-20 12:06发布

[mw_shl_code=c,true][/mw_shl_code] 最近驱动了一款气压计传感器BMP180,拿出来和大家分享一下。希望能帮到那些正为此困惑的人。

实际效果如下图。说明一下,本人在江苏昆山,海平面较低,所以显示海拔只有32.4m。我用真空发生器做过实验,压强会减小,海拔会上升。精度还需做更精确的实验区验证。

此程序完全按照数据手册里面的配置说明一步一步配置,然后读取寄存器参数,然后转换结果。数据手册如附件,我已经标明了重点需要看的地方。
程序源码如下:
[mw_shl_code=c,true]#include "iic.h" #include "delay.h" //调用了延时函数 #include "usart.h" #include <math.h> //SCL -> PC1 //SDA -> PC2 #define SCL_H() GPIO_SetBits(GPIOC, GPIO_Pin_1) #define SCL_L() GPIO_ResetBits(GPIOC, GPIO_Pin_1) #define SDA_H() GPIO_SetBits(GPIOC, GPIO_Pin_2) #define SDA_L() GPIO_ResetBits(GPIOC, GPIO_Pin_2) #define SDA GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2) #define BMP180_SlaveAddr 0xee //BMP180的器件地址 //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; u8 BMP180_ID=0; //BMP180的ID float True_Temp=0; //实际温度,单位:℃ float True_Press=0; //实际气压,单位a float True_Altitude=0; //实际高度,单位:m /*外部芯片IIC引脚初始化 *SCLC1 *SDAC2 */ void IIC_PortInit(void) { GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO_InitTypeDef类型的结构体 GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_1|GPIO_Pin_2); //PC1,PC2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //漏极开漏 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC, GPIO_Pin_1|GPIO_Pin_2); //拉高 } void IIC_Init(void) { SCL_H(); //SCL = 1; delay_us(5); SDA_H(); //SDA = 1; delay_us(5); } void IIC_Start(void) { SDA_H(); //SDA = 1; delay_us(5); SCL_H(); //SCL = 1; delay_us(5); SDA_L(); //SDA = 0; delay_us(5); } void IIC_Stop(void) { SDA_L(); //SDA = 0; delay_us(5); SCL_H(); //SCL = 1; delay_us(5); SDA_H(); //SDA = 1; delay_us(5); } unsigned char IIC_ReceiveACK(void) { unsigned char ACK; SDA_H(); //SDA=1;//要读低电平需先拉高再读,否则读到的是错误数据,很重要! SCL_H(); //SCL=1; delay_us(5); if (SDA==1) //SDA为高 { ACK = 1; } else ACK = 0; //SDA为低 SCL_L(); //SCL = 0;//SCL为低电平时SDA上的数据才允许变化,为传送下一个字节做准备 delay_us(5); return ACK; } void IIC_SendACK(unsigned char ack) { if (ack == 1)SDA_H(); else if (ack == 0)SDA_L(); //SDA = ack; SCL_H(); //SCL = 1; delay_us(5); SCL_L(); //SCL = 0; delay_us(5); } unsigned char IIC_SendByte(unsigned char dat) { unsigned char i; unsigned char bResult=1; SCL_L(); //SCL = 0;//拉低时钟线 delay_us(5); for( i=0;i<8;i++ ) //一个SCK,把dat一位一位的移送到SDA上 { if( (dat<<i)&0x80 )SDA_H(); //SDA = 1;//先发高位 else SDA_L(); //SDA = 0; delay_us(5); SCL_H(); //SCL = 1; delay_us(5); SCL_L(); //SCL = 0; delay_us(5); } bResult=IIC_ReceiveACK(); //发送完一个字节的数据,等待接受应答信号 return bResult; //返回应答信号 } unsigned char IIC_ReadByte(void) { unsigned char dat; unsigned char i; SCL_H(); //SCL = 1;//始终线拉高为读数据做准备 delay_us(5); for( i=0;i<8;i++ ) { dat <<= 1; dat = dat | (SDA); delay_us(5); SCL_L(); //SCL = 0; delay_us(5); SCL_H(); //SCL = 1; delay_us(5); } return dat; } /*从BMP180中读1个字节的数据*/ u8 BMP180_ReadOneByte(u8 ReadAddr) { u8 temp = 0; u8 IIC_ComFlag = 1; //IIC通信标志,为0标志正常,1表示通信错误 IIC_Start(); //IIC start IIC_ComFlag = IIC_SendByte(BMP180_SlaveAddr); //slave address+W:0 //printf("IIC_ComFlag=%u ",IIC_ComFlag); if (IIC_ComFlag == 0) //返回值为0表示通信正常,可以继续通信。否则不通信了 { IIC_SendByte(ReadAddr); //发送命令代码 IIC_Start(); IIC_SendByte(BMP180_SlaveAddr|0x01); //slave address+R:1 temp = IIC_ReadByte(); //读数据 IIC_SendACK(1); IIC_Stop(); } return (temp); } /*从BMP180中读2个字节的数据*/ short BMP180_ReadTwoByte(u8 ReadAddr) { u8 IIC_ComFlag = 1; //IIC通信标志,为0标志正常,1表示通信错误 u8 MSB,LSB; short temp; IIC_Start(); IIC_ComFlag = IIC_SendByte(BMP180_SlaveAddr); if (IIC_ComFlag == 0) { IIC_SendByte(ReadAddr); IIC_Start(); IIC_SendByte(BMP180_SlaveAddr|0x01); MSB = IIC_ReadByte(); //先读高位 IIC_SendACK(0); //ACK LSB = IIC_ReadByte(); //再读低位 IIC_SendACK(1); //NACK IIC_Stop(); } temp = MSB*256+LSB; return temp; } /*向BMP180的寄存器写一个字节的数据*/ void Write_OneByteToBMP180(u8 RegAdd, u8 Data) { IIC_Start(); //IIC start IIC_SendByte(BMP180_SlaveAddr); //slave address+W:0 IIC_SendByte(RegAdd); IIC_SendByte(Data); IIC_Stop(); } /*读取BMP180的校准系数*/ void Read_CalibrationData(void) { AC1 = BMP180_ReadTwoByte(0xaa); AC2 = BMP180_ReadTwoByte(0xac); AC3 = BMP180_ReadTwoByte(0xae); AC4 = BMP180_ReadTwoByte(0xb0); AC5 = BMP180_ReadTwoByte(0xb2); AC6 = BMP180_ReadTwoByte(0xb4); B1 = BMP180_ReadTwoByte(0xb6); B2 = BMP180_ReadTwoByte(0xb8); MB = BMP180_ReadTwoByte(0xba); MC = BMP180_ReadTwoByte(0xbc); MD = BMP180_ReadTwoByte(0xbe); printf("AC1:%d ",AC1); printf("AC2:%d ",AC2); printf("AC3:%d ",AC3); printf("AC4:%d ",AC4); printf("AC5:%d ",AC5); printf("AC6:%d ",AC6); printf("B1:%d ",B1); printf("B2:%d ",B2); printf("MB:%d ",MB); printf("MC:%d ",MC); printf("MD:%d ",MD); } /*读BMP180没有经过补偿的温度值*/ long Get_BMP180UT(void) { long UT; Write_OneByteToBMP180(0xf4,0x2e); //write 0x2E into reg 0xf4 delay_ms(10); //wait 4.5ms UT = BMP180_ReadTwoByte(0xf6); //read reg 0xF6(MSB),0xF7(LSB) printf("UT:%ld ",UT); return UT; } /*读BMP180没有经过补偿的压力值*/ long Get_BMP180UP(void) { long UP=0; Write_OneByteToBMP180(0xf4,0x34); //write 0x34 into reg 0xf4 delay_ms(10); //wait 4.5ms UP = BMP180_ReadTwoByte(0xf6); UP &= 0x0000FFFF; printf("UP:%ld ",UP); return UP; } /*把未经过补偿的温度和压力值转换为时间的温度和压力值 *True_Temp:实际温度值,单位:℃ *True_Press:时间压力值,单位a *True_Altitude:实际海拔高度,单位:m */ void Convert_UncompensatedToTrue(long UT,long UP) { long X1,X2,X3,B3,B5,B6,B7,T,P; unsigned long B4; X1 = ((UT-AC6)*AC5)>>15; //printf("X1:%ld ",X1); X2 = ((long)MC<<11)/(X1+MD); //printf("X2:%ld ",X2); B5 = X1+X2; //printf("B5:%ld ",B5); T = (B5+8)>>4; //printf("T:%ld ",T); True_Temp = T/10.0; printf("Temperature:%.1f ",True_Temp); B6 = B5-4000; //printf("B6:%ld ",B6); X1 = (B2*B6*B6)>>23; //printf("X1:%ld ",X1); X2 = (AC2*B6)>>11; //printf("X2:%ld ",X2); X3 = X1+X2; //printf("X3:%ld ",X3); B3 = (((long)AC1*4+X3)+2)/4; //printf("B3:%ld ",B3); X1 = (AC3*B6)>>13; //printf("X1:%ld ",X1); X2 = (B1*(B6*B6>>12))>>16; //printf("X2:%ld ",X2); X3 = ((X1+X2)+2)>>2; //printf("X3:%ld ",X3); B4 = AC4*(unsigned long)(X3+32768)>>15; //printf("B4:%lu ",B4); B7 = ((unsigned long)UP-B3)*50000; //printf("B7:%lu ",B7); if (B7 < 0x80000000) { P = (B7*2)/B4; } else P=(B7/B4)*2; //printf("P:%ld ",P); X1 = (P/256.0)*(P/256.0); //printf("X1:%ld ",X1); X1 = (X1*3038)>>16; //printf("X1:%ld ",X1); X2 = (-7357*P)>>16; //printf("X2:%ld ",X2); P = P+((X1+X2+3791)>>4); //printf("P:%ld ",P); True_Press = P; printf("Press:%.1fPa ",True_Press); True_Altitude = 44330*(1-pow((P/101325.0),(1.0/5.255))); printf("Altitude:%.3fm ",True_Altitude); }[/mw_shl_code] [mw_shl_code=c,true]int main() {     long UT,UP;     delay_init();                      //延时函数初始化     NVIC_Configuration();             //设置NVIC中断分组2: 2位抢占优先级,2位响应优先级     uart1_init(38400);         //串口1初始化,和上位机通信          System_Init();                  //io,timer,adc,dac,lcd初始化    Read_CalibrationData();         //读取BMP180的校准系数     while(1)     {           BMP180_ID = BMP180_ReadOneByte(0xd0);    //读取ID地址         printf("BMP180_ID:0x%x ",BMP180_ID);         UT = Get_BMP180UT();         UP = Get_BMP180UP();         Convert_UncompensatedToTrue(UT,UP);         sprintf(LCD_Buff,"ID:0x%x",BMP180_ID); Lcd12864_WriteString(0,0,LCD_Buff);         sprintf(LCD_Buff,"Temp:%.1f'C",True_Temp); Lcd12864_WriteString(1,0,LCD_Buff);         sprintf(LCD_Buff,"Press:%.1fPa",True_Press); Lcd12864_WriteString(2,0,LCD_Buff);         sprintf(LCD_Buff,"Altitude:%.1fm",True_Altitude); Lcd12864_WriteString(3,0,LCD_Buff);         delay_ms(1000);[/mw_shl_code] [mw_shl_code=c,true]}     [/mw_shl_code] [mw_shl_code=c,true][/mw_shl_code]




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
25条回答
WengYuH
2019-07-23 17:43
本帖最后由 小朋哥123 于 2017-9-12 11:04 编辑

我自己实践了一下你的程序,感觉有点问题,用你的程序读数总是忽高忽低的,程序里面求UT和UP的语句,用的是BMP180_ReadTwoByte,我换成了BMP180_ReadOneByte就可以了,读数就正常了。。。感觉读两位数据那个函数有点问题,可能我的不对,请大家也可以试一试。。

一周热门 更多>