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

[复制链接]
1508|18
 楼主| 雨果喝水 发表于 2022-11-27 23:56 | 显示全部楼层 |阅读模式
本帖最后由 雨果喝水 于 2022-11-27 23:57 编辑

最近在使用奥松的AHT20对环境温湿度进行采集。本例程采用ST的硬件IIC进行通讯,具体操作如下。
一、ATH20手册连接与注意事项 手册连接:AHT20数据手册
注意事项:
1、手册中器件地址是错误的,如下图:
52182638388df2ccf7.png
此器件地址实际应该是0x70,而不是0x38。
 楼主| 雨果喝水 发表于 2022-11-27 23:58 | 显示全部楼层
在使用模拟IIC读取温湿度数值时,一定注意在停止信号前发送“NACK”非应答信号,而中间读取完一个字节发送的是“ACK”应答信号。如下图所示:
857916383890f0b686.png
 楼主| 雨果喝水 发表于 2022-11-27 23:58 | 显示全部楼层
但是采用HAL库配置的硬件IIC,则直接使用如下两个相关函数即可,无需关注此应答信号。
  1. HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  2. 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,如下图:
82776383896628906.png
 楼主| 雨果喝水 发表于 2022-11-30 15:32 | 显示全部楼层
具体实现代码
1、AHT20.h代码如下:
  1. #ifndef INC_AHT20_H_
  2. #define INC_AHT20_H_

  3. #include "i2c.h"

  4. //****************************************
  5. // 定义 AHT20 命令
  6. //****************************************
  7. #define AHT20_Write             0x00    //读取
  8. #define AHT20_Read              0x01    //写入



  9. //****************************************
  10. // 定义 AHT20 地址
  11. //****************************************
  12. #define AHT20_SLAVE_ADDRESS                0x70                /* I2C从机地址 */



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

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

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

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

  28. extern  AHT20_StructureTypedef  Humiture;

  29. uint8_t AHT20_Init(void);
  30. void    AHT20_Start_Init(void);
  31. uint8_t AHT20_ReadHT(uint32_t *HT);
  32. uint8_t StandardUnitCon(AHT20_StructureTypedef *aht);
  33. uint8_t AHT20_Get_Value(AHT20_StructureTypedef *p);

  34. #endif /* INC_AHT20_H_ */
 楼主| 雨果喝水 发表于 2022-11-30 15:33 | 显示全部楼层
其中,void AHT20_Start_Init(void);参考奥松官方代码编写,未进行验证。
 楼主| 雨果喝水 发表于 2022-11-30 15:34 | 显示全部楼层
AHT20.c代码如下:
  1. #include "AHT20.h"

  2. AHT20_StructureTypedef  Humiture;


  3. /**
  4.   * [url=home.php?mod=space&uid=247401]@brief[/url]  读AHT20 设备状态字
  5.   * @param  void
  6.   * @retval uint8_t 设备状态字
  7.   */
  8. static uint8_t AHT20_ReadStatusCmd(void)
  9. {
  10.         uint8_t tmp = 0;
  11.     HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
  12.         return tmp;
  13. }

  14. /**
  15.   * @brief  读AHT20 设备状态字 中的Bit3: 校准使能位
  16.   * @param  void
  17.   * @retval uint8_t 校准使能位:1 - 已校准; 0 - 未校准
  18.   */
  19. static uint8_t AHT20_ReadCalEnableCmd(void)
  20. {
  21.         uint8_t tmp = 0;
  22.         tmp = AHT20_ReadStatusCmd();
  23.         return (tmp>>3)&0x01;
  24. }

  25. /**
  26.   * @brief  读AHT20 设备状态字 中的Bit7: 忙标志
  27.   * @param  void
  28.   * @retval uint8_t 忙标志:1 - 设备忙; 0 - 设备空闲
  29.   */
  30. static uint8_t AHT20_ReadBusyCmd(void)
  31. {
  32.         uint8_t tmp = 0;
  33.         tmp = AHT20_ReadStatusCmd();
  34.         return (tmp>>7)&0x01;
  35. }

  36. /**
  37.   * @brief  AHT20 芯片初始化命令
  38.   * @param  void
  39.   * @retval void
  40.   */
  41. static void AHT20_IcInitCmd(void)
  42. {
  43.         uint8_t tmp = AHT20_INIT_COMD;
  44.         HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
  45. }

  46. /**
  47.   * @brief  AHT20 软复位命令
  48.   * @param  void
  49.   * @retval void
  50.   */
  51. static void AHT20_SoftResetCmd(void)
  52. {
  53.         uint8_t tmp = AHT20_SoftReset;
  54.         HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
  55. }

  56. /**
  57.   * @brief  AHT20 触发测量命令
  58.   * @param  void
  59.   * @retval void
  60.   */
  61. static void AHT20_TrigMeasureCmd(void)
  62. {
  63.     static uint8_t tmp[3] = {AHT20_TrigMeasure_COMD, 0x33, 0x00};
  64.         HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, tmp, 3, 0xFFFF);
  65. }


  66. /**
  67.   * @brief  AHT20 设备初始化
  68.   * @param  void
  69.   * @retval uint8_t:0 - 初始化AHT20设备成功; 1 - 初始化AHT20失败,可能设备不存在或器件已损坏
  70.   */
  71. uint8_t AHT20_Init(void)
  72. {
  73.         uint8_t rcnt = 2+1;//软复位命令 重试次数,2次
  74.         uint8_t icnt = 2+1;//初始化命令 重试次数,2次

  75.         while(--rcnt)
  76.         {
  77.                 icnt = 2+1;

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

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

  97.         if(rcnt)
  98.         {
  99.                 return 0;// AHT20设备初始化正常
  100.         }
  101.         else
  102.         {
  103.                 return 1;// AHT20设备初始化失败
  104.         }
  105. }

  106. /**
  107.   * @brief  AHT20 寄存器复位
  108.   * @param  void
  109.   * @retval void
  110.   */
  111. static void AHT20_Register_Reset(uint8_t addr)
  112. {
  113.   uint8_t  iic_tx[3] = {0}, iic_rx[3] = {0};
  114.   
  115.   iic_tx[0] = addr;
  116.   HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, iic_tx, 3, 0xFFFF);
  117.   HAL_Delay(5);
  118.   HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, iic_rx, 3, 0xFFFF);
  119.   HAL_Delay(10);
  120.   iic_tx[0] = 0xB0 | addr;
  121.   iic_tx[1] = iic_rx[1];
  122.   iic_tx[2] = iic_rx[2];
  123.   HAL_I2C_Master_Transmit(&hi2c1, AHT20_SLAVE_ADDRESS, iic_tx, 3, 0xFFFF);
  124.   HAL_Delay(10);
  125. }


  126. /**
  127.   * @brief  AHT20 设备开始初始化
  128.   * @param  void
  129.   * @retval void
  130.   */
  131. void AHT20_Start_Init(void)
  132. {
  133.   static uint8_t    temp[3] = {0x1B, 0x1C, 0x1E}, i;
  134.   for(i = 0; i < 3; i++)
  135.   {
  136.     AHT20_Register_Reset(temp[i]);
  137.   }
  138. }



  139. /**
  140.   * @brief  AHT20 设备读取 相对湿度和温度(原始数据20Bit)
  141.   * @param  uint32_t *HT:存储20Bit原始数据的uint32数组
  142.   * @retval uint8_t:0-读取数据正常; 1-读取设备失败,设备一直处于忙状态,不能获取数据
  143.   */
  144. uint8_t AHT20_ReadHT(uint32_t *HT)
  145. {
  146.         uint8_t cnt=3+1;//忙标志 重试次数,3次
  147.         uint8_t tmp[6];
  148.         uint32_t RetuData = 0;

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

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

  154.         if(cnt)//设备闲,可以读温湿度数据
  155.         {
  156.                 HAL_Delay(5);
  157.                 // 读温湿度数据
  158.         HAL_I2C_Master_Receive(&hi2c1, AHT20_SLAVE_ADDRESS, tmp, 6, 0XFFFF);
  159.                 // 计算相对湿度RH。原始值,未计算为标准单位%。
  160.                 RetuData = 0;
  161.                 RetuData = (RetuData|tmp[1]) << 8;
  162.                 RetuData = (RetuData|tmp[2]) << 8;
  163.                 RetuData = (RetuData|tmp[3]);
  164.                 RetuData = RetuData >> 4;
  165.                 HT[0] = RetuData;

  166.                 // 计算温度T。原始值,未计算为标准单位°C。
  167.                 RetuData = 0;
  168.                 RetuData = (RetuData|tmp[3]) << 8;
  169.                 RetuData = (RetuData|tmp[4]) << 8;
  170.                 RetuData = (RetuData|tmp[5]);
  171.                 RetuData = RetuData&0xfffff;
  172.                 HT[1] = RetuData;

  173.                 return 0;
  174.         }
  175.         else//设备忙,返回读取失败
  176.         {
  177.                 return 1;
  178.         }
  179. }

  180. /**
  181.   * @brief  AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
  182.   * @param  struct m_AHT20* aht:存储AHT20传感器信息的结构体
  183.   * @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
  184.   */
  185. uint8_t StandardUnitCon(AHT20_StructureTypedef *aht)
  186. {
  187.         aht->RH = (double)aht->HT[0] *100 / 1048576;//2^20=1048576 //原式:(double)aht->HT[0] / 1048576 *100,为了浮点精度改为现在的
  188.         aht->Temp = (double)aht->HT[1] *200 / 1048576 -50;

  189.         //限幅,RH=0~100%; Temp=-40~85°C
  190.         if((aht->RH >=0)&&(aht->RH <=100) && (aht->Temp >=-40)&&(aht->Temp <=85))
  191.         {
  192.                 aht->flag = 0;
  193.                 return 0;//测量数据正常
  194.         }
  195.         else
  196.         {
  197.                 aht->flag = 1;
  198.                 return 1;//测量数据超出范围,错误
  199.         }
  200. }


  201. /**
  202.   * @brief  AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
  203.   * @param  struct m_AHT20* aht:存储AHT20传感器信息的结构体
  204.   * @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
  205.   */
  206. uint8_t AHT20_Get_Value(AHT20_StructureTypedef *p)
  207. {
  208.   uint8_t   temp = 0;
  209.   
  210.   temp = AHT20_ReadHT(p->HT);
  211.   
  212.   if(temp == 0)
  213.   {
  214.     temp = StandardUnitCon(p);
  215.   }
  216.   
  217.   return temp;
  218. }
 楼主| 雨果喝水 发表于 2022-11-30 15:34 | 显示全部楼层
main.c代码如下:
  1. int main(void)
  2. {
  3.   /* USER CODE BEGIN 1 */

  4.   /* USER CODE END 1 */

  5.   /* MCU Configuration--------------------------------------------------------*/

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

  8.   /* USER CODE BEGIN Init */

  9.   /* USER CODE END Init */

  10.   /* Configure the system clock */
  11.   SystemClock_Config();

  12.   /* USER CODE BEGIN SysInit */

  13.   /* USER CODE END SysInit */

  14.   /* Initialize all configured peripherals */
  15.    MX_I2C1_Init();
  16.   /* USER CODE BEGIN 2 */
  17.   if(AHT20_Init() != 0)
  18.   {
  19.     Humiture.alive = 0;
  20.     printf("AHT20 Initialization failed\r\n");
  21.   }
  22.   else
  23.   {
  24.     Humiture.alive = 1;
  25.     printf("AHT20 Initialization succeeded\r\n");
  26.   }  
  27.   /* USER CODE END 2 */

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

  36.     /* USER CODE BEGIN 3 */
  37.   }
  38.   /* USER CODE END 3 */
  39. }
 楼主| 雨果喝水 发表于 2022-11-30 15:35 | 显示全部楼层
以上代码均已验证可用。
 楼主| 雨果喝水 发表于 2022-11-30 15:36 | 显示全部楼层
试验结果如下图:
81291638707d055645.png
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 | 显示全部楼层
相关手册能方便发一下嘛?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

1213

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部