我的板子是探索者F407,前几天看到
使用串口1配合DMA接收不定长数据,大大减轻CPU载荷这篇帖子,觉得不错,想拿来做实验,结果出问题了,代码反复看了,总是找不出问题,拜托各位大神帮帮忙,我菜鸟一只!!!
使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。此贴的描述说明。
最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断。但是用来做通信的时候需要不停的产生串口接收中断,会严重影响主程序的运行。后来采用DMA接收的方式,但是一般情况下配置的DMA都是接定长的串口数据,对于未知长度的串口数据接收并不适用。后来在网上发现了一种方法可以利用串口的空闲中断+DMA接收的方法完美解决此类问题,特别适用于不需要每个就收字节都判断的串口数据接收,下面说一下事实现思路和程序。
实现思路:采用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。
帖子上使用的是103芯片,我是用F407芯片的,不知道是不是两个芯片的DMA模块上使用有区别,我都是照帖子的程序照搬过来的。
MYDMA_Enable(DMA2_Stream5,SEND_BUF_SIZE); //恢复DMA指针,等待下一次接受
//开启一次DMA传输
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
DMA_Cmd(DMA_Streamx, DISABLE);
while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}
DMA_SetCurrDataCounter(DMA_Streamx,ndtr);
DMA_Cmd(DMA_Streamx, ENABLE);
}
觉得可能是上面这几段代码有问题,感觉DMA指针没有恢复的样子
不要在中断服务函数中使用printf(个人建议),操作步骤大体相当
我的发送函数
void HAL_Submcu_uart_dma_Transmit(uint16_t Size)
{
DMA1_Channel2->CNDTR = (uint16_t)Size;
DMA_Cmd(DMA1_Channel2, ENABLE); //开始传输
}
中断服务函数
void USART3_IRQHandler(void)
{
#if MB_SUB_USER_DMA_EN
if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET) //产生了空闲中断
{
if ((usart_dma_dev.MB_SUB_USART_Flag & MB_SUB_USART_Flag_TC) != 0)
{
DMA_Cmd(DMA1_Channel3, DISABLE); //先关闭,预防干扰
usart_dma_dev.MB_SUB_USART_RX_Index = usart_dma_dev.MB_SUB_USART_RX_Length - DMA_GetCurrDataCounter(DMA1_Channel3); //获取当前接收到的数据长度
DMA1_Channel3->CNDTR = (uint16_t)usart_dma_dev.MB_SUB_USART_RX_Length; //重新配置接收长度
DMA_Cmd(DMA1_Channel3, ENABLE);
(void)USART_ReceiveData(USART3);
usart_dma_dev.MB_SUB_USART_Flag |= MB_SUB_USART_Flag_RXE;
// printf("usart dma rcv ok %d ", usart_dma_dev.MB_SUB_USART_RX_Index);
}
}
/* ==================== STM32F30x Series chips ==================== */
#if __STM32xx == 0x03 //STM32F30x
USART_ClearITPendingBit(USART3, USART_IT_IDLE);
#endif
#else
uint8_t res=0;
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收到数据
{
res = USART_ReceiveData(USART3); //读取接收到的数据
if (HAL_UART_RXCount < HAL_UART_RXD_Num)
{
HAL_UART_RXBuf[HAL_UART_RXCount] = res; //记录接收到的值
HAL_UART_RXCount++; //接收数据增加1
}
}
#endif
}
一周热门 更多>