最近因爲公司項目需要,希望使用 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, DISABLE); /* 使能串口發送請求 */
delay_ms(2 * 1000);
}
}
這樣只需要改變 bufferData 的內容後再調用 USART_DMACmd(USART, USART_DMAReq_Tx, DISABLE) 就能多次發送數據了