基于N32L系列的IIC驱动AHT10驱动代码(以国民技术N32为例)

前言

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的几个重要的寄存器。

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

建议是2s测量一次。

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

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

大概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读一下数据就行 

三、时序截图

初始化

四、串口查看 

五、可能出现的问题

IIC没有收到应答:如果接的是杜邦线,看看插紧了没。

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

时序波特率接近400kbps属于正常速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值