Core→Inc右键→New→Hreader File,命名aht20.h Core→src右键→New→Source File,命名aht20.c 
 
根据数据手册的传感器读取流程1,可以写出AHT20的初始化函数。 # define  AHT20_ADDRESS 	0X70 void  AHT20_Init ( void )  { uint8_t 	readBuffer; HAL_Delay ( 40 ) ; HAL_I2C_Master_Transmit ( & hi2c1,  AHT20_ADDRESS,  & readBuffer,  1 ,  HAL_MAX_DELAY) ; if  ( ( readBuffer &  0x08 )  ==  0x00 )  { uint8_t 	sendBuffer[ 3 ]  =  { 0xBE ,  0x08 ,  0x00 } ; HAL_I2C_Master_Receive ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ,  HAL_MAX_DELAY) ; } 
} 
根据数据手册的传感器读取流程2跟3,还有数据表可以写出AHT20的读取测量数据的函数。 void  AHT20_Read ( float  * Temperature,  float  * Humidity)  { uint8_t 	sendBuffer[ 3 ]  =  { 0xAC ,  0x33 ,  0x00 } ; uint8_t 	readBuffer[ 6 ] ; HAL_I2C_Master_Transmit ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ,  HAL_MAX_DELAY) ; HAL_Delay ( 75 ) ; HAL_I2C_Master_Receive ( & hi2c1,  AHT20_ADDRESS,  readBuffer,  6 ,  HAL_MAX_DELAY) ; if  ( ( readBuffer[ 0 ]  &  0x80 )  ==  0x00 )  { uint32_t  data =  0 ; data =  ( ( uint32_t ) readBuffer[ 3 ]  >>  4 )  +  ( ( uint32_t ) readBuffer[ 2 ]  <<  4 )  +  ( ( uint32_t ) readBuffer[ 1 ]  <<  12 ) ; * Humidity =  data *  100.0f  /  ( 1  <<  20 ) ; data =  ( ( uint32_t ) readBuffer[ 5 ] )  +  ( ( uint32_t ) readBuffer[ 4 ]  <<  8 )  +  ( ( ( uint32_t ) readBuffer[ 3 ]  &  0x0F )  <<  16 ) ; * Temperature =  ( data *  200.0f  /  ( 1  <<  20 ) )  -  50 ; } } 
由于我们使用到浮点数,Cube默认没有启用编译器对浮点数输出的支持,在菜单栏project→properties进入设置页面勾选图纸选项开启此功能。 主函数部分。 先将AHT20初始化,创建两个变量和一个用来临时存放数据的数组。   AHT20_Init ( ) ; float  temperature,  humidity; char  dataArray[ 50 ] ; 
  while  ( 1 ) { AHT20_Read ( & temperature,  & humidity) ; sprintf ( dataArray,  "温度:%.f ℃, 湿度:%.f %%\r\n" ,  temperature,  humidity) ; HAL_UART_Transmit ( & huart1,  ( uint8_t * ) dataArray,  strlen ( dataArray) ,  HAL_MAX_DELAY) ; HAL_Delay ( 1000 ) ; } 
编译代码并烧录,再通过连接串口获取单片机发送的数据。 打开IIC的中断向量并保存生成代码。 前面我们使用的轮询的方式,读取模块的数据时,有等待时间,等待读取成功之后才发送到串口显示出来。如果我们只是简单的将轮询模式中IIC的发送和接受改成中断模式,会导致数据的读取还未完成时就将数据给发送出去,造成数据的错误,所以我们需要对代码进行改造,利用状态机来编码,不同的状态做不同的事。 发送测量指令: 
void  AHT20_Measure ( void )  { static  uint8_t 	sendBuffer[ 3 ]  =  { 0xAC ,  0x33 ,  0x00 } ; HAL_I2C_Master_Transmit_IT ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ) ; 
} 
获取模块的数据: 
void  AHT20_GetData ( void )  { HAL_I2C_Master_Receive_IT ( & hi2c1,  AHT20_ADDRESS,  readBuffer,  6 ) ; 
} 
解析获取的数据: uint8_t 	readBuffer[ 6 ]  =  { 0 } ; 
void  AHT20_AnalysisData ( float  * Temperature,  float  * Humidity)  { if  ( ( readBuffer[ 0 ]  &  0x80 )  ==  0x00 )  { uint32_t  data =  0 ; data =  ( ( uint32_t ) readBuffer[ 3 ]  >>  4 )  +  ( ( uint32_t ) readBuffer[ 2 ]  <<  4 )  +  ( ( uint32_t ) readBuffer[ 1 ]  <<  12 ) ; * Humidity =  data *  100.0f  /  ( 1  <<  20 ) ; data =  ( ( uint32_t ) readBuffer[ 5 ] )  +  ( ( uint32_t ) readBuffer[ 4 ]  <<  8 )  +  ( ( ( uint32_t ) readBuffer[ 3 ]  &  0x0F )  <<  16 ) ; * Temperature =  ( data *  200.0f  /  ( 1  <<  20 ) )  -  50 ; } 
} 
函数注意要在头文件中申明,方便其他文件使用。 
uint8_t  aht20State =  0 ; 
 
0:初始状态,发送测量指令,然后将状态变为1 1:正在发送测量指令中 2:发送完成,按照手册中需要等75ms后才可以进行读取 3:读取中 4:读取完成,对数据进行解析并展示数据并且需要将状态恢复到初始状态,进行下一个循环。 主函数的循环语句中,我们发现没有状态1切换到状态2、状态3切换到状态4的语句,我们需要所以我们需要借助IIC中断的回调函数来实现切换状态的功能。也因为状态aht20State需要在其他函数中使用,所以我们需要将次变量在头文件中加上extern来声明,其他文件中才可以使用。 main.h文件中 
extern  uint8_t  aht20State; 
  while  ( 1 ) { if  ( aht20State ==  0 )  { 			AHT20_Measure ( ) ; aht20State =  1 ; }   else  if  ( aht20State ==  2 )  { 		HAL_Delay ( 75 ) ; AHT20_GetData ( ) ; aht20State =  3 ; }  else  if  ( aht20State ==  4 )  { 		AHT20_AnalysisData ( Temperature,  Humidity) ; sprintf ( dataArray,  "温度:%.f ℃, 湿度:%.f %%\r\n" ,  temperature,  humidity) ; HAL_UART_Transmit ( & huart1,  ( uint8_t * ) dataArray,  strlen ( dataArray) ,  HAL_MAX_DELAY) ; HAL_Delay ( 5000 ) ; aht20State =  0 ; } 
在i2c.c文件中,发送完成和接受完成的回调函数。 void  HAL_I2C_MasterTxCpltCallback ( I2C_HandleTypeDef * hi2c)  { if  ( hi2c ==  & hi2c1)  { aht20State =  2 ; } 
} 
void  HAL_I2C_MasterRxCpltCallback ( I2C_HandleTypeDef * hi2c)  { if  ( hi2c ==  & hi2c1)  { aht20State =  4 ; } 
} 
在上个实例中我们用得是阻塞式IIC通讯,关于AHT20_Init()的函数中也要修改成中断模式: void  AHT20_Init ( void )  { uint8_t 	readBuffer; HAL_Delay ( 40 ) ; HAL_I2C_Master_Transmit_IT ( & hi2c1,  AHT20_ADDRESS,  & readBuffer,  1 ) ; if  ( ( readBuffer &  0x08 )  ==  0x00 )  { uint8_t 	sendBuffer[ 3 ]  =  { 0xBE ,  0x08 ,  0x00 } ; HAL_I2C_Master_Receive_IT ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ) ; } 
} 
烧录后通过串口发送数据,一切正常。 开启IIC的DMA模式,添加两个通道,一个RX一个TX,其他设置无需修改,保持默认。保存生成代码 void  AHT20_Init ( void )  { uint8_t 	readBuffer; HAL_Delay ( 40 ) ; HAL_I2C_Master_Transmit_DMA ( & hi2c1,  AHT20_ADDRESS,  & readBuffer,  1 ) ; if  ( ( readBuffer &  0x08 )  ==  0x00 )  { uint8_t 	sendBuffer[ 3 ]  =  { 0xBE ,  0x08 ,  0x00 } ; HAL_I2C_Master_Receive_DMA ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ) ; } 
} 
void  AHT20_Measure ( void )  { static  uint8_t 	sendBuffer[ 3 ]  =  { 0xAC ,  0x33 ,  0x00 } ; HAL_I2C_Master_Transmit_DMA ( & hi2c1,  AHT20_ADDRESS,  sendBuffer,  3 ) ; 
} 
void  AHT20_GetData ( void )  { HAL_I2C_Master_Receive_DMA ( & hi2c1,  AHT20_ADDRESS,  readBuffer,  6 ) ; 
} 
完成修改,功能没变,只是IIC的模式改变而已。 此文章仅自己学习记录用,是参考小破站keysking的教程。