一.简介

★本设计采用STC89C52RC作为主控芯片,编程简单易于控制。配合使用BMP180气压传感器和AHT10温湿度传感器,可以检测大气温湿度和压强,并可以通过气压换算出绝对高度

★本设计集成CH340模块,可直接通过usb口下载程序。同时还集成降压稳压模块,可以使用5V以上的电池进行供电。

★本设计将剩余的I/O引脚引出,可供二次开发和功能扩展。同时配有5V和3.3V的电源输出引脚。配有4个按键,开源资料的代码中配有按键使用的代码,但没有使用。

二.设计展示

1.实物展示图

在这里插入图片描述

2.原理图

在这里插入图片描述

3.PCB布线图

在这里插入图片描述

4.三维图展示

在这里插入图片描述

三.AHT10介绍

1.简介

AHT10是一款精度高,完全校准,贴片封装的温湿度传感器,MEMS的制作工艺。传感器包括一个MEMS半导体电容式感湿元件、一个标准的片上温度传感器、一个全新设计的ASIC芯片

AHT10 通信方式采用标准IIC通信方式,超小的体积、极低的功耗。温湿度传感器均在高精度的恒温恒湿腔室中进行出厂校准,直接输出经温度补偿后的湿度、温度等信息,用户无需要对湿度进行温度补偿,便可得到准确的温湿度信息。

在这里插入图片描述

AHT10模块实物展示图

2.详细特性介绍(参考AHT10数据手册)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

★AHT10用于测量空气相对湿度温度

★对于相对湿度的测量,其分辨率可达0.024%,典型精度误差为2%,测量范围是0%-100%。一般情况下,相对湿度只需保留小数点后一位即可。

★对于温度的测量,其分辨率可达0.01℃,典型精度误差为±0.3℃,测量范围是-40℃-85℃。一般情况下,温度也只需保留小数点后一位。

★虽然从数据手册中可知,AHT10的最大供电电压为3.6V,但是直接购买的模块基本都配有降压稳压芯片,因此可支持5V供电。此外,测量时的功耗可低至0.07mW。

在这里插入图片描述

AHT10传感器的典型电路

I2C总线中,SDA和SCL都需要接上拉电阻;VDD脚需要外接0.1uF的滤波电容。购买的模块的中所有外围电路都已配备。

3.代码编写指南

在这里插入图片描述

设备地址和读写位图解

由图可知,当需要向设备写字节时,需发送0x70(读写位为0),当需要从设备读字节时,需发送0x71(读写位为1)。

在这里插入图片描述

AHT10需要用到的三条命令

在这里插入图片描述

AHT10状态寄存器

在这里插入图片描述

AHT10软复位流程

以上内容均会体现在下面的代码中,只需对比理解即可。

#define AHT_ADDRESS  0x70	//AHT10器件地址
#define WRITE_CONFIG 0xe1	//写系统配置寄存器命令
#define TRIG_MEASURE 0xac	//触发测量命令
#define SOFT_RESET   0xba	//软复位命令

/******************************************
函数名称:AHT_Read_Status
函数功能:读取AHT10状态寄存器
入口参数:无
返回  值:状态寄存器8位数据
******************************************/
unsigned char AHT_Read_Status(void)
{
	unsigned char Byte_first;
	AHT_Start();
	AHT_SendByte(AHT_ADDRESS+1);	//读命令
	AHT_WaitAck();
	Byte_first = AHT_RecByte();		//读取状态寄存器
	AHT_SendAck(1);
	AHT_Stop();
	
	return Byte_first;
}

/******************************************
函数名称:AHT_Read_Enable
函数功能:AHT10状态寄存器校准使能位读取
入口参数:无
返回  值:0-未校准,1-已校准
******************************************/
unsigned char AHT_Read_Enable(void)
{
	unsigned char val = 0;
	val = AHT_Read_Status();	
	if((val & 0x68) == 0x08)	//判断bit[3]是否为1
		return 1;
	else
		return 0;
}

/******************************************
函数名称:AHT_SendBA
函数功能:AHT10软复位
入口参数:无
返回  值:无
******************************************/
void AHT_SendBA(void)
{
	AHT_Start();
	AHT_SendByte(AHT_ADDRESS);	//写命令
	AHT_WaitAck();
	AHT_SendByte(SOFT_RESET);	//软复位命令
	AHT_WaitAck();
	AHT_Stop();
}

/******************************************
函数名称:AHT_Init
函数功能:AHT10初始化校准函数
入口参数:无
返回  值:0-初始化失败,1-初始化成功
******************************************/
unsigned char AHT_Init(void)
{
	unsigned char counter;
	
	AHT_Start();
	AHT_SendByte(AHT_ADDRESS);	//写命令
	AHT_WaitAck();
	AHT_SendByte(WRITE_CONFIG);	//写系统配置寄存器命令
	AHT_WaitAck();
	AHT_SendByte(0x08);			//初始化命令
	AHT_WaitAck();
	AHT_SendByte(0x00);
	AHT_WaitAck();
	AHT_Stop();
	
	Delay500ms();
	while(AHT_Read_Enable() == 0)	//如果状态寄存器bit[3]为0,代表未校准,重新初始化校准
	{
		AHT_SendBA();	//AHT10软复位
		Delay100ms();
		AHT_Delay(11038);
		
		AHT_Start();
		AHT_SendByte(AHT_ADDRESS);	//写命令
		AHT_WaitAck();
		AHT_SendByte(WRITE_CONFIG); //写系统配置寄存器命令
		AHT_WaitAck();
		AHT_SendByte(0x08);			//初始化命令
		AHT_WaitAck();
		AHT_SendByte(0x00);
		AHT_WaitAck();
		AHT_Stop();
		
		counter++;
		if(counter >=10)	//如果循环10以上,则初始化失败
			return 0;
		Delay500ms();
	}
	return 1;	//初始化成功
}

★上述代码中,只需要在主程序开始阶段使用AHT_Init()函数即可,用于设备的初始化。

在这里插入图片描述

触发测量和数据读取流程图

在这里插入图片描述

相对湿度转换公式

在这里插入图片描述

温度转换公式

AHT10的温湿度均为20位数据,因此转换公式中均除以2的20次方。

extern unsigned long humidity_dat;		//湿度原始数据
extern unsigned long temperature_dat;	//温度原始数据

/******************************************
函数名称:AHT_SendAC
函数功能:AHT10发送触发测量数据命令
入口参数:无
返回  值:无
******************************************/
void AHT_SendAC(void)
{
	AHT_Start();
	AHT_SendByte(AHT_ADDRESS);	//写命令
	AHT_WaitAck();
	AHT_SendByte(TRIG_MEASURE);	//触发测量命令
	AHT_WaitAck();
	AHT_SendByte(0x33);			//后两个为固定命令,无特殊含义
	AHT_WaitAck();
	AHT_SendByte(0x00);
	AHT_WaitAck();	
	AHT_Stop();
}

/******************************************
函数名称:read_hum_temp
函数功能:读取AHT10温湿度值
入口参数:无
返回  值:无
******************************************/
void read_hum_temp(void)
{
	unsigned char cnt=0;
	
	volatile unsigned char Byte_1th = 0;
	volatile unsigned char Byte_2th = 0;
	volatile unsigned char Byte_3th = 0;
	volatile unsigned char Byte_4th = 0;
	volatile unsigned char Byte_5th = 0;
	volatile unsigned char Byte_6th = 0;
	
	AHT_SendAC();	//发送触发测量命令
	Delay100ms();	//发送触发测量命令后至少延时75ms然后检验状态位
	
	while((AHT_Read_Status()&0x80)==0x80)	//校验状态位,判断设备是否繁忙(处于测量状态)
	{
		AHT_Delay(1508);
		if(cnt++>=100)
			break;
	}
	
	AHT_Start();
	AHT_SendByte(AHT_ADDRESS+1);	//读命令
	AHT_WaitAck();
	Byte_1th = AHT_RecByte();	//状态寄存器
	AHT_SendAck(0);
	Byte_2th = AHT_RecByte();	//湿度前8bit
	AHT_SendAck(0);	
	Byte_3th = AHT_RecByte();	//湿度中8bit
	AHT_SendAck(0);
	Byte_4th = AHT_RecByte();	//湿度后4bit和温度前4bit
	AHT_SendAck(0);
	Byte_5th = AHT_RecByte();	//温度中8bit
	AHT_SendAck(0);
	Byte_6th = AHT_RecByte();	//温度后8bit
	AHT_SendAck(1);
	AHT_Stop();
	
	//合并湿度的20位数据
	humidity_dat = (humidity_dat|Byte_2th)<<8;
	humidity_dat = (humidity_dat|Byte_3th)<<8;
	humidity_dat = humidity_dat|Byte_4th;
	humidity_dat = humidity_dat>>4;
	
	//合并温度的20位数据
	temperature_dat = (temperature_dat|(Byte_4th&0x0f))<<8;
	temperature_dat = (temperature_dat|Byte_5th)<<8;
	temperature_dat = temperature_dat|Byte_6th;
}

long temperature,humidity;
//温湿度还原公式,需要将其放在主函数中,即read_hum_temp()函数之后
humidity = humidity_dat*1000.0/1024/1024;	//湿度转换
temperature = temperature_dat*200.0/1024/1024-50;	//温度转换

四.BMP180介绍

1.简介

BMP180是一款高精度、小体积、超低能耗的压力传感器,可以应用在移动设备中。它的性能卓越,绝对精度最低可以达到0.03hPa,并且耗电极低,只有3uA。

BMP180 通信方式采用标准IIC通信方式,其内部集成了温度传感器和压力传感器,可以测量大气温度和气压,可通过对应公式换算出对海拔高度。

其内部有一个EEPROM,用于存放176位校准系数数据。
在这里插入图片描述

BMP180模块实物展示图

2.详细特性介绍(参考BMP180数据手册)

在这里插入图片描述

1.供电电压

在这里插入图片描述

2.气压和温度分辨率

在这里插入图片描述

3.气压和温度数据位数

★气压测量范围为:300hPa~1100hPa;
★温度测量范围为:-40℃~85℃。

3.代码编写指南

(1).首先需要了解BMP180校准系数的读取
在这里插入图片描述

BMP180器件地址

由图可知,当需要向设备写字节时,需发送0xee(读写位为0),当需要从设备读字节时,需发送0xef(读写位为1)。

在这里插入图片描述

176位(22个字节)校准系数数据地址


BMP180获取到气压和温度数据后,不能直接使用。需要用其内部EEPROM中保存的校准系数进行处理,才能还原出对应的气压和温度。

主程序开始时,需要先从EEPROM中将176位的校准系数读取出来,用于后面的气压与气温原始数据的校准。具体代码如下:

#define	BMP180_Address   0xee	  //BMP180器件地址

/******************************************
函数名称:write_bmp
函数功能:向一个寄存器写一个字节数据
入口参数:add-寄存器地址
		  dat-需要写入的数据
返回  值:无 
******************************************/
void write_bmp(unsigned char add,unsigned char dat)
{
	BMP_Start();
	BMP_SendByte(BMP180_Address);	//写命令
	BMP_WaitAck();
	BMP_SendByte(add);				//写寄存器地址
	BMP_WaitAck();
	BMP_SendByte(dat);				//写数据
	BMP_WaitAck();
	BMP_Stop();
}

/******************************************
函数名称:read_bmp
函数功能:从指定寄存器读一个字节数据
入口参数:add-寄存器地址
返回  值:一个字节8位数据 
******************************************/
unsigned char read_bmp(unsigned char add)
{
	unsigned char dat;
	BMP_Start();
	BMP_SendByte(BMP180_Address);	//写命令
	BMP_WaitAck();
	BMP_SendByte(add);	//写寄存器地址
	BMP_WaitAck();
	
	BMP_Start();
	BMP_SendByte(BMP180_Address+1);	//读命令
	BMP_WaitAck();
	dat = BMP_RecByte();	//读取一个字节数据
	BMP_SendAck(1);
	BMP_Stop();
	
	return dat;
}

/******************************************
函数名称:read_bmp
函数功能:从相邻的两个指定寄存器读取两个字节数据
入口参数:add-第一个寄存器地址
返回  值:两个字节16位数据 
******************************************/
short multiple_read(unsigned char add)
{
	unsigned int msb,lsb;
	short dat;
	BMP_Start();
	BMP_SendByte(BMP180_Address);	//写命令
	BMP_WaitAck();
	BMP_SendByte(add);	//写寄存器地址
	BMP_WaitAck();
	
	BMP_Start();
	BMP_SendByte(BMP180_Address+1);	//读命令
	BMP_WaitAck();
	msb = BMP_RecByte();	//读取第一个字节
	BMP_SendAck(0);
	lsb = BMP_RecByte();	//读取第二个字节
	BMP_SendAck(1);
	BMP_Stop();
	
	Delay5ms();
	dat = msb*256+lsb;	//合并成16位数据
	return dat;
}
//校准系数
extern short ac1,ac2,ac3,b1,b2,mb,mc,md;
extern unsigned short ac4,ac5,ac6; 

/******************************************
函数名称:Init_BMP180
函数功能:读取BMP180EEPROM中的176bit校准数据
入口参数:无
返回  值:无
******************************************/
void Init_BMP180(void)
{
	ac1 = multiple_read(0xAA);
	ac2 = multiple_read(0xAC);
	ac3 = multiple_read(0xAE);
	ac4 = multiple_read(0xB0);
	ac5 = multiple_read(0xB2);
	ac6 = multiple_read(0xB4);
	b1 =  multiple_read(0xB6);
	b2 =  multiple_read(0xB8);
	mb =  multiple_read(0xBA);
	mc =  multiple_read(0xBC);
	md =  multiple_read(0xBE);
}

(2).接着进行BMP180的气压与温度原始数据读取
在这里插入图片描述

写入控制寄存器值对应用法

0x2E对应温度采集,后四个对应气压采集(oss表示 oversampling_setting,过采样设置),具体对应如下表所示:

在这里插入图片描述
oss=0时,每次气压数据AD转换采样1次;
oss=1时,每次气压数据AD转换采样2次;

oss=2时,每次气压数据AD转换采样4次;
oss=3时,每次气压数据AD转换采样8次;
★随着采样次数的增加,转换所需要的时间也相应加长,但获得的数据会更加精确,噪声干扰减小。



★有关该控制寄存器具体介绍如下:
在这里插入图片描述
在这里插入图片描述

☆bit[4:0]用于选择需要采样的数据(气压 /温度);
☆bit[5]为转换标志位,为1时代表正在AD转换;
☆bit[7:6]为气压的过采样设置。

有关温度与气压的原始数据读取如下:(一般情况下,两个数据均设定为16bit

/******************************************
函数名称:bmp_read_ut
函数功能:BMP180温度原始值读取
入口参数:无
返回  值:温度原始数据
******************************************/
long bmp_read_ut(void)
{
	BMP_Start();
	BMP_SendByte(BMP180_Address);	//写数据
	BMP_WaitAck();
	BMP_SendByte(0xf4);				//写控制寄存器地址
	BMP_WaitAck();
	BMP_SendByte(0x2e);				//读取温度命令
	BMP_WaitAck();
	BMP_Stop();
	Delay5ms();
	
	return (long)multiple_read(0xf6);
}

/******************************************
函数名称:bmp_read_up
函数功能:BMP180气压原始值读取
入口参数:无
返回  值:气压原始数据
******************************************/
long bmp_read_up(void)
{
	BMP_Start();
	BMP_SendByte(BMP180_Address);	//写数据
	BMP_WaitAck();
	BMP_SendByte(0xf4);				//写控制寄存器地址
	BMP_WaitAck();
	BMP_SendByte(0x34);		        //读取压力值,bit7~6控制过采样率,bit5置1代表开始转换,bit4~0决定采样数据;
							        //0x34时每次只采样一次,耗时4.5ms
	BMP_WaitAck();
	BMP_Stop();
	Delay5ms();
	
	return ((long)multiple_read(0xf6)&0x0000ffff);	//读取2个字节数据
}

在这里插入图片描述
由上图可知,代码中读取数据的第一个字节寄存器地址为0xf6,是因为0xf6和0xf7中分别存储数据的高8位与低8位。

这两个数据寄存器中存储的数据,是由控制寄存器中的数据选择位(bit[4:0])决定,即气压数据和温度数据共用这两个数据寄存器。

(3).最后需要对原始数据进行校准
BMP180的数据手册中给出了校准系数的使用方法,具体如下图所示:
在这里插入图片描述

其代码实现为:

/******************************************
函数名称:bmp180_read_tp
函数功能:BMP180数据读取并校准
入口参数:choice:0-读取温度并校准,1-读取气压并校准
返回  值:温度/气压
******************************************/
long bmp180_read_tp(unsigned char choice)
{
	long ut,up;
	long x1,x2,x3,p;
	long b3,b5,b6,b7;
	unsigned long b4;
	long temperature,pressure;	//校准后的温度和气压
	
	ut = bmp_read_ut();		//第一次读取数据会错误,不能省略该步骤
	ut = bmp_read_ut();		//第二次读取温度原始数据
	up = bmp_read_up();		//读取湿度原始数据
	
	//根据数据手册的方法校准数据
	if(choice == 0)	  //校准温度
	{
		x1 = ((ut -ac6)*ac5)>>15;
		x2 = (((long)mc) << 11)/(x1 + md);
		b5 = x1 + x2;
		temperature = (b5 + 8) >> 4;
		return temperature;
	}
	else	//校准气压
	{
		//只使用气压时,同样需要温度校准时的步骤
		x1 = ((ut -ac6)*ac5)>>15;
		x2 = (((long)mc) << 11)/(x1 + md);
		b5 = x1 + x2;
		
		b6 = b5 - 4000;
		x1 = ((long)b2 * (b6 * b6 >> 12)) >> 11;
		x2 = ((long)ac2) * b6 >> 11;
		x3 = x1 + x2;
		b3 = ((((long)ac1) * 4 + x3) + 2)/4;
		x1 = ((long)ac3) * b6 >> 13;
		x2 = (((long)b1) * (b6 * b6 >> 12)) >> 16;
		x3 = ((x1 + x2) + 2) >> 2;
		b4 = (((long)ac4) * (unsigned long)(x3 + 32768)) >> 15;
		b7 = ((unsigned long) up - b3) * 50000;
		if(b7 < 0x80000000)
			p = (b7 * 2) / b4 ;
		else  
			p = (b7 / b4) * 2;
		x1 = (p >> 8) * (p >> 8);
		x1 = (((long)x1) * 3038) >> 16;
		x2 = (-7357 * p) >> 16;
		pressure = p + ((x1 + x2 + 3791) >> 4);
		return pressure;
	}
}

获取BMP180数据时,只需直接调用此函数即可。

(4).海拔计算
在这里插入图片描述

上述为通过当前气压计算绝对海拔高度的公式,其中P0即为海平面气压。代码实现如下:
此部分代码有BUG,在本设计中无法使用。检查发现是POW函数导致的(加上POW函数后会导致无法开机)但仍未找到解决方法。希望有懂的可以指点一二。

/******************************************
函数名称:cal_altitude
函数功能:计算当前海拔
入口参数:temperature-当前气温
		  pressure-当前气压
返回  值:当前海拔
******************************************/
int cal_altitude(long temperature,long pressure)
{
	float altitude;
	altitude = 44330*(1-pow((pressure/101325.0),(1.0/5.255)));
//	altitude *= 100;
	return (int)altitude;
}

五.开源资料

该开源资料包含PCB文件和程序:
基于STC89C52RC的大气参数检测仪(AHT10温湿度模块、BMP180气压模块)