AHT20 HAL库驱动
首先需要你自己实现delay_us和delay_ms这两个函数,建议使用正点原子的方法,使用systick来计数,systick中断优先级调高一点,就不会被卡住了。
AHT20是一款温湿度传感器,采用I2C接口,其7位设备地址为0x38。第八位是读写位,写为0读为1。具体细节请参看数据手册。网上给出的都是标准库的,我在这里修改成HAL库的硬件IIC驱动。
硬件买的是一个AHT20和BMP280在一起的模块,并夕夕卖家竟然没有资料,没办法只好自己搞一个。
//AHT20.h HAL库版本
#ifndef AHT20_H
#define AHT20_H
#include "delay.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_i2c.h"
#define ATH20_SLAVE_ADDRESS 0x38 /* AHT20 I2C 7位从机地址,不带读写位 */
#define AHT20_WRITE_ADDR (ATH20_SLAVE_ADDRESS<<1)/*设备写地址*/
#define AHT20_READ_ADDR ((ATH20_SLAVE_ADDRESS<<1)+1)/*设备读地址*/
#define AHT20_READWRITE_TIMOUT 200 //iic 读写超时时间
//****************************************
// 定义 AHT20 内部地址
//****************************************
#define INIT 0xBE //初始化
#define SoftReset 0xBA //软复位
#define StartTest 0xAC //开始测试
extern I2C_HandleTypeDef* AHT20_hi2c;
uint8_t AHT20_Read_Status(void);//读取AHT10的状态寄存器,测试用
//init需要传入AHT20挂在的I2C结构体
uint8_t AHT20_Init(I2C_HandleTypeDef* hi2c);//取数据需要先初始化一次
uint8_t ATH20_Read_Cal_Enable(void); //查询cal enable位有没有使能
void ATH20_Read_CTdata(uint32_t *ct); //读取AHT10的温度和湿度数据
#endif
//AHT20.c
#include "AHT20.h"
I2C_HandleTypeDef* AHT20_hi2c;//AHT挂载在那条IIC上。
uint8_t AHT20_Read_Status(void)//读取AHT10的状态寄存器
{
uint8_t Byte_first,tmp=0x71;
//读状态需要先发送一个0x71,然后获取一字节。
//HAL_I2C_Master_Transmit(AHT20_hi2c,AHT20_WRITE_ADDR,&tmp,1,AHT20_READWRITE_TIMOUT);
//HAL_I2C_Master_Receive(AHT20_hi2c,AHT20_READ_ADDR,&Byte_first,1,0xFFFF);
HAL_I2C_Mem_Read(AHT20_hi2c,AHT20_READ_ADDR,0x71,I2C_MEMADD_SIZE_8BIT,&Byte_first,1,AHT20_READWRITE_TIMOUT);
return Byte_first;
}
uint8_t ATH20_Read_Cal_Enable(void)
{
uint8_t val = 0;//ret = 0,
val = AHT20_Read_Status();
if((val & 0x68) == 0x08) //判断NOR模式和校准输出是否有效
return 1;
else
return 0;
}
void ATH20_Read_CTdata(uint32_t *ct) //读取AHT10的温度和湿度数据
{
uint32_t RetuData = 0;
uint16_t cnt = 0;
uint8_t Data[10];
uint8_t tmp[10];
tmp[0] = 0x33;
tmp[1] = 0x00;
// StartTest 0xAC
HAL_I2C_Mem_Write(AHT20_hi2c,AHT20_WRITE_ADDR,StartTest,I2C_MEMADD_SIZE_8BIT,tmp,2,AHT20_READWRITE_TIMOUT);
delay_ms(80);//等待75ms
cnt = 0;
while(((AHT20_Read_Status()&0x80) == 0x80))//等待忙状态结束
{
delay_ms(1);
if(cnt++ >= 100)
{
break;
}
}
HAL_I2C_Master_Receive(AHT20_hi2c,AHT20_READ_ADDR,Data,7,AHT20_READWRITE_TIMOUT);
//不进行CRC校验了,直接转换数据。,需要校验的可以自己加。
RetuData = 0;
RetuData = (RetuData|Data[1]) << 8;
RetuData = (RetuData|Data[2]) << 8;
RetuData = (RetuData|Data[3]);
RetuData = RetuData >> 4;
ct[0] = RetuData;
RetuData = 0;
RetuData = (RetuData|Data[3]) << 8;
RetuData = (RetuData|Data[4]) << 8;
RetuData = (RetuData|Data[5]);
RetuData = RetuData&0xfffff;
ct[1] = RetuData;
}
uint8_t count;
uint8_t AHT20_Init(I2C_HandleTypeDef* hi2c)
{
uint8_t tmp[10];
AHT20_hi2c = hi2c;
//上电后需等待40ms
delay_ms(40);
//数据手册上说要求先查看较准使能位是否为1,然后才发送初始化命令,为了简单我们直接初始化一次,再检测。
tmp[0] = 0x08;
tmp[1] = 0x00;
HAL_I2C_Mem_Write(AHT20_hi2c,AHT20_WRITE_ADDR,INIT,I2C_MEMADD_SIZE_8BIT,tmp,2,AHT20_READWRITE_TIMOUT);
delay_ms(500);
count = 0;
while(ATH20_Read_Cal_Enable() == 0)//需要等待状态字status的Bit[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit[3]=1
{
HAL_I2C_Mem_Write(AHT20_hi2c,AHT20_WRITE_ADDR,SoftReset,I2C_MEMADD_SIZE_8BIT,tmp,0,AHT20_READWRITE_TIMOUT);
/*uint8_t buf[2];
buf[0]=SoftReset;
HAL_I2C_Master_Transmit(AHT20_hi2c,AHT20_WRITE_ADDR,buf,1,AHT20_READWRITE_TIMOUT);*/
delay_ms(200);
HAL_I2C_Mem_Write(AHT20_hi2c,AHT20_WRITE_ADDR,INIT,I2C_MEMADD_SIZE_8BIT,tmp,2,AHT20_READWRITE_TIMOUT);
count++;
if(count >= 10)
return 0;
delay_ms(500);
}
return 1;
}
调用示例:
uint32_t CT_data[2];
int c1,t1;
uint8_t status = AHT20_Init(&hi2c1);
ATH20_Read_CTdata(CT_data); //读取温度和湿度
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℃
uint8_t transBuf[40];
sprintf(transBuf,"AHT20 Temp: %d.%d \r\n",(t1/10),(t1%10));
HAL_UART_Transmit(&huart1, (uint8_t *)transBuf, strlen(transBuf),200);
sprintf(transBuf,"AHT20 Humi: %d.%d %%\r\n",(c1/10),(c1%10));
HAL_UART_Transmit(&huart1, (uint8_t *)transBuf, strlen(transBuf),200);