基于STM32F103驱动AHT20+BMP280模块测量温湿度和压强并在ST7735 LCD显示

电子说

1.4w人已加入

描述

AHT20+BMP280模块简介

本品采用了数字温湿度传感器AHT20与数字气压传感器BPM280 组成, I2C 输出。电压直流3.3V供电(两个模块电源是一起的,板子没有稳压器件,BMP280最高支持电压3.6V,所以这里建议是3.3V供电),体积小巧,方便集成。板子是将两个器件的IIC接到一起了,==板载4.7K的上拉电阻==。

AHT20

AHT20 是一款高精度数字式温湿度传感器,采用 I2C 通信接口,集成度高、功耗极低,能同时精准测量环境温度(-40℃ - 85℃)和相对湿度(0%~100% RH),输出数据稳定可靠,无需额外校准,广泛应用于智能家居、气象监测、消费电子等对温湿度检测精度和功耗有严格要求的场景。AHT20测温误差±0.3℃,湿度误差±2%。
器件IIC地址0x38(7位)
器件读取流程说明:
1.上电后要等待40ms,读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通
过发送0x71可以获取一个字节的状态字),如果不为1,要发送0xBE命令(初始化),此命令参数
有两个字节, 第一个字节为0x08,第二个字节为0x00。
2.直接发送 0xAC命令(触发测量),此命令参数有两个字节,第一个字节为 0x33,第二个字节
为0x00。
3.等待75ms待测量完成,忙状态Bit[7]为0,然后可以读取六个字节(发0X71即可以读取)。
4.计算温湿度值。
读取温湿度数据流程图
ST7735
温湿度数据都是分别20bit,输出数据后需要对数据进行转换,下面是对应的转换公式:
ST7735

BMP280

寄存器相关说明直接查阅这篇文章: [STM32软件SPI驱动BMP280(OLED显示)],这里就不再赘述。上面文章通讯使用的是SPI,这里说下BMP280传感器 IIC通讯。
BMP280主要参数:

  • 大气压强 :300-1100hPa,相对精度±0.12hPa
  • 温度 :-40-85℃,绝对精度±0.5℃(由内部温度传感器测量的温度。此温度值取决于印刷电路板的温度、传感器元件自身的发热情况以及环境温度,通常会高于环境温度)
  • IIC地址 :该 7 位设备地址为 111011x。前 6 位为固定位。最后一位可通过 SDO 值进行更改,并且在运行过程中可以进行更改。将 SDO 连接到 GND 从机地址为 1110110(0x76);将其连接到 Vddio 则从机地址为 1110111(0x77)板子设计吧SDO引脚拉高了,所以这里BMP280的器件地址是0x77(7位)。

寄存器

ST7735
IIC写时序
ST7735

IIC读时序
ST7735

测试接线

AHT20+BMP280STM32F103C8T61.44LCD ST7735
VDD3.3v3.3V
GNDGNDG
SCLPB10--
SDAPB11--
--PA8BLK
--PB1DC
--PB14RST
--PB12CS
--PB13SCL
--PB14MOSI

串口输出使用的是串口1,接线用USB转TTL接到单片机串口上,接线分别是VCC接3.3V,GND接GND,TX接PA10,RX接PA9。这里使用的单片机是直接把串口1接到板载的usb口了,所以就没有单独外接TTL模块了。

代码

AHT20.c

#include "stm32f10x.h"   // Device header
#include "AHT20.h"
#include "MyI2C.h"
#include "Delay.h"

#define AHT20_ADDRESS		  0x38		//AHT20的I2C从机地址
#define AHT20_SoftReset       0xBA

//1读0写

/**
  * 函    数:AHT20写寄存器
  * 参    数:RegAddress 寄存器地址,范围:参考AHT20手册的寄存器描述
  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void AHT20_WriteSingleReg(uint8_t Data)
{
	MyI2C_Start();						//I2C起始
	MyI2C_SendByte(AHT20_ADDRESS < < 1| 0x00);	//发送从机地址,读写位为0,表示即将写入,0x70
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(Data);				//发送要写入寄存器的数据
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_Stop();						//I2C终止
}

//AHT20读单个寄存器
uint8_t AHT20_ReadSingleReg()
{
	uint8_t Data;
	MyI2C_Start();						//I2C重复起始
	MyI2C_SendByte(AHT20_ADDRESS < < 1| 0x01);	//发送从机地址,读写位为1,表示即将读取,0x71
	MyI2C_ReceiveAck();					//接收应答
	Data = MyI2C_ReceiveByte();			//接收指定寄存器的数据
	MyI2C_SendAck(1);					//发送应答,给从机非应答,终止从机的数据输出
	MyI2C_Stop();						//I2C终止
	
	return Data;
}

//AHT20软复位
void AHT20_SoftRes(void)
{
    AHT20_WriteSingleReg(AHT20_SoftReset);
}

//读取AHT20的状态寄存器
uint8_t AHT20_Read_Status(void)
{

	uint8_t Byte_first;	
	Byte_first = AHT20_ReadSingleReg();		
	return Byte_first;
}

//查询cal enable位有没有使能?
uint8_t AHT20_Read_Cal_Enable(void)  
{
    uint8_t val = 0;//ret = 0,

    val = AHT20_Read_Status();
    if((val & 0x68)==0x08)  //判断NOR模式和校准输出是否有效 0110 1000
    return 1;
    else  return 0;
 }

//向AHT20发送AC触发测量命令
 void AHT20_SendAC(void) 
{
    MyI2C_Start();
    MyI2C_SendByte(AHT20_ADDRESS < < 1 |0x00);  //写
    MyI2C_ReceiveAck();
    MyI2C_SendByte(0xac);   //发送AC命令
    MyI2C_ReceiveAck();
    MyI2C_SendByte(0x33);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(0x00);
    MyI2C_ReceiveAck();
    MyI2C_Stop();
}

//读取AHT20的温度和湿度数据
void AHT20_Read_CTdata(uint32_t *ct) 
{
	volatile uint8_t  Byte_1th=0;
	volatile uint8_t  Byte_2th=0;
	volatile uint8_t  Byte_3th=0;
	volatile uint8_t  Byte_4th=0;
	volatile uint8_t  Byte_5th=0;
	volatile uint8_t  Byte_6th=0;
	 uint32_t RetuData = 0;
	
	uint16_t cnt = 0;


	AHT20_SendAC();//向AHT20发送AC命令

	Delay_ms(75);//等待75ms
    cnt = 0;
	while(((AHT20_Read_Status()&0x80)==0x80))//等待忙状态结束
	{
	 Delay_us(1508);
	 if(cnt++ >=100)
	 {
	  break;
	  }
	}
	MyI2C_Start();
	MyI2C_SendByte(AHT20_ADDRESS < < 1 | 0x01);//0x70+1   0x70为设备地址 1为方向位
	MyI2C_ReceiveAck();
	Byte_1th = MyI2C_ReceiveByte();//状态字
	MyI2C_SendAck(0);
	Byte_2th = MyI2C_ReceiveByte();//湿度字节
	MyI2C_SendAck(0);
	Byte_3th = MyI2C_ReceiveByte();//湿度字节
	MyI2C_SendAck(0);
	Byte_4th = MyI2C_ReceiveByte();//高4位为湿度  低4位为温度
	MyI2C_SendAck(0);
	Byte_5th = MyI2C_ReceiveByte();//温度字节
	MyI2C_SendAck(0);
	Byte_6th = MyI2C_ReceiveByte();//温度字节
	MyI2C_SendAck(1);
	MyI2C_Stop();

	RetuData = (RetuData|Byte_2th)< < 8;
	RetuData = (RetuData|Byte_3th)< < 8;
	RetuData = (RetuData|Byte_4th);
	RetuData =RetuData > >4;
	ct[0] = RetuData;
	RetuData = 0;
	RetuData = (RetuData|Byte_4th)< < 8;
	RetuData = (RetuData|Byte_5th)< < 8;
	RetuData = (RetuData|Byte_6th);
	RetuData = RetuData&0xfffff;
	ct[1] =RetuData; 

}
void AHT20_SyetemInit(void)
{
    MyI2C_Start();
	MyI2C_SendByte(AHT20_ADDRESS < < 1| 0x00);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(0x08);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(0x00);
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}

/**
  * 函    数:AHT20初始化
  * 参    数:无
  * 返 回 值:无
  */
	    
uint8_t AHT20_Init(void)   //初始化AHT20
{
	int count;
	MyI2C_Init();
    Delay_us(11038);

    AHT20_SyetemInit();

	Delay_ms(500);//延时0.5S
   while(AHT20_Read_Cal_Enable()==0)//需要等待状态字status的Bit[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT20,再重新初始化AHT20,直至Bit[3]=1
   {
        AHT20_SoftRes();                //软复位AHT20
        Delay_us(11038);
           
        AHT20_SyetemInit();
        count++;
        if(count >=10)return 0;
        Delay_ms(500);
    }
   return 1;
}

BMP280.c

#include "stm32f10x.h"   // Device header
#include "BMP280_Reg.h"
#include "BMP280.h"
#include "MyI2C.h"
#include "Delay.h"

#define BMP280_ADDRESS						0x77		//从设备地址
#define BMP280_RESET_VALUE					0xB6		//复位寄存器写入值

uint16_t    Dig_T1;
int16_t     Dig_T2;
int16_t     Dig_T3;
uint16_t    Dig_P1;
int16_t     Dig_P2;
int16_t     Dig_P3;
int16_t     Dig_P4;
int16_t     Dig_P5;
int16_t     Dig_P6;
int16_t     Dig_P7;
int16_t     Dig_P8;
int16_t     Dig_P9;

/**
  * 函    数:BMP280写寄存器
  * 参    数:RegAddress 寄存器地址
  * 参    数:Data 要写入寄存器的数据,范围:0x00~0xFF
  * 返 回 值:无
  */
void BMP280_WriteReg(uint8_t RegAddress, uint8_t Data)
{
	MyI2C_Start();						//I2C起始
	MyI2C_SendByte(BMP280_ADDRESS < < 1|0x00);	    //发送从机地址,读写位为0,表示即将写入
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(RegAddress);			//发送寄存器地址
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(Data);				//发送要写入寄存器的数据
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_Stop();						//I2C终止
}

/**
  * 函    数:BMP280读寄存器
  * 参    数:RegAddress 寄存器地址
  * 返 回 值:读取寄存器的数据,范围:0x00~0xFF
  */
uint8_t BMP280_ReadReg(uint8_t RegAddress)
{
	uint8_t Data;
	
	MyI2C_Start();						//I2C起始
	MyI2C_SendByte(BMP280_ADDRESS < < 1|0x00);	    //发送从机地址,读写位为0,表示即将写入
	MyI2C_ReceiveAck();					//接收应答
	MyI2C_SendByte(RegAddress);			//发送寄存器地址
	MyI2C_ReceiveAck();					//接收应答
	
	MyI2C_Start();						    //I2C重复起始
	MyI2C_SendByte(BMP280_ADDRESS < < 1|0x01);	//发送从机地址,读写位为1,表示即将读取
	MyI2C_ReceiveAck();					    //接收应答
	Data = MyI2C_ReceiveByte();			    //接收指定寄存器的数据
	MyI2C_SendAck(1);					    //发送应答,给从机非应答,终止从机的数据输出
	MyI2C_Stop();						    //I2C终止
	
	return Data;
}

/**
  * 函    数:BMP280读ID
  * 参    数:无
  * 返 回 值:BMP280的ID号
  */
uint8_t BMP280_ReadID(void)
{
    return BMP280_ReadReg(BMP280_CHIPID_REG);
}

/**
  * 函    数:读取转换3个连续寄存器
  * 参    数:首个读取的寄存器
  * 返 回 值:合并后的总值
  */
long bmp280_MultipleReadThree(unsigned char addr)
{
    unsigned char msb, lsb, xlsb;
    long temp = 0;
    msb = BMP280_ReadReg(addr);
    lsb = BMP280_ReadReg(addr + 1);
    xlsb = BMP280_ReadReg(addr + 2);

    temp = (long)(((unsigned long)msb < < 12)|((unsigned long)lsb < < 4)|((unsigned long)xlsb > > 4));

    return temp;
}

/**
  * 函    数:读取转换2个连续寄存器
  * 参    数:首个读取的寄存器
  * 返 回 值:合并后的总值
  */
short bmp280_MultipleReadTwo(unsigned char addr)
{
    unsigned char msb, lsb;
    short temp = 0;
    lsb = BMP280_ReadReg(addr);
    msb = BMP280_ReadReg(addr + 1);

    temp = (short)msb < < 8;
    temp |= (short)lsb;

    return temp;
}

/**
  * 函    数:BMP280初始化
  * 参    数:无
  * 返 回 值:无
  */
void BMP280_Init(void)
{
	MyI2C_Init();					//先初始化底层的I2C

    uint8_t Osrs_T = 1;             //Temperature oversampling x 1
    uint8_t Osrs_P = 4;             //Pressure oversampling x 1
    uint8_t Mode = 3;               //Normal mode
    uint8_t T_sb= 5;               //Tstandby 1000ms  测量速率1HZ
    uint8_t Filter = 0;             //Filter off 
    uint8_t Spi3w_en = 0;           //3-wire SPI Disable
    
    uint8_t Ctrl_Meas_Reg = (Osrs_T < < 5) | (Osrs_P < < 2) | Mode;
    uint8_t Config_Reg    = (T_sb < < 5) | (Filter < < 2) | Spi3w_en;
    
    //状态全部清零
    BMP280_WriteReg(BMP280_RESET_REG, BMP280_RESET_VALUE);  //将对应的配置值写入寄存器
    BMP280_WriteReg(BMP280_CTRLMEAS_REG, Ctrl_Meas_Reg);
    BMP280_WriteReg(BMP280_CONFIG_REG, Config_Reg);
    
    Dig_T1 = bmp280_MultipleReadTwo(BMP280_DIG_T1_LSB_REG);
    Dig_T2 = bmp280_MultipleReadTwo(BMP280_DIG_T2_LSB_REG);
    Dig_T3 = bmp280_MultipleReadTwo(BMP280_DIG_T3_LSB_REG);
    Dig_P1 = bmp280_MultipleReadTwo(BMP280_DIG_P1_LSB_REG);
    Dig_P2 = bmp280_MultipleReadTwo(BMP280_DIG_P2_LSB_REG);
    Dig_P3 = bmp280_MultipleReadTwo(BMP280_DIG_P3_LSB_REG);
    Dig_P4 = bmp280_MultipleReadTwo(BMP280_DIG_P4_LSB_REG);
    Dig_P5 = bmp280_MultipleReadTwo(BMP280_DIG_P5_LSB_REG);
    Dig_P6 = bmp280_MultipleReadTwo(BMP280_DIG_P6_LSB_REG);
    Dig_P7 = bmp280_MultipleReadTwo(BMP280_DIG_P7_LSB_REG);
    Dig_P8 = bmp280_MultipleReadTwo(BMP280_DIG_P8_LSB_REG);
    Dig_P9 = bmp280_MultipleReadTwo(BMP280_DIG_P9_LSB_REG);
    
    Delay_ms(200);
}

#define BMP280_S32_t long signed int
#define BMP280_U32_t long unsigned int
#define BMP280_S64_t long long signed int
BMP280_S32_t t_fine;
/**
  * 函    数:BMP280获取温度值
  * 参    数:无
  * 返 回 值:温度值
  */
int32_t BMP280_GetTemp(void)
{
    BMP280_S32_t var1, var2, T;
    BMP280_S32_t adc_T;
    adc_T = bmp280_MultipleReadThree(BMP280_TEMPERATURE_MSB_REG);
    
    //Temperature
    
    var1 = ((((adc_T > >3) - ((BMP280_S32_t)Dig_T1< < 1))) * ((BMP280_S32_t)Dig_T2)) > > 11;
    var2 = (((((adc_T > >4) - ((BMP280_S32_t)Dig_T1)) * ((adc_T > >4) - ((BMP280_S32_t)Dig_T1))) > > 12) * 
    ((BMP280_S32_t)Dig_T3)) > > 14;
    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) > > 8;
    return T;
}

/**
  * 函    数:BMP280获取压力值
  * 参    数:无
  * 返 回 值:压力值
  */
uint32_t BMP280_GetPress(void)
{
    BMP280_S64_t var1, var2, p;
    BMP280_S32_t adc_P;
    
    adc_P = bmp280_MultipleReadThree(BMP280_PRESSURE_MSB_REG);
    
    var1 = ((BMP280_S64_t)t_fine) - 128000;
    var2 = var1 * var1 * (BMP280_S64_t)Dig_P6;
    var2 = var2 + ((var1*(BMP280_S64_t)Dig_P5)< < 17);
    var2 = var2 + (((BMP280_S64_t)Dig_P4)< < 35);
    var1 = ((var1 * var1 * (BMP280_S64_t)Dig_P3) > >8) + ((var1 * (BMP280_S64_t)Dig_P2)< < 12);
    var1 = (((((BMP280_S64_t)1)< < 47)+var1))*((BMP280_S64_t)Dig_P1) > >33;
    if (var1 == 0)
    {
    return 0; // avoid exception caused by division by zero
    }
    p = 1048576-adc_P;
    p = (((p< < 31)-var2)*3125)/var1;
    var1 = (((BMP280_S64_t)Dig_P9) * (p > >13) * (p > >13)) > > 25;
    var2 = (((BMP280_S64_t)Dig_P8) * p) > > 19;
    p = ((p + var1 + var2) > > 8) + (((BMP280_S64_t)Dig_P7)< < 4);
    return (BMP280_U32_t)p;

}

main.c

#include "stm32f10x.h"               
#include "Delay.h"
#include "AHT20.h"
#include "uart.h"
#include "stdio.h"
#include "BMP280.h"
#include "lcd_init.h"
#include "lcd.h"

int main(void)
{
    int  c1,t1;
    uint32_t CT_data[2];
    uint8_t ID;
    float BMP_Pressure,BMP_Temperature;
    
    
    /*模块初始化*/
    uart_init(9600);
    BMP280_Init(); 
    LCD_Init();//LCD初始化
    LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
    
    while(1)
    {
        while(AHT20_Read_Cal_Enable()==0)//等到校准输出使能位为1,才读取。
        {
            AHT20_Init();//如果为0再使能一次
            Delay_ms(30);
        }
        AHT20_Read_CTdata(CT_data);  //读取温度和湿度,可间隔1.5S读一次
        c1 = CT_data[0] * 1000 / 1024 / 1024;  //计算得到湿度值(放大了10倍,如果c1=523,表示现在湿度为52.3%)
        t1 = CT_data[1] * 200 * 10 / 1024 / 1024 - 500;//计算得到温度值(放大了10倍,如果t1=245,表示现在温度为24.5℃)
        
        printf("****************************************************n");
        printf("AHT20温湿度传感器测试数据:n");
        printf("温度: %d.%d ℃ n", t1/10, t1%10);
        printf("湿度: %d.%d %% n", c1/10, c1%10);
        printf("n");
        
        ID = BMP280_ReadID();
        BMP_Temperature = BMP280_GetTemp();
        BMP_Pressure =  BMP280_GetPress();
        printf("BMP280传感器测试数据: n");
        printf("ID:0x%xn",ID);
        printf("温度: %0.2f ℃ n",BMP_Temperature/100.0);
        printf("气压: %0.4f hPa n",BMP_Pressure / 25600.0);
        printf("nn");
        
        
        LCD_ShowString(18,0,"AHT20+BMP280",BLACK,WHITE,16,0);
        LCD_ShowString(50,16,"TEST",BLACK,WHITE,16,0);
        
        //AHT20数据显示
        LCD_ShowString(0,32,"AHT20",BLACK,WHITE,16,0);

        //AHT20温度
        LCD_ShowChinese(0,48,"温度",BLACK,WHITE,16,0);
        LCD_ShowString(32,48,":",BLACK,WHITE,16,0);
        LCD_ShowIntNum(40,48,t1/10,2,BLACK,WHITE,16);
        LCD_ShowString(56,48,".",BLACK,WHITE,16,0);
        LCD_ShowIntNum(64,48,t1%10,1,BLACK,WHITE,16);
        LCD_ShowChinese(80,48,"℃",BLACK,WHITE,16,0);
        
        //AHT20湿度
        LCD_ShowChinese(0,64,"湿度",BLACK,WHITE,16,0);
        LCD_ShowString(32,64,":",BLACK,WHITE,16,0);
        LCD_ShowIntNum(40,64,c1/10,2,BLACK,WHITE,16);
        LCD_ShowString(56,64,".",BLACK,WHITE,16,0);
        LCD_ShowIntNum(64,64,c1%10,1,BLACK,WHITE,16);
        LCD_ShowString(80,64,"%",BLACK,WHITE,16,0);
        
        //BMP280数据显示
        LCD_ShowString(0,80,"BMP280",BLACK,WHITE,16,0);
        //BMP280温度
        LCD_ShowChinese(0,96,"温度",BLACK,WHITE,16,0);
        LCD_ShowString(32,96,":",BLACK,WHITE,16,0);
        LCD_ShowFloatNum1(40,96,BMP_Temperature/100.0,4,BLACK,WHITE,16);
        LCD_ShowChinese(80,96,"℃",BLACK,WHITE,16,0);
        
        //BMP280大气压强
        LCD_ShowChinese(0,112,"气压",BLACK,WHITE,16,0);
        LCD_ShowString(32,112,":",BLACK,WHITE,16,0);
        LCD_ShowIntNum(40,112,BMP_Pressure / 25600,4,BLACK,WHITE,16);
        LCD_ShowString(72,112,"hPa",BLACK,WHITE,16,0);
        
        Delay_ms(1000);
        
	 }
}

现象

LCD显示:
ST7735
串口输出
ST7735

总结

需要代码的可以在评论区留言邮箱哦!!!

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分