概述
本篇文章主要介紹如何使用STM32CubeMX移植到雅特力AT32F403AVGT7,并通過(guò)雙串口輸出打印。
直接存儲(chǔ)器訪問(wèn)(DMA)用于在外設(shè)與存儲(chǔ)器之間以及存儲(chǔ)器與存儲(chǔ)器之間提供高速數(shù)據(jù)傳輸??梢栽跓o(wú)需任何CPU操作的情況下通過(guò)DMA快速傳輸傳輸。這樣節(jié)省的CPU資源可供其它操作使用。
DMA允許在后臺(tái)執(zhí)行數(shù)據(jù)傳輸,無(wú)需Cortex-M3處理器干預(yù)。在此操作過(guò)程中,主處理器可以執(zhí)行其它任務(wù),僅當(dāng)整個(gè)數(shù)據(jù)塊需要處理時(shí),才會(huì)中斷主處理器。這樣即使傳輸大量數(shù)據(jù)也不會(huì)對(duì)系統(tǒng)性能造成太大影響。
DMA主要用于為不同的外設(shè)模塊實(shí)現(xiàn)集中數(shù)據(jù)緩沖存儲(chǔ)(通常在系統(tǒng)SRAM中)。與分布式解決方案(其中每個(gè)外設(shè)都需要實(shí)現(xiàn)自己的本地?cái)?shù)據(jù)存儲(chǔ))相比,DMA解決方案在硅片成本和功耗方面的成本較低。
根據(jù)使用的產(chǎn)品型號(hào)的不同,有一個(gè)或兩個(gè)DMA模塊。
本篇文章主要介紹如何使用STM32CubeMX實(shí)現(xiàn)串口DMA讀取,并且打印出去。
硬件準(zhǔn)備
首先需要準(zhǔn)備一個(gè)開(kāi)發(fā)板,這里我準(zhǔn)備的是雅特力AT32F403AVGT7的開(kāi)發(fā)板:
選擇芯片型號(hào)
雅特力AT32F403AVGT7兼容STM32F103系列,故選取STM32f103VG進(jìn)行開(kāi)發(fā)。
配置時(shí)鐘源
HSE與LSE分別為外部高速時(shí)鐘和低速時(shí)鐘,在本文中使用內(nèi)置的時(shí)鐘源,故都選擇Disable選項(xiàng),如下所示:
配置時(shí)鐘樹(shù)
雅特力AT32F403AVGT7最高頻率到240M,但是STM32F1的最高主頻到72M,同時(shí)使用不使用外部晶振時(shí)候,最高速度只能到64M,所以配置64即可:
串口配置
本次實(shí)驗(yàn)使用的串口2,串口3進(jìn)行串口通信,波特率配置為115200。
配置DMA
在DMA 設(shè)置中,Mode有兩種模式,一種是普通模式(Normal),使用一次發(fā)送語(yǔ)句就發(fā)一次,另一種是循環(huán)模式(Circula),使用一次發(fā)送會(huì)一直發(fā)送。這里接收選擇循環(huán)模式。
中斷
在中斷設(shè)置里打開(kāi)串口2,3的中斷。
生成工程設(shè)置
注意在生產(chǎn)工程設(shè)置中不能出現(xiàn)中文,不然會(huì)報(bào)錯(cuò)。
代碼生成設(shè)置
最后設(shè)置生成獨(dú)立的初始化文件
生成代碼
代碼編寫
在main.c中,添加頭文件,若不添加會(huì)出現(xiàn) identifier "FILE" is undefined報(bào)錯(cuò)。
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
變量定義 ,在main.c中添加。
/* USER CODE BEGIN PV */
#define BUFFERSIZE_usart2 1000 //可以接收的最大字符個(gè)數(shù)
uint8_t ReceiveBuff_usart2[BUFFERSIZE_usart2]; //接收緩沖區(qū)
uint8_t recv_end_flag_usart2 = 0,Rx_len_usart2;//接收完成中斷標(biāo)志,接收到字符長(zhǎng)度
#define BUFFERSIZE_usart3 1000 //可以接收的最大字符個(gè)數(shù)
uint8_t ReceiveBuff_usart3[BUFFERSIZE_usart3]; //接收緩沖區(qū)
uint8_t recv_end_flag_usart3 = 0,Rx_len_usart3;//接收完成中斷標(biāo)志,接收到字符長(zhǎng)度
int f1_u1 = 0;
/* USER CODE END PV */
函數(shù)聲明和串口重定向,這里使用串口3進(jìn)行打印,在main.c中添加。
/* USER CODE BEGIN PFP */
void uart2_data(void); //接收函數(shù)
void uart3_data(void); //接收函數(shù)
#ifdef __GNUC__ //串口重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END PFP */
開(kāi)啟串口IDLE中斷,在main.c中添加。
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//使能串口2 IDLE中斷
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);//使能串口2 IDLE中斷
printf("雙串口DMA接收例程
");
/* USER CODE END 2 *
串口DMA獲取,在main.c中添加。
void uart2_data(void)
{
if(recv_end_flag_usart2 ==1)//接收完成標(biāo)志
{
printf("串口2數(shù)據(jù)長(zhǎng)度=%d
",Rx_len_usart2);//打印接收到的數(shù)據(jù)長(zhǎng)度
printf("串口2數(shù)據(jù)內(nèi)容:");
for(int i=0;iprintf("%c",ReceiveBuff_usart2[i]);//向串口打印接收到的數(shù)據(jù)
}
printf("
");
for(int i = 0; i < Rx_len_usart2 ; i++) //清空接收緩存區(qū)
ReceiveBuff_usart2[i]=0;//置0
Rx_len_usart2=0;//接收數(shù)據(jù)長(zhǎng)度清零
recv_end_flag_usart2=0;//接收標(biāo)志位清零
}
//開(kāi)啟下一次接收
HAL_UART_Receive_DMA(&huart2,(uint8_t*)ReceiveBuff_usart2,BUFFERSIZE_usart2);
}
void uart3_data(void)
{
if(recv_end_flag_usart3 ==1)//接收完成標(biāo)志
{
printf("串口3數(shù)據(jù)長(zhǎng)度=%d
",Rx_len_usart3);//打印接收到的數(shù)據(jù)長(zhǎng)度
printf("串口3數(shù)據(jù)內(nèi)容:");
for(int i=0;iprintf("%c",ReceiveBuff_usart3[i]);//向串口打印接收到的數(shù)據(jù)
}
printf("
");
for(int i = 0; i < Rx_len_usart3 ; i++) //清空接收緩存區(qū)
ReceiveBuff_usart3[i]=0;//置0
Rx_len_usart3=0;//接收數(shù)據(jù)長(zhǎng)度清零
recv_end_flag_usart3=0;//接收標(biāo)志位清零
}
//開(kāi)啟下一次接收
HAL_UART_Receive_DMA(&huart3,(uint8_t*)ReceiveBuff_usart3,BUFFERSIZE_usart3);
}
主循環(huán),在main.c中添加。
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
uart2_data();
uart3_data();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 *
中斷外部變量引用,在stm32f0xx_it.c中添加。
/* USER CODE BEGIN 0 */
#define BUFFERSIZE_usart2 255 //可接收的最大數(shù)據(jù)量
extern uint8_t recv_end_flag_usart2,Rx_len_usart2;
#define BUFFERSIZE_usart3 255 //可接收的最大數(shù)據(jù)量
extern uint8_t recv_end_flag_usart3,Rx_len_usart3;
/* USER CODE END 0 */
串口2,3中斷函數(shù),在stm32f0xx_it.c中添加。
/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
uint32_t temp_usart2;
if(USART2 == huart2.Instance)//判斷是否為串口2中斷
{
if(RESET != __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE))//如果為串口2
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除中斷標(biāo)志
HAL_UART_DMAStop(&huart2);//停止DMA接收
temp_usart2 = __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//獲取DMA當(dāng)前還有多少未填充
Rx_len_usart2 = BUFFERSIZE_usart2 - temp_usart2; //計(jì)算串口接收到的數(shù)據(jù)個(gè)數(shù)
recv_end_flag_usart2 = 1;
}
}
/* USER CODE END USART2_IRQn 1 */
}
/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
uint32_t temp_usart3;
if(USART3 == huart3.Instance)//判斷是否為串口3中斷
{
if(RESET != __HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))//如果為串口3
{
__HAL_UART_CLEAR_IDLEFLAG(&huart3);//清除中斷標(biāo)志
HAL_UART_DMAStop(&huart3);//停止DMA接收
temp_usart3 = __HAL_DMA_GET_COUNTER(&hdma_usart3_rx);//獲取DMA當(dāng)前還有多少未填充
Rx_len_usart3 = BUFFERSIZE_usart3 - temp_usart3; //計(jì)算串口接收到的數(shù)據(jù)個(gè)數(shù)
recv_end_flag_usart3 = 1;
}
}
/* USER CODE END USART3_IRQn 1 */
}
結(jié)果演示
開(kāi)機(jī)會(huì)顯示雙串口DMA接收例程。
串口2發(fā)送數(shù)據(jù)會(huì)在串口3中打印,但是會(huì)顯示接收的是串口2。
串口3發(fā)送數(shù)據(jù)會(huì)在串口3中打印,但是會(huì)顯示接收的是串口3。
審核編輯:湯梓紅
-
dma
+關(guān)注
關(guān)注
3文章
561瀏覽量
100583 -
stm32cubemx
+關(guān)注
關(guān)注
5文章
283瀏覽量
14807 -
雅特力
+關(guān)注
關(guān)注
0文章
158瀏覽量
8018
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論