STM32F1与STM32CubeIDE快速入门-USART通过DMA进行数据接收与发送

USART通过DMA进行数据接收与发送

通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。

USART提供了一种灵活的方式,可以与需要行业标准 NRZ 异步串行数据格式的外部设备进行全双工数据交换。 USART使用小数波特率发生器提供非常广泛的波特率范围。

支持同步单向通信和半双工单线通信。 它还支持 LIN(本地互连网络)、智能卡协议和 IrDA(红外数据协会)SIR ENDEC 规范以及调制解调器操作 (CTS/RTS)。 它允许多处理器通信。

在STM32中,还可以通过将DMA用于多缓冲区配置,从而实现高速数据通信。

直接内存访问 (Direct Memory Access ,DMA) 单元是计算机体系结构中的数字逻辑元件,可与同一芯片上的主微处理器结合使用,以卸载内存传输操作。 这显着降低了 CPU 负载。 由于 DMA 控制器可以执行内存到内存的数据传输以及外围设备到内存的数据传输,反之亦然。 DMA 与 CPU 的存在可以将其吞吐量提高几个数量级。

STM32对DMA有很好的支持,在前面的文章中对DMA做了详细的介绍,请参考:

本次实例将实现USART通过DMA进行数据接收与发送。

1、工程创建

工程创建、系统时钟设置、系统调试设置请参考前面文章,在这里不再做介绍。

2、USART与DMA配置

第一步:USART基本参数配置
在这里插入图片描述
第二步:USART中断配置
在这里插入图片描述
第三步:USART的DMA配置
在这里插入图片描述
在这里插入图片描述
第四步:保存配置并生成代码

3、代码实现

STM32Cube IDE生成的主要代码如下:

1)USART初始化

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
/\*\*
\* @brief USART1 Initialization Function
\* @param None
\* @retval None
\*/
static void MX\_USART1\_UART\_Init(void) {

/\* USER CODE BEGIN USART1\_Init 0 \*/

/\* USER CODE END USART1\_Init 0 \*/

/\* USER CODE BEGIN USART1\_Init 1 \*/

/\* USER CODE END USART1\_Init 1 \*/
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();
}
/\* USER CODE BEGIN USART1\_Init 2 \*/
\_\_HAL\_UART\_ENABLE\_IT(&huart1, UART_IT_IDLE);
HAL\_UART\_Receive\_DMA(&huart1, rx_buffer, RX_DMA_BUFFER_SIZE);
/\* USER CODE END USART1\_Init 2 \*/

}

2)DMA初始化

main.c文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/\*\*
\* Enable DMA controller clock
\*/
static void MX\_DMA\_Init(void) {

/\* DMA controller clock enable \*/
\_\_HAL\_RCC\_DMA1\_CLK\_ENABLE();

/\* DMA interrupt init \*/
/\* DMA1\_Channel4\_IRQn interrupt configuration \*/
HAL\_NVIC\_SetPriority(DMA1_Channel4_IRQn, 0, 0);
HAL\_NVIC\_EnableIRQ(DMA1_Channel4_IRQn);
/\* DMA1\_Channel5\_IRQn interrupt configuration \*/
HAL\_NVIC\_SetPriority(DMA1_Channel5_IRQn, 0, 0);
HAL\_NVIC\_EnableIRQ(DMA1_Channel5_IRQn);

}


3)DMA中断响应处理

stm32f1xx_it.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
/\*\*
\* @brief This function handles DMA1 channel4 global interrupt.
\*/
void DMA1\_Channel4\_IRQHandler(void) {
/\* USER CODE BEGIN DMA1\_Channel4\_IRQn 0 \*/

/\* USER CODE END DMA1\_Channel4\_IRQn 0 \*/
HAL\_DMA\_IRQHandler(&hdma_usart1_tx);
/\* USER CODE BEGIN DMA1\_Channel4\_IRQn 1 \*/

/\* USER CODE END DMA1\_Channel4\_IRQn 1 \*/
}

/\*\*
\* @brief This function handles DMA1 channel5 global interrupt.
\*/
void DMA1\_Channel5\_IRQHandler(void) {
/\* USER CODE BEGIN DMA1\_Channel5\_IRQn 0 \*/

/\* USER CODE END DMA1\_Channel5\_IRQn 0 \*/
HAL\_DMA\_IRQHandler(&hdma_usart1_rx);
/\* USER CODE BEGIN DMA1\_Channel5\_IRQn 1 \*/

/\* USER CODE END DMA1\_Channel5\_IRQn 1 \*/
}

4)USART中断处理实现

stm32f1xx_it.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
/\* USER CODE BEGIN EV \*/
extern volatile uint8_t rx_len;//Length of data received
extern volatile uint8_t recv_end_flag; //Receiving Completion Flag Bit
extern uint8_t rx_buffer[RX_DMA_BUFFER_SIZE]; //Data cache array
/\* USER CODE END EV \*/
/\*\*
\* @brief This function handles USART1 global interrupt.
\*/
void USART1\_IRQHandler(void) {
/\* USER CODE BEGIN USART1\_IRQn 0 \*/
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag = \_\_HAL\_UART\_GET\_FLAG(&huart1, UART_FLAG_IDLE);
if ((tmp_flag != RESET)) {
\_\_HAL\_UART\_CLEAR\_IDLEFLAG(&huart1);
temp = huart1.Instance->SR;
temp = huart1.Instance->DR;
HAL\_UART\_DMAStop(&huart1);
temp = hdma_usart1_rx.Instance->CNDTR;
rx_len = RX_DMA_BUFFER_SIZE - temp;
recv_end_flag = 1;
}
/\* USER CODE END USART1\_IRQn 0 \*/
HAL\_UART\_IRQHandler(&huart1);
/\* USER CODE BEGIN USART1\_IRQn 1 \*/

/\* USER CODE END USART1\_IRQn 1 \*/
}

5)输出重写向

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
/\* Private define ------------------------------------------------------------\*/
/\* USER CODE BEGIN PD \*/
volatile uint8_t rx_len = 0; //Length of data received
volatile uint8_t recv_end_flag = 0; //Acceptance success flag
uint8_t rx_buffer[RX_DMA_BUFFER_SIZE]; //Cache array
const uint8_t __r_chr[] = { '\r' };
/\* USER CODE END PD \*/

/\* USER CODE BEGIN 4 \*/
int \_write(int fd, char \*ptr, int len);

/\*
\* Called by libc stdio fwrite functions
\*/
int \_write(int fd, char \*ptr, int len) {
int i = 0;

/\*
\* write "len" of char from "ptr" to file id "fd"
\* Return number of char written.
\*
\* Only work for STDOUT, STDIN, and STDERR
\*/
if (fd > 2) {
return -1;
}

while (\*ptr && (i < len)) {
HAL\_UART\_Transmit(&huart1, (uint8_t\*) ptr, 1, 100);
if (\*ptr == '\n') {
HAL\_UART\_Transmit(&huart1, (uint8_t\*) __r_chr, 1, 100);
}
// HAL\_UART\_Receive\_IT(&huart1, (uint8\_t\*) RX\_Buffer, 1);
i++;
ptr++;
}

return i;
}
/\* USER CODE END 4 \*/

6)程序入口及功能实现

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
/\*\*
\* @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\_DMA\_Init();
MX\_USART1\_UART\_Init();
/\* USER CODE BEGIN 2 \*/

/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
if (recv_end_flag == 1) {
printf("The length of the received data is %d\r\n", rx_len);
HAL\_UART\_Transmit(&huart1, rx_buffer, rx_len, RX_DMA_BUFFER_SIZE);
for (uint8_t i = 0; i < rx_len; i++) {
rx_buffer[i] = 0;
}
printf("\r\n");
rx_len = 0;
recv_end_flag = 0;
}
HAL\_UART\_Receive\_DMA(&huart1, rx_buffer, RX_DMA_BUFFER_SIZE);
}
/\* USER CODE END 3 \*/
}

4、程序运行结果

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/123435512