1.使用STM32Cube 直接先配置串口1的基础信息。
2.然后配置DMA传输
3.就是启动了,在串口初始化之后默认是没有开启串口DMA接收的。所以增加几行代码如下图所示
4.写串口1中断函数:
这个函数就是实现不等长的精髓所在了。这里用到了类似环形队列的方法,至于什么是环形队列这个不知道童鞋自行Google了。
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
}
HAL_UART_IRQHandler(&systemUart);
}
首先将中断函数写出来,如上所示了。这时候帧中断的时候会进这个中断,数据用DMA接收。
第二步建立对应变量
#define UART1_DMA_DATA_LEN 100//数据最大长度
static UART_HandleTypeDef systemUart;
DMA_HandleTypeDef hdma_usart1_rx;
static uint8_t _uartDmaDataBuffer[UART1_DMA_DATA_LEN]; //缓冲区就是初始化的时候用到的
static int dmaDataTail = 0; //将DMA数据传输Buffer 虚拟成一个队列缓冲区
static int dmaDataHead = 0;
static int dmaDataLenght = 0;
第三步实现类似环形队列功能
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
dmaDataTail = hdma_usart1_rx.Instance->NDTR;
dmaDataTail = UART1_DMA_DATA_LEN - dmaDataTail;
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN; //求数据长度
}
HAL_UART_IRQHandler(&systemUart);
}
注意里面 hdma_usart1_rx.Instance->NDTR的NDTR不同的型号可能不同可以在DMA的结构体里找到对应的名字,如下图所示
这个NDTR的值是从UART1_DMA_DATA_LEN开始递减的,因为启动DMA的时候设置了传输长度为UART1_DMA_DATA_LEN
所以我们接收到当前的数据下标就是UART1_DMA_DATA_LEN - hdma_usart1_rx.Instance->NDTR这个。这个其实就是当前接收到数据的结束下标。有了数据结束下标,我们还需要数据起始下标,以及数据长度。
①数据起始下标: 等于上一次的dmaDataTail 所以每次处理完数据都有dmaDataHead = dmaDataTail;
②数据长度:这个利用环形队列求长度的做法:
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN;
现在我们有了数据起始下标 数据长度那么我们就可以访问我们的数据了。当然方法也和环形队列差不多
完成的中断函数就是这样的。可以接收什么返回什么了,要想自己处理可以在这里增加缓冲区或者调用处理函数了。
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
dmaDataTail = hdma_usart1_rx.Instance->NDTR;
dmaDataTail = UART1_DMA_DATA_LEN - dmaDataTail;
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN; //求数据长度
for(int i = 0; i < dmaDataLenght; i++)
{
int index = (dmaDataHead+i)%UART1_DMA_DATA_LEN;
printf("%c",_uartDmaDataBuffer[index]);
}
printf("\r\n");
dmaDataHead = dmaDataTail;
}
HAL_UART_IRQHandler(&systemUart);
}
最后来张测试结果图分别是一顿乱操作发不同的数据长度和数据
最后注意一点的就是这个程序如果你一下子发超过100个字节那估计就不行了。因为超了缓冲区长度数据被覆盖了,当然增加长度就可以解决了。