一、IIC通信协议
(一)IIC协议
IIC(Inter-Integrated Circuit)通信协议,也被称为I2C,是一种串行通信协议,广泛应用于各种电子设备之间的数据传输。IIC通信协议由飞利浦(Philips)公司在20世纪80年代开发.
(二)工作原理
IIC通信协议采用了两根信号线:时钟线(SCL)和数据线(SDA)。其中,时钟线由主设备控制,用于生成时钟信号,而数据线用于双向的数据传输。在IIC通信协议中,设备分为主设备(Master)和从设备(Slave)。主设备负责控制整个通信过程,而从设备则接受主设备的控制并根据需要提供数据。
(三)时序
IIC通信协议的时序分为开始信号、地址字节、数据字节和停止信号四个阶段。
开始信号(Start Signal):
主设备通过拉低数据线(SDA)时钟线(SCL)仍为高电平来发送开始信号。此时,从设备需准备好接收数据,并等待地址字节的到来。
地址字节(Address Byte):
主设备发送一个地址字节到从设备以确定通信对象。地址字节的高七位是设备的地址,最低一位是读写控制位,通常为0表示写操作,1表示读操作。此时,从设备会检查其地址是否与发送的地址字节匹配。
数据字节(Data Byte):
主设备和从设备之间的数据传输是通过数据字节来完成的。主设备发送数据字节,从设备接收数据字节。数据的传输是以字节为单位的,每个数据字节传输后都会有一个应答信号。
停止信号(Stop Signal):
主设备发送停止信号作为传输的结束标志。停止信号通过将数据线从低电平拉升至高电平实现,此时时钟线仍然保持高电平。
(四)总结
IIC通信协议是一种简单而有效的串行通信协议,广泛应用于各种电子设备之间的数据传输。它具有以下几个特点:
简单:IIC通信协议仅使用两根信号线,使得它在硬件电路实现上非常简单。
双向传输:数据线(SDA)用于主设备和从设备之间的双向数据传输,使得主设备可以向从设备发送控制指令,并接收从设备返回的数据。
多从设备:IIC支持多个从设备连接到同一条总线上,每个从设备都有独立的地址,主设备可以通过地址字节确定要与哪个从设备通信。
时钟同步:通过时钟线(SCL)的协调,主设备和从设备之间的数据传输是同步的,提高了通信的可靠性。
强应答机制:每传输完一个字节的数据,接收端都会发送一个应答信号,以确保发生错误时能及时得到通知。
二、程序
(一)新建项目、编写代码
1.STM32Cube——配置新项目
2.Keil——编写代码
官网代码下载:AHT20芯片代码
(1)新建AHT文件并在Keil中添加
2)编写程序
①AHT20-21_DEMO_V1_3.c
添加以下头文件,以及将原PB14、PB15修改为PB6与PB7
#include "gpio.h"
#include "i2c.h"
void SDA_Pin_Output_High(void) //将PB7配置为输出 , 并设置为高电平, PB7作为I2C的SDA
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
}
void SDA_Pin_Output_Low(void) //将P7配置为输出 并设置为低电平
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);
}
void SCL_Pin_Output_High(void) //SCL输出高电平,P6作为I2C的SCL
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
}
void SCL_Pin_Output_Low(void) //SCL输出低电平
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
}
void Init_I2C_Sensor_Port(void) //初始化I2C接口,输出为高电平
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB,& GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
}
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(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)) a=1;
Byte = (Byte<<1)|a;
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
Delay_5us();
}
SDA_Pin_IN_FLOATING();
SensorDelay_us(8);
return Byte;
}
②AHT20-21_DEMO_V1_3.h
不需要修改
#ifndef _AHT20_DEMO_
#define _AHT20_DEMO_
#include "main.h"
void Delay_N10us(uint32_t t);//延时函数
void SensorDelay_us(uint32_t t);//延时函数
void Delay_4us(void); //延时函数
void Delay_5us(void); //延时函数
void Delay_1ms(uint32_t t);
void AHT20_Clock_Init(void); //延时函数
void SDA_Pin_Output_High(void) ; //将PB15配置为输出 , 并设置为高电平, PB15作为I2C的SDA
void SDA_Pin_Output_Low(void); //将P15配置为输出 并设置为低电平
void SDA_Pin_IN_FLOATING(void); //SDA配置为浮空输入
void SCL_Pin_Output_High(void); //SCL输出高电平,P14作为I2C的SCL
void SCL_Pin_Output_Low(void); //SCL输出低电平
void Init_I2C_Sensor_Port(void); //初始化I2C接口,输出为高电平
void I2C_Start(void); //I2C主机发送START信号
void AHT20_WR_Byte(uint8_t Byte); //往AHT20写一个字节
uint8_t AHT20_RD_Byte(void);//从AHT20读取一个字节
uint8_t Receive_ACK(void); //看AHT20是否有回复ACK
void Send_ACK(void) ; //主机回复ACK信号
void Send_NOT_ACK(void); //主机不回复ACK
void Stop_I2C(void); //一条协议结束
uint8_t AHT20_Read_Status(void);//读取AHT20的状态寄存器
uint8_t AHT20_Read_Cal_Enable(void); //查询cal enable位有没有使能
void AHT20_SendAC(void); //向AHT20发送AC命令
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num);
void AHT20_Read_CTdata(uint32_t *ct); //没有CRC校验,直接读取AHT20的温度和湿度数据
void AHT20_Read_CTdata_crc(uint32_t *ct); //CRC校验后,读取AHT20的温度和湿度数据
void AHT20_Init(void); //初始化AHT20
void JH_Reset_REG(uint8_t addr);///重置寄存器
void AHT20_Start_Init(void);///上电初始化进入正常测量状态
#endif
③main.c
引入头文件以及
/* USER CODE BEGIN Includes */
#include<stdio.h>
#include "AHT20-21_DEMO_V1_3.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PTD */
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
//等待发送结束
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC)!=SET){
}
return ch;
}
/* USER CODE BEGIN 2 */
AHT20_Init();
Delay_1ms(500);
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
//AHT20_Read_CTdata(CT_data); //不经过CRC校验,直接读取AHT20的温度和湿度数据 推荐每隔大于1S读一次
AHT20_Read_CTdata_crc(CT_data); //crc校验后,读取AHT20的温度和湿度数据
c1 = CT_data[0]*1000/1024/1024; //计算得到湿度值c1(放大了10倍)
t1 = CT_data[1]*2000/1024/1024-500;//计算得到温度值t1(放大了10倍)
printf("正在检测");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
printf("\r\n");
HAL_Delay(1000);
printf("温度:%d%d.%d",t1/100,(t1/10)%10,t1%10);
printf("湿度:%d%d.%d",c1/100,(c1/10)%10,c1%10);
printf("\r\n");
printf("等待");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
HAL_Delay(100);
printf(".");
printf("\r\n");
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
三、总结
通过使用I2C协议与AHT20传感器完成了此次温湿度采集,让我对传感器的使用更加了解,以及对I2C协议更加了解。