一、要求
学习I2C总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。具体任务:
-
解释什么是“软件I2C”和“硬件I2C”? (阅读野火配套教材的第23章“I2C–读写EEPROM”原理章节)
-
阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件。
二、介绍
(一)I2C总线通信协议
I2C 通讯协议 (Inter - Integrated Circuit) 是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单, 可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路 (IC) 间的通讯。
1、软件I2C
软件I2C,又称为模拟I2C,是指通过通用输入输出(GPIO)引脚,由软件程序模拟I2C协议的时序来实现的I2C通信。在软件I2C中,开发者需要编写程序来控制GPIO引脚的电平,以产生SCL(时钟线)和SDA(数据线)所需的信号。这意味着软件必须精确地控制时序,模拟起始位、停止位、确认位和数据传输。软件I2C的优点是灵活性高,可以在没有硬件I2C支持的微控制器上实现I2C通信,但缺点是速度较慢,且会占用较多的CPU资源。
2、硬件I2C
硬件I2C是指微控制器(MCU)内置的I2C接口。这种接口通过硬件电路实现I2C协议的所有功能,包括起始位、停止位、数据传输和时钟信号。使用硬件I2C时,软件只需通过内置的寄存器配置I2C模块,并读写数据,而无需手动控制I2C协议的每一个细节。硬件I2C的优点是速度快,可以减少CPU的负担,允许CPU处理其他任务。
(二)AHT20
链接: https://pan.baidu.com/s/1GFAfxjL5Wwi_I0fO2mlW5w?pwd=9sga
提取码: 9sga
AHT20是一款由奥松公司生产的I2C接口的MEMS温湿度传感器。这款传感器的主要特点包括体积小、精度高、成本低等。AHT20的ADC位数为20Bit,相较于AHT10,体积更小,从5x4x1.6mm缩小到3x3x1.0mm。在相对湿度方面,其精度为±2%,温度精度为±0.3°C。相对湿度测量范围为0-100%,温度测量范围为-40~85°C。
三、实验
(一)STM32CubeMX创建工程
配置RCC
配置SYS
配置I2C1
用于连接AHT20温湿度传感器
配置I2C2
用于连接OLED显示屏
配置USART1
配置时钟树
(二)代码
新建AHT20-21_DEMO_V1_3.c
//#include "main.h"
#include "AHT20-21_DEMO_V1_3.h"
#include "gpio.h"
#include "i2c.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(CC_APB2Periph_GPIOB,ENABLE);
//}
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 SDA_Pin_IN_FLOATING(void) //SDA配置为浮空输入
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//浮空
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init( GPIOB,&GPIO_InitStruct);
}
void SCL_Pin_Output_High(void) //SCL输出高电平,P14作为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);
}
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