一、I2C总线通信协议
软件I2C
软件I2C,也称为模拟I2C或bit-bang I2C,是一种通过微控制器的通用输入输出(GPIO)引脚来模拟I2C总线通信的方式。它不依赖于专门的硬件I2C接口,而是通过编程控制GPIO引脚的电平状态来实现I2C协议的数据传输。在软件I2C中,通常需要两个GPIO引脚:一个是SCL(时钟线),另一个是SDA(数据线)。通过精确地控制这两个引脚上的电压变化,可以发送和接收数据。
硬件I2C
硬件I2C是一种利用微控制器或其他设备上的专用硬件模块来进行I2C通信的方法。这种硬件模块内置了I2C协议的逻辑,能够自动处理时钟信号(SCL)和数据线(SDA)的操作,从而允许微控制器以更高效和可靠的方式与其他I2C兼容设备通信。
二、AHT20芯片
了解AHT20芯片的相关信息,具体信息请到官方下载对应产品介绍文档。
资料链接:http://www.aosong.com/class-36.html
官方代码使用的是PB14,PB15引脚需要修改对应的引脚才可以正常使用。
下图为AHT20芯片的典型电路(芯片正面有孔)。
三、工程配置
要求:每隔2秒钟采集一次温湿度数据,显示到OLED上,同时通过串口发送到上位机的“串口助手”软件。
首先进入CubeMX新疆工程,选择STM32F103C8T6芯片。
1.RCC配置。
2.SYS配置。
3.TIM1配置。
4.UASART串口配置。
5.I2C1配置(用于AHT20)。
6..I2C2配置(用于u8g2)。
7.时钟树配置。
8.代码配置。
四、代码修改
首先参考作者上篇文章进行u8g2的基础配置,以及字模的获取。
STM32—U8g2图形库练习
然后在usart.c文件中添加如下代码(添加头文件#include "stdio.h")。
/* USER CODE BEGIN 1 */
int fputc(int ch,FILE *f){
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
/* USER CODE END 1 */
main.c文件修改
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "u8g2.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include<stdio.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
//温
static const unsigned char wen[] =
{0x00,0x00,0xC4,0x1F,0x48,0x10,0x48,0x10,0xC1,0x1F,0x42,0x10,0x42,0x10,0xC8,0x1F,0x08,0x00,0xE4,0x3F,0x27,0x25,0x24,0x25,0x24,0x25,0x24,0x25,0xF4,0x7F,0x00,0x00};
//湿
static const unsigned char shi[] ={0x00,0x00,0xE4,0x1F,0x28,0x10,0x28,0x10,0xE1,0x1F,0x22,0x10,0x22,0x10,0xE8,0x1F,0x88,0x04,0x84,0x04,0x97,0x24,0xA4,0x14,0xC4,0x0C,0x84,0x04,0xF4,0x7F,0x00,0x00};
//度
static const unsigned char du[] ={0x80,0x00,0x00,0x01,0xFC,0x7F,0x44,0x04,0x44,0x04,0xFC,0x3F,0x44,0x04,0x44,0x04,0xC4,0x07,0x04,0x00,0xF4,0x0F,0x24,0x08,0x42,0x04,0x82,0x03,0x61,0x0C,0x1C,0x70};
//待
static const unsigned char dai[]={0x10,0x02,0x10,0x02,0x08,0x02,0xC4,0x3F,0x12,0x02,0x10,0x02,0xE8,0x7F,0x0C,0x08,0x0A,0x08,0xE9,0x7F,0x08,0x08,0x48,0x08,0x88,0x08,0x88,0x08,0x08,0x0A,0x08,0x04};
//检
static const unsigned char jian[]={0x08,0x02,0x08,0x02,0x08,0x05,0x08,0x05,0xBF,0x08,0x48,0x10,0xAC,0x6F,0x1C,0x00,0x2A,0x11,0x0A,0x12,0x49,0x12,0x88,0x0A,0x88,0x08,0x08,0x04,0xE8,0x7F,0x08,0x00};
//测
static const unsigned char che[]={0x00,0x20,0xE4,0x23,0x28,0x22,0x28,0x2A,0xA1,0x2A,0xA2,0x2A,0xA2,0x2A,0xA8,0x2A,0xA8,0x2A,0xA4,0x2A,0xA7,0x2A,0x84,0x20,0x44,0x21,0x44,0x22,0x24,0x28,0x10,0x10};
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void oled_write(int temperature,int humidity){
char t[5]; // 创建一个足够大的字符数组来存储转换后的数字
char h[5];
double t1=( double)temperature;
double h1=(double)humidity;
sprintf(t, "%.2f",t1/10 ); // 使用sprintf将int变量转换为字符串
sprintf(h, "%.2f",h1/10);
u8g2_t u8g2;
u8g2Init(&u8g2);
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//设置字体格式
u8g2_DrawXBMP(&u8g2,16,0,16,16,wen);//(参数顺序依次是,结构体、x、y、字宽、字高、储存要显示的字点阵的数组)
u8g2_DrawXBMP(&u8g2,32,0,16,16,du);
u8g2_DrawStr(&u8g2,48,16,":");
u8g2_DrawXBMP(&u8g2,16,32,16,16,shi);
u8g2_DrawXBMP(&u8g2,32,32,16,16,du);
u8g2_DrawStr(&u8g2,48,48,":");
u8g2_DrawUTF8(&u8g2,55,16,t);
u8g2_DrawUTF8(&u8g2,55,48,h);
u8g2_SendBuffer(&u8g2);
}
void oled_write_init(){
u8g2_t u8g2;
u8g2Init(&u8g2);
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//设置字体格式
u8g2_DrawXBMP(&u8g2,16,0,16,16,wen);//(参数顺序依次是,结构体、x、y、字宽、字高、储存要显示的字点阵的数组)
u8g2_DrawXBMP(&u8g2,32,0,16,16,du);
u8g2_DrawStr(&u8g2,48,16,":");
u8g2_DrawXBMP(&u8g2,16,32,16,16,shi);
u8g2_DrawXBMP(&u8g2,32,32,16,16,du);
u8g2_DrawStr(&u8g2,48,48,":");
u8g2_DrawXBMP(&u8g2,58,0,16,16,dai);
u8g2_DrawXBMP(&u8g2,74,0,16,16,jian);
u8g2_DrawXBMP(&u8g2,90,0,16,16,che);
u8g2_DrawXBMP(&u8g2,58,32,16,16,dai);
u8g2_DrawXBMP(&u8g2,74,32,16,16,jian);
u8g2_DrawXBMP(&u8g2,90,32,16,16,che);
u8g2_SendBuffer(&u8g2);
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint32_t CT_data[2]={0,0};
volatile int c1,t1;
Delay_1ms(500);
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
MX_TIM1_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
//初始化AHT20
AHT20_Init();
Delay_1ms(500);
u8g2_t u8g2;
u8g2Init(&u8g2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
oled_write_init();
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("正在检测");
for(int i=0;i<10;i++)
{
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("等待");
for(int i=0;i<10;i++)
{
HAL_Delay(100);
printf(".");
}
printf("\r\n");
HAL_Delay(1000);
oled_write(t1,c1);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
五、实验结果
六、总结
本次STM32编程练习结合了串口通信、AHT20的温湿度检测和u8g2的oled显示,让我学到了很多。
七、参考资料
stm32通过I2C接口实现温湿度(AHT20)的采集
I2C总线通信协议及实操stm32通过I2C实现温湿度(AHT20)采集
STM32F103基于I2C协议的AHT20温湿度传感器的数据采集(HAL库,提供源码)