最近因为公司项目需要,希望使用 USART 通过 DMA 多次发送数据,因为每次发送数据的内容都不一样,所以不能采用 DMA 的循环模式,只能通过 DMA 正常模式、USART 多次请求的方式来实现,下面附上 DMA 的配置代码
#define USART USART3
#define DMA_CLK RCC_AHB1Periph_DMA1
#define DMA_STREAM DMA1_Stream3
#define DMA_CHANNEL DMA_Channel_4
#define BUFFER_SIZE 12
/*
注意:
本文中使用的是 STM32F405 系列单片机,串口使用的 USART3 (DMA 数据流和通道参考《STM32F4xx中文参考手册》9.3.3 功能选择 进行选择),请读者参照自身情况修改。
*/
uint8_t bufferData[BUFFER_SIZE] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
/* 配置 DMA1_Stream3 中断*/
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* 配置 DMA1 */
void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(DMA_CLK, ENABLE);
DMA_DeInit(DMA_STREAM); /* 复位通道 DMA_STREAM(DMA1_Stream3) */
while(DMA_GetCmdStatus(DMA_STREAM)); /* 等待通道 DMA_STREAM(DMA1_Stream3)复位完成 */
DMA_InitStructure.DMA_Channel = DMA_CHANNEL;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) (&USART->DR); /* 外设基址为串口的 DR 寄存器地址 */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32) srcData;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; /* 设置传输模式为从存储器到外设模式 */
DMA_InitStructure.DMA_BufferSize = (uint32_t) BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* 外设地址不可变 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* 正常模式,数据传送完毕就不再传送 */
DMA_InitStructure.DMA_Priority = DMA_Prioriry_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_Init(DMA_STREAM, &DMA_InitStructure);
DMA_Cmd(DMA_STREAM, ENABLE);
NVIC_Config();
DMA_ITConfig(DMA_STREAM, DMA_IT_TC, ENABLE); /* 使能 DMA_STREAM 传输完成中断 */
while(!DMA_GetCmdStatus(DMA_STREAM)); /* 等待 DMA_STREAM 初始化完成*/
}
/* DMA_STREAM 传输完成中断服务函数 */
void DMA1_Stream3_IRQHandler(void)
{
if(DMA_GetITStatus(DMA_STREAM, DMA_IT_TCIF3)) /* 获取 DMA_STREAM 传输完成中断标志 */
{
USART_DMACmd(USART, USART_DMAReq_Tx, DISABLE); /* 失能串口发送请求 */
DMA_Cmd(DMA_STREAM, DISABLE); /* 失能 DMA_STREAM */
DMA_ClearITPendingBit(DMA_STREAM, DMA_IT_TCIF3); /* 清除 DMA_STREAM 传输完成中断标志位,否则程序会无限陷入中断 */
DMA_Cmd(DMA_STREAM, ENABLE); /* 重新使能 DMA_STREAM */
}
}
/* 延时函数 */
void delay_ms(uint16_t time)
{
uint16_t count;
while(time--)
{
count = 12000;
count--;
}
}
/* main 函数 */
int main(void)
{
USART_Config(); /* 该函数省略,有兴趣的朋友可以看我上一篇文章的配置方式 */
DMA_Config();
while(1)
{
printf("\r\n");
USART_DMACmd(USART, USART_DMAReq_Tx, ENABLE); /* 使能串口发送请求 */
delay_ms(2 * 1000);
}
}
这样只需要改变 bufferData 的内容后再调用 USART_DMACmd(USART, USART_DMAReq_Tx, DISABLE) 就能多次发送数据了