首先说一下,我做的是模拟的IIC进行数据的读取,所以相对比较简单,时钟按照芯片主频稍作修改即可,我们目前使用的是PB9作为SCL引脚,PB8作为SDA引脚,整个连接如下图

00-连接图.png
完成了引脚的连接,那么我们就来修改AHT11的代码,这里直接上代码
#include "DRV_AHT10.h"

  • float TempData=0,WetData=0;


  • void Delay_N10us(uint32_t t)//延时函数
  • {
  •   uint32_t k;

  •    while(t--)
  •   {
  •      for (k = 0; k < 719; k++)//110
  •       ;
  •   }
  • }



  • void SensorDelay_us(uint32_t t)//延时函数
  • {
  •         t = t-2;       
  •         for(; t>0; t--)
  •         {
  •                 Delay_N10us(1);
  •         }

  • }

  • void Delay_3us(void)                //延时函数
  • {       
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  • }
  • void Delay_1us(void)                //延时函数
  • {       
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  •         Delay_N10us(1);
  •         Delay_N10us(1);

  • }
  • //--SCL_PA00---SDA-PA01---

  • void SDA_Pin_Output_High(void)   //将P15配置为输出 , 并设置为高电平, P15作为I2C的SDA
  • {
  •   GPIO_Pins_Set(GPIOB,GPIO_PIN_8);
  • }

  • void SDA_Pin_Output_Low(void)  //将P15配置为输出  并设置为低电平
  • {
  •   GPIO_Pins_Reset(GPIOB,GPIO_PIN_8);
  • }



  • void SDA_Pin_IN_FLOATING(void)  //SDA配置为悬浮输入
  • {
  •        
  •        
  •           GPIO_InitType GPIO_InitStructure;
  •                 RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
  •           //PA1-PA7-PA9
  •                 GPIO_InitStructure.Pin          = GPIO_PIN_8;
  •                 GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_INPUT;
  •                 GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
  •                 GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
  •        
  •        
  •        
  • }

  • void SDA_Pin_OUT_PP(void)  //SDA配置为悬浮输入
  • {
  •           GPIO_InitType GPIO_InitStructure;
  •                 RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
  •           //PA1-PA7-PA9
  •                 GPIO_InitStructure.Pin          = GPIO_PIN_8;
  •                 GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_OUT_PP;
  •                 GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
  •                 GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
  • }



  • void SCL_Pin_Output_High(void) //SCL输出高电平,P14作为I2C的SCL
  • {
  •     GPIO_Pins_Set(GPIOB,GPIO_PIN_9);
  • }

  • void SCL_Pin_Output_Low(void) //SCL输出低电平
  • {
  • GPIO_Pins_Reset(GPIOB,GPIO_PIN_9);
  • }

  • void Init_I2C_Sensor_Port(void) //初始化I2C接口
  • {       
  •        
  •                   GPIO_InitType GPIO_InitStructure;
  •                 RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
  •           //--SDA_PB8
  •                 GPIO_InitStructure.Pin          = GPIO_PIN_8;
  •                 GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_OUT_PP;
  •                 GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
  •                 GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
  •                
  •                 RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
  •           //SCL_PB9
  •                 GPIO_InitStructure.Pin          = GPIO_PIN_9;
  •                 GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_OUT_PP;
  •                 GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
  •                 GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
  •                
  •                
  • }


  • void I2C_Start(void)                 //I2C主机发送START信号
  • {
  • SDA_Pin_Output_High();
  • SensorDelay_us(8);
  • SCL_Pin_Output_High();
  • SensorDelay_us(8);
  • SDA_Pin_Output_Low();
  • SensorDelay_us(8);
  • SCL_Pin_Output_Low();
  • SensorDelay_us(8);   
  • }


  • void ZSSC_I2C_WR_Byte(uint8_t Byte) //往AHT10写一个字节
  • {
  •         uint8_t Data,N,i;       
  •         SDA_Pin_OUT_PP();
  •         Data=Byte;
  •         i = 0x80;
  •         for(N=0;N<8;N++)
  •         {
  •                 SCL_Pin_Output_Low();
  •           
  •                 Delay_3us();       
  •                
  •                 if(i&Data)
  •                 {
  •                         SDA_Pin_Output_High();
  •                 }
  •                 else
  •                 {
  •                         SDA_Pin_Output_Low();
  •                 }       
  •                        
  •         SCL_Pin_Output_High();
  •                 Delay_3us();
  •                
  •                 Data <<= 1;
  •                  
  •         }
  •         SCL_Pin_Output_Low();
  •         SensorDelay_us(8);   
  •         SDA_Pin_IN_FLOATING();
  •         SensorDelay_us(8);       
  • }       


  • uint8_t ZSSC_I2C_RD_Byte(void)//从AHT10读取一个字节
  • {
  •         uint8_t Byte,i,a;
  •         Byte = 0;
  •         SCL_Pin_Output_Low();
  •         SDA_Pin_IN_FLOATING();
  •         SensorDelay_us(8);       
  •         for(i=0;i<8;i++)
  •         {
  •     SCL_Pin_Output_High();               
  •                 Delay_1us();
  •                 a=0;
  •                 if(GPIO_Input_Pin_Data_Get(GPIOB,GPIO_PIN_8)==PIN_SET)//--读取引脚状态
  •                 {
  •                         a=1;
  •                 }

  •                 Byte = (Byte<<1)|a;
  •                 SCL_Pin_Output_Low();
  •                 Delay_1us();
  •         }
  •     SDA_Pin_IN_FLOATING();
  •         SensorDelay_us(8);       
  •         return Byte;
  • }


  • uint8_t Receive_ACK(void)   //看AHT10是否有回复ACK
  • {
  •         uint16_t CNT;
  •         CNT = 0;
  •         SCL_Pin_Output_Low();       
  •         SDA_Pin_IN_FLOATING();
  •         SensorDelay_us(8);       
  •         SCL_Pin_Output_High();       
  •         SensorDelay_us(8);       
  •         while((GPIO_Input_Pin_Data_Get(GPIOB,GPIO_PIN_8)==PIN_SET)        && CNT < 100)
  •         {
  •                 CNT++;
  •         }               

  •         if(CNT == 100)
  •         {
  •                 return 0;
  •         }
  •         SCL_Pin_Output_Low();       
  •         SensorDelay_us(8);       
  •         return 1;
  • }

  • void Send_ACK(void)                  //主机回复ACK信号
  • {
  •        
  •         SDA_Pin_OUT_PP();
  •         SCL_Pin_Output_Low();       
  •         SensorDelay_us(8);       
  •         SDA_Pin_Output_Low();
  •         SensorDelay_us(8);       
  •         SCL_Pin_Output_High();       
  •         SensorDelay_us(8);
  •         SCL_Pin_Output_Low();       
  •         SensorDelay_us(8);
  •         SDA_Pin_IN_FLOATING();
  •         SensorDelay_us(8);
  • }

  • void Send_NOT_ACK(void)        //主机不回复ACK
  • {
  •         SDA_Pin_OUT_PP();
  •         SCL_Pin_Output_Low();       
  •         SensorDelay_us(8);
  •         SDA_Pin_Output_High();
  •         SensorDelay_us(8);
  •         SCL_Pin_Output_High();       
  •         SensorDelay_us(8);               
  •         SCL_Pin_Output_Low();       
  •         SensorDelay_us(8);
  •     SDA_Pin_Output_Low();
  •         SensorDelay_us(8);
  • }

  • void Stop_I2C(void)          //一条协议结束
  • {
  •         SDA_Pin_OUT_PP();
  •         SDA_Pin_Output_Low();
  •         SensorDelay_us(8);
  •         SCL_Pin_Output_High();       
  •         SensorDelay_us(8);
  •         SDA_Pin_Output_High();
  •         SensorDelay_us(8);
  • }

  • uint8_t JH_Read_Status(void)//读取AHT10的状态寄存器
  • {

  •         uint8_t Byte_first;       
  •         I2C_Start();
  •         ZSSC_I2C_WR_Byte(0x71);
  •         Receive_ACK();
  •         Byte_first = ZSSC_I2C_RD_Byte();
  •                

  •         Send_NOT_ACK();
  •         Stop_I2C();


  •         return Byte_first;
  • }

  • uint8_t JH_Read_Cal_Enable(void)  //查询cal enable位有没有使能?
  • {
  •         uint8_t val = 0;//ret = 0,

  •   val = JH_Read_Status();
  •   if((val & 0x68)==0x08)  //判断NOR模式和校准输出是否有效
  •   return 1;
  •   else  return 0;
  • }



  • void JH_SendAC(void) //向AHT10发送AC命令
  • {

  • I2C_Start();
  • ZSSC_I2C_WR_Byte(0x70);
  • Receive_ACK();
  • ZSSC_I2C_WR_Byte(0xac);
  • Receive_ACK();
  • ZSSC_I2C_WR_Byte(0x33);
  • Receive_ACK();
  • ZSSC_I2C_WR_Byte(0x00);
  • Receive_ACK();
  • Stop_I2C();

  • }

  • void JH_Send_BA(void)//向AHT10发送BA命令
  • {


  • I2C_Start();
  • ZSSC_I2C_WR_Byte(0x70);
  • Receive_ACK();
  • ZSSC_I2C_WR_Byte(0xba);
  • Receive_ACK();
  • Stop_I2C();


  • }

  • void JH_Read_CTdata(uint32_t *ct) //读取AHT10的温度和湿度数据
  • {
  •         volatile uint8_t  Byte_1th=0;
  •         volatile uint8_t  Byte_2th=0;
  •         volatile uint8_t  Byte_3th=0;
  •         volatile uint8_t  Byte_4th=0;
  •         volatile uint8_t  Byte_5th=0;
  •         volatile uint8_t  Byte_6th=0;
  •          uint32_t RetuData = 0;
  •        
  •         uint16_t cnt = 0;


  •         JH_SendAC();//向AHT10发送AC命令

  •          SysTick_Delay_Ms(75);//等待75ms
  •     cnt = 0;
  •         while(((JH_Read_Status()&0x80)==0x80))//等待忙状态结束
  •         {
  •          SensorDelay_us(1508);
  •          if(cnt++>=100)
  •          {
  •           break;
  •           }
  •         }
  •         I2C_Start();

  •         ZSSC_I2C_WR_Byte(0x71);//0x70+1   0x70为设备地址 1为方向位
  •         Receive_ACK();
  •         Byte_1th = ZSSC_I2C_RD_Byte();//状态字
  •         Send_ACK();
  •         Byte_2th = ZSSC_I2C_RD_Byte();//湿度字节
  •         Send_ACK();
  •         Byte_3th = ZSSC_I2C_RD_Byte();//湿度字节
  •         Send_ACK();
  •         Byte_4th = ZSSC_I2C_RD_Byte();//高4位为湿度  低4位为温度
  •         Send_ACK();
  •         Byte_5th = ZSSC_I2C_RD_Byte();//温度字节
  •         Send_ACK();
  •         Byte_6th = ZSSC_I2C_RD_Byte();//温度字节
  •         Send_NOT_ACK();
  •         Stop_I2C();

  •         RetuData = (RetuData|Byte_2th)<<8;
  •         RetuData = (RetuData|Byte_3th)<<8;
  •         RetuData = (RetuData|Byte_4th);
  •         RetuData =RetuData >>4;
  •         ct[0] = RetuData;
  •         RetuData = 0;
  •         RetuData = (RetuData|Byte_4th)<<8;
  •         RetuData = (RetuData|Byte_5th)<<8;
  •         RetuData = (RetuData|Byte_6th);
  •         RetuData = RetuData&0xfffff;
  •         ct[1] =RetuData;

  • }


  • unsigned  char  JH_Init(void)   //初始化AHT10
  • {

  •         unsigned int count=0;
  •         Init_I2C_Sensor_Port();
  •         SensorDelay_us(11038);

  •         I2C_Start();
  •         ZSSC_I2C_WR_Byte(0x70);
  •         Receive_ACK();
  •         ZSSC_I2C_WR_Byte(0xe1);//写系统配置寄存器
  •         Receive_ACK();
  •         ZSSC_I2C_WR_Byte(0x08);
  •         Receive_ACK();
  •         ZSSC_I2C_WR_Byte(0x00);
  •         Receive_ACK();
  •         Stop_I2C();

  •         SysTick_Delay_Ms(500);//延时0.5S
  •    while(JH_Read_Cal_Enable()==0)//需要等待状态字status的Bit[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit[3]=1
  •    {
  •    
  •                                 JH_Send_BA();  //复位
  •                                 SysTick_Delay_Ms(100);
  •                                 SensorDelay_us(11038);

  •                                 I2C_Start();
  •                                 ZSSC_I2C_WR_Byte(0x70);
  •                                 Receive_ACK();
  •                                 ZSSC_I2C_WR_Byte(0xe1);//写系统配置寄存器
  •                                 Receive_ACK();
  •                                 ZSSC_I2C_WR_Byte(0x08);
  •                                 Receive_ACK();
  •                                 ZSSC_I2C_WR_Byte(0x00);
  •                                 Receive_ACK();
  •                                 Stop_I2C();
  •                                 count++;
  •                                 if(count>=10)
  •                                         return 0;
  •                                 SysTick_Delay_Ms(500);
  •     }
  •    return 1;
  • }



  • void Get_Data(void)
  • {
  •     uint32_t CT_data[2];
  •                 volatile int  c1,t1;

  •          
  •                 if(0)
  •                 {


  •                 }
  •                 else
  •                 {
  •                        
  •                                 while(JH_Read_Cal_Enable()==0)//等到校准输出使能位为1,才读取。
  •                                 {
  •                                         JH_Init();//如果为0再使能一次
  •                                         SysTick_Delay_Ms(50);
  •                                 }
  •                                 JH_Read_CTdata(CT_data);  //读取温度和湿度 , 可间隔1.5S读一次
  •                                 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℃)
  •                                 TempData=t1*0.1;//因为设置了两位小数--
  •                                 WetData=c1*0.1;//--放大了两倍----
  •                 }

  • }



  • 复制代码
    这里就只上传传感器的代码,然后是MAIN函数的代码,非常的简单

  • #include "n32g401.h"
  • #include "bsp_delay.h"
  • #include "DRV_UART.h"
  • #include "DRV_TIM.h"
  • #include "DRV_AHT10.h"


  • int main(void)
  •                           {
  •         LED_Init();
  •         UART_Init();
  •         TIM_Init();
  •         JH_Init();   //初始化AHT10;
  •         while(1)
  •         {
  •                 Get_Data();
  •                 printf("TempData is %2f3 %\r\n",TempData);
  •                 printf("WetData  is %2f3 %\r\n",WetData);
  •                 SysTick_Delay_Ms(500);
  •                
  •         }
  • }


  • 复制代码
    好了,我们来看看实时的结果:
    串口结果.png
    测试结果还是比较准确的,我拍了视频,后面上传上来,主要是在办公室,不太好说话,所以大家感受一下结果就行了,感兴趣的话可以自己复制代码去测试。

    视频链接:
    https://www.bilibili.com/video/BV1AusjeuEL7/?buvid=XU268A1260BC1080F6C5DE9BB8885853A284E&is_story_h5=false&mid=ZPNijV8XOdBxHvi4hyDZnQ%3D%3D&plat_id=240&share_from=ugc&share_medium=android&share_plat=android&share_session_id=34ec3807-b268-440c-a310-66412bf9f865&share_source=WEIXIN&share_tag=s_i&spmid=dt.space-dt.0.0×tamp=1724649027&unique_k=HwCthPZ&up_id=474849000