/*******************************************/ /*@版权所有:广州奥松电子有限公司 */ /*@作者:温湿度传感器事业部 */ /*@版本:V1.2 */ /*******************************************/ #include "stm32f10x.h" #include "AHT20.h" void Delay_N10us(uint32_t t)//延时函数 { uint32_t k; while(t--) { for (k = 0; k < 2; k++);//110 } } void SensorDelay_us(uint32_t t)//延时函数 { for(t = t-2; t>0; t--) { Delay_N10us(1); } } void Delay_4us(void) //延时函数 { Delay_N10us(1); Delay_N10us(1); Delay_N10us(1); Delay_N10us(1); } void Delay_5us(void) //延时函数 { Delay_N10us(1); Delay_N10us(1); Delay_N10us(1); Delay_N10us(1); Delay_N10us(1); } void Delay_1ms(uint32_t t) //延时函数 { while(t--) { SensorDelay_us(1000);//////延时1ms } } void AHT20_Clock_Init(void) //延时函数 { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); } void SDA_Pin_Output_High(void) //将PB15配置为输出 , 并设置为高电平, PB15作为I2C的SDA { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,& GPIO_InitStruct); GPIO_SetBits(GPIOB,GPIO_Pin_1); } void SDA_Pin_Output_Low(void) //将P15配置为输出 并设置为低电平 { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,& GPIO_InitStruct); GPIO_ResetBits(GPIOB,GPIO_Pin_1); } void SDA_Pin_IN_FLOATING(void) //SDA配置为浮空输入 { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;// GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOB,&GPIO_InitStruct); } void SCL_Pin_Output_High(void) //SCL输出高电平,P14作为I2C的SCL { GPIO_SetBits(GPIOB,GPIO_Pin_0); } void SCL_Pin_Output_Low(void) //SCL输出低电平 { GPIO_ResetBits(GPIOB,GPIO_Pin_0); } void Init_I2C_Sensor_Port(void) //初始化I2C接口,输出为高电平 { GPIO_InitTypeDef GPIO_InitStruct; AHT20_Clock_Init(); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); GPIO_SetBits(GPIOB,GPIO_Pin_1);//输出高电平 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStruct); GPIO_SetBits(GPIOB,GPIO_Pin_0);//输出高电平 } 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 AHT20_WR_Byte(uint8_t Byte) //往AHT20写一个字节 { uint8_t Data,N,i; Data=Byte; i = 0x80; for(N=0;N<8;N++) { SCL_Pin_Output_Low(); Delay_4us(); if(i&Data) { SDA_Pin_Output_High(); } else { SDA_Pin_Output_Low(); } SCL_Pin_Output_High(); Delay_4us(); Data <<= 1; } SCL_Pin_Output_Low(); SensorDelay_us(8); SDA_Pin_IN_FLOATING(); SensorDelay_us(8); } uint8_t AHT20_RD_Byte(void)//从AHT20读取一个字节 { 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_5us(); a=0; if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)) a=1; Byte = (Byte<<1)|a; SCL_Pin_Output_Low(); Delay_5us(); } SDA_Pin_IN_FLOATING(); SensorDelay_us(8); return Byte; } uint8_t Receive_ACK(void) //看AHT20是否有回复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_ReadInputDataBit(GPIOB,GPIO_Pin_1)) && 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 AHT20_Read_Status(void)//读取AHT20的状态寄存器 { uint8_t Byte_first; I2C_Start(); AHT20_WR_Byte(0x71); Receive_ACK(); Byte_first = AHT20_RD_Byte(); Send_NOT_ACK(); Stop_I2C(); return Byte_first; } void AHT20_SendAC(void) //向AHT20发送AC命令 { I2C_Start(); 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现实代码: uint8_t Calc_CRC8(uint8_t *message,uint8_t Num) { uint8_t i; uint8_t byte; uint8_t crc=0xFF; for(byte=0; byte0;--i) { if(crc&0x80) crc=(crc<<1)^0x31; else crc=(crc<<1); } } return crc; } void AHT20_Read_CTdata(uint32_t *ct) //没有CRC校验,直接读取AHT20的温度和湿度数据 { 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; AHT20_SendAC();//向AHT20发送AC命令 Delay_1ms(80);//延时80ms左右 cnt = 0; while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态 { SensorDelay_us(1508); if(cnt++>=100) { break; } } I2C_Start(); AHT20_WR_Byte(0x71); Receive_ACK(); Byte_1th = AHT20_RD_Byte();//状态字,查询到状态为0x98,表示为忙状态,bit[7]为1;状态为0x1C,或者0x0C,或者0x08表示为空闲状态,bit[7]为0 Send_ACK(); Byte_2th = AHT20_RD_Byte();//湿度 Send_ACK(); Byte_3th = AHT20_RD_Byte();//湿度 Send_ACK(); Byte_4th = AHT20_RD_Byte();//湿度/温度 Send_ACK(); Byte_5th = AHT20_RD_Byte();//温度 Send_ACK(); 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&0xfffff; ct[1] =RetuData; //温度 } void AHT20_Read_CTdata_crc(uint32_t *ct) //CRC校验后,读取AHT20的温度和湿度数据 { 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; volatile uint8_t Byte_7th=0; uint32_t RetuData = 0; uint16_t cnt = 0; // uint8_t CRCDATA=0; uint8_t CTDATA[6]={0};//用于CRC传递数组 AHT20_SendAC();//向AHT20发送AC命令 Delay_1ms(80);//延时80ms左右 cnt = 0; while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态 { SensorDelay_us(1508); if(cnt++>=100) { break; } } I2C_Start(); 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(); Byte_7th = AHT20_RD_Byte();//CRC数据 Send_NOT_ACK(); //注意: 最后是发送NAK Stop_I2C(); if(Calc_CRC8(CTDATA,6)==Byte_7th) { 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; //温度 } else { ct[0]=0x00; ct[1]=0x00;//校验错误返回值,客户可以根据自己需要更改 }//CRC数据 } void JH_Reset_REG(uint8_t addr) { uint8_t Byte_first,Byte_second,Byte_third,Byte_fourth; I2C_Start(); 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_1ms(5);//延时5ms左右 I2C_Start(); 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_1ms(10);//延时10ms左右 I2C_Start(); 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); } //int32_t main(void) //{ // uint32_t CT_data[2]; // volatile int c1,t1; // /***********************************************************************************/ // /**///上电初始化SDA,SCL的IO口 // /***********************************************************************************/ // Init_I2C_Sensor_Port(); // /***********************************************************************************/ // /**///①刚上电,产品芯片内部就绪需要时间,延时100~500ms,建议500ms // /***********************************************************************************/ // Delay_1ms(500); // /***********************************************************************************/ // /**///②上电第一次发0x71读取状态字,判断状态字是否为0x18,如果不是0x18,进行寄存器初始化 // /***********************************************************************************/ // if((AHT20_Read_Status()&0x18)!=0x18) // { // AHT20_Start_Init(); //重新初始化寄存器 // Delay_1ms(10); // } // // /***********************************************************************************/ // /**///③根据客户自己需求发测量命令读取温湿度数据,当前while(1)循环发测量命令读取温湿度数据,仅供参考 // /***********************************************************************************/ // while(1) // { // AHT20_Read_CTdata(CT_data); //不经过CRC校验,直接读取AHT20的温度和湿度数据 推荐每隔大于1S读一次 // //AHT20_Read_CTdata_crc(CT_data); //crc校验后,读取AHT20的温度和湿度数据 // // c1 = CT_data[0]*100*10/1024/1024; //计算得到湿度值c1(放大了10倍) // t1 = CT_data[1]*200*10/1024/1024-500;//计算得到温度值t1(放大了10倍) // ////下一步客户处理显示数据, // /***********************************************************************************/ // /**///延时1.5s,建议间隔1.5s读一次 // /***********************************************************************************/ // delay_ms(1500); // } // }