一、IIC总线
1、IIC总线概念
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。由于其管脚少,硬件实现简单,可扩展性强等特点,因此被广泛的使用在各大集成芯片内。
1.1、IIC总线分类
作为用户如何使用IIC?那就首先明确IIC的分类,从使用上看,可以分为硬件IIC和软件IIC
(1)硬件IIC
硬件IIC是指对于一些高度集成化的芯片中集成了IIC总线,例如:STM32单片机芯片就集成了IIC总线(类似于AHB总线、APB总线等等);用户使用硬件IIC相对来说操作简单,只需要在芯片上配置IIC总线(例如:在STM32CubeMX/STM32CubeIDE和上配置即可生成IIC初始化代码)之后,调用相应的IIC通信API即可实现IIC通信,这种方式虽简单,但是往往很多初学者掌握不了IIC总线时序,实际面试中很难回答出IIC总线时序,导致拿不到心仪的offer,故作者建议,在不考虑通信速率情况下(硬件算力始终比软件算力更快速),选择软件IIC来实现。
(2)软件IIC
软件IIC是指通过芯片的引脚来模拟IIC总线要求的时序,达到通过模拟IIC总线来完成IIC通信的目的。通过软件模拟IIC总线时序,用户可以深刻掌握IIC总线核心概念起始信号、数据有效性、应答/非应答信号、停止信号等,建议初学者通过这种方式来学习IIC总线,等IIC总线掌握成熟之后,后期可以根据项目情况选择硬件IIC还是软件IIC。
1.2、IIC总线引脚
IIC总线是由两根线组成,分别是时钟信号线和数据总线,IIC通信就靠这两根线实现
(1)时钟信号线
单词:serial clock,简称:SCL
该线是用于收、发双方两个设备之间数据的同步,即发送方发送数据时需要通过时钟信号线告诉接收方(例如:你要去你朋友家做客,你首先提前告诉你朋友,你朋友知道你要来之后,就开始准备饭菜等待你过来),从这里可以看出IIC总线通信实质上是一种同步通信(常用的串口UART是一种异步通信)
(2)数据总线
单词:serial data,简称:SDA
该线是用于收、发双方两个设备之间数据的传输,即发送方发送数据时需要通过数据总线发送给接收方(例如:你要去你朋友家做客,你提前告诉给你朋友时是通过什么方式告诉给你朋友,企鹅?微信?还是其他的通道等)
1.3、IIC总线寻址
IIC总线寻址方式默认有两种,分别是7位寻址和10位寻址,但大多数IIC总线设备采用7位寻址。
(1)7位
7位是指地址的表示为7个bit(即共2^7=128个设备地址),但有些厂家在生产设备时往往会将7bit里的部分bit设置为固定,剩余部分预留为可供用户编程来实现确定设备地址。
例如OLED屏幕地址如下:
b2-b7这6位厂家设置为固定,b1和b0是可编程位,用户可以根据实际情况对b0和b1进行编程设置。
(2)寻址
寻址是指寻找地址,即主设备与挂接在IIC总线上的设备进行通信时,需要知道设备的地址(注:挂接在IIC总线上设备有唯一地址,如果不唯一则通信就会紊乱,就好比一个班级里有2个名为张三的学生,老师请张三起来回答问题,到底是哪个张三起来回答问题?)。
(3)从设备地址表示
从设备地址由7bit+1bit读写位组成,如果读写位1bit是0,则表示主设备向从设备写数据,如果读写位1bit是1,则表示主设备从从设备读数据。
例如:
1.4、IIC总线数据传输大小
IIC总线数据传输是以字节byte为单位,即一个字节=8bit,每次传输的字节数量无限制,根据实际情况进行传输即可。
2、IIC总线时序
IIC总时序图如下:
2.1、起始信号(START Condition)
是指数据发送开始的信号。
时序步骤:
(1)SCL保持输出高电平
(2)SDA输出高电平变为输出低电平
2.2、停止信号(STOP Condition)
是指数据发送停止的信号。
时序步骤:
(1)SCL保持输出高电平
(2)SDA由输出低电平变为输出高电平
2.3、数据有效性(DATA Validation)
是指数据在收、发双方之间传输时什么时候是稳定可靠的,什么时候变化的。
时序步骤:
(1)SCL输出低电平
(2)SDA读取/输出电平
(3)SCL输出高电平
(4)SCL输出低电平
2.4、应答/非应答信号(ACK/NACK)
是指接收方是否接收到发送方发送的数据,需要给发送方的一个应答信号,如果接收到(也可以理解为数据接收正确),则应答(ACK);反之,则不应答(NACK)。根据IIC总线时序,如果SDA读取为低电平0,则是应答(ACK)信号,如果SDA读取为高电平1,则是非应答(NACK)信号
时序步骤:
(1)SCL输出低电平
(2)SDA读取/输出电平
(3)SCL输出高电平
(4)SCL输出低电平
3、AHT20概念
AHT20温湿度传感器嵌入了适于回流焊的双列扁平无引脚SMD封装,传感器输出经过标定的数字信号,标准IIC格式。AHT20配有ASIC专用芯片、MEMS半导体电容式湿度传感元件和片上温度传感元件,使其性能大大提升,每一个传感器都经过校准和测试,并印有产品批号。
广泛应用于智能家居、消费电子、医疗、汽车、工业、气象等领域,例如:暖通空调、除湿器和冰箱等家电产品,测试和检测设备及其他相关温湿度检测产品。
3.1、AHT20重置指令
指令代码:
0x70(AHT20设备写地址)
0xBA(AHT20软件复位指令)
3.2、AHT20初始化指令
指令代码:
0x70(AHT20设备写地址)
0xE1(AHT20特殊状态使用指令)
0x08(AHT20启动初始化过程指令)
0x00(AHT20辅助完成初始化过程指令)
3.3、AHT20状态字节表示
状态字节表示如图所示:
3.4、AHT20温度和湿度的表示
(1)湿度数据
AHT20采集的湿度数据由20位(20bit)组成,由高位向低位进行采集。
湿度计算公式:
(2)温度数据
AHT20采集的温度数据由20位(20bit)组成,由高位向低位进行采集。
温度计算公式:
3.5、AHT20温湿度测量流程
步骤流程如下所示:
(1)AHT20软件重置(发送指令:0x70、0xBA)
(2)AHT20初始化(发送指令:0x70、0xE1、0x08、0x00)
(3)AHT20读取温湿度数据,如下图流程
4、STM32F407ZET6测量AHT20温湿度源码
4.1、AHT20.h
/*
AHT20采用模拟IIC实现,初始需要在软件STM32CubeMX或CubeIDE上将PF0和PF1设置为推挽输出模式
SCL引脚:PF1
SDA引脚:PF0
*/
#include "stm32f4xx_hal.h"
#include "string.h"
#include "stdlib.h"
#include "math.h"
#define IIC_SCL_HIGH() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_1,GPIO_PIN_SET)
#define IIC_SCL_LOW() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_1,GPIO_PIN_RESET)
#define IIC_SDA_HIGH() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,GPIO_PIN_SET)
#define IIC_SDA_LOW() HAL_GPIO_WritePin(GPIOF,GPIO_PIN_0,GPIO_PIN_RESET)
#define IIC_SDA_READ() HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_0)
#define IIC_SDA_IN() {GPIOF->MODER &=~(3<<(0*2));GPIOF->MODER|=0<<0*2;}
#define IIC_SDA_OUT() {GPIOF->MODER &=~(3<<(0*2));GPIOF->MODER|=1<<0*2;}
//IIC时序API
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Master_ACK(void);
void IIC_Master_NACK(void);
unsigned char IIC_Slave_ACK_NACK(void);
void IIC_Write_Byte(unsigned char data);
unsigned char IIC_Read_Byte(void);
//AHT20API
struct AHT20_MSG
{
unsigned char status;//状态数据
int temp;//温度数据
int hum;//湿度数据
unsigned char crc;//校验数据
};
void AHT20_Reset(void);
void AHT20_Init(void);
void AHT20_Measure(void);
struct AHT20_MSG * AHT20_Read_Temp_Hum(void);
void AHT20_Hum_Add(int *hum_array,unsigned char data);
void AHT20_Temp_Add(int *temp_array,unsigned char data);
void AHT20_Hum_Temp_Split(int *hum_array,int *temp_array,unsigned char data);
void AHT20_Display_Hum_Temp(struct AHT20_MSG *AHT20_P);
4.1、AHT20.c
#include "AHT20.h"
/*
IIC起始信号
*/
void IIC_Start(void)
{
IIC_SCL_HIGH();
IIC_SDA_HIGH();
IIC_SDA_LOW();
}
/*
IIC停止信号
*/
void IIC_Stop(void)
{
IIC_SCL_HIGH();
IIC_SDA_LOW();
IIC_SDA_HIGH();
}
/*
IIC主机应答从机信号
*/
void IIC_Master_ACK(void)
{
IIC_SCL_LOW();
IIC_SDA_LOW();
IIC_SCL_HIGH();
IIC_SCL_LOW();
}
/*
IIC主机不应答从机信号
*/
void IIC_Master_NACK(void)
{
IIC_SCL_LOW();
IIC_SDA_HIGH();
IIC_SCL_HIGH();
IIC_SCL_LOW();
}
/*
IIC从机应答或不应答主机信号
返回值:unsigned char,返回的是从机的应答/不应答信号
*/
unsigned char IIC_Slave_ACK_NACK(void)
{
unsigned char ack=0;
IIC_SCL_LOW();
//将SDA引脚设置为输入
IIC_SDA_IN();
IIC_SCL_HIGH();
if(IIC_SDA_READ())
{
ack=1;
}
else
{
ack=0;
}
IIC_SCL_LOW();
//将SDA引脚设置为输出
IIC_SDA_OUT();
return ack;
}
/*
IIC主机向从机写一个字节数据
参数:data,写入的1byte数据
*/
void IIC_Write_Byte(unsigned char data)
{
for(int i=0;i<8;i++)
{
IIC_SCL_LOW();
if(data&0x80)
{
IIC_SDA_HIGH();
IIC_SCL_HIGH();
}
else
{
IIC_SDA_LOW();
IIC_SCL_HIGH();
}
IIC_SCL_LOW();
data=data<<1;
}
}
/*
IIC主机从从机读一个字节数据
返回值:unsigned char,返回的是读取到的1byte数据
*/
unsigned char IIC_Read_Byte(void)
{
unsigned char data=0;
IIC_SCL_LOW();
// //将引脚设置为输入
IIC_SDA_IN();
for(int i=0;i<8;i++)
{
IIC_SCL_HIGH();
data=data<<1;
if(IIC_SDA_READ())
{
data+=1;
}
IIC_SCL_LOW();
}
// //将引脚设置为输出
IIC_SDA_OUT();
return data;
}
/*
AHT20复位(重置)
*/
void AHT20_Reset(void)
{
IIC_Start();
IIC_Write_Byte(0x70);//AHT20从机地址
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0xBA);//复位命令
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Stop();
}
/*
AHT20初始化
*/
void AHT20_Init(void)
{
IIC_Start();
IIC_Write_Byte(0x70);//AHT20从机地址
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0xE1);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0x08);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0x00);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Stop();
}
/*
AHT20测量指令
*/
void AHT20_Measure(void)
{
IIC_Start();
IIC_Write_Byte(0x70);//AHT20从机地址
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0xAC);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0x33);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Write_Byte(0x00);
IIC_Slave_ACK_NACK();//等待从机应答
IIC_Stop();
}
/*
AHT20湿度数据的拼接函数
参数1:*hum_array,拼接后存储的湿度数据
参数2:data,待拼接的湿度数据
*/
void AHT20_Hum_Add(int *hum_array,unsigned char data)
{
for(int i=0;i<8;i++)
{
*hum_array=*hum_array<<1;
if(data&0x80)
{
*hum_array+=1;
}
data=data<<1;
}
}
/*
AHT20温度数据的拼接函数
参数1:*temp_array,拼接后存储的温度数据
参数2:data,待拼接的温度数据
*/
void AHT20_Temp_Add(int *temp_array,unsigned char data)
{
for(int i=0;i<8;i++)
{
*temp_array=*temp_array<<1;
if(data&0x80)
{
*temp_array+=1;
}
data=data<<1;
}
}
/*
AHT20温度和湿度拆分函数
参数1:*hum_array,拆分后存储的湿度数据
参数2:*temp_array,拆分后存储的温度数据
参数3:data,待拆分的数据
*/
void AHT20_Hum_Temp_Split(int *hum_array,int *temp_array,unsigned char data)
{
for(int i=0;i<8;i++)
{
if(i<=3)
{
//存储在湿度
*hum_array=*hum_array<<1;
if(data&0x80)
{
*hum_array+=1;
}
data=data<<1;
}
else
{
//存储在温度
*temp_array=*temp_array<<1;
if(data&0x80)
{
*temp_array+=1;
}
data=data<<1;
}
}
}
/*
读取AHT20温度和湿度数据
*/
struct AHT20_MSG * AHT20_Read_Temp_Hum(void)
{
struct AHT20_MSG *AHT20_P=(struct AHT20_MSG *)malloc(sizeof(struct AHT20_MSG));
if(!AHT20_P) //空间分配失败
{
return NULL;
}
AHT20_P->status=0;
AHT20_P->temp=0;
AHT20_P->hum=0;
AHT20_P->crc=0;
AHT20_Reset();//重置AHT20
HAL_Delay(10);
AHT20_Init();//初始化AHT20
HAL_Delay(10);
AHT20_Measure();//发送AHT20测量指令
HAL_Delay(80);
//读取AHT20数据
IIC_Start();
IIC_Write_Byte(0x71);//AHT20从机地址
IIC_Slave_ACK_NACK();//等待从机应答
unsigned data=IIC_Read_Byte();//读取1byte数据---状态数据
AHT20_P->status=data;
IIC_Master_ACK();
data=IIC_Read_Byte();//读取1byte数据---相对湿度的高8位数据
AHT20_Hum_Add(&AHT20_P->hum,data);//将读取出来的8位湿度数存储在湿度中
IIC_Master_ACK();
data=IIC_Read_Byte();//读取1byte数据---相对湿度的中8位数据
AHT20_Hum_Add(&AHT20_P->hum,data);//将读取出来的8位湿度数存储在湿度中
IIC_Master_ACK();
data=IIC_Read_Byte();//读取1byte数据---包含了湿度的低4位数据和温度的高4位数据
AHT20_Hum_Temp_Split(&AHT20_P->hum,&AHT20_P->temp,data);
IIC_Master_ACK();
data=IIC_Read_Byte();//读取1byte数据---相对温度的中8位数据
AHT20_Temp_Add(&AHT20_P->temp,data);
IIC_Master_ACK();
data=IIC_Read_Byte();//读取1byte数据---相对温度的中8位数据
AHT20_Temp_Add(&AHT20_P->temp,data);
IIC_Master_ACK();
//读取的是CRC(作者暂未用到)
data=IIC_Read_Byte();//读取1byte数据---CRC校验数据
AHT20_P->crc=data;
IIC_Master_NACK();
IIC_Stop();
return AHT20_P;
}
/*
显示AHT20读取到的温度和湿度数据
参数:AHT20_P,待显示的温度和湿度数据结构体指针
*/
void AHT20_Display_Hum_Temp(struct AHT20_MSG *AHT20_P)
{
if((AHT20_P->status&0x68)==0x08)
{
//打印和显示
printf("温度数据:%0.2f ℃\r\n",(AHT20_P->temp/pow(2,20))*200-50);
printf("湿度数据:%0.2f%%\r\n",(AHT20_P->hum/pow(2,20))*100);
}
free(AHT20_P);
HAL_Delay(1000);
}
4.3、main.c
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2025 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
#include "AHT20.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
int fputc(int c, FILE*f)
{
HAL_UART_Transmit(&huart1, (uint8_t*)&c,1,2);
return c;
}
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
*
* @retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* 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_USART1_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
AHT20_Display_Hum_Temp(AHT20_Read_Temp_Hum());
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
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(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pins : PF0 PF1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param file: The file name as string.
* @param line: The line in file as a number.
* @retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
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,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/