进阶篇 III [UART & USART]

项目&教程仓库-STM32-RoboMaster-


1.0 什么是UART和USART?有什么区别嘛?

1.1 UART定义

Universal Asynchronous Receiver/Transmitter:通用异步收发传输器,是一种串行异步收发协议,应用十分广泛。UART工作原理是将数据的二进制位一位一位的进行传输。在UART通讯协议中信号线上的状态位高电平代表’1’低电平代表’0’。当然两个设备使用UART串口通讯时,必须先约定好传输速率和一些数据位。分类属于并行传输,通常1字节数据的8位同时传输,结束后再继续传第2个字节,如同波浪一般,一波一波传输。

1.2 UART与USART的区别

  • UART

UART.png

​ 从图上可以看出整个传输过程。首先,在没有数据传输任务的时候,互相之间都是高电平 ( 1 ) ,然后,在有传输任务的时候,有1.5字节宽的起始信号,然后开始传输真正的信号,结束任务后,再给1.5字节宽的结束信号,最后回归没有数据传输的高电平。

  • USART <– Universal Synchronous/Asynchronous Receiver/Transmitter 通用同步异步接收发送器

USART.png

​ USART是UART的升级版,区别在于多了CLK线,在CLK没有信号的时候,就表明没有数据传输任务,有CLK信号的时候,就是正在传输信号,并且CLK提供了时钟同步功能,效验也更精确。但在实际使用的时候,其实并不会感觉UART和USART有很大的区别,除非接触非常底层的东西。

2.0 UART和USART在哪里?

RM A detail.jpg

UART detail.png

  • UART

    • UART7

    尽管大疆第一个图中标明的是USART7,但是其实只能使用异步通讯,也就是普通的UART。

    • UART8

    尽管大疆第一个图中标明的是USART8,但是其实只能使用异步通讯,也就是普通的UART。

  • USART

    • USART6
  • DJI ON BOARD SDK

    • USART3

    这个是大疆预留的官方接口,与一般的USART的接线不同,不能直接使用,也不推荐使用。

3.0 UART和USART有啥用?

  1. 与PC端通讯

    可以作为Debug的一种手段,或者监控数据流通的方法。

  2. 与其他设备通讯

    比如两个MCU互相通讯,也就是作为主从机来使用。

4.0 UART和USART的两种不同使用模式

4.1 Polling

1
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  • 参数
    • huart:指向UART引脚配置结构体
    • pData:指向需要传输的字符串
    • Size:传输数据的字节大小
    • Timeout:最大等待完成时限,单位为毫秒,也可以用HAL_MAX_DELAY来直接无限等待
  • 返回值
    • HAL_StatusTypeDef:如果传输完成,返回HAL_OK;如果没有在时限内完成,返回HAL_TIMEOUT;如果在传输出错,返回HAL_ERROR;如果该UART正在被占用,返回HAL_BUSY

1
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
  • 参数
    • huart:指向UART引脚配置结构体
    • pData:指向需要传输的字符串
    • Size:传输数据的字节大小
    • Timeout:最大等待完成时限,单位为毫秒,也可以用HAL_MAX_DELAY来直接无限等待
  • 返回值
    • HAL_StatusTypeDef:如果传输完成,返回HAL_OK;如果没有在时限内完成,返回HAL_TIMEOUT;如果在传输出错,返回HAL_ERROR;如果该UART正在被占用,返回HAL_BUSY

4.2 Interrupt

1
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
  • 参数
    • huart:指向UART引脚配置结构体
    • pData:指向需要传输的字符串
    • Size:传输数据的字节大小
  • 返回值
    • HAL_StatusTypeDef:如果传输完成,返回HAL_OK;如果在传输出错,返回HAL_ERROR;如果该UART正在被占用,返回HAL_BUSY

1
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
  • 参数
    • huart:指向UART引脚配置结构体
    • pData:指向需要传输的字符串
    • Size:传输数据的字节大小
  • 返回值
    • HAL_StatusTypeDef:如果传输完成,返回HAL_OK;如果在传输出错,返回HAL_ERROR;如果该UART正在被占用,返回HAL_BUSY

这里的函数并不是直接接收数据,而是表明开启UART的Interrupt模式
接收完数据后,该UART的Interrupt模式会自动关闭,需要再手动开启


1
2
3
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
......
}
  • 在写代码的时候,在main.c中创建HAL_UART_TxCpltCallback函数
  • 在该函数中填写UART发送结束后,需要执行的代码

1
2
3
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
......
}
  • 在写代码的时候,在main.c中创建HAL_UART_RxCpltCallback函数
  • 在该函数中填写UART接收结束后,需要执行的代码

5.0 练习项目

5.1 项目简介

  • 电脑控制LED灯:在电脑上按下r,反转红色LED状态,按下g,反转绿色LED状态,按下1~8,反转对应的LED1~8的状态,并且返回打印反转的LED灯号

5.2 芯片配置

  • 芯片视角

Chip for RM03.png

  • GPIO配置列表

GPIO for RM03.png

  • NVIC配置列表

NVIC for RM03.png

5.3 项目代码

  • 我只放了main.c,完整的工程文件可以在这里找到!

  • Src/main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* 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 ---------------------------------------------------------*/
UART_HandleTypeDef huart7;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_UART7_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
char readBuf[1];
/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
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_UART7_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart7,(uint8_t*)readBuf,1);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 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 = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** 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();
}
}

/**
* @brief UART7 Initialization Function
* @param None
* @retval None
*/
static void MX_UART7_Init(void)
{

/* USER CODE BEGIN UART7_Init 0 */

/* USER CODE END UART7_Init 0 */

/* USER CODE BEGIN UART7_Init 1 */

/* USER CODE END UART7_Init 1 */
huart7.Instance = UART7;
huart7.Init.BaudRate = 115200;
huart7.Init.WordLength = UART_WORDLENGTH_8B;
huart7.Init.StopBits = UART_STOPBITS_1;
huart7.Init.Parity = UART_PARITY_NONE;
huart7.Init.Mode = UART_MODE_TX_RX;
huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart7.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart7) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN UART7_Init 2 */

/* USER CODE END UART7_Init 2 */

}

/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOG, LD8_Pin|LD7_Pin|LD6_Pin|LD5_Pin
|LD4_Pin|LD3_Pin|LD2_Pin|LD1_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD_RED_GPIO_Port, LD_RED_Pin, GPIO_PIN_RESET);

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD_GREEN_GPIO_Port, LD_GREEN_Pin, GPIO_PIN_RESET);

/*Configure GPIO pins : LD8_Pin LD7_Pin LD6_Pin LD5_Pin
LD4_Pin LD3_Pin LD2_Pin LD1_Pin */
GPIO_InitStruct.Pin = LD8_Pin|LD7_Pin|LD6_Pin|LD5_Pin
|LD4_Pin|LD3_Pin|LD2_Pin|LD1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

/*Configure GPIO pin : LD_RED_Pin */
GPIO_InitStruct.Pin = LD_RED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD_RED_GPIO_Port, &GPIO_InitStruct);

/*Configure GPIO pin : LD_GREEN_Pin */
GPIO_InitStruct.Pin = LD_GREEN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD_GREEN_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle){
switch(readBuf[0]){
case 'r':
HAL_GPIO_TogglePin(LD_RED_GPIO_Port,LD_RED_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED_RED!\r\n",strlen("LED_RED!\r\n"),HAL_MAX_DELAY);
break;
case 'g':
HAL_GPIO_TogglePin(LD_GREEN_GPIO_Port,LD_GREEN_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED_GREEN!\r\n",strlen("LED_GREEN!\r\n"),HAL_MAX_DELAY);
break;
case '1':
HAL_GPIO_TogglePin(LD1_GPIO_Port,LD1_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED1!\r\n",strlen("LED1!\r\n"),HAL_MAX_DELAY);
break;
case '2':
HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED2!\r\n",strlen("LED2!\r\n"),HAL_MAX_DELAY);
break;
case '3':
HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED3!\r\n",strlen("LED3!\r\n"),HAL_MAX_DELAY);
break;
case '4':
HAL_GPIO_TogglePin(LD4_GPIO_Port,LD4_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED4!\r\n",strlen("LED4!\r\n"),HAL_MAX_DELAY);
break;
case '5':
HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED5!\r\n",strlen("LED5!\r\n"),HAL_MAX_DELAY);
break;
case '6':
HAL_GPIO_TogglePin(LD6_GPIO_Port,LD6_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED6!\r\n",strlen("LED6!\r\n"),HAL_MAX_DELAY);
break;
case '7':
HAL_GPIO_TogglePin(LD7_GPIO_Port,LD7_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED7!\r\n",strlen("LED7!\r\n"),HAL_MAX_DELAY);
break;
case '8':
HAL_GPIO_TogglePin(LD8_GPIO_Port,LD8_Pin);
HAL_UART_Transmit(&huart7,(uint8_t*)"LED8!\r\n",strlen("LED8!\r\n"),HAL_MAX_DELAY);
break;
}
HAL_UART_Receive_IT(&huart7,(uint8_t*)readBuf,1);
}
/* 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 */

/* 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****/

5.4 效果展示


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!