雨果喝水 发表于 2022-11-27 23:56

STM32CubeMX配置STM32F407的硬件IIC采集AHT20的温湿度

本帖最后由 雨果喝水 于 2022-11-27 23:57 编辑

最近在使用奥松的AHT20对环境温湿度进行采集。本例程采用ST的硬件IIC进行通讯,具体操作如下。
一、ATH20手册连接与注意事项 手册连接:AHT20数据手册
注意事项:
1、手册中器件地址是错误的,如下图:

此器件地址实际应该是0x70,而不是0x38。

雨果喝水 发表于 2022-11-27 23:58

在使用模拟IIC读取温湿度数值时,一定注意在停止信号前发送“NACK”非应答信号,而中间读取完一个字节发送的是“ACK”应答信号。如下图所示:

雨果喝水 发表于 2022-11-27 23:58

但是采用HAL库配置的硬件IIC,则直接使用如下两个相关函数即可,无需关注此应答信号。
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

雨果喝水 发表于 2022-11-27 23:59

从此处可以明显体现出硬件IIC的优势。
二、STM32CubeMX配置硬件IIC

使用STM32CubeMX配置硬件IIC,如下图:

雨果喝水 发表于 2022-11-30 15:32

具体实现代码
1、AHT20.h代码如下:
#ifndef INC_AHT20_H_
#define INC_AHT20_H_

#include "i2c.h"

//****************************************
// 定义 AHT20 命令
//****************************************
#define AHT20_Write             0x00    //读取
#define AHT20_Read            0x01    //写入



//****************************************
// 定义 AHT20 地址
//****************************************
#define AHT20_SLAVE_ADDRESS                0x70                /* I2C从机地址 */



//****************************************
// 定义 AHT20 命令
//****************************************
#define        AHT20_INIT_COMD                0xBE        //初始化 寄存器地址
#define        AHT20_SoftReset                        0xBA        //软复位 单指令
#define        AHT20_TrigMeasure_COMD        0xAC        //触发测量 寄存器地址

// 存储AHT20传感器信息的结构体

typedef struct m_AHT20
{
        uint8_t alive;        // 0-器件不存在; 1-器件存在
        uint8_t flag;        // 读取/计算错误标志位。0-读取/计算数据正常; 1-读取/计算设备失败
        uint32_t HT;        // 湿度、温度 原始传感器的值(20Bit).

        float RH;                // 湿度,转换单位后的实际值,标准单位%
        float Temp;                // 温度,转换单位后的实际值,标准单位°C
}AHT20_StructureTypedef;

externAHT20_StructureTypedefHumiture;

uint8_t AHT20_Init(void);
void    AHT20_Start_Init(void);
uint8_t AHT20_ReadHT(uint32_t *HT);
uint8_t StandardUnitCon(AHT20_StructureTypedef *aht);
uint8_t AHT20_Get_Value(AHT20_StructureTypedef *p);

#endif /* INC_AHT20_H_ */

雨果喝水 发表于 2022-11-30 15:33

其中,void AHT20_Start_Init(void);参考奥松官方代码编写,未进行验证。

雨果喝水 发表于 2022-11-30 15:34

AHT20.c代码如下:
#include "AHT20.h"

AHT20_StructureTypedefHumiture;


/**
* @brief读AHT20 设备状态字
* @paramvoid
* @retval uint8_t 设备状态字
*/
static uint8_t AHT20_ReadStatusCmd(void)
{
        uint8_t tmp = 0;
    HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
        return tmp;
}

/**
* @brief读AHT20 设备状态字 中的Bit3: 校准使能位
* @paramvoid
* @retval uint8_t 校准使能位:1 - 已校准; 0 - 未校准
*/
static uint8_t AHT20_ReadCalEnableCmd(void)
{
        uint8_t tmp = 0;
        tmp = AHT20_ReadStatusCmd();
        return (tmp>>3)&0x01;
}

/**
* @brief读AHT20 设备状态字 中的Bit7: 忙标志
* @paramvoid
* @retval uint8_t 忙标志:1 - 设备忙; 0 - 设备空闲
*/
static uint8_t AHT20_ReadBusyCmd(void)
{
        uint8_t tmp = 0;
        tmp = AHT20_ReadStatusCmd();
        return (tmp>>7)&0x01;
}

/**
* @briefAHT20 芯片初始化命令
* @paramvoid
* @retval void
*/
static void AHT20_IcInitCmd(void)
{
        uint8_t tmp = AHT20_INIT_COMD;
        HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
}

/**
* @briefAHT20 软复位命令
* @paramvoid
* @retval void
*/
static void AHT20_SoftResetCmd(void)
{
        uint8_t tmp = AHT20_SoftReset;
        HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
}

/**
* @briefAHT20 触发测量命令
* @paramvoid
* @retval void
*/
static void AHT20_TrigMeasureCmd(void)
{
    static uint8_t tmp = {AHT20_TrigMeasure_COMD, 0x33, 0x00};
        HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, tmp, 3, 0xFFFF);
}


/**
* @briefAHT20 设备初始化
* @paramvoid
* @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;

                HAL_Delay(40);//上电后要等待40ms
                // 读取温湿度之前,首先检查[校准使能位]是否为1
                while((!AHT20_ReadCalEnableCmd()) && (--icnt))// 2次重试机会
                {
                        HAL_Delay(1);
                        // 如果不为1,要发送初始化命令
                        AHT20_IcInitCmd();
                        HAL_Delay(40);//这个时间手册没说,按上电时间算40ms
                }

                if(icnt)//[校准使能位]为1,校准正常
                {
                        break;//退出rcnt循环
                }
                else//[校准使能位]为0,校准错误
                {
                        AHT20_SoftResetCmd();//软复位AHT20器件,重试
                        HAL_Delay(20);//这个时间手册标明不超过20ms.
                }
        }

        if(rcnt)
        {
                return 0;// AHT20设备初始化正常
        }
        else
        {
                return 1;// AHT20设备初始化失败
        }
}

/**
* @briefAHT20 寄存器复位
* @paramvoid
* @retval void
*/
static void AHT20_Register_Reset(uint8_t addr)
{
uint8_tiic_tx = {0}, iic_rx = {0};

iic_tx = addr;
HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, iic_tx, 3, 0xFFFF);
HAL_Delay(5);
HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, iic_rx, 3, 0xFFFF);
HAL_Delay(10);
iic_tx = 0xB0 | addr;
iic_tx = iic_rx;
iic_tx = iic_rx;
HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, iic_tx, 3, 0xFFFF);
HAL_Delay(10);
}


/**
* @briefAHT20 设备开始初始化
* @paramvoid
* @retval void
*/
void AHT20_Start_Init(void)
{
static uint8_t    temp = {0x1B, 0x1C, 0x1E}, i;
for(i = 0; i < 3; i++)
{
    AHT20_Register_Reset(temp);
}
}



/**
* @briefAHT20 设备读取 相对湿度和温度(原始数据20Bit)
* @paramuint32_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;
        uint32_t RetuData = 0;

        // 发送触发测量命令
        AHT20_TrigMeasureCmd();

        do{
                HAL_Delay(75);//等待75ms待测量完成,忙标志Bit7为0
        }while(AHT20_ReadBusyCmd() && (--cnt));//重试3次

        if(cnt)//设备闲,可以读温湿度数据
        {
                HAL_Delay(5);
                // 读温湿度数据
      HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, tmp, 6, 0XFFFF);
                // 计算相对湿度RH。原始值,未计算为标准单位%。
                RetuData = 0;
                RetuData = (RetuData|tmp) << 8;
                RetuData = (RetuData|tmp) << 8;
                RetuData = (RetuData|tmp);
                RetuData = RetuData >> 4;
                HT = RetuData;

                // 计算温度T。原始值,未计算为标准单位°C。
                RetuData = 0;
                RetuData = (RetuData|tmp) << 8;
                RetuData = (RetuData|tmp) << 8;
                RetuData = (RetuData|tmp);
                RetuData = RetuData&0xfffff;
                HT = RetuData;

                return 0;
        }
        else//设备忙,返回读取失败
        {
                return 1;
        }
}

/**
* @briefAHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
* @paramstruct m_AHT20* aht:存储AHT20传感器信息的结构体
* @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
*/
uint8_t StandardUnitCon(AHT20_StructureTypedef *aht)
{
        aht->RH = (double)aht->HT *100 / 1048576;//2^20=1048576 //原式:(double)aht->HT / 1048576 *100,为了浮点精度改为现在的
        aht->Temp = (double)aht->HT *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;//测量数据超出范围,错误
        }
}


/**
* @briefAHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
* @paramstruct m_AHT20* aht:存储AHT20传感器信息的结构体
* @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
*/
uint8_t AHT20_Get_Value(AHT20_StructureTypedef *p)
{
uint8_t   temp = 0;

temp = AHT20_ReadHT(p->HT);

if(temp == 0)
{
    temp = StandardUnitCon(p);
}

return temp;
}

雨果喝水 发表于 2022-11-30 15:34

main.c代码如下:
int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
   MX_I2C1_Init();
/* USER CODE BEGIN 2 */
if(AHT20_Init() != 0)
{
    Humiture.alive = 0;
    printf("AHT20 Initialization failed\r\n");
}
else
{
    Humiture.alive = 1;
    printf("AHT20 Initialization succeeded\r\n");
}
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{   
    AHT20_Get_Value(&Humiture);
    printf("environment temperature is : %.2f;\r\nenvironment humidity is : %.2f",Humiture.Temp, Humiture.RH);
    HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

雨果喝水 发表于 2022-11-30 15:35

以上代码均已验证可用。

雨果喝水 发表于 2022-11-30 15:36

试验结果如下图:

sesefadou 发表于 2022-12-14 10:31

硬件iic会不会有bug呢?            

macpherson 发表于 2022-12-15 12:43

怎么计算是否需要应答信号?            

kkzz 发表于 2022-12-15 18:13

HAL做硬件简单了很多。            

Undshing 发表于 2022-12-17 17:41

硬件iic确实有点问题,建议用模拟的

kkzz 发表于 2022-12-18 15:15

AHT20和sht30一样的吗?

AloneKaven 发表于 2022-12-18 18:18

这个应用用硬件iic应该没问题的

jimmhu 发表于 2022-12-18 20:59

AHT20的测量温度范围是多少?

gygp 发表于 2022-12-19 20:07

这个的温度井独自怎么样            

小小蚂蚁举千斤 发表于 2022-12-20 09:42

相关手册能方便发一下嘛?
页: [1]
查看完整版本: STM32CubeMX配置STM32F407的硬件IIC采集AHT20的温湿度