这里将我写的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的存在:
未检测到BMP180的存在:
测试程序:
#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__*/