一、前言 1、簡介 回顧上一篇UART發送當中,已經講解瞭如何實現UART的發送操作了,接下來這一篇將會繼續講解如何實現UART的接收操作。 2、UART簡介 嵌入式開發中,UART串口通信協議是我們常用的通信協議之一,全稱叫做通用非同步收發傳輸器(Universal Asynchronous Rec ...
一、前言
1、簡介
回顧上一篇UART發送當中,已經講解瞭如何實現UART的發送操作了,接下來這一篇將會繼續講解如何實現UART的接收操作。
2、UART簡介
嵌入式開發中,UART串口通信協議是我們常用的通信協議之一,全稱叫做通用非同步收發傳輸器(Universal Asynchronous Receiver/Transmitter)。
3、準備工作
在UART詳解中已經有了詳細的說明,按照裡面的說明即可。
註:
建議每次編寫好一個相關功能且測試功能成功使用後,保存備份並壓縮成一份Demo常式,方便日後有需要的時候可以直接使用。
例如:
二、CubeMx配置及函數說明
說明:
如果有看過我寫的UART發送的兄弟姐妹們應該會知道,在UART發送和UART詳解中的CubeMx配置都是一樣的。
但這一次不同,會在原本配置CubeMx的基礎上,添加一些UART的中斷配置來實現中斷接收操作。
1、CubeMx配置
1)按照UART詳解配置UART(若配置過,可以繼續使用)
2)使能串口中斷
3)設置中斷優先順序(如果沒開啟其他中斷,那就預設即可,直接跳過)
4)代碼生成(點擊前最好把原本的工程關掉,不然有可能會有問題)
2、函數說明
1)CubeMx生成的UART初始化(在usart.c中)
說明:
會與上一篇UART發送的UART初始化有所不同,因為在這一篇我們開啟了中斷處理,簡單瞭解一下即可。
1 UART_HandleTypeDef huart1;
2
3 /* USART1 init function */
4
5 void MX_USART1_UART_Init(void)
6 {
7
8 huart1.Instance = USART1;
9 huart1.Init.BaudRate = 115200;
10 huart1.Init.WordLength = UART_WORDLENGTH_8B;
11 huart1.Init.StopBits = UART_STOPBITS_1;
12 huart1.Init.Parity = UART_PARITY_NONE;
13 huart1.Init.Mode = UART_MODE_TX_RX;
14 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
15 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
16 if (HAL_UART_Init(&huart1) != HAL_OK)
17 {
18 Error_Handler();
19 }
20
21 }
22
23 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
24 {
25
26 GPIO_InitTypeDef GPIO_InitStruct = {0};
27 if(uartHandle->Instance==USART1)
28 {
29 /* USER CODE BEGIN USART1_MspInit 0 */
30
31 /* USER CODE END USART1_MspInit 0 */
32 /* USART1 clock enable */
33 __HAL_RCC_USART1_CLK_ENABLE();
34
35 __HAL_RCC_GPIOA_CLK_ENABLE();
36 /**USART1 GPIO Configuration
37 PA9 ------> USART1_TX
38 PA10 ------> USART1_RX
39 */
40 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
41 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
42 GPIO_InitStruct.Pull = GPIO_PULLUP;
43 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
44 GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
45 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
46
47 /* USART1 interrupt Init */
48 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
49 HAL_NVIC_EnableIRQ(USART1_IRQn);
50 /* USER CODE BEGIN USART1_MspInit 1 */
51
52 /* USER CODE END USART1_MspInit 1 */
53 }
54 }
55
56 void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
57 {
58
59 if(uartHandle->Instance==USART1)
60 {
61 /* USER CODE BEGIN USART1_MspDeInit 0 */
62
63 /* USER CODE END USART1_MspDeInit 0 */
64 /* Peripheral clock disable */
65 __HAL_RCC_USART1_CLK_DISABLE();
66
67 /**USART1 GPIO Configuration
68 PA9 ------> USART1_TX
69 PA10 ------> USART1_RX
70 */
71 HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
72
73 /* USART1 interrupt Deinit */
74 HAL_NVIC_DisableIRQ(USART1_IRQn);
75 /* USER CODE BEGIN USART1_MspDeInit 1 */
76
77 /* USER CODE END USART1_MspDeInit 1 */
78 }
79 }
UART init
2)CubeMx生成的UART中斷處理函數(在stm32f4xx_it.c中)
說明:
當USART1發生中斷事件時,程式會進行該函數,所以我們會在這個函數編寫好程式,來處理我們的中斷事件。
1 /** 2 * @brief This function handles USART1 global interrupt. 3 */ 4 void USART1_IRQHandler(void) 5 { 6 /* USER CODE BEGIN USART1_IRQn 0 */ 7 8 /* USER CODE END USART1_IRQn 0 */ 9 HAL_UART_IRQHandler(&huart1); 10 /* USER CODE BEGIN USART1_IRQn 1 */ 11 12 /* USER CODE END USART1_IRQn 1 */ 13 }
3)HAL庫函數HAL_UART_Transmit(在stm32f4xx_hal_uart.c中)
說明:
該函數能夠通過huart串口發送Size位pData數據。
參數說明:
huart :選擇用來發送的UART串口
pData :指向將要發送的數據的指針
Size :發送數據的大小
Timeout:超時時間
1 /**
2 * @brief Sends an amount of data in blocking mode.
3 * @param huart Pointer to a UART_HandleTypeDef structure that contains
4 * the configuration information for the specified UART module.
5 * @param pData Pointer to data buffer
6 * @param Size Amount of data to be sent
7 * @param Timeout Timeout duration
8 * @retval HAL status
9 */
10 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
11 {
12 uint16_t *tmp;
13 uint32_t tickstart = 0U;
14
15 /* Check that a Tx process is not already ongoing */
16 if (huart->gState == HAL_UART_STATE_READY)
17 {
18 if ((pData == NULL) || (Size == 0U))
19 {
20 return HAL_ERROR;
21 }
22
23 /* Process Locked */
24 __HAL_LOCK(huart);
25
26 huart->ErrorCode = HAL_UART_ERROR_NONE;
27 huart->gState = HAL_UART_STATE_BUSY_TX;
28
29 /* Init tickstart for timeout managment */
30 tickstart = HAL_GetTick();
31
32 huart->TxXferSize = Size;
33 huart->TxXferCount = Size;
34 while (huart->TxXferCount > 0U)
35 {
36 huart->TxXferCount--;
37 if (huart->Init.WordLength == UART_WORDLENGTH_9B)
38 {
39 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
40 {
41 return HAL_TIMEOUT;
42 }
43 tmp = (uint16_t *) pData;
44 huart->Instance->DR = (*tmp & (uint16_t)0x01FF);
45 if (huart->Init.Parity == UART_PARITY_NONE)
46 {
47 pData += 2U;
48 }
49 else
50 {
51 pData += 1U;
52 }
53 }
54 else
55 {
56 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
57 {
58 return HAL_TIMEOUT;
59 }
60 huart->Instance->DR = (*pData++ & (uint8_t)0xFF);
61 }
62 }
63
64 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
65 {
66 return HAL_TIMEOUT;
67 }
68
69 /* At end of Tx process, restore huart->gState to Ready */
70 huart->gState = HAL_UART_STATE_READY;
71
72 /* Process Unlocked */
73 __HAL_UNLOCK(huart);
74
75 return HAL_OK;
76 }
77 else
78 {
79 return HAL_BUSY;
80 }
81 }
HAL_UART_Transmit
4)HAL庫函數HAL_UART_Receive(在stm32f4xx_hal_uart.c中)
說明:
該函數能夠通過huart串口接收Size位pData數據。
參數說明:
- huart :選擇用來接收的UART串口
- pData :指向將要存放數據的指針
- Size :接收數據的大小
- Timeout:超時時間
1 /**
2 * @brief Receives an amount of data in blocking mode.
3 * @param huart Pointer to a UART_HandleTypeDef structure that contains
4 * the configuration information for the specified UART module.
5 * @param pData Pointer to data buffer
6 * @param Size Amount of data to be received
7 * @param Timeout Timeout duration
8 * @retval HAL status
9 */
10 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
11 {
12 uint16_t *tmp;
13 uint32_t tickstart = 0U;
14
15 /* Check that a Rx process is not already ongoing */
16 if (huart->RxState == HAL_UART_STATE_READY)
17 {
18 if ((pData == NULL) || (Size == 0U))
19 {
20 return HAL_ERROR;
21 }
22
23 /* Process Locked */
24 __HAL_LOCK(huart);
25
26 huart->ErrorCode = HAL_UART_ERROR_NONE;
27 huart->RxState = HAL_UART_STATE_BUSY_RX;
28
29 /* Init tickstart for timeout managment */
30 tickstart = HAL_GetTick();
31
32 huart->RxXferSize = Size;
33 huart->RxXferCount = Size;
34
35 /* Check the remain data to be received */
36 while (huart->RxXferCount > 0U)
37 {
38 huart->RxXferCount--;
39 if (huart->Init.WordLength == UART_WORDLENGTH_9B)
40 {
41 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
42 {
43 return HAL_TIMEOUT;
44 }
45 tmp = (uint16_t *) pData;
46 if (huart->Init.Parity == UART_PARITY_NONE)
47 {
48 *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
49 pData += 2U;
50 }
51 else
52 {
53 *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
54 pData += 1U;
55 }
56
57 }
58 else
59 {
60 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
61 {
62 return HAL_TIMEOUT;
63 }
64 if (huart->Init.Parity == UART_PARITY_NONE)
65 {
66 *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
67 }
68 else
69 {
70 *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
71 }
72
73 }
74 }
75
76 /* At end of Rx process, restore huart->RxState to Ready */
77 huart->RxState = HAL_UART_STATE_READY;
78
79 /* Process Unlocked */
80 __HAL_UNLOCK(huart);
81
82 return HAL_OK;
83 }
84 else
85 {
86 return HAL_BUSY;
87 }
88 }
HAL_UART_Receive
三、代碼編寫:實現UART接收
1、直接接收(不建議)
1)在main主函數中定義一個變數,負責接收數據
1 /* USER CODE BEGIN 1 */ 2 unsigned char uRx_Data = 0; 3 /* USER CODE END 1 */
2)在main主函數while迴圈中調用HAL庫UART接收函數
1 /* Infinite loop */ 2 /* USER CODE BEGIN WHILE */ 3 while (1) 4 { 5 /* 判斷是否接收成功 */ 6 if(HAL_UART_Receive(&huart1, &uRx_Data, 1, 1000) == HAL_OK) 7 { 8 /* 將接收成功的數據通過串口發出來 */ 9 HAL_UART_Transmit(&huart1, &uRx_Data, 1, 0xffff); 10 } 11 12 /* USER CODE END WHILE */ 13 14 /* USER CODE BEGIN 3 */ 15 } 16 /* USER CODE END 3 */
整個main函數如下:
1 /** 2 * @brief The application entry point. 3 * @retval int 4 */ 5 int main(void) 6 { 7 /* USER CODE BEGIN 1 */ 8 unsigned char uRx_Data = 0; 9 /* USER CODE END 1 */ 10 11 12 /* MCU Configuration--------------------------------------------------------*/ 13 14 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 15 HAL_Init(); 16 17 /* USER CODE BEGIN Init */ 18 19 /* USER CODE END Init */ 20 21 /* Configure the system clock */ 22 SystemClock_Config(); 23 24 /* USER CODE BEGIN SysInit */ 25 26 /* USER CODE END SysInit */ 27 28 /* Initialize all configured peripherals */ 29 MX_GPIO_Init(); 30 MX_USART1_UART_Init(); 31 /* USER CODE BEGIN 2 */ 32 33 /* USER CODE END 2 */ 34 35 /* Infinite loop */ 36 /* USER CODE BEGIN WHILE */ 37 while (1) 38 { 39 /* 判斷是否接收成功 */ 40 if(HAL_UART_Receive(&huart1, &uRx_Data, 1, 1000) == HAL_OK) 41 { 42 /* 將接收成功的數據通過串口發出來 */ 43 HAL_UART_Transmit(&huart1, &uRx_Data, 1, 0xffff); 44 } 45 46 /* USER CODE END WHILE */ 47 48 /* USER CODE BEGIN 3 */ 49 } 50 /* USER CODE END 3 */ 51 }
3)編譯、下載燒寫
4)實現效果(接收到數據後,調用UART發送函數將數據發送到電腦)
說明:
這種接收方式是直接在main函數里的while迴圈里不斷接收,會嚴重占用程式的進程,且接收較長的數據時,會發生接收錯誤,如下:
2、中斷接收(接收併發送)(不推薦)
1)在HAL_UART_MspInit(在usart.c中)使能接收中斷
1 /* USER CODE BEGIN USART1_MspInit 1 */ 2 __HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE); 3 /* USER CODE END USART1_MspInit 1 */
整個HAL_UART_MspInit函數如下:
1 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) 2 { 3 4 GPIO_InitTypeDef GPIO_InitStruct = {0}; 5 if(uartHandle->Instance==USART1) 6 { 7 /* USER CODE BEGIN USART1_MspInit 0 */ 8 9 /* USER CODE END USART1_MspInit 0 */ 10 /* USART1 clock enable */ 11 __HAL_RCC_USART1_CLK_ENABLE(); 12 13 __HAL_RCC_GPIOA_CLK_ENABLE(); 14 /**USART1 GPIO Configuration 15 PA9 ------> USART1_TX 16 PA10 ------> USART1_RX 17 */ 18 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; 19 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 20 GPIO_InitStruct.Pull = GPIO_PULLUP; 21 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 22 GPIO_InitStruct.Alternate = GPIO_AF7_USART1; 23 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 24 25 /* USART1 interrupt Init */ 26 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); 27 HAL_NVIC_EnableIRQ(USART1_IRQn); 28 /* USER CODE BEGIN USART1_MspInit 1 */ 29 __HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE); 30 /* USER CODE END USART1_MspInit 1 */ 31 } 32 }
2)在USART1_IRQHandler(在stm32f4xx_it.c中)定義一個變數,負責接收數據
1 unsigned char uRx_Data = 0;
3)在USART1_IRQHandler(在stm32f4xx_it.c中)調用HAL庫的UART接收函數以及發送函數
1 /* -1- 接收 */ 2 HAL_UART_Receive(&huart1, &uRx_Data, 1, 1000); 3 /* -2- 將接收成功的數據通過串口發出去 */ 4 HAL_UART_Transmit(&huart1, &uRx_Data, 1, 0xffff);
整個USART1_IRQHandler(在stm32f4xx_it.c中)函數如下:
1 /** 2 * @brief This function handles USART1 global interrupt. 3 */ 4 void USART1_IRQHandler(void) 5 { 6 /* USER CODE BEGIN USART1_IRQn 0 */ 7 unsigned char uRx_Data; 8 9 /* -1- 接收 */ 10 HAL_UART_Receive(&huart1, &uRx_Data, 1, 1000); 11 /* -2- 將接收成功的數據通過串口發出去 */ 12 HAL_UART_Transmit(&huart1, &uRx_Data, 1, 0xffff); 13 14 /* USER CODE END USART1_IRQn 0 */ 15 HAL_UART_IRQHandler(&huart1); 16 /* USER CODE BEGIN USART1_IRQn 1 */ 17 18 /* USER CODE END USART1_IRQn 1 */ 19 }
4)編譯、下載燒寫
5)實現效果(接收到數據後,調用UART發送函數將數據發送到電腦)
說明:
相對於前面的直接接收方式,該中斷接收方式就顯得特別人性化了,在沒有什麼特別事件的時候,單片機會按照原本的程式運行著,等到有數據從UART串口發送過來時,會馬上進入UART串口的中斷處理函數中,完成相應的中斷處理操作,完成後會退出中斷函數,並繼續原本在進行的程式,這樣就不會占用單片機程式太多的進程了。
但仍會發生前面直接接收方式的接收異常狀況,主要原因是,在中斷處理函數中,我們在接收了數據後並緊接著作出發送的操作,這會出現一個狀況,還沒來得及將上一次接收到的數據發送出去,就進入下一次接收的中斷,然而導致失去了一些數據了。
3、中斷接收(先接收完,後處理)(推薦)
說明:
這種接收方式,是在方式2的基礎上稍作改進的,較於前兩種接收方式,是更好的一種接收方式,不會給原本的程式進程造成太大影響。還可以先接收全部數據(提示:通過定義一個較大的數組來存儲),再將數據進行處理,這樣能確保接收數據的完整性,並能將數據進行有效的處理、分析。
既然這種方式明顯會好一點,那為什麼一開始不用這個方式呢?因為通過前面兩種方法,可以更容易明白UART接收的操作。
而這次就只要在方式2的基礎上作出一些簡單的修改就可以了。
1)在HAL_UART_MspInit(在usart.c中)使能接收中斷(與方式2相同)
1 /* USER CODE BEGIN USART1_MspInit 1 */ 2 __HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE); 3 /* USER CODE END USART1_MspInit 1 */
整個HAL_UART_MspInit(在usart.c中)函數如下:
1 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) 2 { 3 4 GPIO_InitTypeDef GPIO_InitStruct = {0}; 5 if(uartHandle->Instance==USART1) 6 { 7 /* USER CODE BEGIN USART1_MspInit 0 */ 8 9 /* USER CODE END USART1_MspInit 0 */ 10 /* USART1 clock enable */ 11 __HAL_RCC_USART1_CLK_ENABLE(); 12 13 __HAL_RCC_GPIOA_CLK_ENABLE(); 14 /**USART1 GPIO Configuration 15 PA9 ------> USART1_TX 16 PA10 ------> USART1_RX 17 */ 18 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; 19 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 20 GPIO_InitStruct.Pull = GPIO_PULLUP; 21 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 22 GPIO_InitStruct.Alternate = GPIO_AF7_USART1; 23 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 24 25 /* USART1 interrupt Init */ 26 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); 27 HAL_NVIC_EnableIRQ(USART1_IRQn); 28 /* USER CODE BEGIN USART1_MspInit 1 */ 29 __HAL_UART_ENABLE_IT(uartHandle, UART_IT_RXNE); 30 /* USER CODE END USART1_MspInit 1 */ 31 } 32 }
2)在USART1_IRQHandler(在stm32f4xx_it.c中)定義三個靜態變數
1 static unsigned char uRx_Data[1024] = {0} ; //存儲數組 2 static unsigned char * pRx_Data = uRx_Data; //指向存儲數組將要存儲數據的位 3 static unsigned char uLength = 0 ; //接收數據長度
3)在USART1_IRQHandler(在stm32f4xx_it.c中)調用HAL庫的UART接收函數以及發送函數
註:
如下的第2、3步都可以根據自身要求進行改進。
- 第2步:判斷接收結束條件,這個可以根據自己想要接收何種類型的數據而定。
- 第3步:數據處理,大家可以在這一步執行自己想要對數據做的一些操作,我這裡只是將接收到的數據重新發送出去而已。
1 /* -1- 接收數據 */ 2 HAL_UART_Receive(&huart1, pRx_Data, 1, 1000); 3 4 /* -2- 判斷數據結尾 */ 5 if(*pRx_Data == '\n') 6 { 7 /* -3- 將接收成功的數據通過串口發出去 */ 8 HAL_UART_Transmit(&huart1, uRx_Data, uLength, 0xffff); 9 10 /* -4- 初始化指針和數據長度 */ 11 pRx_Data = uRx_Data; //重新指向數組起始位置 12 uLength = 0; //長度清零 13 } 14 /* -5- 若未結束,指針往下一位移動,長度自增一 */ 15 else 16 { 17 pRx_Data++; 18 uLength++; 19 }
整個USART1_IRQHandler(在stm32f4xx_it.c中)函數如下:
1 /** 2 * @brief This function handles USART1 global interrupt. 3 */ 4 void USART1_IRQHandler(void) 5 { 6 /* USER CODE BEGIN USART1_IRQn 0 */ 7 static unsigned char uRx_Data[1024] = {0} ; //存儲數組 8 static unsigned char * pRx_Data = uRx_Data; //指向存儲數組將要存儲數據的位 9 static unsigned char uLength = 0 ; //接收數據長度 10 11 /* -1- 接收數據 */ 12 HAL_UART_Receive(&huart1, pRx_Data, 1, 1000); 13 14 /* -2- 判斷數據結尾 */ 15 if(*pRx_Data == '\n') 16 { 17 /* -3- 將接收成功的數據通過串口發出去 */ 18 HAL_UART_Transmit(&huart1, uRx_Data, uLength, 0xffff); 19 20 /* -4- 初始化指針和數據長度 */ 21 pRx_Data = uRx_Data; //重新指向數組起始位置 22 uLength = 0; //長度清零 23 } 24 /* -5- 若未結束,指針往下一位移動,長度自增一 */ 25 else 26 { 27 pRx_Data++; 28 uLength++; 29 } 30 31 32 /* USER CODE END USART1_IRQn 0 */ 33 HAL_UART_IRQHandler(&huart1); 34 /* USER CODE BEGIN USART1_IRQn 1 */ 35 36 /* USER CODE END USART1_IRQn 1 */ 37 }
4)編譯、下載燒寫
5)實現效果(接收到數據後,調用UART發送函數將數據發送到電腦)
四、結尾
1、總結
這一篇博客帶來的是兩種簡單的接收方式(方式1:直接接收、方式2:中斷接收1),還有一種接收方式(方式3:中斷接收2),並實現了接收的操作。
但前面兩種方式是不推薦的,因為在接收數據的時候,建議程式只在負責接收程式,直至接收完畢為止,數據接收完畢再進入自己處理數據的函數內。
除了上面的方法,還有DMA接收方法沒介紹,這裡先不說了。
整體來說,自我感覺還是講解得比較清楚得,如果還有對於此篇博客不懂之處,可以在下方評論留言提問,我會儘快回覆的。
2、後續
待補充……
~
~
~
~
感謝閱讀~
歡迎大家關註我的博客,一起分享嵌入式知識~