使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集
文章目录
- 一、什么是“软件I2C”和“硬件I2C”
- 1.1 什么是“软件I2C”
- 1.2 什么是“硬件I2C”
- 二、软件I2C和硬件I2C
- 2.1 软件模拟
- 2.2硬件I2C
- 三、配置STM32CubeMX
- 四、配置keil代码
- 4.1 创建文件
- 4.2 复制文件
- 4.3 在keil中添加文件
- 4.4 添加路径
- 4.5 代码修改
- 五、硬件连接
- 六、总结
一、什么是“软件I2C”和“硬件I2C”
1.1 什么是“软件I2C”
软件I2C (Software I2C)
软件I2C是通过软件代码模拟I2C协议的时序和信号来实现通信的。这种方法不依赖于特定的硬件I2C模块,因此几乎可以在任何微控制器上实现。以下是一些关键点:
-
灵活性高:由于是通过软件实现,可以在没有硬件I2C支持的设备上使用。
-
占用资源:软件I2C需要CPU周期来处理时序和数据传输,因此会占用更多的处理器时间,可能影响整体系统性能。
-
速度限制:受限于软件执行速度,通常不能达到硬件I2C的最高速率。
-
实现复杂度:需要编写代码来管理全部I2C时序,错误处理也需要额外的代码。
1.2 什么是“硬件I2C”
硬件I2C (Hardware I2C)
硬件I2C利用微控制器内置的I2C模块来实现通信。这种方式依赖于专门设计的硬件单元来处理I2C协议。以下是一些关键点:
-
效率高:硬件I2C模块独立于CPU运行,可以大幅减轻CPU负担,提高整体系统效率。
-
速度高:硬件I2C通常支持更高的通信速率,能够轻松达到I2C标准的最大速率(例如400kHz或更高)。
-
可靠性高:由硬件处理时序和协议,通常更加稳定和可靠。
-
配置简单:大多数微控制器提供易于使用的寄存器配置来启用和控制硬件I2C。
二、软件I2C和硬件I2C
想要控制STM32产生I2C方式的通讯,可以采用软件模拟或硬件I2C 这两种方式。
硬件I2C直接使用外设来控制引脚,可以减轻 CPU 的负担。不过使用硬件I2C时必须使用某些固定的引脚作为 SCL 和 SDA,软件模拟IIC则可以使用任意GPIO引脚,相对比较灵活。在本开发板中,由于 STM32RCT6 芯片引脚较少,资源比较紧张,在设计硬件时不方便使用硬件I2C指定的引脚连接外部设备(EEPROM 存储器芯片),所以在控制程序上只能使用软件模拟 I2C的方式。
2.1 软件模拟
所谓软件模拟,即直接使用 CPU 内核按照 IIC协议的要求控制 GPIO 输出高低电平。如控制产生IIC的起始信号时,先控制作为 SCL 线的 GPIO 引脚输出高电平,然后控制作为 SDA 线的 GPIO 引脚在此期间完成由高电平至低电平的切换,最后再控制 SCL 线切换为低电平,这样就输出了一个标准的IIC起始信号。
2.2硬件I2C
硬件I2C是指直接利用 STM32 芯片中的硬件I2C外设,该硬件I2C外设跟 USART串口外设类似,只要配置好对应的寄存器,外设就会产生标准串口协议的时序。使用它的IIC外设则可以方便地通过外设寄存器产生I2C协议方式的通讯,如初始化好I2C外设后,只需要把某寄存器位置 1,那么外设就会控制对应的 SCL 及 SDA 线自动产生IIC起始信号,而不需要内核直接控制引脚的电平。
三、配置STM32CubeMX
-
RCC设置:

-
USART1设置:

-
GPIO设置:

-
时钟设置:

-
I2C1设置:

四、配置keil代码
AHT20芯片代码官网下载
4.1 创建文件
在创建好的项目文件中创建一个新文件

4.2 复制文件
将在官网下载的文件复制到新建文件夹中

4.3 在keil中添加文件

4.4 添加路径

4.5 代码修改
- 修改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
- 修改AHT20-21_DEMO_V1_3.c
/*******************************************/
/*@版权所有:广州奥松电子有限公司 */
/*@作者:温湿度传感器事业部 */
/*@版本:V1.2 */
/*******************************************/
//#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=0;N<8;N++){SCL_Pin_Output_Low(); Delay_4us(); if(i&Data){SDA_Pin_Output_High();}else{SDA_Pin_Output_Low();} SCL_Pin_Output_High();Delay_4us();Data <<= 1;}SCL_Pin_Output_Low();SensorDelay_us(8); SDA_Pin_IN_FLOATING();SensorDelay_us(8);
} 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(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_15)) a=1;if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)) a=1;Byte = (Byte<<1)|a;//SCL_Pin_Output_Low();HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);Delay_5us();}SDA_Pin_IN_FLOATING();SensorDelay_us(8); return Byte;
}uint8_t Receive_ACK(void) //看AHT20是否有回复ACK
{uint16_t CNT;CNT = 0;SCL_Pin_Output_Low(); SDA_Pin_IN_FLOATING();SensorDelay_us(8); SCL_Pin_Output_High(); SensorDelay_us(8); while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)) && CNT < 100) CNT++;if(CNT == 100){return 0;}SCL_Pin_Output_Low(); SensorDelay_us(8); return 1;
}void Send_ACK(void) //主机回复ACK信号
{SCL_Pin_Output_Low(); SensorDelay_us(8); SDA_Pin_Output_Low();SensorDelay_us(8); SCL_Pin_Output_High(); SensorDelay_us(8);SCL_Pin_Output_Low(); SensorDelay_us(8);SDA_Pin_IN_FLOATING();SensorDelay_us(8);
}void Send_NOT_ACK(void) //主机不回复ACK
{SCL_Pin_Output_Low(); SensorDelay_us(8);SDA_Pin_Output_High();SensorDelay_us(8);SCL_Pin_Output_High(); SensorDelay_us(8); SCL_Pin_Output_Low(); SensorDelay_us(8);SDA_Pin_Output_Low();SensorDelay_us(8);
}void Stop_I2C(void) //一条协议结束
{SDA_Pin_Output_Low();SensorDelay_us(8);SCL_Pin_Output_High(); SensorDelay_us(8);SDA_Pin_Output_High();SensorDelay_us(8);
}uint8_t AHT20_Read_Status(void)//读取AHT20的状态寄存器
{uint8_t Byte_first; I2C_Start();AHT20_WR_Byte(0x71);Receive_ACK();Byte_first = AHT20_RD_Byte();Send_NOT_ACK();Stop_I2C();return Byte_first;
}uint8_t AHT20_Read_Cal_Enable(void) //查询cal enable位有没有使能
{uint8_t val = 0;//ret = 0,val = AHT20_Read_Status();if((val & 0x68)==0x08)return 1;else return 0;}void AHT20_SendAC(void) //向AHT20发送AC命令
{I2C_Start();AHT20_WR_Byte(0x70);Receive_ACK();AHT20_WR_Byte(0xac);//0xAC采集命令Receive_ACK();AHT20_WR_Byte(0x33);Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();Stop_I2C();}//CRC校验类型:CRC8/MAXIM
//多项式:X8+X5+X4+1
//Poly:0011 0001 0x31
//高位放到后面就变成 1000 1100 0x8c
//C现实代码:
uint8_t Calc_CRC8(uint8_t *message,uint8_t Num)
{uint8_t i;uint8_t byte;uint8_t crc=0xFF;for(byte=0; byte<Num; byte++){crc^=(message[byte]);for(i=8;i>0;--i){if(crc&0x80) crc=(crc<<1)^0x31;else crc=(crc<<1);}}return crc;
}void AHT20_Read_CTdata(uint32_t *ct) //没有CRC校验,直接读取AHT20的温度和湿度数据
{volatile uint8_t Byte_1th=0;volatile uint8_t Byte_2th=0;volatile uint8_t Byte_3th=0;volatile uint8_t Byte_4th=0;volatile uint8_t Byte_5th=0;volatile uint8_t Byte_6th=0;uint32_t RetuData = 0;uint16_t cnt = 0;AHT20_SendAC();//向AHT10发送AC命令Delay_1ms(80);//延时80ms左右 cnt = 0;while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态{SensorDelay_us(1508);if(cnt++>=100){break;}}I2C_Start();AHT20_WR_Byte(0x71);Receive_ACK();Byte_1th = AHT20_RD_Byte();//状态字,查询到状态为0x98,表示为忙状态,bit[7]为1;状态为0x1C,或者0x0C,或者0x08表示为空闲状态,bit[7]为0Send_ACK();Byte_2th = AHT20_RD_Byte();//湿度Send_ACK();Byte_3th = AHT20_RD_Byte();//湿度Send_ACK();Byte_4th = AHT20_RD_Byte();//湿度/温度Send_ACK();Byte_5th = AHT20_RD_Byte();//温度Send_ACK();Byte_6th = AHT20_RD_Byte();//温度Send_NOT_ACK();Stop_I2C();RetuData = (RetuData|Byte_2th)<<8;RetuData = (RetuData|Byte_3th)<<8;RetuData = (RetuData|Byte_4th);RetuData =RetuData >>4;ct[0] = RetuData;//湿度RetuData = 0;RetuData = (RetuData|Byte_4th)<<8;RetuData = (RetuData|Byte_5th)<<8;RetuData = (RetuData|Byte_6th);RetuData = RetuData&0xfffff;ct[1] =RetuData; //温度}void AHT20_Read_CTdata_crc(uint32_t *ct) //CRC校验后,读取AHT20的温度和湿度数据
{volatile uint8_t Byte_1th=0;volatile uint8_t Byte_2th=0;volatile uint8_t Byte_3th=0;volatile uint8_t Byte_4th=0;volatile uint8_t Byte_5th=0;volatile uint8_t Byte_6th=0;volatile uint8_t Byte_7th=0;uint32_t RetuData = 0;uint16_t cnt = 0;// uint8_t CRCDATA=0;uint8_t CTDATA[6]={0};//用于CRC传递数组AHT20_SendAC();//向AHT10发送AC命令Delay_1ms(80);//延时80ms左右 cnt = 0;while(((AHT20_Read_Status()&0x80)==0x80))//直到状态bit[7]为0,表示为空闲状态,若为1,表示忙状态{SensorDelay_us(1508);if(cnt++>=100){break;}}I2C_Start();AHT20_WR_Byte(0x71);Receive_ACK();CTDATA[0]=Byte_1th = AHT20_RD_Byte();//状态字,查询到状态为0x98,表示为忙状态,bit[7]为1;状态为0x1C,或者0x0C,或者0x08表示为空闲状态,bit[7]为0Send_ACK();CTDATA[1]=Byte_2th = AHT20_RD_Byte();//湿度Send_ACK();CTDATA[2]=Byte_3th = AHT20_RD_Byte();//湿度Send_ACK();CTDATA[3]=Byte_4th = AHT20_RD_Byte();//湿度/温度Send_ACK();CTDATA[4]=Byte_5th = AHT20_RD_Byte();//温度Send_ACK();CTDATA[5]=Byte_6th = AHT20_RD_Byte();//温度Send_ACK();Byte_7th = AHT20_RD_Byte();//CRC数据Send_NOT_ACK(); //注意: 最后是发送NAKStop_I2C();if(Calc_CRC8(CTDATA,6)==Byte_7th){RetuData = (RetuData|Byte_2th)<<8;RetuData = (RetuData|Byte_3th)<<8;RetuData = (RetuData|Byte_4th);RetuData =RetuData >>4;ct[0] = RetuData;//湿度RetuData = 0;RetuData = (RetuData|Byte_4th)<<8;RetuData = (RetuData|Byte_5th)<<8;RetuData = (RetuData|Byte_6th);RetuData = RetuData&0xfffff;ct[1] =RetuData; //温度}else{ct[0]=0x00;ct[1]=0x00;//校验错误返回值,客户可以根据自己需要更改}//CRC数据
}void AHT20_Init(void) //初始化AHT20
{ Init_I2C_Sensor_Port();I2C_Start();AHT20_WR_Byte(0x70);Receive_ACK();AHT20_WR_Byte(0xa8);//0xA8进入NOR工作模式Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();Stop_I2C();Delay_1ms(10);//延时10ms左右I2C_Start();AHT20_WR_Byte(0x70);Receive_ACK();AHT20_WR_Byte(0xbe);//0xBE初始化命令,AHT20的初始化命令是0xBE, AHT10的初始化命令是0xE1Receive_ACK();AHT20_WR_Byte(0x08);//相关寄存器bit[3]置1,为校准输出Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();Stop_I2C();Delay_1ms(10);//延时10ms左右
}
void JH_Reset_REG(uint8_t addr)
{uint8_t Byte_first,Byte_second,Byte_third;I2C_Start();AHT20_WR_Byte(0x70);//原来是0x70Receive_ACK();AHT20_WR_Byte(addr);Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();AHT20_WR_Byte(0x00);Receive_ACK();Stop_I2C();Delay_1ms(5);//延时5ms左右I2C_Start();AHT20_WR_Byte(0x71);//Receive_ACK();Byte_first = AHT20_RD_Byte();Send_ACK();Byte_second = AHT20_RD_Byte();Send_ACK();Byte_third = AHT20_RD_Byte();Send_NOT_ACK();Stop_I2C();Delay_1ms(10);//延时10ms左右I2C_Start();AHT20_WR_Byte(0x70);///Receive_ACK();AHT20_WR_Byte(0xB0|addr);//寄存器命令Receive_ACK();AHT20_WR_Byte(Byte_second);Receive_ACK();AHT20_WR_Byte(Byte_third);Receive_ACK();Stop_I2C();Byte_second=0x00;Byte_third =0x00;
}void AHT20_Start_Init(void)
{JH_Reset_REG(0x1b);JH_Reset_REG(0x1c);JH_Reset_REG(0x1e);
}
- 修改mian.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2022 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include<stdio.h>
#include "AHT20-21_DEMO_V1_3.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* 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 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 *//* 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_USART1_UART_Init();MX_DMA_Init();MX_I2C1_Init(); MX_USART1_UART_Init();/* USER CODE BEGIN 2 */AHT20_Init();Delay_1ms(500);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */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 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
在main.c和usart.c中添加头文件 #include “stdio.h” 之后,勾选 Target 中的 use MicroLIB
完成后点击编译

五、硬件连接

连接图如下:

六、总结
通过本次实验,熟悉了 STM32 I2C 外设的配置和使用,掌握了如何与外部传感器进行通信并采集数据。同时,了解了 AHT20 传感器的工作原理和数据格式
相关文章:
使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集
文章目录 一、什么是“软件I2C”和“硬件I2C”1.1 什么是“软件I2C”1.2 什么是“硬件I2C” 二、软件I2C和硬件I2C2.1 软件模拟2.2硬件I2C 三、配置STM32CubeMX四、配置keil代码4.1 创建文件4.2 复制文件4.3 在keil中添加文件4.4 添加路径4.5 代码修改 五、硬件连接六、总结 一…...
Huffman树——AcWing 148. 合并果子
目录 Huffman树 定义 运用情况 注意事项 解题思路 AcWing 148. 合并果子 题目描述 运行代码 代码思路 其它代码 代码思路 Huffman树 定义 它是一种最优二叉树。通过构建带权路径长度最小的二叉树,经常用于数据压缩等领域。 运用情况 在数据压缩中&a…...
05 Pytorch 数据读取 + 二分类模型
05 Pytorch 数据读取 二分类模型05 Pytorch 数据读取 二分类模型05 Pytorch 数据读取 二分类模型 01 数据读取 DataLoader(set作为参数) 02 Dataset 从哪读,怎么读? 功能:数据从哪里读取? 如何读取…...
数据仓库之Kappa架构
Kappa架构是一种简化的数据处理架构,旨在处理实时数据流,解决传统Lambda架构中批处理和实时处理的复杂性。Kappa架构完全基于流处理,不区分批处理和实时处理,所有数据都是通过流处理系统进行处理。以下是对Kappa架构的详细介绍&am…...
ReactNative进阶(二十八)Metro
文章目录 一、前言二、Metro生命周期2.1 解析(Resolution)2.2 转换(Transformation)2.3 序列化(Serialization) 三、拓展阅读 一、前言 众所周知,Metro 是 React Native 默认的 JavaScript 打包模块。对于前端项目,打包工具已有webpack(大而全ÿ…...
python爬虫入门到精通路线
当谈及Python爬虫从入门到精通的路线时,我们可以将其分为几个关键阶段,每个阶段都有其特定的学习目标和内容。以下是一个清晰的路线规划: 1. 入门阶段 基础知识 学习Python的基础语法、数据类型、控制流等。了解基本的网络协议(…...
Java 笔记:常见正则使用
文章目录 Java 笔记:常见正则使用正则简介常用匹配年月日的时间匹配手机号码校验 参考文章 Java 笔记:常见正则使用 正则简介 正则表达式定义了字符串的模式。 正则表达式可以用来搜索、编辑或处理文本。 正则表达式并不仅限于某一种语言,但…...
vue 2.0项目中使用tinymce富文本框遇到的问题
安装Tinymce 现在tinymce-vue最新版本是4.0,用的vue3.0的了,所以搭建的vue2.0项目要使用之前的版本 ( 安装指定版本 ). 首先安装tinymce的vue组件,因为没有注册服务 npm install tinymce/tinymce-vue2.0.0 -S接着安装tinymce: npm install…...
【STM32+FPGA】先进算力+强安全+边缘AI,64位STM32MP2聚焦工业4.0应用
工业应用数字化和智能化程度,是衡量新质生产力的重要标准。STM32最新一代64位微处理器STM32MP2凭借先进算力、丰富接口和高安全性,为高性能和高度互联的工业4.0应用赋能。 STM32MP2四大关键特性,为工业4.0应用赋能 STM32MP2系列的第一颗产品S…...
Git 和 TortoiseGit 安装和配置(图文详解)
使用git,需要在Windows上需要安装两个软件:1)Git 2)TortoiseGit 若需要,可以下载TortoiseGit汉化语言包。 注意:tortoiseGit是在安装了Git的基础上运行的,所以需要先安装Git,后安装…...
OpenAI CTO谈GPT-5将达博士生智力水平;斯坦福评估排名前十两款来自中国
🦉 AI新闻 🚀 OpenAI CTO谈GPT-5将达博士生智力水平 摘要:美国达特茅斯工程学院采访了OpenAI首席技术官米拉・穆拉蒂,她表示GPT-4的智力相当于高中生,而GPT-5将在一年半后发布,预计达到博士生水平。穆拉蒂…...
焦化超低排平台组成部分
焦化行业作为重工业的重要组成部分,其环保问题一直备受关注。近年来,随着环保意识的提升和技术的不断进步,朗观视觉焦化超低排平台应运而生,成为推动焦化行业绿色发展的重要力量。本文将深入剖析焦化超低排平台的组成部分…...
鸿蒙 navigation路由跳转,页面struct 下的生命周期、onShow、onHidden等不会触发问题
经常用安卓思维考虑问题,用习惯了Router方式跳转,但是官方推荐用 navigation,当然它有它的有点, 也有小瑕疵,用了api11 后 发现 navigation路由跳转 ,只要被它包裹的跳转到下页面的,有些生命周期…...
BUUCTF [CISCN2019 华北赛区 Day2 Web1] Hack World
1、通过题目,可以知道该题目为SQL注入类型: 2、判断注入类型为数字注入: 3、通过BP抓包,来判断注入点。 字典爆破发现常规的注入方式都被过滤。 4、因此可以尝试通过布尔盲注的方式来得到flag。编写脚本得到flag import requests…...
wsl2平台鸿蒙全仓docker编译环境快速创建方法
文章目录 1 文章适用范围:2 WSL环境安装3 镜像迁移非C盘4 Docker环境准备4.1 docker用户组和用户创建4.2 Docker环境配置4.2.1 Ubuntu下安装docker工具4.2.2 鸿蒙Docker环境安装4.2.3 鸿蒙全仓代码拉取编译 5 鸿蒙全仓代码的更新策略6 参考文献7 FAQ7.1 缺头文件xcr…...
商业秘密侵权
一、商业秘密侵权行为 (一)员工违规获取并使用企业后台用户行为数据构成商业秘密侵权 (二)离职员工将新单位“冒名顶替”为原单位构成对原单位商业秘密的侵犯 二、商业秘密侵权主体 (一)主体范围界定&a…...
高通安卓12-固件升级
下载步骤 第一步 格式化 「下载一次即可;能开机能下载的板子 忽略这一步,直接执行第二步即可」 QFIL工具配置为UFS类型,勾选Provision,如下图: Programmer选择prog_firehose_ddr.elf,Provision Xml选择prov…...
我的常见问题记录
1,maven在idea工具可以正常使用,在命令窗口执行出现问题 代码: E:\test-hello\simple-test>mvn clean compile [INFO] Scanning for projects... [WARNING] [WARNING] Some problems were encountered while building the effective model for org.consola:simple-test:jar…...
Python 3.12 环境搭建(Windows版)
目录 1. 下载Python 3.12安装包2. 安装Python 3.123. 验证安装5. (可选)配置其他开发工具 在Windows系统中搭建Python 3.11环境,可以按照以下步骤进行,以确保过程清晰且详细: 1. 下载Python 3.12安装包 打开浏览器&a…...
植物大战僵尸杂交版如何手动修改金币钻石数
前言 最近在玩植物大战僵尸杂交版,非常好玩,但是刷钻石真的好慢!只能在排山倒海里眼巴巴等着黄金吞噬者产钻石qaq 但是好歹咱是学CS的,怎会被这点困难难住!挑战不用修改器手动修改配置文件! 原参考文章&…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
CppCon 2015 学习:Time Programming Fundamentals
Civil Time 公历时间 特点: 共 6 个字段: Year(年)Month(月)Day(日)Hour(小时)Minute(分钟)Second(秒) 表示…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...
Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
