基於HAL庫軟件模擬IIC讀取AHT10溫濕度數據的實現步驟


 

       本人自己想做一個項目,做到AHT10獲取溫濕度時,由於開發經驗不足,在網上不斷查找資料,但都沒有完整詳細的步驟講解,在此卡了好幾天。經歷幾天的摸索,最終一步步實現軟件模擬IIC通訊,讀取AHT10溫濕度數據。在此做個記錄分享,給跟我一樣的初學者們一點借鑒。

       首先想要跟I2C設備通訊實現方式上有兩種,一種是軟件模擬I2C協議,就是本文所講的內容,另一種就是硬件I2C,通過STM32CubeMX配置I2C,再進行一些應用編程。我還沒有嘗試過。

      基於HAL庫軟件實現I2C的話,要注意的一點是微秒延時。HAL庫只有毫秒延時,沒有微秒延時。具體一些內容可以百度看看。

    手冊的內容我就不做分享了,百度下載手冊,代碼結合手冊內容和I2C協議內容理解。

    我的MCU是STM32L151C8T6。

    先貼微秒延時代碼。這段代碼沒有實測過到底准不准確,建議只在I2C通訊中使用,是沒什么問題的。

void Delay_us(uint16_t usec)
{
    uint16_t i=4;
    
    usec >>= 1;
    
    while (usec--)
    {
        while(i--)
        {
            ;
        }
    }    
}

  第一步就是要對我們的I2C接口進行初始化了。我選用的是PB6/PB7引腳。

 1 static void AHT10_IIC_Init(void)
 2 {                         
 3     GPIO_InitTypeDef GPIO_InitStruct;
 4     __HAL_RCC_GPIOB_CLK_ENABLE();
 5 
 6     GPIO_InitStruct.Pin = AHT10_SDA_GPIO_PIN;
 7         GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 8         GPIO_InitStruct.Pull = GPIO_NOPULL;
 9         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
10         HAL_GPIO_Init(AHT10_SDA_GPIO_PORT, &GPIO_InitStruct);
11     
12     GPIO_InitStruct.Pin = AHT10_SCL_GPIO_PIN;
13         GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
14         GPIO_InitStruct.Pull = GPIO_NOPULL;
15         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
16         HAL_GPIO_Init(AHT10_SCL_GPIO_PORT, &GPIO_InitStruct);
17     
18     AHT10_SDA_H;
19     AHT10_SCL_H;
20 }

然后我們定義一個SDA初始化的函數,設置入口參數,方便配置各種參數配置。

void AHT10_SDA_INIT(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin, uint32_t Mode, uint32_t Pull)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = Mode;
    GPIO_InitStruct.Pull = Pull;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

 設置幾個讀寫函數

 1 void AHT10_SDA_State(GPIO_PinState PinState)
 2 {
 3     HAL_GPIO_WritePin(AHT10_SDA_GPIO_PORT,AHT10_SDA_GPIO_PIN,PinState);
 4 }
 5 
 6 void AHT10_SCL_State(GPIO_PinState PinState)
 7 {
 8     HAL_GPIO_WritePin(AHT10_SCL_GPIO_PORT,AHT10_SCL_GPIO_PIN,PinState);
 9 }
10 
11 uint8_t read_sda_data(void)
12 {
13     return HAL_GPIO_ReadPin(AHT10_SDA_GPIO_PORT,AHT10_SDA_GPIO_PIN);
14 }

I2C啟動函數。I2C啟動,SCL為高時,SDA從高變低。(結合通訊協議來理解。)

 1 void AHT10_IIC_Start(void)
 2 {
 3     AHT10_SDA_INIT_OUT;
 4     AHT10_SDA_H;
 5     AHT10_SCL_H;
 6     AHT10_Delay_us(4);
 7   AHT10_SDA_L;
 8   AHT10_Delay_us(4);
 9   AHT10_SCL_L;
10 }

I2C停止函數,SCL為高時,SDA從低變高

 1 void AHT10_IIC_Stop(void)
 2 {
 3     AHT10_SDA_INIT_OUT;
 4     AHT10_SDA_L;
 5     AHT10_SCL_L;
 6     AHT10_Delay_us(4);
 7     AHT10_SCL_H;
 8     AHT10_SDA_H;
 9     AHT10_Delay_us(4);
10 }

啟動和停止寫完了。我們來寫等待從機設備響應ACK部分。

SCL為高時,SDA為高則未響應,反之。

 1 static uint8_t AHT10_IIC_Wait_Ack(void)
 2 {
 3     uint8_t ucErrTime=0;
 4     AHT10_SDA_INIT_IN;
 5     AHT10_SDA_H;
 6     AHT10_Delay_us(1);
 7     AHT10_SCL_H;
 8     AHT10_Delay_us(1);
 9     while(read_sda_data())
10    {
11         ucErrTime++;
12       if(ucErrTime>250)
13         {
14             AHT10_IIC_Stop();
15             return 1;
16         }
17     }
18     AHT10_SCL_L;
19     return 0; 
20 }

主機向從機發送應答ACK部分和非應答NACK部分

 1 static void AHT10_IIC_Ack(void)
 2 {    
 3     AHT10_SCL_L;
 4     AHT10_SDA_INIT_OUT;
 5     AHT10_SDA_L;
 6     AHT10_Delay_us(2);
 7     AHT10_SCL_H;
 8     AHT10_Delay_us(2);
 9     AHT10_SCL_L;
10 }

 1 static void AHT10_IIC_NAck(void)  2 {  3  AHT10_SCL_L;  4  AHT10_SDA_INIT_OUT;  5  AHT10_SDA_H;  6 AHT10_Delay_us(2);  7  AHT10_SCL_H;  8 AHT10_Delay_us(2);  9  AHT10_SCL_L; 10 }

主機向從機發送一個字節。

 1 static void AHT10_IIC_Send_Byte(uint8_t txd)
 2 {
 3     //uint8_t t;
 4     AHT10_SDA_INIT_OUT;
 5     AHT10_SCL_L;
 6     for(uint8_t t=0;t<8;t++)
 7   {
 8         if((txd&0x80)>>7)//高位先傳,&1000 0000后將第八位右移至第一位
 9             AHT10_SDA_H;
10         else
11             AHT10_SDA_L;
12         txd<<=1;//每傳完一位后,低位向高位進1
13       AHT10_Delay_us(2);
14       AHT10_SCL_H;
15         AHT10_Delay_us(2); 
16         AHT10_SCL_L;
17         AHT10_Delay_us(2);
18     }
19 }

主機讀取一個字節。

 1 static uint8_t AHT10_IIC_Read_Byte(unsigned char ack)
 2 {
 3     unsigned char i,receive=0;
 4     AHT10_SDA_INIT_IN;
 5     for(i=0;i<8;i++)
 6   {
 7       AHT10_SCL_L;
 8       AHT10_Delay_us(2);
 9         AHT10_SCL_H;
10         receive<<=1;
11         if(read_sda_data())
12             receive++;
13         AHT10_Delay_us(1);
14     }
15     if (!ack)
16     AHT10_IIC_NAck();//發送nack
17   else
18     AHT10_IIC_Ack(); //發送ack 
19   return receive;
20 }

以上就是實現I2C通訊的幾個基本流程,將其模塊化,方便調用。

檢查AHT10模塊是否響應。

1 uint8_t AHT10Check(void)
2 {
3   uint8_t ack=0;
4   AHT10_IIC_Start();
5     AHT10_IIC_Send_Byte(AHT10_ADDRESS);
6     ack = AHT10_IIC_Wait_Ack();
7     AHT10_IIC_Stop();
8     return ack;//返回1則未檢測到
9 }

AHT10的軟件復位

1 void AHT10Reset(void)
2 {
3     AHT10_IIC_Start();
4     AHT10_IIC_Send_Byte(AHT10_WRITE);
5     AHT10_IIC_Wait_Ack();
6     AHT10_IIC_Send_Byte(0xba);
7     AHT10_IIC_Wait_Ack();
8     AHT10_IIC_Stop();    
9 }

接下來是AHT10的初始化。

 1 void AHT10Init()
 2 {
 3     AHT10_IIC_Init();
 4     
 5     AHT10_IIC_Start();
 6     AHT10_IIC_Send_Byte(AHT10_ADDRESS);
 7     AHT10_IIC_Send_Byte(0xe1);    //AHT10啟動的初始化指令
 8     AHT10_IIC_Send_Byte(0x08);
 9     AHT10_IIC_Send_Byte(0x00);
10     AHT10_IIC_Stop();    
11     AHT10_Delay_ms(40);//延時40MS讓傳感器穩定
12 }

AHT10讀取溫濕度數據

 1 uint8_t AHT10ReadData(uint16_t *temperature,uint16_t *humidity)
 2 {
 3     uint8_t ack;
 4     uint32_t SRH=0,ST=0;
 5     uint8_t databuff[6];
 6     AHT10_IIC_Start();
 7     AHT10_IIC_Send_Byte(AHT10_WRITE);
 8     AHT10_IIC_Wait_Ack();
 9     AHT10_IIC_Send_Byte(0xac);
10     AHT10_IIC_Wait_Ack();
11     AHT10_IIC_Send_Byte(0x33);
12     AHT10_IIC_Wait_Ack();
13     AHT10_IIC_Send_Byte(0x00);
14     AHT10_IIC_Wait_Ack();
15     AHT10_IIC_Stop();      
16     AHT10_Delay_ms(80);//延時等待數據讀取。
17     AHT10_IIC_Start();
18     AHT10_IIC_Send_Byte(AHT10_READ);
19     AHT10_IIC_Wait_Ack();
20     ack=AHT10_IIC_Read_Byte(1);
21     if((ack&0x40)==0)
22     {
23         databuff[0]=AHT10_IIC_Read_Byte(1);
24         databuff[1]=AHT10_IIC_Read_Byte(1);
25         databuff[2]=AHT10_IIC_Read_Byte(1);
26         databuff[3]=AHT10_IIC_Read_Byte(1);
27         databuff[4]=AHT10_IIC_Read_Byte(0);
28         AHT10_IIC_Stop();
29         SRH=(databuff[0]<<12)+(databuff[1]<<4)+(databuff[2]>>4);
30         ST=((databuff[2]&0X0f)<<16)+(databuff[3]<<8)+(databuff[4]);
31 
32         *humidity = SRH*1000/1024/1024;  
33             *temperature = ST *200*10/1024/1024-500;
34          return 1;
35     }
36     AHT10_IIC_Stop();    
37     return 0;
38 }

以上就是全部流程,將其放在一個新的.c文件中就行了。代碼網上可以找到類似的,我就是在基礎上進行了結合而已。

最后我們定義一個讀取函數,在main里直接調用就行,不過要先定義緩存變量,把地址傳進來存儲溫濕度數據。

1 void aht10_read(uint16_t *AHT10_tem,uint16_t *AHT10_hum)
2 {    
3   AHT10Init();
4   AHT10ReadData(AHT10_tem,AHT10_hum);  
5 }

 

.h文件的代碼我也貼在下面。全部流程的代碼都在這里面了,直接復制就可以用,注意GPIO口是否一致。

 1 #ifndef _AHT10_H_
 2 #define _AHT10_H_
 3 
 4 #include "stm32l1xx_hal.h"
 5 
 6 #define AHT10_ADDRESS 0x70
 7 #define AHT10_WRITE 0x70
 8 #define AHT10_READ 0x71
 9 
10 
11 #define AHT10_Delay_us(time)                                Delay_us(time)
12 #define AHT10_Delay_ms(time)                                HAL_Delay(time)
13 #define AHT10_SDA_GPIO_PIN GPIO_PIN_7
14 #define AHT10_SCL_GPIO_PIN GPIO_PIN_6
15 #define AHT10_SDA_GPIO_PORT GPIOB
16 #define AHT10_SCL_GPIO_PORT GPIOB
17 
18 #define AHT10_SDA_INIT_OUT AHT10_SDA_INIT(AHT10_SDA_GPIO_PORT,AHT10_SDA_GPIO_PIN,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL)
19 #define AHT10_SDA_INIT_IN  AHT10_SDA_INIT(AHT10_SDA_GPIO_PORT,AHT10_SDA_GPIO_PIN,GPIO_MODE_INPUT,GPIO_PULLUP)
20 #define AHT10_SDA_H        AHT10_SDA_State(GPIO_PIN_SET)
21 #define AHT10_SDA_L        AHT10_SDA_State(GPIO_PIN_RESET)
22 
23 #define AHT10_SCL_H        AHT10_SCL_State(GPIO_PIN_SET)
24 #define AHT10_SCL_L        AHT10_SCL_State(GPIO_PIN_RESET)
25 
26 
27 void AHT10_SDA_INIT(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin, uint32_t Mode, uint32_t Pull);
28 void AHT10_SDA_State(GPIO_PinState PinState);
29 void AHT10_SCL_State(GPIO_PinState PinState);
30 
31 
32 void AHT10Init(void);
33 uint8_t AHT10Check(void);
34 void AHT10Reset(void);
35 uint8_t AHT10ReadData(uint16_t *temperature,uint16_t *humidity);
36 void Delay_us(uint16_t usec);
37 void aht10_read(uint16_t *AHT10_tem,uint16_t *AHT10_hum);
38 #endif 

 

結束啦~,沒有對代碼進行解釋,是因為結合手冊看就行了~,還是比較清楚的。

 

 1 static void AHT10_IIC_Init(void)
 2 {                         
 3     GPIO_InitTypeDef GPIO_InitStruct;
 4     __HAL_RCC_GPIOB_CLK_ENABLE();//ʹÄÜGPIOʱÖÓ
 5 
 6     GPIO_InitStruct.Pin = AHT10_SDA_GPIO_PIN;
 7   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 8   GPIO_InitStruct.Pull = GPIO_NOPULL;
 9   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
10   HAL_GPIO_Init(AHT10_SDA_GPIO_PORT, &GPIO_InitStruct);
11     
12     GPIO_InitStruct.Pin = AHT10_SCL_GPIO_PIN;
13   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
14   GPIO_InitStruct.Pull = GPIO_NOPULL;
15   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
16   HAL_GPIO_Init(AHT10_SCL_GPIO_PORT, &GPIO_InitStruct);
17     
18     AHT10_SDA_H;
19     



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM