完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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 基本参数 [tr] AHT10AHT15AHT20[/tr][tr]供电电压[td]1.8-3.6V[tr]工作电流(休眠)[td]0.25uA[tr]工作电流(测量)[td]23uA[tr]测量范围(湿度)[td]0~100%RH[tr]测量范围(温度)[td]-40~+85℃[tr]湿度精度[td]±2%RH(25℃)[tr]温度精度[td]±0.3℃[tr]分辨率[td]温度: 0.01℃ 湿度: 0.024%RH[tr]信号输出[td]I²C信号[tr]防护[td]无[tr]封装大小[td]5x4x1.6mm(DFN)
2. 管脚定义、参考电路
3. I2C时序特性
4. 寄存器映射AHT10/15/20数据手册中提供的寄存器映射不完整,且手册对I2C操作器件的描述有误导倾向,建议各位直接看下面代码。 (AHT10/15/20的I2C时序与MPU6050等标准8Bit寄存器地址的器件相同,I2C读写时序可以照搬) 5. 实验器件、环境MCU使用stm32F103,使用软件模拟I2C。 AHT20使用网上的模块,引脚与DHT12兼容,正好可以放在我自己的物联网测试板上。 6. stm32F103驱动代码
#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 // 读取温湿度之前,首先检查[校准使能位]是否为1 while((!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°C if((aht->RH >=0)&&(aht->RH <=100) && (aht->Temp >=-40)&&(aht->Temp <=85)) { aht->flag = 0; return 0;//测量数据正常 } else { aht->flag = 1; return 1;//测量数据超出范围,错误 } }
#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]; // 湿度、温度 原始传感器的值,20Bit float RH; // 湿度,转换单位后的实际值,标准单位% float Temp; // 温度,转换单位后的实际值,标准单位°C }; uint8_t AHT20_Init(void); uint8_t AHT20_ReadHT(uint32_t *HT); uint8_t StandardUnitCon(struct m_AHT20* aht); #endif
#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 high delay_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();//发送nACK else IIC_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 IIC_Send_Byte(data_buf);//发送数据 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);//读数据,发送nACK else *data_buf=IIC_Read_Byte(1);//读数据,发送ACK len--; data_buf++; } IIC_Stop();//产生一个停止条件 return 0; }
#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
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_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,所以时序不是特别标准)
Jlink 调试器读数:
|
|
|
|
只有小组成员才能发言,加入小组>>
3308 浏览 9 评论
2988 浏览 16 评论
3490 浏览 1 评论
9049 浏览 16 评论
4083 浏览 18 评论
1167浏览 3评论
601浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
592浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2329浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1892浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 09:43 , Processed in 1.126448 second(s), Total 49, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号