本文是實作STM32F103ZET6串口通過使用STM32的IDLE空閑中斷(USAR_TFLAG_IDLE)實作UART_DMA接收和發送(Rx和Tx均通過DMA通道)不定長資料,本文實作了UART1_DMA、UART2_DMA、UART3_DMA、UART4_DMA,文末均有代碼下載,
本文以UART1_DMA為例,
一、為什么要使用 UART DMA 傳輸
直接存盤器存取(DMA)用來提供在外設和存盤器之間或者存盤器和存盤器之間的高速資料傳輸,無須CPU干預,資料可以通過DMA快速地移動,這就節省了CPU的資源來做其他操作,通俗的講就是CPU不需要負責具體資料的收發,只要告訴DMA將一塊資料從某處搬運到某處,搬完后,CPU再去使用,
二、STM32F103ZET6 DMA控制器
STM32F103ZET6有2個DMA控制器,UART1/2/3在DMA1控制器,UART4在DMA2控制器,UART5不支持DMA功能,
外設的DMA請求,可以通過設定相應外設暫存器中的控制位,被獨立地開啟或關閉,查詢手冊,STM32F103ZET6的DMA通道如下表,由表可知,UART1的TX是通道4,RX是通道5,
如圖:


代碼:
(1)串口初始化
/**********************************************************************
* @brief USART1初始化
* @param null
* @retval null
**********************************************************************/
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//打開串口GPIO時鐘
USART1_GPIO_APBxClkCmd(USART1_GPIO_CLK, ENABLE);
//打開串口外設時鐘
USART1_APBxClkCmd(USART1_CLK, ENABLE);
//將USART_Tx的GPIO配置為推挽復用模式
GPIO_InitStructure.GPIO_Pin = USART1_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStructure);
//將USART_Rx的GPIO配置為浮空輸入模式
GPIO_InitStructure.GPIO_Pin = USART1_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStructure);
//配置串口作業引數
//配置波特率
USART_InitStructure.USART_BaudRate = USART1_BAUDRATE;
//配置針數資料字長
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
//配置停止位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
//配置校驗位
USART_InitStructure.USART_Parity = USART_Parity_No ;
//配置硬體流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//配置作業模式,收發一起
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//完成串口初始化配置
USART_Init(USART1, &USART_InitStructure);
//配置串口中斷優先級
NVIC_Configuration(USART1_IRQ);
//使能串口接收中斷,接收一幀資料產生USART_IT_IDLE中斷
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
//使能串口接收中斷,發送完一幀資料產生USART_IT_TC中斷
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
//使能串口
USART_Cmd(USART1, ENABLE);
}
(2)USARTx_TX DMA初始化
/**
* @brief USARTx TX DMA 配置,記憶體到外設(USART1->DR)
* @param null
* @retval null
*/
void USART1_TX_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(USART1_TX_DMA_CHANNEL); //USART_TX_DMA
//開啟DMA時鐘,DMA1
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//設定DMA源地址,串口資料暫存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_ADDRESS;
//記憶體地址(要傳輸的變數的指標)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_TX_BUF;
//方向:從記憶體到外設
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
//傳輸大小
DMA_InitStructure.DMA_BufferSize = 0;
//外設地址不增
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模式,一次或者回圈模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
//優先級:中
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//禁止記憶體到記憶體傳輸
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//配置DMA UART TX通道
DMA_Init(USART1_TX_DMA_CHANNEL, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Tx , ENABLE);
//使能DMA TX通道
DMA_Cmd(USART1_TX_DMA_CHANNEL,DISABLE);
}
(3)USARTx_RX DMA初始化
/**
* @brief USARTx RX DMA 配置,外設到記憶體(USART1->DR)
* @param null
* @retval null
*/
void USART1_RX_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(USART1_RX_DMA_CHANNEL); // USART_TX_DMA
//開啟DMA時鐘
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//設定DMA源地址,串口資料暫存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_ADDRESS;
//記憶體地址(要傳輸的變數的指標)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RX_BUF;
//方向:外設到記憶體
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;
//傳輸大小
DMA_InitStructure.DMA_BufferSize = sizeof(USART1_RX_BUF);
//外設地址不增
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模式,一次或者回圈模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
//優先級:中
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//禁止記憶體到記憶體的傳輸
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(USART1_RX_DMA_CHANNEL , &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
//使能DMA_Rx通道
DMA_Cmd(USART1_RX_DMA_CHANNEL,ENABLE);
}
(4)串口中斷&DMA接收資料
/***********************************************************************
* @brief 配置嵌套向量中斷控制器NVIC
* @param null
* @retval null
**********************************************************************/
static void NVIC_Configuration(uint8_t NVIC_IRQChannel)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中斷控制器組選擇 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART為中斷源 */
NVIC_InitStructure.NVIC_IRQChannel = NVIC_IRQChannel;
/* 搶斷優先級 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子優先級 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/*使能中斷 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/***********************************************************************
* @brief USART1中斷
* @param null
* @retval null
**********************************************************************/
void USART1_IRQHandler(void)
{
uint8_t clear = clear;
//串口接收一次資料結束
if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE) !=RESET )
{
clear = USART1->SR;
clear = USART1->DR;
//清除USART1空閑中斷標志
USART_ClearITPendingBit(USART1, USART_FLAG_IDLE);
USART1_Rx_Len = UART_BUF_SIZE - DMA_GetCurrDataCounter(USART1_RX_DMA_CHANNEL);
//清除RX_DMA的傳輸暫存器
USART1_DMA_RX_CLC(USART1_RX_DMA_CHANNEL);//RX
//Todo
//...
//對收到的資料再此進行決議
//本Demo將接收到的資料復制到發送資料,發送出去,即收發的資料原封不動發送出去
//...
USART1_Tx_Len = USART1_Rx_Len;
memcpy(USART1_TX_BUF,USART1_RX_BUF,USART1_Rx_Len);
//發送資料
USART1_DMA_SendBuf(USART1_TX_BUF, USART1_Tx_Len);
}
//資料發送完成中斷
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
{
//清除資料發送完成中斷
USART_ClearITPendingBit(USART1, USART_IT_TC);
//關閉SART1 DMA Tx通道
DMA_Cmd(USART1_TX_DMA_CHANNEL, DISABLE);
//初始化接收發送陣列等
USART1_Rx_Len = 0;
USART1_Tx_Len = 0;
memset(USART1_RX_BUF,0,UART_BUF_SIZE);
memset(USART1_TX_BUF,0,UART_BUF_SIZE);
}
}
(5)DMA發送資料
//開啟一次DMA資料傳輸
void USART1_DMA_RX_CLC(DMA_Channel_TypeDef *DMA_CHx)
{
DMA_Cmd(DMA_CHx, DISABLE ); //關閉SART1 TX DMA1所指示的通道
DMA_SetCurrDataCounter(DMA_CHx,UART_BUF_SIZE);//設定DMA通道的DMA快取大小
DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1所指示的通道
}
//USART1 DMA發送資料
void USART1_DMA_SendBuf(uint8_t *arr, uint8_t len)
{
uint8_t sendLen= 0;
if(len == 0)
{
return;
}
sendLen = len > UART_BUF_SIZE ? UART_BUF_SIZE : len;
//判斷DMA通道里是否還有資料,即上一幀資料是否發送完畢
while(DMA_GetCurrDataCounter(USART1_TX_DMA_CHANNEL));
if(arr)
{
memcpy(USART1_TX_BUF, arr, sendLen);
}
//關閉USART1_DMA_Tx通道
DMA_Cmd(USART1_TX_DMA_CHANNEL, DISABLE);
//設定DMA_TX要傳輸的資料長度
DMA_SetCurrDataCounter(USART1_TX_DMA_CHANNEL, sendLen);
//使能USART1 DMA Tx通道,發送資料
DMA_Cmd(USART1_TX_DMA_CHANNEL, ENABLE);
}
-------------------------------------------------
代碼下載:
(1)STM32F103ZET6 UART1_DMA收發不定長資料:
https://download.csdn.net/download/wangzhichunnihao/69328698
(2)STM32F103ZET6 UART2_DMA收發不定長資料:
https://download.csdn.net/download/wangzhichunnihao/69329351
(3)STM32F103ZET6 UART3_DMA收發不定長資料:
https://download.csdn.net/download/wangzhichunnihao/69330092
(4)STM32F103ZET6 UART4_DMA收發不定長資料:
STM32F103ZET6UART4_DMA收發不定長資料-嵌入式檔案類資源-CSDN下載
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/392233.html
標籤:其他
下一篇:物聯網工程專業 軟硬結合課設 智能蜂箱管理系統 計算機專業課程設計 大作業 專案(安卓,Springboot后端,網頁資料展示前端,ESP8266傳輸資料,MQTT服務器)
