這裡教程是選擇的STM32F407。STM32F103也測試過。
1.首先選擇序列槽,選擇異步通信。
2.添加DMA
3.打開中斷
4.生成代碼,生成代碼選擇了每個外設單獨使用.c/.h
5.我使用的是Keil5。打開工程,首先注釋掉dma.c裡的DMA接收中斷,因為不需要DMA接收中斷,DMA發送中斷是需要的。(dma.c)
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
/* DMA2_Stream2_IRQn interrupt configuration */
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
/* DMA2_Stream7_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
}
6.在usart.h檔案裡定義序列槽接收資料類型我是如下定義的(usart.h)
/* USER CODE BEGIN Private defines */
#define RECEIVELEN 1024
#define USART_DMA_SENDING 1//發送未完成
#define USART_DMA_SENDOVER 0//發送完成
typedef struct
{
uint8_t receive_flag:1;//空閑接收标記
uint8_t dmaSend_flag:1;//發送完成标記
uint16_t rx_len;//接收長度
uint8_t usartDMA_rxBuf[RECEIVELEN];//DMA接收緩存
}USART_RECEIVETYPE;
extern USART_RECEIVETYPE UsartType1;
/* USER CODE END Private defines */
7.然後在usart.c裡需要添加空閑中斷處理函數,以及DMA發送函數等。(usart.c)
首先定義序列槽資料類型:
/* USER CODE BEGIN 0 */
USART_RECEIVETYPE UsartType1;
/* USER CODE END 0 */
然後定義空閑中斷處理函數和DMA發送函數
/* USER CODE BEGIN 1 */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
//DMA發送函數
void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
{
while(UsartType1.dmaSend_flag == USART_DMA_SENDING);
UsartType1.dmaSend_flag = USART_DMA_SENDING;
HAL_UART_Transmit_DMA(&huart1, pdata, Length);
}
//DMA發送完成中斷回調函數
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_DMA_DISABLE(huart->hdmatx);
UsartType1.dmaSend_flag = USART_DMA_SENDOVER;
}
//序列槽接收空閑中斷
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t temp;
if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
temp = huart1.hdmarx->Instance->NDTR;
UsartType1.rx_len = RECEIVELEN - temp;
UsartType1.receive_flag=1;
HAL_UART_Receive_DMA(&huart1,UsartType1.usartDMA_rxBuf,RECEIVELEN);
}
}
/* USER CODE END 1 */
</pre><p></p><pre>
8.在中斷檔案裡添加(當然,上面的空閑中斷處理函數需要聲明)(stm32f4xxit.c)
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
UsartReceive_IDLE(&huart1);
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
9.主函數裡,打開空閑中斷,初始化DMA接收
/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, UsartType1.usartDMA_rxBuf, RECEIVELEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE END 2 */
10.然後就可以在while(1)裡處理資料了
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(UsartType1.receive_flag)//如果産生了空閑中斷
{
UsartType1.receive_flag=0;//清零标記
Usart1SendData_DMA(UsartType1.usartDMA_rxBuf,UsartType1.rx_len);//序列槽列印收到的資料。
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */