一、关于软件I2C和硬件I2C的介绍和理解
I2C(Inter-Integrated Circuit)是一种由飞利浦公司(现恩智浦半导体)开发的串行通信协议,用于连接低速外围设备。它是一种多主控、多从机、半双工的通信协议,可以在同一总线上连接多个设备。
硬件I2C: 硬件I2C是指微控制器(MCU)内置的I2C接口。这种接口通过硬件电路实现I2C协议的所有功能,包括起始位、停止位、数据传输和时钟信号。使用硬件I2C时,软件只需通过内置的寄存器配置I2C模块,并读写数据,而无需手动控制I2C协议的每一个细节。硬件I2C的优点是速度快,可以减少CPU的负担,允许CPU处理其他任务。
软件I2C: 软件I2C,又称为模拟I2C,是指通过通用输入输出(GPIO)引脚,由软件程序模拟I2C协议的时序来实现的I2C通信。在软件I2C中,开发者需要编写程序来控制GPIO引脚的电平,以产生SCL(时钟线)和SDA(数据线)所需的信号。这意味着软件必须精确地控制时序,模拟起始位、停止位、确认位和数据传输。软件I2C的优点是灵活性高,可以在没有硬件I2C支持的微控制器上实现I2C通信,但缺点是速度较慢,且会占用较多的CPU资源。
简单来说,硬件I2C是利用微控制器内置的I2C硬件模块来实现的,而软件I2C是通过软件编程控制GPIO引脚来模拟I2C协议的时序。
二、每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件
按如下图配置STM32CubeMX各个端口
在奥松官网下载AHT20芯片代码,之后修改对应引脚SDA和SCL
再次移植u8g2图形库,对应输出到oled即可
部分main.c代码如下:
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include <stdio.h>
#include "AHT20-21_DEMO_V1_3.h"
void SystemClock_Config(void);
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;
}
int main(void)
{
uint32_t CT_data[2] = {0, 0};
volatile int c1, t1;
Delay_1ms(500);
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
AHT20_Init();
Delay_1ms(500);
while (1)
{
AHT20_Read_CTdata(CT_data);
c1 = CT_data[0] * 1000 / 1024 / 1024;
t1 = CT_data[1] * 2000 / 1024 / 1024 - 500;
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);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
三、结果
串口现象:
oled屏幕: