单片机控制气压海拔模块BMP180之模块化编程(持续更新中)

这里将我写的STC12C5A60S2单片机控制气压海拔测量模块BMP180的程序共享一下,是为了让前辈给予斧正。

更新:

2015/05/05  08:30  完善了温度值的类型及其运算(没有进行实物验证)

2014/04/17 10:22

(也可以用官网封装好的函数BMP180_API  :http://www.general-files.org/download/gs64624bfeh32i0/bmp180_api.zip.html)

(补充:只需要修改bmp180.h文件中含有 “选择” 字样的部分,就可以达到复用的效果,只需注意中文注释部分)

对于lcd2004部分,请参考《单片机控制2004A液晶屏之模块化编程点击进入

模块:

单片机控制气压海拔模块BMP180之模块化编程(持续更新中)_第1张图片

检测到BMP180的存在:

单片机控制气压海拔模块BMP180之模块化编程(持续更新中)_第2张图片

单片机控制气压海拔模块BMP180之模块化编程(持续更新中)_第3张图片

未检测到BMP180的存在:

单片机控制气压海拔模块BMP180之模块化编程(持续更新中)_第4张图片

测试程序:

#include 
#include 
#include "lcd2004.h"
#include "bmp180.h"

UB8 *table0 = "Module     :BMP180" ;
UB8 *table1 = "Temperature:" ;
UB8 *table2 = "Pressure   :" ;
UB8 *table3 = "Altitude   :" ;

void display(BMP180_info temp) ;

void main()
{ 
	BMP180_info temp ;
	
	lcd2004Init(); 
	lcd2004WriteCommand(0x0c) ;/*为了显示效果更佳明显,暂时取消光标显示和闪烁,也可以在LCD2004模块内部修改*/

	lcd2004AddressWriteString(LCD2004_ROW0,0,table0) ;
	lcd2004AddressWriteString(LCD2004_ROW1,0,table1) ;
	lcd2004AddressWriteString(LCD2004_ROW2,0,table2) ;
	lcd2004AddressWriteString(LCD2004_ROW3,0,table3) ;
  
    BMP180Init(&temp);  
    
	while(1)                        
	{ 
		if(temp.ExistFlag == BMP180_EXISTENCE)	 //存在
		{
			BMP180Convert(&temp);
			display(temp) ;
		}
		else									//不存在
		{
			lcd2004CleanAll() ;
			lcd2004AddressWriteString(LCD2004_ROW0,0,"Error") ;
			while(1);
		}
	}
} 

void display(BMP180_info temp)
{
	// 温度
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1),((UL32)temp.Temperature)%1000/100+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+1,((UL32)temp.Temperature)%100/10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+2,((UL32)temp.Temperature)%10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+3,'.') ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+4,((UL32)(temp.Temperature*10))%10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+5,0xdf) ;
	lcd2004AddressWriteByte(LCD2004_ROW1,strlen(table1)+6,'C') ;
	
	//气压
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2),temp.GasPress%1000000/100000+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+1,temp.GasPress%100000/10000+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+2,temp.GasPress%10000/1000+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+3,'.') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+4,temp.GasPress%1000/100+'0') ;
	//数据没有全部显示出来
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+5,'K') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+6,'p') ;
	lcd2004AddressWriteByte(LCD2004_ROW2,strlen(table2)+7,'a') ;
	
	//海拔
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3),(UL32)temp.Altitude%10000/1000+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+1,(UL32)temp.Altitude%1000/100+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+2,(UL32)temp.Altitude%100/10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+3,(UL32)temp.Altitude%10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+4,'.') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+5,(UL32)(temp.Altitude*10)%10+'0') ;
	lcd2004AddressWriteByte(LCD2004_ROW3,strlen(table3)+6,'m') ;
}


/*################BMP180.h start################*/

#ifndef __BMP180_H__
#define __BMP180_H__

#include 
#include "common.h"

sbit BMP180_sclk_bit = P3^6 ;	/*根据硬件连接选择*/
sbit BMP180_sda_bit  = P3^7 ;	/*根据硬件连接选择*/

//BMP180校正参数(calibration param)
typedef struct {
	SW16 AC1 ;
	SW16 AC2 ;
	SW16 AC3 ;
	UW16 AC4 ;
	UW16 AC5 ;
	UW16 AC6 ;
	SW16 B1 ;
	SW16 B2 ;
	SW16 MB ;
	SW16 MC ;
	SW16 MD ;
}BMP180_cal_param;

typedef struct {
	UB8  ExistFlag ;  //存在标志

	BMP180_cal_param  cal_param;//修正系数

	UB8 Version ;				//版本

	SL32 UnsetTemperature ;		//未校正的温度值
	SL32 UnsetGasPress	  ;		//未校正的气压值

	float Temperature ;			/*校正后的温度值*/
	SL32 GasPress ;				/*校正后的气压值*/

	float Altitude ;				/*海拔*/
	
}BMP180_info ;

#define BMP180_NOT_EXISTENCE 0	/*不存在*/
#define BMP180_EXISTENCE     1	/*存在*/

#define OSS  2	//范围(0~3)

#define BMP180_READ		0x01
#define BMP180_WRITE	(0x01 &(~(0x01<<0)))	

#define	BMP180_DEVICE_ADDRESS_BASE_VALUE   0xee			 /*器件地址基值*/                  
//#define BMP180_CONTROL_REGISTER_ADDRESS_BASE_VALUE	0xf4 /*控制寄存器地址*/
#define BMP180_ID_REGISTER_ADDRESS		0xd0 /*ID编号寄存器(0x55固定)*/
#define BMP180_VERSION_REGISTER_ADDRESS	0XD1 /*版本编号*/
//#define BMP180_SOFT_RESET_REGISTER_BASE_VALUE	    0xe0 /*软件复位寄存器,只写,设置0xb6*/


//control register
//#define BMP180_CONTROL_REGISTER_SCO_BIT (0X01<<5)

//id register 
#define BMP180_ID_FIXED_VALUE		0x55 /*id固定编号(0x55)*/



/*****************内部函数******************/
//初始化
extern void BMP180Init(BMP180_info *p);				

//转换,修正温度、气压,计算海拔
extern void BMP180Convert(BMP180_info *temp) ;		

/*下面两个函数一般不在外部使用,也可以直接声明为BMP180.c的内部函数*/
//地址写数据
extern void BMP180AddressWrite(UB8 addresss,UB8 dataCode) ;

//地址读数据
extern UB8 BMP180AddressReadByte(UB8 address) ;
/**********************************************/


#endif /*__BMP180_H__*/



/*################BMP180.h start################*/


/*################BMP180.c start################*/

/***************************************************************************
Module	:BMP180.c

Purpose	:Implementation of BMP180 module.

Version	:0.01							2014/02/03 12:00(OK)

Complier:Keil 8051 C complier V9.01

MCU		:STC12C5A60S2

Author	:yangrui

QQ		:279729201

Email	:[email protected]


Modification:
=================
	2015/05/05 09:06
	Reason:
		1.在BMP180.h中的结构体BMP180_info中修改
		SL32 Temperature ;	//校正后的温度值
		为
		float Temperature ;	//校正后的温度值
		因为BMP180内部通过校正得到的温度值为的单位是0.1摄氏度,比如校正后得到280,表示28
		摄氏度 。 之前的程序是在其他地方修改注意一下,但是这样做不是太好。这里完善一下。

		2.将函数BMP180Convert(BMP180_info *temp)里面的:
		temp->Temperature= ((B5 + 8) >> 4;
		修改为:
		temp->Temperature= (((B5 + 8) >> 4)*0.1;
=================

=================
	2014/04/16 23:06
	Reason:
		1.在BMP180.h中的结构体BMP180_info中添加了器件存在标志位。
		2.在初始化函数BMP180Init(...)中添加了器件存在检测功能。

=================

=================
	2014/04/16 15:39
	Reason:
		1.完成

=================

***************************************************************************/
#include 
#include  
#include 
#include "bmp180.h"


/*外部接口函数在BMP180.h中声明*/

/*****************内部函数******************/
static void delay5msForBMP180(void)	;
static void BMP180StartSignal(void) ;
static void BMP180StopSignal(void) ;
static void BMP180Acknowledge(void) ;
static void BMP180WriteByte(UB8 dataCode) ;
static UB8  BMP180ReadByte(void) ;
static SL32 BMP180AddressRead2Byte(UB8 address) ;
static SL32 BMP180ReadUnsetTemperature(void) ;
static SL32 BMP180ReadUnsetPressure(void) ;
static void BMP180ReadCalibrateParam(BMP180_info *p) ;
/**********************************************/



/******************************************************
Function	:delay5msForBMP180
Input		:N/A
Output		:N/A
Return		:N/A
Description	:N/A
Note		:由STC-ISP V6.67软件针对相应MCU生成,若MCU不同
			最好也要修改此函数。
******************************************************/
static void delay5msForBMP180(void)	//@11.0592MHZ
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 54;
	j = 198;
	do
	{
		while (--j);
	} while (--i);

}

/******************************************************
Function	:BMP180StartSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:BMP180 start signal
Note		:N/A
******************************************************/
static void BMP180StartSignal(void)
{
	BMP180_sda_bit = HIGH_LEVEL ;
	//_nop_() ;
	BMP180_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	BMP180_sda_bit = LOW_LEVEL ;
	//_nop_();    
}

/******************************************************
Function	:BMP180StopSignal
Input		:N/A
Output		:N/A
Return		:N/A
Description	:BMP180  stop signal
Note		:N/A
******************************************************/
static void BMP180StopSignal(void)
{
	BMP180_sda_bit = LOW_LEVEL ;
	//_nop_() ;
	BMP180_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;
	BMP180_sda_bit = HIGH_LEVEL ;

	/*BMP180 self timed write cycle (5ms max)*/
	delay5msForBMP180();	
}

/******************************************************
Function	:BMP180Acknowledge
Input		:N/A
Output		:N/A
Return		:N/A
Description	:When BMP180 receive a data from mcu , BMP180 write the data
			to internal address, after completed write ,BMP180 send a zero
			to mcu,then mcu can input data into BMP180.
			(Once the internally timed write cycle has started and 
			the EEPROM inputs are disabled until write finished.)
Note		:N/A
******************************************************/
static void BMP180Acknowledge(void)
{
	UB8 i=0 ;

	BMP180_sclk_bit = LOW_LEVEL ;
	//_nop_() ;

	BMP180_sclk_bit = HIGH_LEVEL ;
	//_nop_() ;

	
	while((BMP180_sda_bit) && (i<250))
	{
		i++;//暂时,具体见调试
		//经过测试,这里的250足够大了
	}
	BMP180_sclk_bit = LOW_LEVEL ;
}


/******************************************************
Function	:BMP180WriteByte
Input		:the data which is ready to write to BMP180
Output		:N/A
Return		:N/A
Description	:N/A
Note		:N/A
******************************************************/
static void BMP180WriteByte(UB8 dataCode)
{
	UB8 i ;
	UB8 temp = dataCode ;

	for(i=0 ; i<8 ; i++)
	{
		BMP180_sclk_bit = LOW_LEVEL ;
		//_nop_();

		//方法一
		BMP180_sda_bit = (bit)(temp & (0x80>>i)) ;

		//方法二
		//temp <<= 1 ;
		//BMP180_sda_bit = CY ;

		//_nop_();
		BMP180_sclk_bit = HIGH_LEVEL ;
		//_nop_();
	}
}

/******************************************************
Function	:BMP180AddressWrite
Input		:address,data
Output		:N/A
Return		:N/A
Description	:write 'dataCode' to 'address'
Note		:N/A
******************************************************/
void BMP180AddressWrite(UB8 addresss,UB8 dataCode)
{
    BMP180StartSignal();    
    
    BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_WRITE);   
    BMP180Acknowledge() ;
    
    BMP180WriteByte(addresss);   
    BMP180Acknowledge() ;
    
    BMP180WriteByte(dataCode);       
    BMP180Acknowledge() ;
    
    BMP180StopSignal();                   
}

/******************************************************
Function	:BMP180ReadByte
Input		:N/A
Output		:N/A
Return		:the byte-data which read from BMP180
Description	:N/A
Note		:N/A
******************************************************/
static UB8 BMP180ReadByte(void)
{
	UB8 i ;
	UB8 dataCode = 0x00 ;

	//Ready
	/*Data on sda pin may change during scl low timer period*/
	BMP180_sclk_bit = LOW_LEVEL ;
	//_nop_() ;
	BMP180_sda_bit = HIGH_LEVEL ;//ready to read
	//_nop_() ;

	for(i=0; i<8 ; i++)
	{
		BMP180_sclk_bit = HIGH_LEVEL ;
		//_nop_() ;
		dataCode<<= 1;
		dataCode |= BMP180_sda_bit ;
		//_nop_() ;
		BMP180_sclk_bit = LOW_LEVEL ;
		//_nop_() ;
	}

	return dataCode ;
}


/******************************************************
Function	:BMP180AddressReadByte
Input		:address
Output		:N/A
Return		:data which read from bmp180's address
Description	:read byte-data from bmp180's address
Note		:不需要应答.
******************************************************/
UB8 BMP180AddressReadByte(UB8 address)
{  
	UB8 dataCode;
	
    BMP180StartSignal();                          
    
    BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_WRITE);   
    BMP180Acknowledge() ;
    
    BMP180WriteByte(address);           
    BMP180Acknowledge() ;
    
    BMP180StartSignal();                          
    
    BMP180WriteByte(BMP180_DEVICE_ADDRESS_BASE_VALUE | BMP180_READ);  
    BMP180Acknowledge() ;
    
    dataCode=BMP180ReadByte();             
	  
	BMP180StopSignal();  
	
    return dataCode; 
}

/******************************************************
Function	:BMP180AddressRead2Byte
Input		:address
Output		:N/A
Return		:long data
Description	:从连续地址读取数据,并"组装"为long型数据
Note		:N/A
******************************************************/
static SL32 BMP180AddressRead2Byte(UB8 address)
{
	UB8 msb , lsb ;

	msb = BMP180AddressReadByte(address)   ;
	lsb = BMP180AddressReadByte(address+1) ;

	return ( ((SL32)msb) << 8 | lsb) ;
}

/******************************************************
Function	:BMP180ReadUnsetTemperature
Input		:address
Output		:N/A
Return		:shour int byte-data
Description	:读取未校正的温度值
Note		:接收后面的一字节数据,主机不需要应答
******************************************************/
static SL32 BMP180ReadUnsetTemperature(void)
{
	BMP180AddressWrite(0xf4,0x2e) ;
	
	return (BMP180AddressRead2Byte(0xf6));
}

/******************************************************
Function	:BMP180ReadUnsetPressure
Input		:N/A
Output		:N/A
Return		:未校正气压值
Description	:读取未校正的气压值
Note		:N/A
******************************************************/
static SL32 BMP180ReadUnsetPressure(void)
{
	
	SL32 pressure = 0;

	BMP180AddressWrite(0xf4,0x34 + (OSS<<6)) ;

	delay5msForBMP180();
	delay5msForBMP180();
	

	pressure = BMP180AddressRead2Byte(0xf6) ;
	pressure = (((SL32)pressure <<8) + BMP180AddressReadByte(0xf8)) >>(8-OSS) ;
	
	return pressure;	

}

/******************************************************
Function	:BMP180ReadCalibrateParam
Input		:BMP180_info type point
Output		:AC1,AC3,AC3,AC4,AC5,AC6,B1,B2,MB,MC,MD
Return		:N/A
Description	:读取校正参数
Note		:N/A
******************************************************/
static void BMP180ReadCalibrateParam(BMP180_info *p)
{
	p->cal_param.AC1= BMP180AddressRead2Byte(0xAA);
	p->cal_param.AC2= BMP180AddressRead2Byte(0xAC);
	p->cal_param.AC3= BMP180AddressRead2Byte(0xAE);
	p->cal_param.AC4= BMP180AddressRead2Byte(0xB0);
	p->cal_param.AC5= BMP180AddressRead2Byte(0xB2);
	p->cal_param.AC6= BMP180AddressRead2Byte(0xB4);
	p->cal_param.B1=  BMP180AddressRead2Byte(0xB6);
	p->cal_param.B2=  BMP180AddressRead2Byte(0xB8);
	p->cal_param.MB=  BMP180AddressRead2Byte(0xBA);
	p->cal_param.MC=  BMP180AddressRead2Byte(0xBC);
	p->cal_param.MD=  BMP180AddressRead2Byte(0xBE);
}


/******************************************************
Function	:Init_BMP180
Input		:BMP180_info type point
Output		:p->ExistFlag  存在标志位
			 p->Version    版本号
Return		:N/A
Description	:初始化
Note		:N/A
******************************************************/
void BMP180Init(BMP180_info *p)
{
	if(BMP180AddressReadByte(BMP180_ID_REGISTER_ADDRESS)== BMP180_ID_FIXED_VALUE)
	{//存在
		p->ExistFlag = BMP180_EXISTENCE ;
		
		BMP180ReadCalibrateParam(p);

		p->Version = BMP180AddressReadByte(BMP180_VERSION_REGISTER_ADDRESS);
	}
	else
	{//不存在
		p->ExistFlag = BMP180_NOT_EXISTENCE ;
	}
}

/******************************************************
Function	:BMP180Convert
Input		:BMP180_info type point
Output		:temp->UnsetTemperature 未经过校正的温度值
			 temp->UnsetGasPress    未经过校正的气压值
			 temp->Temperature      校正后的温度值
			 temp->GasPress         校正后的气压值
			 temp->Altitude         海拔计算值
Return		:N/A
Description	:温度值、气压值的校正和海拔的计算
Note		:N/A
******************************************************/
void BMP180Convert(BMP180_info *temp)
{	
	SL32 x1, x2, B5, B6, x3, B3, p;
	unsigned long b4, b7;

	//未校正的温度值
	temp->UnsetTemperature = BMP180ReadUnsetTemperature();
	//未校正的气压值
	temp->UnsetGasPress = BMP180ReadUnsetPressure();

	//温度校正
	x1 = ((temp->UnsetTemperature) - temp->cal_param.AC6) * (temp->cal_param.AC5) >> 15;
	x2 = ((SL32)(temp->cal_param.MC) << 11) / (x1 + temp->cal_param.MD);
	B5 = x1 + x2;
	temp->Temperature= ((B5 + 8) >> 4)*0.1;

	//气压校正
	B6 = B5- 4000;
	x1 = ((SL32)(temp->cal_param.B2) * (B6 * B6 >> 12)) >> 11;
	x2 = ((SL32)temp->cal_param.AC2) * B6 >> 11;
	x3 = x1 + x2;
	B3 = ((((SL32)(temp->cal_param.AC1) * 4 + x3)<cal_param.AC3) * B6 >> 13;
	x2 = ((SL32)(temp->cal_param.B1) * (B6 * B6 >> 12)) >> 16;
	x3 = ((x1 + x2) + 2) >> 2;
	b4 = ((SL32)(temp->cal_param.AC4) * (unsigned long) (x3 + 32768)) >> 15;
	b7 = ((unsigned long)(temp->UnsetGasPress) - B3) * (50000 >> OSS);
	if( b7 < 0x80000000)
	{
	     p = (b7 * 2) / b4 ;
	}
    else
    {
		 p = (b7 / b4) * 2;
	}
	x1 = (p >> 8) * (p >> 8);
	x1 = ((SL32)x1 * 3038) >> 16;
	x2 = (-7357 * p) >> 16;
	temp->GasPress= p + ((x1 + x2 + 3791) >> 4);

	//海拔计算
	temp->Altitude =(44330.0 * (1.0-pow((float)(temp->GasPress) / 101325.0, 1.0/5.255)) );
}




/*################BMP180.c start################*/


补充:common.h

#ifndef __COMMON_H__
#define __COMMON_H__

typedef unsigned char UB8 ;
typedef unsigned short int UW16 ;
typedef unsigned long UL32 ;

typedef char SB8;
typedef short int SW16 ;
typedef long SL32 ;
	
#define HIGH_LEVEL 1	
#define LOW_LEVEL  0


#endif	/*__COMMON_H__*/


你可能感兴趣的:(单片机)