51单片机AHT20-21源代码

AHT20,新一代温湿度传感器在尺寸与智能方面建立了新的标准:它嵌入了适 于回流焊的双列扁平无引脚SMD封装,底面3 x 3mm ,高度1.0mm。传感器输出经过 标定的数字信号,标准 I 2 C 格式。AHT20 配有一个全新设计的 ASIC专用芯片、一 个经过改进的MEMS半导体电容式湿度传感元件和一个标准的片上温度传感元件,其 性能已经大大提升甚至超出了前一代传感器的可靠性水平,新一代温湿度传感器, 经过改进使其在恶劣环境下的性能更稳定。每一个传感器都经过校准和测试,在产 品表面印有产品批号。由于对传感器做了改良和微型化改进,因此它的性价比更高, 并且最终所有设备都将得益于尖端的节能运行模式。

但是现在网上的大多数原码都是针对stm32等的这种多位单片机,而我们都知道51单片机是8位单片机,无法对浮点数进行运算,对32位的整数计算有时候也不是很准确,所以我对网上stm32的例程进行了修改。

#include "AHT20.h"
#include "intrins.h"



//定义IIC引脚
sbit SDA=P1^3;
sbit SCL=P1^2;

char buffer[100]={0};//串口打印的缓存
u8  CTDATA[7]={0};//用于CRC传递数组
u8 CRC_WrongFlag=0;//CRC错误标志位   1:Wrong,0:True
u8 ACK_Flag=0;//应答标志位   1:ACK,0:NACK



/**************************延时部分*****************************
用逻辑分析仪测得:1个nop:6us, 2个Nop:7us, 3个Nop:8.5us, 4个Nop:9.5us,
								5个Nop:10.5us, 6个Nop:11.5us
****************************************************************/
void delay_10us()//延时10us
{
	unsigned char i;

	i = 35;
	while (--i);
}

//**********************************************
void delay_1ms()		//延时1ms,用逻辑分析仪测得i=84时,延时为1ms
{
	unsigned char i, j;

	i = 15;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}



//**********************************************
void delay_ms(u16 i)	//延时 i ms,不是十分精准,当i大于58时误差会超过1ms
{
	for(;i>0;i--)
	{
		delay_1ms();
	}
}









/**************************IIC部分*****************************/

//送起始位 sda=1->0
void I2C_Start2()
{
  SDA=1;
  SCL=1;
  delay_10us();
  SDA=0;
  delay_10us();
  SCL=0; 
}
//送停止位 sda=0->1
void Stop_I2C()
{
  SDA=0;
  SCL=1;
  delay_10us();
  SDA=1;
}
//主机发送ACK(包含ack:sda=0)
void Send_ACK(void)
{  //设置SDA 口为输出
   SDA=0;
   SCL=0;
   delay_10us();
   SCL=1;
   delay_10us();	
   SCL=0;
   SDA=1;
}
//主机发送NACK(no_ack:sda=1)
void Send_NOT_ACK(void)
{  //设置SDA 口为输出
   SDA=1;  
   SCL=0;
   delay_10us();
   SCL=1;
   delay_10us();
   SDA=1;
   SCL=0;
}

// 检测 SDA是否回ACK(ack:sda=1;Nack:sda=0)
u8 Receive_ACK(void)
{  //设置SDA 口为输入
	u8 cnt=0;
   SCL=0;
   delay_10us();
   SCL=1;
   delay_10us();
	while((SDA==1)&&cnt<100)
		cnt++;
	if(cnt==100)
	{
		ACK_Flag=0;//nack
	}else
	{
		ACK_Flag=1;//ack
	}
	SCL=0;
	delay_10us();
	 return ACK_Flag;
}






void AHT20_WR_Byte(u8 Byte) //往AHT20写一个字节
{
	u8 Data,N,i;	
	Data=Byte;
	i = 0x80;
	for(N=0;N<8;N++)
	{
		SCL=0; 
		delay_10us();	
		if(i&Data)
		{
			SDA=1;
		}
		else
		{
			SDA=0;
		}	
		SCL=1;
		delay_10us();
		Data <<= 1;
		 
	}
	SCL=0;
	delay_10us();   
}	


u8 AHT20_RD_Byte(void)//从AHT20读取一个字节
{
	u8 Byte,i,a;
	Byte = 0;
	
	for(i=0;i<8;i++)
	{
		SCL=0;
		delay_10us();
		SCL=1;
		delay_10us();
		a=0;
		if(SDA==1)a=1;
		Byte=(Byte<<1);
		Byte|=a;
		SCL=0;
		
	}
	return Byte;
	
	
	
}




u8 AHT20_Read_Status(void)//读取AHT20的状态寄存器
{

	u8 Byte_first;	
	I2C_Start2();
	AHT20_WR_Byte(0x71);
	
	Receive_ACK();
	Byte_first = AHT20_RD_Byte();
	Send_NOT_ACK();
	Stop_I2C();
	return Byte_first;
}

//u8 AHT20_Read_Cal_Enable(void)  //查询cal enable位有没有使能
//{
//	u8 val = 0;//ret = 0,
//  val = AHT20_Read_Status();
//	 if((val & 0x68)==0x08)
//		 return 1;
//   else  return 0;
// }

void AHT20_SendAC(void) //向AHT20发送AC命令
{

	I2C_Start2();
	AHT20_WR_Byte(0x70);
	Receive_ACK();
	AHT20_WR_Byte(0xac);//0xAC采集命令
	Receive_ACK();
	AHT20_WR_Byte(0x33);
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();

}


//CRC校验类型:CRC8/MAXIM
//多项式:X8+X5+X4+1
//Poly:0011 0001  0x31
//高位放到后面就变成 1000 1100 0x8c
//C现实代码:
u8 Calc_CRC8(u8 *message,u8 Num)
{
        u8 i;
        u8 byte;
        u8 crc=0xFF;
  for(byte=0; byte<Num; byte++)
  {
    crc^=(message[byte]);
    for(i=8;i>0;--i)
    {
      if(crc&0x80) crc=(crc<<1)^0x31;
      else crc=(crc<<1);
    }
  }
        return crc;
}





void AHT20_Read_CTdata(u16 *ct) //没有CRC校验,直接读取AHT20的温度和湿度数据
{
	volatile u8  Byte_1th=0;
	volatile u8  Byte_2th=0;
	volatile u8  Byte_3th=0;
	volatile u8  Byte_4th=0;
	volatile u8  Byte_5th=0;
	volatile u8  Byte_6th=0;
	volatile u8  Byte_7th=0;
	u16 RetuData = 0;
	u16 cnt = 0;
	AHT20_SendAC();//向AHT10发送AC命令
	delay_ms(80);//延时80ms左右	
    cnt = 0;
	while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态
	{
		delay_ms(2);
		if(cnt++>=100)
		{
		 break;
		 }
	}
	I2C_Start2();
	AHT20_WR_Byte(0x71);
	Receive_ACK();
	CTDATA[0]=Byte_1th = AHT20_RD_Byte();//状态字,查询到状态为0x98,表示为忙状态,bit[7]为1;状态为0x1C,或者0x0C,或者0x08表示为空闲状态,bit[7]为0
	Send_ACK();
	CTDATA[1]=Byte_2th = AHT20_RD_Byte();//湿度
	Send_ACK();
	CTDATA[2]=Byte_3th = AHT20_RD_Byte();//湿度
	Send_ACK();
	CTDATA[3]=Byte_4th = AHT20_RD_Byte();//湿度/温度
	Send_ACK();
	CTDATA[4]=Byte_5th = AHT20_RD_Byte();//温度
	Send_ACK();
	CTDATA[5]=Byte_6th = AHT20_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>>4)&0x00ff;
	ct[1] =RetuData; //温度
	

}


void AHT20_Read_CTdata_crc(u16 *ct) //CRC校验后,读取AHT20的温度和湿度数据
{
	volatile u8  Byte_1th=0;
	volatile u8  Byte_2th=0;
	volatile u8  Byte_3th=0;
	volatile u8  Byte_4th=0;
	volatile u8  Byte_5th=0;
	volatile u8  Byte_6th=0;
	volatile u8  Byte_7th=0;
	 u16 RetuData = 0;
	 u16 cnt = 0;

	
	AHT20_SendAC();//向AHT10发送AC命令
	delay_ms(80);//延时80ms左右	
    cnt = 0;
	while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态
	{
		delay_ms(1);
		if(cnt++>=100)
		{
		 break;
		}
	}
	
	I2C_Start2();

	AHT20_WR_Byte(0x71);
	Receive_ACK();
	CTDATA[0]=Byte_1th = AHT20_RD_Byte();//状态字,查询到状态为0x98,表示为忙状态,bit[7]为1;状态为0x1C,或者0x0C,或者0x08表示为空闲状态,bit[7]为0
	Send_ACK();
	CTDATA[1]=Byte_2th = AHT20_RD_Byte();//湿度
	Send_ACK();
	CTDATA[2]=Byte_3th = AHT20_RD_Byte();//湿度
	Send_ACK();
	CTDATA[3]=Byte_4th = AHT20_RD_Byte();//湿度/温度
	Send_ACK();
	CTDATA[4]=Byte_5th = AHT20_RD_Byte();//温度
	Send_ACK();
	CTDATA[5]=Byte_6th = AHT20_RD_Byte();//温度
	Send_ACK();
	CTDATA[6]=Byte_7th = AHT20_RD_Byte();//CRC数据
	Send_NOT_ACK();                           //注意: 最后是发送NAK
	Stop_I2C();
	
	if(Calc_CRC8(CTDATA,6)==Byte_7th)
	{
	CRC_WrongFlag=0;
		
	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>>4)&0x00ff;
	ct[1] =RetuData; //温度
		
	}
	else
	{
//		ct[0]=0x00;
//		ct[1]=0x00;//校验错误返回值,客户可以根据自己需要更改
		CRC_WrongFlag=1;//CRC错误标志位

	}//CRC数据
}


void AHT20_Init(void)   //初始化AHT20
{	
	I2C_Start2();
	AHT20_WR_Byte(0x70);
	Receive_ACK();
	AHT20_WR_Byte(0xa8);//0xA8进入NOR工作模式
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();

	delay_ms(10);//延时10ms左右

	I2C_Start2();
	AHT20_WR_Byte(0x70);
	Receive_ACK();
	AHT20_WR_Byte(0xbe);//0xBE初始化命令,AHT20的初始化命令是0xBE,   AHT10的初始化命令是0xE1
	Receive_ACK();
	AHT20_WR_Byte(0x08);//相关寄存器bit[3]置1,为校准输出
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();
	delay_ms(10);//延时10ms左右
}
void JH_Reset_REG(u8 addr)
{
	
	u8 Byte_first,Byte_second,Byte_third;
	I2C_Start2();
	AHT20_WR_Byte(0x70);//原来是0x70
	Receive_ACK();
	AHT20_WR_Byte(addr);
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	AHT20_WR_Byte(0x00);
	Receive_ACK();
	Stop_I2C();

	delay_ms(5);//延时5ms左右
	I2C_Start2();
	AHT20_WR_Byte(0x71);//
	Receive_ACK();
	Byte_first = AHT20_RD_Byte();
	Send_ACK();
	Byte_second = AHT20_RD_Byte();
	Send_ACK();
	Byte_third = AHT20_RD_Byte();
	Send_NOT_ACK();
	Stop_I2C();
	
    delay_ms(10);//延时10ms左右
	I2C_Start2();
	AHT20_WR_Byte(0x70);///
	Receive_ACK();
	AHT20_WR_Byte(0xB0|addr);寄存器命令
	Receive_ACK();
	AHT20_WR_Byte(Byte_second);
	Receive_ACK();
	AHT20_WR_Byte(Byte_third);
	Receive_ACK();
	Stop_I2C();
	
	Byte_second=0x00;
	Byte_third =0x00;
}

void AHT20_Start_Init(void)
{
	JH_Reset_REG(0x1b);
	JH_Reset_REG(0x1c);
	JH_Reset_REG(0x1e);
}

在这里我选用的是stc8g的单片机,所以延时函数和传统的51单片机有所不同,请大家根据实际情况进行更改。

在这个程序中最主要的其实就是这两个函数:

void AHT20_Read_CTdata(u16 *ct)
void AHT20_Read_CTdata_crc(u16 *ct)

因为我此次的设计只是为了日常的使用,所以不需要用到太高的精度,只从AHT20的寄存器中读取了温度和湿度的最高八位,并返回。在主函数调用读取函数后需用公式进行换算。 

c1 = CT_data[0]*100/255;      
t1 = (CT_data[1]*200/255)-50; 

同时,AHT20的寄存器如下图:

我们也可以根据需要的精度对函数进行修改和换算。 

aht10温湿度传感器是一款数字式温湿度传感器,可通过I2C接口与微控制器进行通信。对于C51单片机来说,可以通过编写相应的程序来读取aht10传感器输出的温湿度数据。以下是一个简单的示例程序,可以帮助你开始使用aht10传感器: ```c #include <reg51.h> sbit SDA=P1^0; // I2C数据线 sbit SCL=P1^1; // I2C时钟线 void delay_us(unsigned char t) { while(t--); } void i2c_start() { SDA=1; SCL=1; delay_us(10); SDA=0; delay_us(10); SCL=0; } void i2c_stop() { SDA=0; SCL=1; delay_us(10); SDA=1; delay_us(10); } unsigned char i2c_write_byte(unsigned char dat) { unsigned char i; for(i=0;i<8;i++) { SDA=dat&(0x80>>i); delay_us(10); SCL=1; delay_us(10); SCL=0; } SDA=1; delay_us(10); SCL=1; delay_us(10); if(SDA) return 0; else return 1; } unsigned char i2c_read_byte() { unsigned char i,dat=0; SDA=1; for(i=0;i<8;i++) { SCL=1; delay_us(10); dat<<=1; dat|=SDA; SCL=0; delay_us(10); } return dat; } void aht10_init() { i2c_start(); i2c_write_byte(0x38); i2c_write_byte(0xE1); i2c_write_byte(0x08); i2c_stop(); } unsigned char aht10_read_data(unsigned char* buf) { unsigned char i; i2c_start(); i2c_write_byte(0x38); i2c_write_byte(0xAC); i2c_write_byte(0x33); i2c_stop(); delay_us(500); i2c_start(); i2c_write_byte(0x39); if(!i2c_read_byte()) { i2c_stop(); return 0; } for(i=0;i<6;i++) { buf[i]=i2c_read_byte(); if(i!=5) i2c_write_byte(1); } i2c_stop(); return 1; } void main() { unsigned char buf[6]; unsigned short t,h; aht10_init(); while(1) { if(aht10_read_data(buf)) { t=buf[1]<<12|buf[2]<<4|buf[3]>>4; h=buf[3]&0x0F<<16|buf[4]<<8|buf[5]; printf("Temperature:%.2fC Humidity:%.2f%%\r\n",(float)t*200/1048576-50,(float)h*100/1048576); } delay_us(500); } } ``` 该程序使用了C51单片机的GPIO口模拟了I2C接口,通过aht10_init函数初始化aht10传感器,然后通过aht10_read_data函数读取温湿度数据,并将其转换为实际温湿度值输出。需要注意的是,程序中使用了printf函数输出数据,因此需要在编译时包含相应的库文件。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值