[N32L4xx] 基于N32L系列的IIC驱动AHT10驱动代码

[复制链接]
53|0
观海 发表于 2025-11-6 16:15 | 显示全部楼层 |阅读模式
前言

76785690c4be1315ac.png

N32L40X系列采用32 bit Arm® Cortex®-M4F内核,最高工作主频64MHz,支持浮点运算和DSP指令,集成高达 128KB嵌入式Flash,24KB SRAM,集成丰富的高性能模拟器件,内置1个12bit 4.5Msps ADC,2路独立轨到轨运 算放大器,2个高速比较器,1个1Msps 12bit DAC,集成U(S)ART、LPUART、I2C、SPI、USB、CAN等数字通信接口, Segment LCD驱动接口,内置多种密码算法硬件加速引擎。

由于AHT10是基于IIC协议,IIC协议我们就不做多余介绍。重要的就是IIC从机地址与AHT10的几个重要的寄存器。

12538690c4bdb1c532.png

83175690c4bd79a7db.png

引脚上不用过多关注,就看ADR怎么接,如果是接地。那从机地址就是0x38<<1,写地址0x38<<1,读地址(0x38<<1 )| 1

49124690c4bd3d8797.png

建议是2s测量一次。

8284690c4bcf84c45.png

73175690c4bcb672ef.png

最主要的三条命令(三个寄存器):初始化(0xE1),测量(0xAC),软复位(0xBA)

73179690c4bc588e49.png

状态位在我们进行测量后,读取数据的时候有用,那时可以决定是否转换完毕,是留下数据还是舍去数据再重新转换。

15129690c4bbc3a0dd.png

大概AHT10的内容就那么多。

一、基于N32库函数的IIC通用软件接口
代码参考:智能手表OV-Watch - 立创开源硬件平台

立创天地星卡发板驱动:AHT10温湿度传感器 | 立创开发板技术文档中心

与一个GitCode上的老哥的基于stm32F103C8t6代码包GitCode - 全球开发者的开源社区,开源代码托管平台

#include "iic_basen32lib.h"

/**
* @brief  Inserts a delay time.
* @param count specifies the delay time length.
*/
void delay_us(uint32_t count)
{
    count=(count*4);
    for (; count > 0; count--)
    {
        __nop();
        __nop();
        __nop();
        __nop();
        __nop();
        __nop();
        __nop();
        __nop();
        __nop();


    }
}
void delay_ms(uint32_t count)
{
    for (; count > 0; count--)
   {
        delay_us(1006);
   }
}

/**
  * @brief SDA线输入模式配置
  * @param bus IIC总线控制器
  * @retval None
  */
static void SDA_Input_Mode(s_iic_bus_t* bus)
{
    GPIO_InitType GPIO_InitStructure ;
    GPIO_InitStruct(&GPIO_InitStructure);
         

    GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Input;
    GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
    GPIO_InitPeripheral(bus->IIC_SDA_GPIO, &GPIO_InitStructure);
}
/**
  * @brief SDA线输出模式配置
  * @param bus IIC总线控制器
  * @retval None
  */
static void SDA_Output_Mode(s_iic_bus_t *bus)
{
       
    GPIO_InitType GPIO_InitStructure;
    GPIO_InitStruct(&GPIO_InitStructure);

    GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pull = GPIO_No_Pull;
    GPIO_InitPeripheral(bus->IIC_SDA_GPIO, &GPIO_InitStructure);
}

/**
  * @brief SDA线输出一个位
  * @param bus IIC总线控制器 val 输出的数据 1/0
  * @retval None
  */
static void SDA_Output(s_iic_bus_t *bus, uint8_t val)
{
                if(val)GPIO_SetBits(bus->IIC_SDA_GPIO,bus->IIC_SDA_PIN);
                else GPIO_ResetBits(bus->IIC_SDA_GPIO,bus->IIC_SDA_PIN);
}

/**
  * @brief SCL线输出一个位
  * @param bus IIC总线控制器 val 输出的数据 1/0
  * @retval None
  */
static void SCL_Output(s_iic_bus_t *bus, uint8_t val)
{
          if(val)GPIO_SetBits(bus->IIC_SCL_GPIO,bus->IIC_SCL_PIN);
                else GPIO_ResetBits(bus->IIC_SCL_GPIO,bus->IIC_SCL_PIN);
}

/**
  * @brief SDA输入一位
  * @param bus IIC总线控制器
        * @return 读到的一位数据
  * @retval GPIO读入一位
  */
uint8_t SDA_Input(s_iic_bus_t *bus)
{
        return GPIO_ReadInputDataBit(bus->IIC_SDA_GPIO,bus->IIC_SDA_PIN);
}
// _____
// SDA: |_____
// _______
// SCL:   |___
/**
  * @brief IIC起始信号
  * @param bus IIC总线控制器
  * @retval None
  */
void IICStart(s_iic_bus_t *bus)
{
        SDA_Output_Mode(bus);
       
        SDA_Output(bus,1);
        SCL_Output(bus,1);
        delay_us(4);
       
        SDA_Output(bus,0);
        delay_us(4);
        SCL_Output(bus,0);
       
}
//            _____
// SDA: _____|
//          _______
// SCL: ___|
/**
  * @brief IIC结束信号
  * @param bus IIC总线控制器
  * @retval None
  */
void IICStop(s_iic_bus_t *bus)
{
        SDA_Output_Mode(bus);
        SCL_Output(bus,0);
        SDA_Output(bus,0);
        delay_us(4);

        SCL_Output(bus,1);
        delay_us(4);
        SDA_Output(bus,1);
        delay_us(4);
}
// 应答___        非应答      __________      
// SDA:   |_______     SDA:
//         _____                  _____
// SCL:___|     |      SCL:   ___|     |
/**
  * @brief IIC主机等待从机应答
  * @param bus IIC总线控制器
  * @retval None
  */
uint8_t IICWaitAck(s_iic_bus_t *bus)
{
        uint8_t ucErrTime=0;
        SDA_Input_Mode(bus);
       
       
        SDA_Output(bus,1);
        delay_us(1);
        SCL_Output(bus,1);
        delay_us(1);
       
        while((SDA_Input(bus)==1))//应答超时
        {
                        ucErrTime++;
                if(ucErrTime >=250)
                {
                        IICStop(bus);
                        return 1;
                }
       
        }
                SCL_Output(bus,0);
       
                return 0;
}
/**
  * @brief IIC发送应答信号(主机)
  * @param bus IIC总线控制器
  * @retval None
  */
void IICSendAck(s_iic_bus_t *bus)
{

        SCL_Output(bus,0);
        SDA_Output_Mode(bus);
        SDA_Output(bus,0);
        delay_us(2);
       
        SCL_Output(bus,1);
        delay_us(2);
        SCL_Output(bus,0);
       
}
/**
  * @brief IIC发送非应答信号(主机)
  * @param bus IIC总线控制器
  * @retval None
  */
void IICSendNotAck(s_iic_bus_t *bus)
{

        SCL_Output(bus,0);
        SDA_Output_Mode(bus);
        SDA_Output(bus,1);
        delay_us(2);
        SCL_Output(bus,1);
        delay_us(2);
        SCL_Output(bus,0);
}
/**
  * @brief IIC发送一个字节
  * @param byte 需要发送的字节
  * @retval None
  */
void IICSendByte(s_iic_bus_t *bus,uint8_t cSendByte)
{
  uint8_t  i = 0;
        SDA_Output_Mode(bus);
        SCL_Output(bus,0);
       
        for(i=0;i<8;i++)
        {

                if((cSendByte&0x80)>>7)SDA_Output(bus,1);
                else SDA_Output(bus,0);
               
                cSendByte <<=1;
                delay_us(2);
                SCL_Output(bus,1);
                delay_us(2);
                SCL_Output(bus,0);
                delay_us(2);
       
        }
}
/**
  * @brief IIC接收一个字节
  * @param None 0 nack 1 ack
  * @retval 接收到的字节
  */
uint8_t IICReceiveByte(s_iic_bus_t *bus, uint8_t ack)
{
                uint8_t i = 0;
    uint8_t cReceiveByte = 0;
    SDA_Input_Mode(bus);
          for(i=0;i<8;i++)
                {
                        SCL_Output(bus,0);
                        delay_us(2);
                        SCL_Output(bus,1);
                        cReceiveByte <<=1;
                        if(SDA_Input(bus))
                        {
                                cReceiveByte++;
                        }
                        delay_us(1);
                }
                if(!ack ) IICSendNotAck(bus);
                else IICSendAck(bus);
                return cReceiveByte;
}


void IICInit(s_iic_bus_t *bus)
{

         GPIO_InitType GPIO_InitStructure ;   /*初始化GPIO结构体*/
         GPIO_InitStruct(&GPIO_InitStructure);
       
         GPIO_InitStructure.Pin            = bus->IIC_SCL_PIN ;
         GPIO_InitStructure.GPIO_Current   = GPIO_DC_4mA;
         GPIO_InitStructure.GPIO_Pull      = GPIO_No_Pull;
         GPIO_InitStructure.GPIO_Mode      =  GPIO_Mode_Out_PP;
         GPIO_InitStructure.GPIO_Slew_Rate = GPIO_Slew_Rate_High;//以高速50M速率为例 翻转电平仅需20ns
       
         GPIO_InitPeripheral(bus->IIC_SCL_GPIO, &GPIO_InitStructure);
         GPIO_InitStructure.Pin            = bus->IIC_SDA_PIN ;
         GPIO_InitPeripheral(bus->IIC_SDA_GPIO, &GPIO_InitStructure);
       
       
         GPIO_SetBits(bus->IIC_SDA_GPIO,bus->IIC_SDA_PIN);/*拉高总线*/
   GPIO_SetBits(bus->IIC_SCL_GPIO,bus->IIC_SCL_PIN);

}



头文件

#ifndef __IIC_SOFT_H
#define __IIC_SOFT_H

#include "n32l40x.h"


typedef struct
{
        GPIO_Module* IIC_SDA_GPIO;
        GPIO_Module* IIC_SCL_GPIO;
        uint16_t IIC_SDA_PIN;
        uint16_t IIC_SCL_PIN;

}s_iic_bus_t;/*IIC总线控制器*/
void delay_us(uint32_t count);
void delay_ms(uint32_t count);

void IICStart(s_iic_bus_t *bus);
void IICStop(s_iic_bus_t *bus);
uint8_t IICWaitAck(s_iic_bus_t *bus);
void IICSendAck(s_iic_bus_t *bus);
void IICSendNotAck(s_iic_bus_t *bus);
void IICSendByte(s_iic_bus_t *bus, uint8_t cSendByte);
uint8_t IICReceiveByte(s_iic_bus_t *bus, uint8_t ack);
void IICInit(s_iic_bus_t *bus);

#endif




延时函数要自己解决(推荐是移植正点原子关于滴答定时器的)

二、基于IIC接口实例化的AHT10驱动
AHT10驱动

#include "iic_basen32lib.h"
#include "AHT10.h"
#include <stdio.h>

s_iic_bus_t AHT_bus =
{
        .IIC_SDA_GPIO = AHT10_SDA_GPIO,
        .IIC_SCL_GPIO = AHT10_SCL_GPIO,
        .IIC_SDA_PIN  = AHT10_SDA_PIN,
        .IIC_SCL_PIN  = AHT10_SCL_PIN,
};
/**
  * @brief aht10的SCL与SDA时钟使能
  * @param None
  * @retval None
  */
static void aht10_clk_en(void)
{
                aht10_scl_clk_en();
                aht10_sda_clk_en();
}
/**
brief AHT10初始化函数
param NONE
return NONE
*/
void AHT10Init()
{
        u8 ack=0;
        aht10_clk_en();
        IICInit(&AHT_bus);
        delay_ms(100);

        IICStart(&AHT_bus);
        IICSendByte(&AHT_bus, AHT10_ADDRESS);
        ack=IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus,0xe1);
        ack=IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus,0x08);
        ack=IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus,0x00);
        IICStop(&AHT_bus);
        delay_ms(40);//延时40ms让传感器稳定
}

/**
brief 检查AHT10是否存在
param NONE
return 0存在  1不存在
*/
u8 AHT10Check(void)
{
        u8 ack=0;
        IICStart(&AHT_bus);
        IICSendByte(&AHT_bus, AHT10_ADDRESS );
        ack=IICWaitAck(&AHT_bus);
        IICStop(&AHT_bus);
        return ack;
}

/**
brief AHT10软复位
param NONE
return NONE
*/
void AHT10Reset(void)
{
        IICStart(&AHT_bus);
        IICSendByte(&AHT_bus, AHT10_WRITE);
        IICWaitAck(&AHT_bus);
        IICSendByte(&AHT_bus, 0xba);
        IICWaitAck(&AHT_bus);
        IICStop(&AHT_bus);
}

/**
brief 检查AHT10读温湿度数据
param *temperature:需要读出的温度数据,float指针类型,精度范围+-0.3C
param *humidity:需要读出的湿度数据,u8指针类型,精度范围+-2RH
return 0 读数据正常 1读数据失败
*/
u8 AHT10ReadData(float *temperature,u8 *humidity)
{
        u8 ack;
        u32 SRH=0,ST=0;
        u8 databuff[6];
        IICStart(&AHT_bus);
        IICSendByte(&AHT_bus,AHT10_WRITE);
        ack = IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus, 0xac);
        ack = IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus,0x33);
        ack = IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICSendByte(&AHT_bus,0x00);
        ack = IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        IICStop(&AHT_bus);
        delay_ms(80);//延时一会等待数据读出
        IICStart(&AHT_bus);
        IICSendByte(&AHT_bus,AHT10_READ);
        ack = IICWaitAck(&AHT_bus);//printf("ack is %d\r\n",ack);
        ack=IICReceiveByte(&AHT_bus,1);//printf("ack is %d\r\n",ack);
        if((ack&0x40)==0)
        {
                databuff[0]=IICReceiveByte(&AHT_bus,1);
                databuff[1]=IICReceiveByte(&AHT_bus,1);
                databuff[2]=IICReceiveByte(&AHT_bus,1);
                databuff[3]=IICReceiveByte(&AHT_bus,1);
                databuff[4]=IICReceiveByte(&AHT_bus,0);
                //printf("buff is %d %d %d %d %d\r\n",databuff[0],databuff[1],databuff[2],databuff[3],databuff[4]);
                IICStop(&AHT_bus);
                SRH=(databuff[0]<<12)+(databuff[1]<<4)+(databuff[2]>>4);
                ST=((databuff[2]&0X0f)<<16)+(databuff[3]<<8)+(databuff[4]);
                *humidity=(int)(SRH*100.0/1024/1024+0.5);
                *temperature=((int)(ST*2000.0/1024/1024+0.5))/10.0-50;
                return 0;
        }
        IICStop(&AHT_bus);
        return 1;
}







头文件

#ifndef _AHT10_H__
#define _AHT10_H__

#include "n32l40x.h"
#define aht10_scl_clk_en()        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE)
#define aht10_sda_clk_en()        RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE)
#define AHT10_SCL_PIN             GPIO_PIN_12
#define AHT10_SDA_PIN             GPIO_PIN_11
#define AHT10_SCL_GPIO            GPIOA
#define AHT10_SDA_GPIO            GPIOA

#define AHT10_ADDRESS 0x70
#define AHT10_WRITE 0x70
#define AHT10_READ 0x71

/*****************函数声明******************/
extern void AHT10Init(void);
extern uint8_t AHT10Check(void);
extern void AHT10Reset(void);
extern uint8_t AHT10ReadData(float *temperature,uint8_t *humidity);

#endif






在main函数里初始化,隔1s读一下数据就行

三、时序截图
初始化

57395690c4ba0abcf0.png



93213690c4b9be821e.png

四、串口查看

47716690c4b95de130.png

五、可能出现的问题
IIC没有收到应答:如果接的是杜邦线,看看插紧了没。

自己焊的元器件虚汗了没,推荐买个小模块玩,才几块钱。

时序波特率接近400kbps属于正常速度。
————————————————
版权声明:本文为CSDN博主「NEWEVA__zzera22」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/NEWEVA__zzera22/article/details/144972687

您需要登录后才可以回帖 登录 | 注册

本版积分规则

158

主题

4410

帖子

1

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