STM32F401用配置串口2的dma,并用串口dma发送数据给上位机,请只用c语言标准库详细编写相关代码
时间: 2023-11-22 14:54:53 浏览: 98
以下是使用标准库配置STM32F401串口2 DMA发送数据的代码:
```c
#include "stm32f4xx.h"
#include <string.h>
#define USART_TX_BUFFER_SIZE 100
uint8_t usart_tx_buffer[USART_TX_BUFFER_SIZE]; // 串口发送缓冲区
volatile uint16_t usart_tx_head = 0; // 缓冲区头指针
volatile uint16_t usart_tx_tail = 0; // 缓冲区尾指针
void USART2_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
// 使能GPIOA时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// 配置PA2为USART2_TX
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置USART2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// 初始化USART2参数
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_Init(USART2, &USART_InitStruct);
// 使能USART2
USART_Cmd(USART2, ENABLE);
// 配置DMA1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
// 配置DMA1_Stream6
DMA_InitStruct.DMA_Channel = DMA_Channel_4;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)usart_tx_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = 0;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream6, &DMA_InitStruct);
// 使能DMA1_Stream6传输完成中断
DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);
// 配置NVIC中断优先级
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = DMA1_Stream6_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void USART2_DMA_Send(uint8_t *data, uint16_t len) {
uint16_t i;
for (i = 0; i < len; i++) {
// 将数据写入缓冲区
usart_tx_buffer[usart_tx_head] = data[i];
usart_tx_head = (usart_tx_head + 1) % USART_TX_BUFFER_SIZE;
}
// 如果DMA未在传输,则启动DMA传输
if (DMA_GetCmdStatus(DMA1_Stream6) == DISABLE) {
DMA_Cmd(DMA1_Stream6, DISABLE);
DMA_SetCurrDataCounter(DMA1_Stream6, usart_tx_head > usart_tx_tail ? usart_tx_head - usart_tx_tail : USART_TX_BUFFER_SIZE - usart_tx_tail);
DMA_Cmd(DMA1_Stream6, ENABLE);
}
}
void DMA1_Stream6_IRQHandler(void) {
// 清除传输完成中断标志位
DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
// 更新缓冲区尾指针
usart_tx_tail = usart_tx_head;
// 如果缓冲区不为空,则启动DMA传输
if (usart_tx_head != usart_tx_tail) {
DMA_Cmd(DMA1_Stream6, DISABLE);
DMA_SetCurrDataCounter(DMA1_Stream6, usart_tx_head > usart_tx_tail ? usart_tx_head - usart_tx_tail : USART_TX_BUFFER_SIZE - usart_tx_tail);
DMA_Cmd(DMA1_Stream6, ENABLE);
}
}
int main(void) {
USART2_Init();
// 发送字符串 "Hello, world!\r\n"
USART2_DMA_Send((uint8_t *)"Hello, world!\r\n", strlen("Hello, world!\r\n"));
while (1);
return 0;
}
```
在上面的代码中,首先定义了一个`usart_tx_buffer`数组作为串口发送缓冲区,以及`usart_tx_head`和`usart_tx_tail`两个指针来指示缓冲区的头和尾。然后,在`USART2_Init()`函数中,配置了USART2和DMA1,使其能够通过DMA发送数据。其中,`USART2_DMA_Send()`函数用于将数据写入缓冲区,并启动DMA传输。最后,在`main()`函数中,调用`USART2_DMA_Send()`发送字符串"Hello, world!\r\n"。当DMA传输完成时,会触发`DMA1_Stream6_IRQHandler()`中断处理函数,更新缓冲区的尾指针,并在缓冲区不为空时启动DMA传输。
阅读全文