AHT20温湿度传感器STM32-I2C驱动,替代DHT11/DHT12/AM2320/SHT20/SHT30,IIC代码兼容AHT10/15-MEMS温湿度传感器

news/2024/11/24 6:34:51/

AHT20是国内奥松生成的I2C接口的MEMS温湿度传感器,ADC位数为20Bit,具有体积小、精度高、成本低等优点。相较于AHT10,最显著的变化是体积由 5*4*1.6mm,缩小到 3*3*1.0mm。相对湿度精度 RH=±2%,温度精度 T=±0.3°C。相对湿度测量范围 RH=0~100%,温度测量范围 T=-40~85°C。从数据手册上看,AHT10/15/20只是供电电压不同,其他参数没有什么不同,其中AHT15具有聚四氟乙烯防水防尘膜,允许传感器在恶劣环境条件下使用(如喷淋水和高接触灰尘)。

由于AHT10/15/20 具有国产化、体积小、精度高、成本低等特点,可以替代 DHT11/DHT12/AM2320/SHT20/SHT30,单芯片价格在¥2~3,体积小巧很轻松嵌入到产品上。

 

1. 基本参数

 

AHT10/15/20 基本参数
 AHT10AHT15AHT20
供电电压1.8-3.6V1.8-3.6V2.0-5.5V
工作电流(休眠)0.25uA0.25uA0.25uA
工作电流(测量)23uA23uA23uA
测量范围(湿度)0~100%RH0~100%RH0~100%RH
测量范围(温度)-40~+85℃-40~+85℃-40~+85℃
湿度精度±2%RH(25℃)±2%RH(25℃)±2%RH(25℃)
温度精度±0.3℃±0.3℃±0.3℃
分辨率温度: 0.01℃  湿度: 0.024%RH温度: 0.01℃  湿度: 0.024%RH温度: 0.01℃  湿度: 0.024%RH
信号输出I²C信号I²C信号I²C信号
防护聚四氟乙烯防水防尘膜
封装大小5x4x1.6mm(DFN)6x5x17.7mm(直插模块)3x3x1.0mm(DFN)

 

 

2. 管脚定义、参考电路

  • AHT20 - IC管脚定义:

 

 

  • AHT20 - 参考电路:

 

 

3. I2C时序特性

  • I2C时序特性:(支持标准100KHz,高速400KHz)

 

 

4. 寄存器映射

AHT10/15/20数据手册中提供的寄存器映射不完整,且手册对I2C操作器件的描述有误导倾向,建议各位直接看下面代码。

(AHT10/15/20的I2C时序与MPU6050等标准8Bit寄存器地址的器件相同,I2C读写时序可以照搬)

 

5. 实验器件、环境

MCU使用stm32F103,使用软件模拟I2C。

AHT20使用网上的模块,引脚与DHT12兼容,正好可以放在我自己的物联网测试板上。

 

 

 

6. stm32F103驱动代码

  • AHT20.c:
#include "AHT20.h"/*** @brief  读AHT20 设备状态字* @param  void* @retval uint8_t 设备状态字*/
static uint8_t AHT20_ReadStatusCmd(void)
{uint8_t tmp[1];Soft_I2C_Read(ATH20_SLAVE_ADDRESS, AHT20_STATUS_REG, 1, tmp);return tmp[0];
}/*** @brief  读AHT20 设备状态字 中的Bit3: 校准使能位* @param  void* @retval uint8_t 校准使能位:1 - 已校准; 0 - 未校准*/
static uint8_t AHT20_ReadCalEnableCmd(void)
{uint8_t tmp;tmp = AHT20_ReadStatusCmd();return (tmp>>3)&0x01;
}/*** @brief  读AHT20 设备状态字 中的Bit7: 忙标志* @param  void* @retval uint8_t 忙标志:1 - 设备忙; 0 - 设备空闲*/
static uint8_t AHT20_ReadBusyCmd(void)
{uint8_t tmp;tmp = AHT20_ReadStatusCmd();return (tmp>>7)&0x01;
}/*** @brief  AHT20 芯片初始化命令* @param  void* @retval void*/
static void AHT20_IcInitCmd(void)
{uint8_t tmp[2];tmp[0] = 0x08;tmp[1] = 0x00;Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_INIT_REG, 2, tmp);
}/*** @brief  AHT20 触发测量命令* @param  void* @retval void*/
static void AHT20_TrigMeasureCmd(void)
{uint8_t tmp[2];tmp[0] = 0x33;tmp[1] = 0x00;Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_TrigMeasure_REG, 2, tmp);
}/*** @brief  AHT20 软复位命令* @param  void* @retval void*/
static void AHT20_SoftResetCmd(void)
{uint8_t tmp[1];Soft_I2C_Write(ATH20_SLAVE_ADDRESS, AHT20_SoftReset, 0, tmp);
}/*** @brief  AHT20 设备初始化* @param  void* @retval uint8_t:0 - 初始化AHT20设备成功; 1 - 初始化AHT20失败,可能设备不存在或器件已损坏*/
uint8_t AHT20_Init(void)
{uint8_t rcnt = 2+1;//软复位命令 重试次数,2次uint8_t icnt = 2+1;//初始化命令 重试次数,2次while(--rcnt){icnt = 2+1;delay_ms(40);//上电后要等待40ms// 读取温湿度之前,首先检查[校准使能位]是否为1while((!AHT20_ReadCalEnableCmd()) && (--icnt))// 2次重试机会{delay_ms(10);// 如果不为1,要发送初始化命令AHT20_IcInitCmd();delay_ms(200);//这个时间不确定,手册没讲}if(icnt)//[校准使能位]为1,校准正常{break;//退出rcnt循环}else//[校准使能位]为0,校准错误{AHT20_SoftResetCmd();//软复位AHT20器件,重试delay_ms(200);//这个时间不确定,手册没讲}}if(rcnt){delay_ms(200);//这个时间不确定,手册没讲return 0;// AHT20设备初始化正常}else{return 1;// AHT20设备初始化失败}
}/*** @brief  AHT20 设备读取 相对湿度和温度(原始数据20Bit)* @param  uint32_t *HT:存储20Bit原始数据的uint32数组* @retval uint8_t:0-读取数据正常; 1-读取设备失败,设备一直处于忙状态,不能获取数据*/
uint8_t AHT20_ReadHT(uint32_t *HT)
{uint8_t cnt=3+1;//忙标志 重试次数,3次uint8_t tmp[6];uint32_t RetuData = 0;// 发送触发测量命令AHT20_TrigMeasureCmd();do{delay_ms(75);//等待75ms待测量完成,忙标志Bit7为0}while(AHT20_ReadBusyCmd() && (--cnt));//重试3次if(cnt)//设备闲,可以读温湿度数据{delay_ms(5);// 读温湿度数据Soft_I2C_Read(ATH20_SLAVE_ADDRESS, AHT20_STATUS_REG, 6, tmp);// 计算相对湿度RH。原始值,未计算为标准单位%。RetuData = 0;RetuData = (RetuData|tmp[1]) << 8;RetuData = (RetuData|tmp[2]) << 8;RetuData = (RetuData|tmp[3]);RetuData = RetuData >> 4;HT[0] = RetuData;// 计算温度T。原始值,未计算为标准单位°C。RetuData = 0;RetuData = (RetuData|tmp[3]) << 8;RetuData = (RetuData|tmp[4]) << 8;RetuData = (RetuData|tmp[5]);RetuData = RetuData&0xfffff;HT[1] = RetuData;return 0;}else//设备忙,返回读取失败{return 1;}
}/*** @brief  AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)* @param  struct m_AHT20* aht:存储AHT20传感器信息的结构体* @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围*/
uint8_t StandardUnitCon(struct m_AHT20* aht)
{aht->RH = (double)aht->HT[0] *100 / 1048576;//2^20=1048576 //原式:(double)aht->HT[0] / 1048576 *100,为了浮点精度改为现在的aht->Temp = (double)aht->HT[1] *200 / 1048576 -50;//限幅,RH=0~100%; Temp=-40~85°Cif((aht->RH >=0)&&(aht->RH <=100) && (aht->Temp >=-40)&&(aht->Temp <=85)){aht->flag = 0;return 0;//测量数据正常}else{aht->flag = 1;return 1;//测量数据超出范围,错误}
}

 

  • AHT20.h:
#ifndef __AHT20_H
#define __AHT20_H
#include "sys.h"
#include "myiic.h"
#include "delay.h"#define ATH20_SLAVE_ADDRESS		0x38		/* I2C从机地址 *///****************************************
// 定义 AHT20 内部地址
//****************************************
#define	AHT20_STATUS_REG		0x00	//状态字 寄存器地址
#define	AHT20_INIT_REG			0xBE	//初始化 寄存器地址
#define	AHT20_SoftReset			0xBA	//软复位 单指令
#define	AHT20_TrigMeasure_REG	0xAC	//触发测量 寄存器地址// 存储AHT20传感器信息的结构体
struct m_AHT20
{uint8_t alive;	// 0-器件不存在; 1-器件存在uint8_t flag;	// 读取/计算错误标志位。0-读取/计算数据正常; 1-读取/计算设备失败uint32_t HT[2];	// 湿度、温度 原始传感器的值,20Bitfloat RH;		// 湿度,转换单位后的实际值,标准单位%float Temp;		// 温度,转换单位后的实际值,标准单位°C
};uint8_t AHT20_Init(void);
uint8_t AHT20_ReadHT(uint32_t *HT);
uint8_t StandardUnitCon(struct m_AHT20* aht);#endif

 

  • myiic.c:(使用的软件模拟iic,使用stm32F103的PB6.7)
#include "myiic.h"
#include "delay.h"//初始化IIC
void IIC_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);	//PB6,PB7 输出高
}
//产生IIC起始信号
void IIC_Start(void)
{SDA_OUT();     //sda线输出IIC_SDA=1;	  	  IIC_SCL=1;delay_us(4);IIC_SDA=0;//START:when CLK is high,DATA change form high to low delay_us(4);IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{SDA_OUT();//sda线输出IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(4);IIC_SCL=1; IIC_SDA=1;//发送I2C总线结束信号delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{u8 ucErrTime=0;SDA_IN();      //SDA设置为输入  IIC_SDA=1;delay_us(1);	   IIC_SCL=1;delay_us(1);	 while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;//时钟输出0 	   return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        u8 t;SDA_OUT();IIC_SCL=0;//拉低时钟开始数据传输for(t=0;t<8;t++){IIC_SDA=(txd&0x80)>>7;txd<<=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0;delay_us(2);}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(READ_SDA)receive++;   delay_us(1); }					 if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACK   return receive;
}/* 对器件读写的封装,从机器件地址为1字节 *//*** @brief  向I2C设备连续写数据(适用于符合IIC通信协议的寄存器地址为uint8类型的器件)* @param  addr:I2C从机器件地址* @param  reg: I2C从机寄存器地址* @param  len: 写入长度* @param  buf: uint8数据数组* @retval 0,正常; 其他,错误代码;*/
uint8_t Soft_I2C_Write(uint8_t dev_addr, uint8_t reg_addr, uint8_t len, unsigned char *data_buf)
{uint8_t i;IIC_Start();IIC_Send_Byte(dev_addr << 1 | I2C_Direction_Transmitter);//发送器件地址+写命令if(IIC_Wait_Ack())//等待应答{IIC_Stop();return 1;}IIC_Send_Byte(reg_addr);//写寄存器地址IIC_Wait_Ack();//等待应答for(i=0;i<len;i++){IIC_Send_Byte(data_buf[i]);//发送数据if(IIC_Wait_Ack())//等待ACK{IIC_Stop();return 1;}}IIC_Stop();return 0;
}/*** @brief  从I2C设备连续读数据(适用于符合IIC通信协议的寄存器地址为uint8类型的器件)* @param  addr:I2C从机器件地址* @param  reg: I2C从机寄存器地址* @param  len: 读出长度* @param  buf: uint8数据数组* @retval 0,正常; 其他,错误代码;*/
uint8_t Soft_I2C_Read(uint8_t dev_addr, uint8_t reg_addr, uint8_t len, unsigned char *data_buf)
{uint8_t result;IIC_Start();IIC_Send_Byte(dev_addr << 1 | I2C_Direction_Transmitter);//发送器件地址+写命令if(IIC_Wait_Ack())//等待应答{IIC_Stop();return 1;}IIC_Send_Byte(reg_addr);//写寄存器地址IIC_Wait_Ack();//等待应答IIC_Start();IIC_Send_Byte(dev_addr << 1 | I2C_Direction_Receiver);//发送器件地址+读命令IIC_Wait_Ack();//等待应答while(len){if(len==1)*data_buf=IIC_Read_Byte(0);//读数据,发送nACKelse *data_buf=IIC_Read_Byte(1);//读数据,发送ACKlen--;data_buf++;}IIC_Stop();//产生一个停止条件return 0;
}

 

  • myiic.h:
#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"//IO方向设置
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}//IO操作函数
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA
#define READ_SDA   PBin(7)  //输入SDA//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号uint8_t Soft_I2C_Write(uint8_t dev_addr, uint8_t reg_addr, uint8_t len, unsigned char *data_buf);
uint8_t Soft_I2C_Read(uint8_t dev_addr, uint8_t reg_addr, uint8_t len, unsigned char *data_buf);#endif

 

  • main.c:
struct m_AHT20 AHT20;int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4delay_init();	    				//延时函数初始化IIC_Init();							//IIC管脚初始化AHT20.alive=!AHT20_Init();	        //AHT20温湿度传感器初始化while(1){if(AHT20.alive)// 如果AHT20传感器存在,则读取温湿度数据{//读取AHT20的 20Bit原始数据AHT20.flag = AHT20_ReadHT(AHT20.HT);//实际标准单位转换StandardUnitCon(&AHT20);}delay_ms(2000);}
}

 

 

I2C波形、读出数据

(使用的软件模拟IIC,所以时序不是特别标准)

  • AHT20-ReadStatus:

 

  • AHT20-ReadData:

 

Jlink 调试器读数:

  • 室内温度、湿度:

 

  • 冲着AHT20哈哈气,后的温湿度读数,跟上面有鲜明对比

 

 


http://www.ppmy.cn/news/139334.html

相关文章

ZOJ 2320 Cracking' RSA

其次布尔线性方程组&#xff0c;高斯消元。这道题目的关键部分是看的神牛watashi的思路。另附上watashi的思路 我把他的java模板翻译成了C的了。。。存起来以后当模板用。。。a[i][j]表示第i个数含有质数p[j]的个数&#xff0c;奇数个的话就是true&#xff0c;偶数个就是false。…

STM32 AM2320 温湿度万年历 微信小程序显示及控制

功能描述: 使用STM32F103R8T6&#xff0c;红外遥控器&#xff0c;数码管&#xff0c;串口&#xff0c;预留ADC&#xff08;4~20mA输入、0~10V输入&#xff09;、485、以太网、WiFi、SD卡、USB_OTG等功能。单总线的方式采集温湿度&#xff08;因整个系统时序要求&#xff0c;所…

STM32单片机软件模拟I2C读取AM2320温湿度传感器数据

STM32单片机使用软件模拟IIC读取AM2320温湿度传感器的数据并显示在0.96寸OLED屏上。 我用的单片机是STM32F103C8T6&#xff0c;程序用的是ST标准库写的。 STM32使用硬件I2C读取SHTC3温湿度传感器&#xff1a;https://blog.zeruns.tech/archives/692.html STM32单片机读取AHT1…

bzoj2320: 最多重复子串

2320: 最多重复子串 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 246 Solved: 66[Submit][Status][Discuss] Description 一个字符串P的重复数定义为最大的整数R&#xff0c;使得P可以分为R段连续且相同的子串。比方说&#xff0c;“ababab”的重复数为3&#xff0c;“a…

OX 【HRBUST - 2320】

题目链接 HRBUST 2320 Kim喜欢玩井字棋。但是他从来都没有赢过&#xff1a;&#xff09;Kim非常好奇井字棋是否有一个必胜的策略。 给定一个局面&#xff0c;以及下一步该谁走&#xff08;o或x&#xff09;&#xff0c;请判断在双方都足够聪明的情况下&#xff08;双方一直采用…

Stm32F103 Hal库硬件iic 访问AM2320温湿度传感器

Stm32F103 Hal库硬件iic 访问AM2320温湿度传感器 管脚配置 PB6 PB7 之前用库函数&#xff0c;一直读不到&#xff0c;换hal库后正常了&#xff0c;因为要在android板上调试&#xff0c;但是板卡没来&#xff0c;只好用stm32 先调试下。 很简单&#xff0c;先初始化i2C1 i2c.c …

洛谷 2320

解题思路&#xff1a; 首先所有的钱袋都可以看成一个取或不取的情况。那么这些钱袋取或不取就可以看作0或1&#xff0c;也就是说&#xff0c;要使用一些数字表示一个范围里的所有数&#xff0c;同时这又很二进制&#xff08;取或不取&#xff09;。所以我们就把钱袋里钱的数量定…