一、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引腳:PF1SDA引腳: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();//重置AHT20HAL_Delay(10);AHT20_Init();//初始化AHT20HAL_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****/