STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块

今日学习一下这款AHT10 温湿度传感器模块,给我的OLED手环添加上测温湿度的功能。

文章提供源码、测试工程下载、测试效果图。

目录

AHT10温湿度传感器:

特性:

连接方式:

适用场所范围:

程序设计:

设计目标:

 程序设计注意点:

AHT10代码:

 主函数代码:

测试效果:

 完整工程下载:


AHT10温湿度传感器:

下图为AHT温湿度传感器模块,它长这样,这里的介绍不重要,了解就行,快速浏览即可

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第1张图片

AHT10,新一代温湿度传感器在尺寸与智能方面建立了新的标准:

它嵌入了适于回流焊的双列扁平无引脚SMD封装,底面4x5mm,高度1.6mm。

传感器偷出经过标定的数字信号,标准I2C格式。AHT10配有一个全新设计的ASIC专用芯片、一个经过改进的MEMS半导体电容式湿度传感元件和一个标准的片上温度传感元件,其性能己经大大提升甚至超出了前一代传感器的可靠性水平,一代温湿度传感器,经过改进使其在恶劣环境下的性能更稳定。 

特性:

1.模块尺寸:    16*11mm
2.接口类型:    I2C
3.工作电压:    1.8-6.0V
4.接口尺寸:    4*2.54mm间距
5.湿度精度:    典型 士 2%
6.湿度分辨率:0.024%
7.温度精度:    典型 土 0.3C
8.温度分辨率:典型0.01C
9.工作温度:    -40°C--85C 

连接方式:

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第2张图片

适用场所范围:

  • 暖通空调 、除湿器
  • 检测设备
  • 自动控制、数据记录器
  • 气象站、家电
  • 医疗及其他相关湿度检测控制。

程序设计:

设计目标:

1.使用IIC通信初始化和读取AHT10传感器的温湿度信息,并通过OLED打印

2.IIC通信引脚:PB3(SCL)   PB4(SDA)

3.使用定时器2,周期性读取AHT10的温湿度信息(300ms为周期)

 程序设计注意点:

1.上电启动传感器,启动后需要先等待40ms(设备才开始正常工作),然后发送0x71 来获取状态字节

2.获取到校准使能位后,查看其是否已校准,若已校准则跳过当前步骤;若未校准则发送0xe1,进行初始化,然后发送0x080x00

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第3张图片

3.接着开始触发测量,测量先发送0xac,然后发送0x330x00

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第4张图片

 4.测量命令发送完成后,需要等待80ms,用于温湿度的测量;之后再发送命令0x71,以读取状态寄存器是否处于空闲状态(bit7 => idle);若是空闲状态,可以直接读取之后六个字节的温湿度数值;

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第5张图片

 

5.相对湿度和温度转换公式:
STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第6张图片

 接受的处理是使用char类型的数组 去接受每个读取到的八位数据,然后根据运算公式计算:(1024*1024=2^20 )  ,( int )强制类型转换为int是为了不丢符号:
STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第7张图片

 最后还有俩个函数,一个是检查,一个是复位的:

STM32 F103C8T6学习笔记13:IIC通信—AHT10温湿度传感器模块_第8张图片

 

AHT10代码:

#include "AHT10.h"
/**
brief AHT10初始化函数
param NONE
return NONE
*/
void AHT10Init()
{
	//IIC_Init();
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOBA	
	GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);				 //PA4 输出高
	
	delay_ms(50);//延时50ms让传感器稳定
	I2C_Start();
	I2C_Send_Byte(AHT10_ADDRESS);  //获取状态
	//初始化校准
	I2C_Send_Byte(0xe1);	
	I2C_Send_Byte(0x08);
	I2C_Send_Byte(0x00);
	I2C_Stop();	
	delay_ms(50);//延时50ms让传感器稳定
}

/**
brief 检查AHT10是否存在
param NONE
return 0存在  1不存在
*/
u8 AHT10Check(void)
{
	u8 ack=0;
	I2C_Start();
	I2C_Send_Byte(AHT10_ADDRESS);
	ack=I2C_Wait_Ack();
	I2C_Stop();	
	return ack;
}

/**
brief AHT10软复位
param NONE
return NONE
*/
void AHT10Reset(void)
{
	I2C_Start();
	I2C_Send_Byte(AHT10_WRITE);
	I2C_Wait_Ack();
	I2C_Send_Byte(0xba);
	I2C_Wait_Ack();
	I2C_Stop();	
}

/**
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];
	I2C_Start();
	I2C_Send_Byte(AHT10_WRITE);
	I2C_Wait_Ack();
	I2C_Send_Byte(0xac);
	I2C_Wait_Ack();
	I2C_Send_Byte(0x33);
	I2C_Wait_Ack();
	I2C_Send_Byte(0x00);
	I2C_Wait_Ack();
	I2C_Stop();	  
	delay_ms(80);//延时一会等待数据读出
	I2C_Start();
	I2C_Send_Byte(AHT10_READ);
	I2C_Wait_Ack();
	ack=I22C_Read_Byte(1);
	if((ack&0x40)==0)
	{
		databuff[0]=I22C_Read_Byte(1);
		databuff[1]=I22C_Read_Byte(1);
		databuff[2]=I22C_Read_Byte(1);
		databuff[3]=I22C_Read_Byte(1);
		databuff[4]=I22C_Read_Byte(0);
		I2C_Stop();
		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;
	}
	I2C_Stop();	
	return 1;
}


//初始化IIC
void I22C_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB时钟
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4); 	//PB6,PB7 输出高
}
//产生IIC起始信号
void I2C_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void I2C_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 I2C_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			I2C_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void I2C_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//不产生ACK应答		    
void I2C_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void I2C_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        //IIC_SDA=(txd&0x80)>>7;
		if((txd&0x80)>>7)
			IIC_SDA=1;
		else
			IIC_SDA=0;
		txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    


//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 I22C_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        I2C_NAck();//发送nACK
    else
        I2C_Ack(); //发送ACK   
    return receive;
}
#ifndef _AHT10_h_
#define _AHT10_h_

#include "headfire.h"
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
//输出寄存器
#define GPIOA_ODR_Addr (GPIOA_BASE+12)//0x4001280C
#define GPIOB_ODR_Addr (GPIOB_BASE+12)//0x40010C0C
//输入寄存器
#define GPIOA_IDR_Addr (GPIOA_BASE+8)//0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8)//0x40010C08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)	BIT_ADDR(GPIOA_ODR_Addr,n)//输出
#define PAin(n) 	BIT_ADDR (GPIOA_IDR_Addr,n)//输入
 
#define PBout(n) 	BIT_ADDR(GPIOB_ODR_Addr,n)//输出
#define PBin(n) 	BIT_ADDR(GPIOB_IDR_Addr,n)//输入

#define SDA_IN()  {GPIOB->CRL&=0XFFF0FFFF;GPIOB->CRL|=(u32)8<<16;}
#define SDA_OUT() {GPIOB->CRL&=0XFFF0FFFF;GPIOB->CRL|=(u32)3<<16;}

//IO操作函数	 
#define IIC_SCL    PBout(3) //SCL
#define IIC_SDA    PBout(4) //SDA	 
#define READ_SDA   PBin(4)  //输入SDA 


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

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



//IIC所有操作函数
void I22C_Init(void);                //初始化IIC的IO口				 
void I2C_Start(void);				//发送IIC开始信号
void I2C_Stop(void);	  			//发送IIC停止信号
void I2C_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 I2C_Wait_Ack(void); 				//IIC等待ACK信号
void I2C_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void I2C_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 I2C_Read_One_Byte(u8 daddr,u8 addr);	  
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 I22C_Read_Byte(unsigned char ack);

#endif

 主函数代码:

#include "main.h"

float temp;
u8 hum;
int humm,temper;
uint16_t AHT10_cnt,AHT10_flag;
char buf[30];


int main(void)
{	
	init_ALL();     //初始化所有函数
  while(1)
	{	
		if(AHT10_flag==1)
		{
			AHT10_flag=0;
			AHT10ReadData(&temp,&hum);
			temper=temp*10;
			humm=hum;
			OLED_ShowCHinese(0,0,0);  //打印中文“温”
			OLED_ShowCHinese(16,0,2);  //打印中文“度”
		  sprintf(buf,": %d.%d",temper/10,temper%10);		
 		  OLED_ShowString(32,0,(u8 *)buf,16);	   
			
			OLED_ShowCHinese(0,2,1);  //打印中文“湿”
			OLED_ShowCHinese(16,2,2);  //打印中文“度”
		  sprintf(buf,": %d ",humm);		
 		  OLED_ShowString(32,2,(u8 *)buf,16);	      			
		}
	}
}


//初始化所有函数:
void init_ALL(void)
{
	SysTick_Init(72);         //初始化滴答计时器
	Timer2_Init();						//初始化定时器2
	i2c_GPIO_Config();	      //IIC初始化
	OLED_Init();              //初始化OLED屏幕
	OLED_Clear();             //清空屏幕数据
	AHT10Init();              //初始化温湿度传感器
	
}


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++AHT10_cnt==30)         //每300ms刷新一次温湿度数据
		{AHT10_cnt=0;AHT10_flag=1;}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

测试效果:

 完整工程下载:

https://download.csdn.net/download/qq_64257614/88248711?spm=1001.2014.3001.5503

你可能感兴趣的:(STM32,F103,C8T6笔记,硬件模块与传感器的驱动,stm32,学习,笔记,嵌入式硬件)