BMP085气压传感器驱动 &MS5611经验

BMP085是新一代的小封装气压传感器,主要用于气压温度检测,在四轴飞行器上可以用作定高检测,该传感器属于IIC总线接口,依然沿用标准IIC驱动程序

   使用该传感器需要注意的是我们不能直接读出转换好的二进制温度数据或者气压数据,必须先读出一整套约176位的矫正数据,然后启动转换,将转换的数据与矫正数据一起进行矫正运算才能正常获得温度,温度精度为0.1,大气压有16bit或者19bit的精度,一般选择16位精度,

  所以对于该传感器设备,驱动模式如下

  1.获取矫正数据-->启动温度转换--->获取原始温度数据-->启动大气压转换-->获取原始大气压数据-->计算实际温度数据大气压数据

   另,转换时的转换时间也是计算时的重要参数,计算大气压时的过程中需要使用冤死温度


矫正数据如下

BMP085气压传感器驱动 &MS5611经验_第1张图片

矫正数据都是16位有符号的,所以读出的时候需要连续读取两个字节

通过计算得到的大气压强可以计算得到当前传感器相对于海平面的绝对高度

BMP085气压传感器驱动 &MS5611经验_第2张图片


具体驱动代码如下所示

[cpp]  view plain  copy
  1. #ifndef __BMP085_H_  
  2. #define __BMP085_H_  
  3. #include "ioremap.h"  
  4. #include "common.h"  
  5. #include "stm32f10x.h"  
  6. #include "uart.h"  
  7. #include "delay.h"  
  8.   
  9. //BMP SDA PC0  
  10. //BMP SCL PC1  
  11.   
  12. #define BMP_ACK_WAIT_TIME   200     //iic通讯时的ack等待时间  
  13.   
  14. #define BMP085_DEBUG    1  
  15.   
  16. #define OSS 0   // 大气压的转换时间,有0-3可选值  
  17.   
  18. //地址均为读地址  
  19. #define BMP085_ADDR     0xEE      //定义器件在IIC总线中的写地址   
  20.   
  21. #define BMP_AC1_ADDR        0XAA      //定义校准寄存器的地址  
  22. #define BMP_AC2_ADDR        0XAC  
  23. #define BMP_AC3_ADDR        0XAE  
  24. #define BMP_AC4_ADDR        0XB0  
  25. #define BMP_AC5_ADDR        0XB2  
  26. #define BMP_AC6_ADDR        0XB4  
  27. #define BMP_B1_ADDR         0XB6  
  28. #define BMP_B2_ADDR         0XB8  
  29. #define BMP_MB_ADDR         0XBA  
  30. #define BMP_MC_ADDR         0XBC  
  31. #define BMP_MD_ADDR         0XBE  
  32.   
  33. #define CONTROL_REG_ADDR    0XF4    //控制寄存器,在这个寄存器中设置不同的值可以设置不同转换时间,同时不同的值可以确认转换大气压或者温度  
  34. #define BMP_COVERT_TEMP     0X2E    //转换温度 4.5MS  
  35. #define BMP_COVERT_PRES_0   0X34    //转换大气压 4.5ms  
  36. #define BMP_COVERT_PRES_1   0X74    //转换大气压 7.5ms  
  37. #define BMP_COVERT_PRES_2   0XB4    //转换大气压 13.5ms  
  38. #define BMP_COVERT_PRES_3   0XF4    //转换大气压 25.5ms  
  39.   
  40. #define BMP_TEMP_PRES_DATA_REG  0XF6    //两个字节温度数据  
  41.   
  42. //0xf6 0xf7 0xf8 压强地址  
  43. //0xf6 0xf7 温度地址  
  44.   
  45. typedef struct BMP085PARAM //校准参数表  
  46. {  
  47.   s16 ac1;  
  48.   s16 ac2;  
  49.   s16 ac3;  
  50.   u16 ac4;  
  51.   u16 ac5;  
  52.   u16 ac6;  
  53.   s16 b1;  
  54.   s16 b2;  
  55.   s16 mb;  
  56.   s16 mc;  
  57.   s16 md;  
  58. }BMP085PARAM;  
  59.   
  60.   
  61.   
  62. void BmpInit(void);         //接口与参数初始化  
  63.   
  64. //读取温度数据并校正转换  
  65. long BmpConvertTemp(void);  
  66.   
  67. //读取压强数据并校正转换  
  68. long BmpConvertPressure(void);  
  69.   
  70.   
  71.   
  72. #endif  

[cpp]  view plain  copy
  1. #include "bmp085.h"  
  2.   
  3. static struct BMP085PARAM bmp085ParamStruct = {0,0,0,0,0,0,0,0,0,0,0};  
  4.   
  5. //IO方向设置  
  6. #define BMP_SDA_IN()  {GPIOC->CRL&=0XFFFFFFF0;GPIOC->CRL|=8;}  
  7. #define BMP_SDA_OUT() {GPIOC->CRL&=0XFFFFFFF0;GPIOC->CRL|=3;}  
  8.   
  9. //IO操作函数       
  10. #define BMP_SCL    PCout(1) //SCL  
  11. #define BMP_SDA    PCout(0) //SDA      
  12. #define BMP_READ_SDA   PCin(0)  //输入SDA   
  13.   
  14. /**************************BMP5883 IIC驱动函数*********************************/  
  15.   
  16. static void BMP085IOInit(void)  
  17. {  
  18.     GPIO_InitTypeDef GPIO_InitStructure;  
  19.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );   
  20.       
  21.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;  
  22.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出  
  23.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  24.     GPIO_Init(GPIOC, &GPIO_InitStructure);  
  25.       
  26.     BMP_SCL = 1;  
  27.     BMP_SDA = 1;  
  28. }  
  29.   
  30.   
  31.   
  32. //发送IIC起始信号  
  33. static void ComStart(void)  
  34. {  
  35.     BMP_SDA_OUT();     //sda线输出  
  36.     BMP_SDA=1;          
  37.     BMP_SCL=1;  
  38.     DelayUs(5);  
  39.     BMP_SDA=0;//START:when CLK is high,DATA change form high to low   
  40.     DelayUs(5);  
  41.     BMP_SCL=0;//钳住I2C总线,准备发送或接收数据  
  42. }  
  43. //发送IIC停止信号  
  44. static void ComStop(void)  
  45. {  
  46.     BMP_SDA_OUT();//sda线输出  
  47.     BMP_SDA=0;//STOP:when CLK is high DATA change form low to high  
  48.     BMP_SCL=1;  
  49.     DelayUs(5);  
  50.     BMP_SDA=1;//发送I2C总线结束信号  
  51.     DelayUs(5);       
  52. }  
  53. //等待ACK,为1代表无ACK 为0代表等到了ACK  
  54. static u8 ComWaitAck(void)  
  55. {  
  56.     u8 waitTime = 0;  
  57.     BMP_SDA_OUT();//sda线输出  
  58.     BMP_SDA = 1;  
  59.     DelayUs(5);  
  60.     BMP_SDA_IN();      //SDA设置为输入  
  61.     BMP_SCL=1;  
  62.     DelayUs(5);  
  63.     while(BMP_READ_SDA)  
  64.     {  
  65.         waitTime++;  
  66.         DelayUs(1);  
  67.         if(waitTime > BMP_ACK_WAIT_TIME)  
  68.         {  
  69.             ComStop();  
  70.             return 1;  
  71.         }  
  72.     }  
  73.     BMP_SCL = 0;  
  74.     return 0;  
  75.       
  76. }  
  77.   
  78. static void ComSendAck(void)  
  79. {  
  80.     BMP_SCL = 0;  
  81.     BMP_SDA_OUT();  
  82.     BMP_SDA = 0;  
  83.     DelayUs(2);  
  84.     BMP_SCL = 1;  
  85.     DelayUs(5);  
  86.     BMP_SCL = 0;  
  87.     DelayUs(5);  
  88. }  
  89.   
  90. static void ComSendNoAck(void)  
  91. {  
  92.     BMP_SCL = 0;  
  93.     BMP_SDA_OUT();  
  94.     BMP_SDA = 1;  
  95.     DelayUs(2);  
  96.     BMP_SCL = 1;  
  97.     DelayUs(5);  
  98.     BMP_SCL = 0;  
  99.     DelayUs(5);  
  100. }  
  101. //返回0 写入收到ACK 返回1写入未收到ACK  
  102. static u8 ComSendByte(u8 byte)  
  103. {  
  104.     u8 t;     
  105.     BMP_SDA_OUT();    
  106.     for(t=0;t<8;t++)  
  107.     {                
  108.         BMP_SDA=(byte&0x80)>>7;  
  109.         byte<<=1;          
  110.         BMP_SCL=1;  
  111.         DelayUs(5);   
  112.         BMP_SCL=0;    
  113.         DelayUs(5);  
  114.     }      
  115.     return ComWaitAck();  
  116. }  
  117.   
  118. static void ComReadByte(u8* byte)  
  119. {  
  120.     u8 i,receive=0;  
  121.     BMP_SDA_IN();//SDA设置为输入  
  122.     for(i=0;i<8;i++ )  
  123.     {  
  124.         receive <<= 1;  
  125.         BMP_SCL=1;   
  126.         DelayUs(5);  
  127.         if(BMP_READ_SDA)receive++;  
  128.         BMP_SCL=0;   
  129.         DelayUs(5);   
  130.     }                       
  131.     *byte = receive;  
  132. }  
  133.   
  134. /**************************BMP5883 IIC驱动函数*********************************/  
  135.   
  136. //**************************************  
  137. //向I2C设备写入一个字节数据  
  138. //**************************************  
  139. u8 BmpWriteByte(u8 addr,u8 dataValue)  
  140. {  
  141.     u8 res = 0;  
  142.     ComStart();                  //起始信号  
  143.     res = ComSendByte(BMP085_ADDR);   //发送设备地址+写信号  
  144.     if(res)  
  145.     {  
  146.         #ifdef BMP085_DEBUG  
  147.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  148.         #endif  
  149.         return res;  
  150.     }  
  151.     res = ComSendByte(addr);    //内部寄存器地址,  
  152.     if(res)  
  153.     {  
  154.         #ifdef BMP085_DEBUG  
  155.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  156.         #endif  
  157.         return res;  
  158.     }  
  159.     res = ComSendByte(dataValue);       //内部寄存器数据,  
  160.     if(res)  
  161.     {  
  162.         #ifdef BMP085_DEBUG  
  163.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  164.         #endif  
  165.         return res;  
  166.     }  
  167.     ComStop();                   //发送停止信号  
  168.     return 0;  
  169. }  
  170.   
  171. //**************************************  
  172. //从I2C设备读取一个字节数据  
  173. //**************************************  
  174. u8  BmpReadByte(u8 addr,u8* data)   //读取一个字节  
  175. {  
  176.     u8 REG_data,res = 0;  
  177.     ComStart();                   //起始信号  
  178.     res = ComSendByte(BMP085_ADDR);    //发送设备地址+写信号  
  179.     if(res)  
  180.     {  
  181.         #ifdef BMP085_DEBUG  
  182.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  183.         #endif  
  184.         return res;  
  185.     }  
  186.     res = ComSendByte(addr);     //发送存储单元地址,从0开始  
  187.     if(res)  
  188.     {  
  189.         #ifdef BMP085_DEBUG  
  190.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  191.         #endif  
  192.         return res;  
  193.     }     
  194.     ComStart();                   //起始信号  
  195.     res = ComSendByte(BMP085_ADDR+1);  //发送设备地址+读信号  
  196.     if(res)  
  197.     {  
  198.         #ifdef BMP085_DEBUG  
  199.         printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);  
  200.         #endif  
  201.         return res;  
  202.     }  
  203.     ComReadByte(®_data);       //读出寄存器数据  
  204.     ComSendNoAck();                //接收应答信号  
  205.     ComStop();                    //停止信号  
  206.     *data = REG_data;  
  207.     return 0;  
  208. }  
  209.   
  210. s16 BmpReadTwoByte(u8 addr)     //读出BMP085内部数据,连续两个  
  211. {  
  212.   u8 msb, lsb;  
  213.   short dataValue;  
  214.   BmpReadByte(addr,&msb);  
  215.   BmpReadByte(addr + 1,&lsb);  
  216.   dataValue = ((short)msb)<<8;  
  217.   dataValue |= lsb;  
  218.   return dataValue;  
  219. }  
  220.   
  221.   
  222. //获取校正参数,读出十一个字的校准系数**************  
  223. void BmpGetParam(BMP085PARAM* bmpParam)  
  224. {  
  225.    bmpParam->ac1 = BmpReadTwoByte(BMP_AC1_ADDR);  
  226.    bmpParam->ac2 = BmpReadTwoByte(BMP_AC2_ADDR);  
  227.    bmpParam->ac3 = BmpReadTwoByte(BMP_AC3_ADDR);  
  228.    bmpParam->ac4 = BmpReadTwoByte(BMP_AC4_ADDR);  
  229.    bmpParam->ac5 = BmpReadTwoByte(BMP_AC5_ADDR);  
  230.    bmpParam->ac6 = BmpReadTwoByte(BMP_AC6_ADDR);  
  231.    bmpParam->b1 = BmpReadTwoByte(BMP_B1_ADDR);  
  232.    bmpParam->b2 = BmpReadTwoByte(BMP_B2_ADDR);  
  233.    bmpParam->mb = BmpReadTwoByte(BMP_MB_ADDR);  
  234.    bmpParam->mc = BmpReadTwoByte(BMP_MC_ADDR);  
  235.    bmpParam->md = BmpReadTwoByte(BMP_MD_ADDR);  
  236. }  
  237.   
  238. void BmpInit(void)          //接口与参数初始化  
  239. {  
  240.   BMP085IOInit();  
  241.   BmpGetParam(&bmp085ParamStruct);  
  242. }  
  243.   
  244. //读取温度数据(未经过校正的)  
  245. s32 BmpReadTemp(void)             
  246. {  
  247.   BmpWriteByte(CONTROL_REG_ADDR,BMP_COVERT_TEMP);   //启动温度转换  
  248.   DelayMs(5);                   //等待转换完成,最大转换4.5MS  
  249.   return (s32)BmpReadTwoByte(BMP_TEMP_PRES_DATA_REG);   //返回温度数据  
  250. }  
  251.   
  252. //读取压强数据未校正  
  253. s32 Bmp085ReadPressure(void)      
  254. {  
  255.   s32 pressure = 0;  
  256.   BmpWriteByte(CONTROL_REG_ADDR,BMP_COVERT_PRES_0); //启动温度转换  
  257.   DelayMs(10);                  //等待转换完成,最大转换4.5MS,所以换算的时候要用OSS=0  
  258.   pressure =  (s32)BmpReadTwoByte(BMP_TEMP_PRES_DATA_REG);  //返回压力数据,默认使用16字节压力数据  
  259.   pressure &= 0x0000FFFF;  
  260.   return pressure;  
  261. }  
  262.   
  263. //读取温度数据并校正转换  
  264. long BmpConvertTemp(void)  
  265. {  
  266.   u32 ut;  
  267.   long x1, x2, b5;   
  268.   long  temperature;  
  269.     
  270.   ut = BmpReadTemp();      // 读取温度  
  271.   x1 = (((long)ut - (long)bmp085ParamStruct.ac6)*(long)bmp085ParamStruct.ac5) >> 15;  
  272.   x2 = ((long) bmp085ParamStruct.mc << 11) / (x1 + bmp085ParamStruct.md);  
  273.   b5 = x1 + x2;  
  274.   temperature = ((b5 + 8) >> 4);  //温度计算,官方公式  
  275.   #ifdef BMP085_DEBUG  
  276.   printf("bmp085 temp is %f 'C\r\n",((float)temperature)/10.0);  
  277.   #endif  
  278.   return temperature;  
  279. }  
  280.   
  281. //读取压强数据并校正转换  
  282. long BmpConvertPressure(void)  
  283. {  
  284.   unsigned int ut;  
  285.   unsigned long up;  
  286.   long x1, x2, b5, b6, x3, b3, p;  
  287.   unsigned long b4, b7;  
  288.   long  pressure;  
  289.     
  290.   ut = BmpReadTemp();      // 读取温度,计算压强时需要温度做参数  
  291.   up = Bmp085ReadPressure();  // 读取压强  
  292.     
  293.   x1 = (((long)ut - (long)bmp085ParamStruct.ac6)*(long)bmp085ParamStruct.ac5) >> 15;  
  294.   x2 = ((long)bmp085ParamStruct.mc << 11) / (x1 + bmp085ParamStruct.md);  
  295.   b5 = x1 + x2;  
  296.     
  297.   b6 = b5 - 4000;  
  298.   // Calculate B3  
  299.   x1 = (bmp085ParamStruct.b2 * (b6 * b6)>>12)>>11;  
  300.   x2 = (bmp085ParamStruct.ac2 * b6)>>11;  
  301.   x3 = x1 + x2;  
  302.   b3 = (((((long)bmp085ParamStruct.ac1)*4 + x3)<>2;  
  303.     
  304.   // Calculate B4  
  305.   x1 = (bmp085ParamStruct.ac3 * b6)>>13;  
  306.   x2 = (bmp085ParamStruct.b1 * ((b6 * b6)>>12))>>16;  
  307.   x3 = ((x1 + x2) + 2)>>2;  
  308.   b4 = (bmp085ParamStruct.ac4 * (unsigned long)(x3 + 32768))>>15;  
  309.     
  310.   b7 = ((unsigned long)(up - b3) * (50000>>OSS));  
  311.   if (b7 < 0x80000000)  
  312.     p = (b7<<1)/b4;  
  313.   else  
  314.     p = (b7/b4)<<1;  
  315.     
  316.   x1 = (p>>8) * (p>>8);  
  317.   x1 = (x1 * 3038)>>16;  
  318.   x2 = (-7357 * p)>>16;  
  319.   pressure = p+((x1 + x2 + 3791)>>4);  
  320.     
  321.   #ifdef BMP085_DEBUG  
  322.   printf("bmp085 pressure is %f KPa\r\n",((float)pressure)/1000.0);  
  323.   #endif  
  324.   return pressure;  
【经验交流】使用MS5611高精度气压计之后的感想
http://bbs.elecfans.com/jishu_469008_1_1.html
(出处: 中国电子技术论坛)
  1. 【经验交流】使用MS5611高精度气压计之后的感想 :【经验交流】使用MS5611高精度气压计之后的感想
    http://bbs.elecfans.com/jishu_469008_1_1.html
    (出处: 中国电子技术论坛)
  2.   我是在房间内测试MS5611的,模块一直放着不动,然后,通过stm32读取芯片内存储气压值(用其他芯片读取没试过,但应该没有影响)。最后发现,读数据的频率非常影响气压的值,或者是温度的值。这里我已经考虑到了传感器芯片内部做AD转换的时间了。

你可能感兴趣的:(学习算法)