历史上的今天
今天是:2024年09月07日(星期六)
2020年09月07日 | BMP180测量海拔高度传感器单片机程序
2020-09-07 来源:51hei
在测量海拔高度时,传统的做法是通过测量某一高度的大气压力,再经过换算才能得到高度数据。为了测量大气压力,就得用上气压传感器,下面就来讨论一下气压传感器的应用。
气压传感器是压力传感器中的一种,它专用于测量气体的绝对压强。目前市场上能见到的气压传感器有很多种,下面就以市场上常见的Bosch公司推出的BMP180来进行讨论。BMP180不仅可以实时的测量大气压力,还能测量实时温度。同时它还具有IIC总线的接口,便于单片机进行访问。另外它的使用也很方便,不需要太多的操作就可读取到气压及测量数据。
BMP180采用强大的8脚陶瓷无引线芯片承载(LCC)超薄封装,它性能卓越,内置有校准补偿,绝对精度最低可以达到0.03hPa(0.25米),并且耗电极低,只有3μA。气压测量范围从300hPa到1100hPa,换算成高度为海拔9000米到500米。下图是其封装外形和引脚排列。

引脚各功能如下:1脚(GND)接电源地,2脚(EOC)为完成转换输出,3脚(VDDA)为正电源,4脚(VDDD)为数字正电源,5脚为空,6脚(SCL)为IIC的时钟端,7脚(SDA)为IIC的数据端,8脚(XCLR)为主清除信号输入端,低电平有效,用来复位BMP180和初始化寄存器和控制器,在不用的情况下可以空置。
BMP180的工作电压为1.8V~3.6V,典型工作电压为2.5V,其与单片机相连的典型电路如下图所示。

从上图中可以看到,BMP180内包含有电阻式压力传感器、AD转换器和控制单元,其中控制单元包括了EEPROM和IIC接口。读取BMP180时会直接传送没有经过补偿的温度值和压力值。而在EEPROM中则储存了176位单独的校准数据,这些数据将对读取的温度压力值进行补偿。176位的EEPROM被划分为11个字,每个字16位,这样就包含有11个校准系数。每个器件模块都有自己单独的校准系数,在第一次计算温度压力数据之前,单片机就应该先读出读出EEPROM中的这些校准数据,然后再开始采集数据温度和压力数据。
和所有的IIC总线器件一样,BMP180也有一个器件的固定地址,根据其数据手册,出厂时默认BMP180的从机地址为0xEE(写入方向),或0xEF(读出方向)。温度数据UT和压力数据UP都存储在寄存器的第0到15位之中,压力数据UP的精度还可扩展至16~19位。

上图中左边是Bosch公司技术手册上提供的读取顺序的流程图,右边是EEPROM中的校准数据。
从流程图中可以看出,单片机发送开始信号启动温度和压力测量,经过一定的转换时间(4.5ms)后,从IIC接口读出结果。为了将温度的单位换算成℃和将压力的单位换算成hPa,需要用到EEPROM中的校准数据来进行补偿计算,这些数据也可以从IIC接口读出。事实上,EEPROM中的这些校准数据应该在程序初始化的时候就读出,以方便后面的计算。 在同一个采样周期中BMP180可以采128次压力值和1次温度值,并且这些值在读取后会被及时更新掉。若不想等待到最大转化时间之后才读取数据,可以有效利用BMP180的输出管脚EOC来检查转化是否完毕。若为1表示转换完成,为0表示转换正在进行中。
要得到温度或气压的值,必须要访问地址为0xF4的控制寄存器。它根据写入数据的不同,回应的值也不一样,具体如下表所示。

从图中可以看出,要获得温度数据,必须先向控制寄存器(地址0xF4)写0x2E,然后等待至少4.5ms,才可以从地址0xF6和0xF7读取十六位的温度数据。同样,要获得气压数据,必须先向控制寄存器(地址0xF4)写0x34,然后等待至少4.5ms,才可以从地址0xF6和0xF7读取16位的气压数据,若要扩展分辨率,还可继续读取0xF8(XLSB)扩展16位数据到19位。获取到的数据还要根据EEPROM中的校准数据来进行补偿后才能用,EEPROM的数据读取可根据上图中的地址来进行,地址从0xAA~0xBF,具体的补偿算法可参看官方的数据手册,这里就不赘述了。
下面以一个例子来看一下BMP180的具体应用。
例子:利用单片机读取来自BMP180的温度和气压数据,并把它们通过LCD1602显示出来。
BMP180的SDA、SCL端分别接到ATMega16的TWI端(PC1、PC0),EOC和XCLR端悬空,LCD1602的接法与前面的一致。参考代码如下。
#include //=========================定义从器件地址和读写方式============================= #define rd_device_add 0xef //即11101111,1110111是BMP180器件的固定地址,最后的1表示对从器件进行读操作 #define wr_device_add 0xee //即11101110,1110111是BMP180器件的固定地址,最后的0表示对从器件时行写操作 //===============================TWI状态定义================================== #define START 0x08 #define RE_START 0x10 #define MT_SLA_ACK 0x18 #define MT_SLA_NOACK 0x20 #define MT_DATA_ACK 0x28 #define MT_DATA_NOACK 0x30 #define MR_SLA_ACK 0x40 #define MR_SLA_NOACK 0x48 #define MR_DATA_ACK 0x50 #define MR_DATA_NOACK 0x58 //=============================常用TWI操作定义================================ #define Start() (TWCR=(1< #define SetAck() (TWCR|=(1< #define LCM_RS_1 PORTB_Bit0=1 //RS脚输出高电平 #define LCM_RS_0 PORTB_Bit0=0 //RS脚输出低电平 #define LCM_RW_1 PORTB_Bit1=1 //RW脚输出高电平 #define LCM_RW_0 PORTB_Bit1=0 //RW脚输出低电平 #define LCM_EN_1 PORTB_Bit2=1 //EN脚输出高电平 #define LCM_EN_0 PORTB_Bit2=0 //EN脚输出低电平 #define DataPort PORTA //PORTA为数据端口 #define Busy 0x80 //忙信号 //==============定义全局变量================ unsigned char ge,shi,bai,qian,wan,shiwan; //显示变量 unsigned char ReadTemp[2]; //接收到的温度数据缓冲区 unsigned char ReadPressure[2]; //接收到的气压数据缓冲区 int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; //==============定义显示字符串================ const unsigned char str0[]={" T: . C "}; //显示温度 const unsigned char str1[]={" P: . Kpa "}; //显示气压 //===============1mS延时=================== void delay_1ms(void) { unsigned int i; for(i=1;i<(unsigned int)(8*143-2);i++) ; } //=============n*1mS延时=============== void delay_nms(unsigned int n) { unsigned int i=0; while(i i++; } } //===============IIC总线写n个字节(成功返回0,失败返回1)===================== unsigned char I2C_Write(unsigned char RomAddress,unsigned char *buf,unsigned char len) { unsigned char i; Start(); //启动I2C总线 Wait(); //等待回应 if(TestAck()!=START) return 1; //若回应的不是启动信号,则失败返回1 Write8Bit(wr_device_add); //写I2C从器件地址、写方向 Wait(); //等待回应 if(TestAck()!=MT_SLA_ACK) return 1; //若回应的不是ACK信号,则失败返回值1 Write8Bit(RomAddress); //写BMP180的ROM地址 Wait(); //等待回应 if(TestAck()!=MT_DATA_ACK) return 1; //若回应的不是ACK信号则失败返回值1 for(i=0;i Write8Bit(buf[i]); //写数据到BMP180的ROM中 Wait(); //等待回应 if(TestAck()!=MT_DATA_ACK) {return 1;} //若回应的不是ACK信号则失败返回值1 delay_nms(10); } Stop(); //停止I2C总线 delay_nms(10); //延时等待BMP180写完 return 0; //写入成功,返回值0 } //====================IIC总线读n个字节(成功返回0,失败返回1)========================= unsigned char I2C_Read(unsigned char RomAddress,unsigned char *buf,unsigned char len) { unsigned char i; Start(); //启动I2C总线 Wait(); //等待回应 if(TestAck()!=START) return 1; //若回应的不是启动信号,则失败返回1 Write8Bit(wr_device_add); //写I2C从器件地址、写方向 Wait(); //等待回应 if(TestAck()!=MT_SLA_ACK) return 1; //若回应的不是ACK信号,则失败返回值1 Write8Bit(RomAddress); //写BMP180的ROM地址 Wait(); //等待回应 if(TestAck()!=MT_DATA_ACK) return 1; //若回应的不是ACK信号,则失败返回值1
下一篇:AVR单片机教程——ADC
史海拾趣
|
如下所示,EBOOT已经把NK调度到内存,并且已经跳到NK去执行。为什么NK还要初始化FLASH,并且要花十几秒的时间去读FLASH? Windows CE Kernel for ARM (Thumb Enabled) Built on Feb 8 2007 at 23:36:51 ProcessorType=0920 &nbs ...… 查看全部问答> |
|
目前开发完一个针对philips saa7130的视频采集驱动,安装完后,系统提示出现“未知设备”,但卡的驱动已经成功装上。分析后发现“未知设备”是saa7130芯片支持的TV tuner,但目前我们的用户不需要该功能,所以想在装上驱动后,不再出现提示用户安装 ...… 查看全部问答> |
|
我想学单片机,现在准备买设备。大家帮忙推荐几个好点的东西。 编程器我想买多功能编程器,不知道有哪些?还有其他的配件大家也帮帮忙推荐一下,我现在对这方面还不懂。 我学过c,8086汇编,模拟电路,数字电路 微机原理 verilog等课程。欢迎大 ...… 查看全部问答> |
|
如题,没啥技术含量,不过,我记得我最初对这个题目很是蛋疼。为何?全在于理解上出了问题。我以为,这个题的奥义是要实现在一组元素上任意顺序的四则运算符。不过这也不难,当时我考虑的方法是。做一个和数据元素一样长或者小一个单位的数组,用来 ...… 查看全部问答> |
|
我有个nxp p89lpc9221芯片,用来控制7段数码管显示,用ICP口编程。 我现在设置p0.0,p0.1,p0.2为开漏输出;P0M1 |= 0x07; P0M2 |= 0x07; 三个脚都上拉到3.3v; 然后设置三个脚输出为0: sbit p00 = P0 ^ 0; sbit p01 = P0 ^ 1; sbit ...… 查看全部问答> |
|
//用的是STM32F107VCT 25MHz的外部晶振 //固件库是V3.5的 //想实现串口通信(USART2),却怎么也发不出去数据,求看看是哪里出错了,我新手。。。谢谢啦! #include \"stm32f10x.h\" void RCC_Configuration(void); void GPIO_ ...… 查看全部问答> |




