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

文章目录

  • 前言
  • 一、ATH20手册连接与注意事项
  • 二、STM32CubeMX配置硬件IIC
  • 三、具体实现代码
  • 前言

    最近在使用奥松的AHT20对环境温湿度进行采集。本例程采用ST的硬件IIC进行通讯,具体操作如下。

    一、ATH20手册连接与注意事项

    手册连接:AHT20数据手册
    注意事项:
    1、手册中器件地址是错误的,如下图:
    AHT20器件地址
    此器件地址实际应该是0x70,而不是0x38。

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

    但是采用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);
    

    从此处可以明显体现出硬件IIC的优势。

    二、STM32CubeMX配置硬件IIC

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

    三、具体实现代码

    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[2];	// 湿度、温度 原始传感器的值(20Bit).
    
    	float RH;		// 湿度,转换单位后的实际值,标准单位%
    	float Temp;		// 温度,转换单位后的实际值,标准单位°C
    }AHT20_StructureTypedef;
    
    extern  AHT20_StructureTypedef  Humiture;
    
    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_ */
    

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

    2、AHT20.c代码如下:

    #include "AHT20.h"
    
    AHT20_StructureTypedef  Humiture;
    
    
    /**
      * @brief  读AHT20 设备状态字
      * @param  void
      * @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: 校准使能位
      * @param  void
      * @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: 忙标志
      * @param  void
      * @retval uint8_t 忙标志:1 - 设备忙; 0 - 设备空闲
      */
    static uint8_t AHT20_ReadBusyCmd(void)
    {
    	uint8_t tmp = 0;
    	tmp = AHT20_ReadStatusCmd();
    	return (tmp>>7)&0x01;
    }
    
    /**
      * @brief  AHT20 芯片初始化命令
      * @param  void
      * @retval void
      */
    static void AHT20_IcInitCmd(void)
    {
    	uint8_t tmp = AHT20_INIT_COMD;
    	HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
    }
    
    /**
      * @brief  AHT20 软复位命令
      * @param  void
      * @retval void
      */
    static void AHT20_SoftResetCmd(void)
    {
    	uint8_t tmp = AHT20_SoftReset;
    	HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
    }
    
    /**
      * @brief  AHT20 触发测量命令
      * @param  void
      * @retval void
      */
    static void AHT20_TrigMeasureCmd(void)
    {
        static uint8_t tmp[3] = {AHT20_TrigMeasure_COMD, 0x33, 0x00};
    	HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, tmp, 3, 0xFFFF);
    }
    
    
    /**
      * @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;
    
    		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设备初始化失败
    	}
    }
    
    /**
      * @brief  AHT20 寄存器复位
      * @param  void
      * @retval void
      */
    static void AHT20_Register_Reset(uint8_t addr)
    {
      uint8_t  iic_tx[3] = {0}, iic_rx[3] = {0};
      
      iic_tx[0] = 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[0] = 0xB0 | addr;
      iic_tx[1] = iic_rx[1];
      iic_tx[2] = iic_rx[2];
      HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, iic_tx, 3, 0xFFFF);
      HAL_Delay(10);
    }
    
    
    /**
      * @brief  AHT20 设备开始初始化
      * @param  void
      * @retval void
      */
    void AHT20_Start_Init(void)
    {
      static uint8_t    temp[3] = {0x1B, 0x1C, 0x1E}, i;
      for(i = 0; i < 3; i++)
      {
        AHT20_Register_Reset(temp[i]);
      }
    }
    
    
    
    /**
      * @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{
    		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[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(AHT20_StructureTypedef *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;//测量数据超出范围,错误
    	}
    }
    
    
    /**
      * @brief  AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
      * @param  struct 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;
    }
    

    3、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 */
    }
    

    以上代码均已验证可用。

    试验结果如下图:

    本文参考模拟IIC文章:AHT20温湿度传感器STM32-I2C驱动,替代DHT11/DHT12/AM2320/SHT20/SHT30,IIC代码兼容AHT10/15-MEMS温湿度传感器
    奥松官网例程

    本程序几乎适用于所有基于IIC通讯的温湿度传感器。

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32CubeMX配置STM32F407的硬件IIC采集AHT20的温湿度

    发表回复