AHT10温湿度传感器STM32驱动
大家所熟悉都用过的温湿度传感器应该是DHT11了吧,基本上学习单片机的都用过,但是DHT11的精度不是很高,湿度±5%RH,温度±1℃,而且测试的时候一般还要延时3S左右测一下,测试频率慢,而且体积大,价格大概3块多一个吧。在淘宝上搜索温湿度传感器,偶然发现AHT10传感器,价格2.5一个,体积小,精度湿度±2%RH,温度精度±0.3℃。这个是国产温湿度传感器,性价比是比较高的,所以在这里介绍一下AHT10温湿度传感器的使用。
关于AHT10温湿度传感器的数据手册在官方网站上面可以下载到:AHT10温湿度传感器的数据手册
例程程序下载链接:AHT10温湿度传感器STM32驱动程序
引脚说明:
电路设计:
AHT10通信协议为IIC协议驱动代码如下所示,采用的是STM32103C8T6单片机。
AHT10.H
#ifndef _AHT10_H__
#define _AHT10_H__
#include "sys.h"
#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);
#endif
AHT10.c文件
#include "aht10.h"
#include "myiic.h"
#include "delay.h"
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 输出高
IIC_Start();
IIC_Send_Byte(AHT10_ADDRESS);
IIC_Send_Byte(0xe1);
IIC_Send_Byte(0x08);
IIC_Send_Byte(0x00);
IIC_Stop();
delay_ms(40);//延时20ms让传感器稳定
}
u8 AHT10Check(void)
{
u8 ack=0;
IIC_Start();
IIC_Send_Byte(AHT10_ADDRESS);
ack=IIC_Wait_Ack();
IIC_Stop();
return ack;
}
void AHT10Reset(void)
{
IIC_Start();
IIC_Send_Byte(AHT10_WRITE);
IIC_Wait_Ack();
IIC_Send_Byte(0xba);
IIC_Wait_Ack();
IIC_Stop();
}
u8 AHT10ReadData(float *temperature,u8 *humidity)
{
u8 ack;
u32 SRH=0,ST=0;
u8 databuff[6];
IIC_Start();
IIC_Send_Byte(AHT10_WRITE);
IIC_Wait_Ack();
IIC_Send_Byte(0xac);
IIC_Wait_Ack();
IIC_Send_Byte(0x33);
IIC_Wait_Ack();
IIC_Send_Byte(0x00);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(80);//延时一会等待数据读出
IIC_Start();
IIC_Send_Byte(AHT10_READ);
IIC_Wait_Ack();
ack=IIC_Read_Byte(1);
if((ack&0x40)==0)
{
databuff[0]=IIC_Read_Byte(1);
databuff[1]=IIC_Read_Byte(1);
databuff[2]=IIC_Read_Byte(1);
databuff[3]=IIC_Read_Byte(1);
databuff[4]=IIC_Read_Byte(0);
IIC_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;
}
IIC_Stop();
return 1;
}
这里需要注意的是我用的 IIC引脚:SCL PB3,SDA PB4,所以使用的时候需要将JTAG功能关闭,一开始调试的时候因为没注意所以弄了一下午,才发现这个问题。
u8 AHT10ReadData(float *temperature,u8 *humidity);
读出温湿度数据只需通过这个函数就行了,需要输入定义的数据类型地址,温度为浮点型数据,精度范围到小数点后一位,湿度为无符号char型数据,因为本身传感器的精度就是±2%RH,如果精度再设置成浮点型数据也没啥意义了所以就弄了u8类型。
下图是获取到的温湿度数据,在我对传感器哈了一口气候效果如图所示,Temp表示温度,hum表示湿度。
关于整个例程的程序我上传到了我的博客上面,大家可以自行下载,采用的单片机是STM32F103C8T6单片机,就是淘宝上10块钱一个的那种,里面还带了一些别的驱动文件我懒得删掉了,大家不用就行了,下面是IIC的实现函数。
myiic.h
#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"
//IO方向设置
#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
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
#endif
myiic.c
#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_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 IIC_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 IIC_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 IIC_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)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void IIC_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 IIC_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 IIC_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)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}