AHT10传感器使用记录-esp8266

AHT10传感器使用记录-esp8266

把踩了的坑记录下来,以后忘了还能回头看看权当成功后的记录吧


part1 AHT10是什么

AHT10是一款温湿度传感器,使用IIC通信协议,参考手册可以在 奥松官网中找到


part2 为什么选择AHT10

因为假期在家也回不去学校,为了能够做一些能做的工作我买了esp8266的开发板,单有板子没有执行器和传感器也不成啊,那就整一个传感器玩呗,顺便熟悉一下协议也为后期工作做点 预热
家在北方,选择传感器也是有做智能家居的考量,量程要在 -40°C~40°C 以内,这款传感器刚好能用


part3 阅读手册的那点事

传感器手册下载好,先看工作电压

在这里插入图片描述

电压为3.3V,开发板刚好也是3.3V电压输出

  • 接线
aht10esp8266
vin3V3
GNDGND
SCLSCL(D1)
SDASDA(D2)
  • 开发板上的丝印有错误,需要注意接线顺序。可以通过获取开发板原理图来查看,可以向店家索要。

连接线参考

原理图

这里可以看到硬件的介绍。

  • 环境搭建

  1. 使用arduino的ide进行程序烧录,代码编写使用vscode。参考
  2. vscode安装插件arduino(Microsoft) C/C++ ESP8266FS
  3. 修改配置文件,arduino设置 settings.json文件中arduino的安装位置。
"arduino.path": "C:\\Arduino"

在view-command palette…中选择编辑 C++ edit configurations(JSON).编辑c_cpp_properties.json 的includePdath属性修改 <用户名> 改成你的计算机名字

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "C:\\Users\\<用户名>\\AppData\\Local\\Arduino15\\packages\\esp8266\\tools\\**",
                "C:\\Users\\<用户名>\\AppData\\Local\\Arduino15\\packages\\esp8266\\hardware\\esp8266\\2.6.3\\**",
                "C:\\Arduino\\tools\\**",
                "C:\\Arduino\\hardware\\arduino\\avr\\**",
                "{$workspaceFolder}/libraries",
                "C:/Arduino/hardware/tools/avr/lib/gcc/avr/5.4.0/include",
                "C:/Arduino/hardware/arduino/avr/cores/arduino",
                "C:/Arduino/hardware/arduino/avr/variants/standard",
                "C:/Arduino"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "compilerPath": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "${default}",
            "forcedInclude": []
        }
    ],
    "version": 4
}

之后就可以在vscode中写代码,使用 arduino ide 编译和上传。也可以使用快捷键 Ctrl+ Alt+R进行编译
使用Ctrl+ Alt+U进行上传。

代码部分

#include <Wire.h>
uint8_t adress = 0x38; //设备地址 默认7位2进制数
float T; 

float RH; 

int data[6]; 

void setup()
{

    Wire.begin();
    Serial.begin(9600);

}

void loop()
{

    AHT10_measure();
    delay(2000);

}

void AHT10_measure()
{

    Wire.beginTransmission(0x38);

    Wire.requestFrom(0x38, 6);

    while (Wire.available())
    {
        for (int i = 0; i < 6; i++)
        {
            data[i] = Wire.read();
            // Serial.println(data[i]);
        }

        if (data[0] & 0x08 == 0)
        {
            // Serial.println("进行初始化");
            // Serial.println(Wire.read());
            Wire.write(0xE1);
            Wire.write(0x08);
            Wire.write(0x00);
        }
        else
        {
            Serial.println("不需要初始化");
            // Serial.println(Wire.read());
            Wire.write(0xAC);
            Wire.write(0x33);
            Wire.write(0x00);
            delayMicroseconds(75);


            if (data[0] & 0x80 == 0)
            {
                Serial.println("需要等待完成");
                // Serial.println(Wire.read());
            }
            else
            {
                Serial.println("不需要等待");
                // Serial.println(Wire.read());
            }
        }
    }
    Wire.endTransmission();
    RH = ((data[1] << 12) | (data[2] << 4)) | (data[3] >> 4);
    T = ((data[3] & 0x0f) << 16) | (data[4] << 8) | data[5];
    RH = (RH / pow(2, 20)) * 100;
    T = (T / pow(2, 20)) * 200 - 50;
    Serial.print("湿度为");
    Serial.println(RH);
    Serial.print("温度为");
    Serial.println(T);

}

值得注意的地方是:每次传输开始既要要求6字节的数据,根据手册所述,取得的第一字节内容为状态字,对状态字进行判断决定后边的5个字节的数据是否是有效的。

    Wire.beginTransmission(0x38);

    Wire.requestFrom(0x38, 6);
    while (Wire.available())
       {     for (int i = 0; i < 6; i++)
        {
            data[i] = Wire.read();
            // Serial.println(data[i]);
        }
       }

后续就是发送测量命令后再次获取6字节计算后边5字节的数据湿度数据由第2、3个字节和第4字节前四位,温度数据由第4字节后四位、第5、6字节组成。温湿度都是20位数据根据手册进行计算:

    RH = ((data[1] << 12) | (data[2] << 4)) | (data[3] >> 4);
    T = ((data[3] & 0x0f) << 16) | (data[4] << 8) | data[5];
    RH = (RH / pow(2, 20)) * 100;
    T = (T / pow(2, 20)) * 200 - 50;

这里RH为湿度,T为温度。官网给出的示例程序中计算算式有问题。

/*******************************************/
/*@版权所有:广州奥松电子有限公司          */
/*@作者:温湿度传感器事业部                */
/*@版本:V1.2                              */
/*******************************************/
/*******************************************/
/*@版本说明:                              */
/*@版本号:V1.2 修改AC命令的参数。         */
/*@版本号:V1.1 增加校准输出使能检测。     */
/*@版本号:V1.0 最初版本。                 */
/*******************************************/



void Delay_N10us(uint32_t t)//延时函数
{
  uint32_t k;

   while(t--)
  {
    for (k = 0; k < 2; k++)//110
      ;
  }
}



void SensorDelay_us(uint32_t t)//延时函数
{
	t = t-2;	
	for(; t>0; t--)
	{
		Delay_N10us(1);
	}

}

void Delay_3us(void)		//延时函数
{	
	Delay_N10us(1);
	Delay_N10us(1);
	Delay_N10us(1);
	Delay_N10us(1);
}
void Delay_1us(void)		//延时函数
{	
	Delay_N10us(1);
	Delay_N10us(1);
	Delay_N10us(1);
	Delay_N10us(1);
	Delay_N10us(1);

}


void SDA_Pin_Output_High(void)   //将P15配置为输出 , 并设置为高电平, P15作为I2C的SDA
{

 Gpio_InitIOExt(1,5,GpioDirOut,TRUE, FALSE, TRUE, FALSE);//config P15 to output
 Gpio_SetIO(1,5,1); 
}

void SDA_Pin_Output_Low(void)  //将P15配置为输出  并设置为低电平
{
 Gpio_InitIOExt(1,5,GpioDirOut,TRUE, FALSE, TRUE, FALSE);//config P15 to output
 Gpio_SetIO(1,5,0);  
}

void SDA_Pin_IN_FLOATING(void)  //SDA配置为悬浮输入
{
 Gpio_InitIO(1, 5, GpioDirIn);
}



void SCL_Pin_Output_High(void) //SCL输出高电平,P14作为I2C的SCL
{
 Gpio_SetIO(1, 4, 1);
}

void SCL_Pin_Output_Low(void) //SCL输出低电平
{
 Gpio_SetIO(1, 4, 0);
}

void Init_I2C_Sensor_Port(void) //初始化I2C接口
{	

 Gpio_InitIOExt(1,5,GpioDirOut,TRUE, FALSE, TRUE, FALSE);//将P15配置为开漏输出  并设置为高电平
 Gpio_SetIO(1,5,1);
	

 Gpio_InitIOExt(1,4,GpioDirOut,TRUE, FALSE, TRUE, FALSE);//将P14配置为开漏输出  并设置为高电平
 Gpio_SetIO(1,4,1);
	
}


void I2C_Start(void)		 //I2C主机发送START信号
{
 SDA_Pin_Output_High();
 SensorDelay_us(8);
 SCL_Pin_Output_High();
 SensorDelay_us(8);
 SDA_Pin_Output_Low();
 SensorDelay_us(8);
 SCL_Pin_Output_Low();
 SensorDelay_us(8);   
}


void ZSSC_I2C_WR_Byte(uint8_t Byte) //往AHT10写一个字节
{
	uint8_t Data,N,i;	
	Data=Byte;
	i = 0x80;
	for(N=0;N<8;N++)
	{
		SCL_Pin_Output_Low();
	  
		Delay_3us();	
		
		if(i&Data)
		{
			SDA_Pin_Output_High();
		}
		else
		{
			SDA_Pin_Output_Low();
		}	
			
        SCL_Pin_Output_High();
		Delay_3us();
		
		Data <<= 1;
		 
	}
	SCL_Pin_Output_Low();
	SensorDelay_us(8);   
	SDA_Pin_IN_FLOATING();
	SensorDelay_us(8);	
}	


uint8_t ZSSC_I2C_RD_Byte(void)//从AHT10读取一个字节
{
	uint8_t Byte,i,a;
	Byte = 0;
	SCL_Pin_Output_Low();
	SDA_Pin_IN_FLOATING();
	SensorDelay_us(8);	
	for(i=0;i<8;i++)
	{
    SCL_Pin_Output_High();		
		Delay_1us();
		a=0;
		if(Gpio_GetIO(1,5))a=1;
		Byte = (Byte<<1)|a;
		SCL_Pin_Output_Low();
		Delay_1us();
	}
    SDA_Pin_IN_FLOATING();
	SensorDelay_us(8);	
	return Byte;
}


uint8_t Receive_ACK(void)   //看AHT10是否有回复ACK
{
	uint16_t CNT;
	CNT = 0;
	SCL_Pin_Output_Low();	
	SDA_Pin_IN_FLOATING();
	SensorDelay_us(8);	
	SCL_Pin_Output_High();	
	SensorDelay_us(8);	
	while((Gpio_GetIO(1,5))  && CNT < 100) 
	CNT++;
	if(CNT == 100)
	{
		return 0;
	}
 	SCL_Pin_Output_Low();	
	SensorDelay_us(8);	
	return 1;
}

void Send_ACK(void)		  //主机回复ACK信号
{
	SCL_Pin_Output_Low();	
	SensorDelay_us(8);	
	SDA_Pin_Output_Low();
	SensorDelay_us(8);	
	SCL_Pin_Output_High();	
	SensorDelay_us(8);
	SCL_Pin_Output_Low();	
	SensorDelay_us(8);
	SDA_Pin_IN_FLOATING();
	SensorDelay_us(8);
}

void Send_NOT_ACK(void)	//主机不回复ACK
{
	SCL_Pin_Output_Low();	
	SensorDelay_us(8);
	SDA_Pin_Output_High();
	SensorDelay_us(8);
	SCL_Pin_Output_High();	
	SensorDelay_us(8);		
	SCL_Pin_Output_Low();	
	SensorDelay_us(8);
    SDA_Pin_Output_Low();
	SensorDelay_us(8);
}

void Stop_I2C(void)	  //一条协议结束
{
	SDA_Pin_Output_Low();
	SensorDelay_us(8);
	SCL_Pin_Output_High();	
	SensorDelay_us(8);
	SDA_Pin_Output_High();
	SensorDelay_us(8);
}

uint8_t JH_Read_Status(void)//读取AHT10的状态寄存器
{

	uint8_t Byte_first;	
	I2C_Start();
	ZSSC_I2C_WR_Byte(0x71);
	Receive_ACK();
	Byte_first = ZSSC_I2C_RD_Byte();
		

	Send_NOT_ACK();
	Stop_I2C();


	return Byte_first;
}

uint8_t JH_Read_Cal_Enable(void)  //查询cal enable位有没有使能?
{
	uint8_t val = 0;//ret = 0,
 
  val = JH_Read_Status();
  if((val & 0x68)==0x08)  //判断NOR模式和校准输出是否有效
  return 1;
  else  return 0;
 }



void JH_SendAC(void) //向AHT10发送AC命令
{

 I2C_Start();
 ZSSC_I2C_WR_Byte(0x70);
 Receive_ACK();
 ZSSC_I2C_WR_Byte(0xac);
 Receive_ACK();
 ZSSC_I2C_WR_Byte(0x33);
 Receive_ACK();
 ZSSC_I2C_WR_Byte(0x00);
 Receive_ACK();
 Stop_I2C();

}

void JH_Send_BA(void)//向AHT10发送BA命令
{


 I2C_Start();
 ZSSC_I2C_WR_Byte(0x70);
 Receive_ACK();
 ZSSC_I2C_WR_Byte(0xba);
 Receive_ACK();
 Stop_I2C();


}

void JH_Read_CTdata(uint32_t *ct) //读取AHT10的温度和湿度数据
{
	volatile uint8_t  Byte_1th=0;
	volatile uint8_t  Byte_2th=0;
	volatile uint8_t  Byte_3th=0;
	volatile uint8_t  Byte_4th=0;
	volatile uint8_t  Byte_5th=0;
	volatile uint8_t  Byte_6th=0;
	 uint32_t RetuData = 0;
	
	uint16_t cnt = 0;


	JH_SendAC();//向AHT10发送AC命令

	delay_ms(75);//等待75ms
    cnt = 0;
	while(((JH_Read_Status()&0x80)==0x80))//等待忙状态结束
	{
	 SensorDelay_us(1508);
	 if(cnt++>=100)
	 {
	  break;
	  }
	}
	I2C_Start();

	ZSSC_I2C_WR_Byte(0x71);//0x70+1   0x70为设备地址 1为方向位
	Receive_ACK();
	Byte_1th = ZSSC_I2C_RD_Byte();//状态字
	Send_ACK();
	Byte_2th = ZSSC_I2C_RD_Byte();//湿度字节
	Send_ACK();
	Byte_3th = ZSSC_I2C_RD_Byte();//湿度字节
	Send_ACK();
	Byte_4th = ZSSC_I2C_RD_Byte();//高4位为湿度  低4位为温度
	Send_ACK();
	Byte_5th = ZSSC_I2C_RD_Byte();//温度字节
	Send_ACK();
	Byte_6th = ZSSC_I2C_RD_Byte();//温度字节
	Send_NOT_ACK();
	Stop_I2C();

	RetuData = (RetuData|Byte_2th)<<8;
	RetuData = (RetuData|Byte_3th)<<8;
	RetuData = (RetuData|Byte_4th);
	RetuData =RetuData >>4;
	ct[0] = RetuData;
	RetuData = 0;
	RetuData = (RetuData|Byte_4th)<<8;
	RetuData = (RetuData|Byte_5th)<<8;
	RetuData = (RetuData|Byte_6th);
	RetuData = RetuData&0xfffff;
	ct[1] =RetuData; 

}


u8 JH_Init(void)   //初始化AHT10
{

	
	Init_I2C_Sensor_Port();
	SensorDelay_us(11038);

	I2C_Start();
	ZSSC_I2C_WR_Byte(0x70); //进入写状态
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0xe1);//写系统配置寄存器
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0x08);
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();

	delay_ms(500);//延时0.5S
   while(JH_Read_Cal_Enable()==0)//需要等待状态字status的Bit[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit[3]=1
   {
    
	JH_Send_BA();  //复位
	delay_ms(100);
	SensorDelay_us(11038);

	I2C_Start();
	ZSSC_I2C_WR_Byte(0x70);
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0xe1);//写系统配置寄存器
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0x08);
	Receive_ACK();
	ZSSC_I2C_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();
	count++;
	if(count>=10)return 0;
	delay_ms(500);
    }
   return 1;
}

int32_t main(void)
{
 uint32_t CT_data[2];
	volatile int  c1,t1;
	u8 ret=0;
	ret = JH_Init(); //初始化
	if(ret == 0)
	{
	 LCD_display("ERROR"):
	 while(1);
	 }
	
	while(1)
	{
	 while(JH_Read_Cal_Enable()==0)//等到校准输出使能位为1,才读取。
	 {
	  JH_Init();//如果为0再使能一次
      delay_ms(30);
	 }
	 //DisableIrq(); //由于是模拟I2C,为读取数据更准确 ,读取之前禁止中断
	 JH_Read_CTdata(CT_data);  //读取温度和湿度 , 可间隔1.5S读一次
	 c1 = CT_data[0]*1000/1024/1024;  //计算得到湿度值(放大了10倍,如果c1=523,表示现在湿度为52.3%)
	 t1 = CT_data[1] *200*10/1024/1024-500;//计算得到温度值(放大了10倍,如果t1=245,表示现在温度为24.5℃)
	 //EnableIrq(); //恢复中断
	 delay_ms(1500); //延时1.5S
	 
	 //为读取的数据更稳定,还可以使用平均值滤波或者窗口滤波,或者前面读取的值与后面的值相差不能太大。
	 }
	

 }	

t1计算式和手册不一致应该以手册为准。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值