您的位置 首页 厂商

根据STM32的串口DMA发送

基于STM32的串口DMA发送-使用STM32的串口进行DMA发送(Noraml模式),在某个任务中连续调用两次发送函数log_printf(),但是发回的数据在串口调试助手上显示与预期不符。第一次发送的数据有一部分被第二次发送的数据覆盖。

问题描绘

运用STM32的串口进行DMA发送(Noraml形式),在某个使命中接连调用两次发送函数log_printf(),可是发回的数据在串口调试助手上显现与预期不符。第一次发送的数据有一部分被第2次发送的数据掩盖,如图所示:

根据STM32的串口DMA发送

使命代码如下:

/* Log_Task funcTIon */void Log_Task(void const * argument)

{ /* USER CODE BEGIN Log_Task */

/* Infinite loop */

for(;;)

{ if(router_rx_flag == 1)

{

router_rx_flag = 0;

log_printf(“Get ok\r\n”);

log_printf(“%s”,router_rx_buffer);

}

osDelay(100);

} /* USER CODE END Log_Task */}1234567891011121314151617

从代码中可以看出,希望的成果应该是下图这样:

根据STM32的串口DMA发送

log_printf函数代码如下:

/*

* 称号: log_printf

* 功用: 在串口1上打印出日志内容

* 输入: 格式化输出的字符

* 输出: 无

*/

void log_printf(const char *format ,。。。 )

{

va_list arg;

staTIc char tx_buffer[256]={“”};

//把数据处理后放进缓冲区

va_start(arg, format);

vsprintf((char *)tx_buffer, format, arg);

va_end(arg);

//开端发送数据

send_to_router((u8 *)tx_buffer,strlen(tx_buffer));

}

send_to_router函数代码如下:

void send_to_router(unsigned char *buffer,unsigned int length)

{

//等候上一次的数据发送结束

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

/* 封闭DMA */

__HAL_DMA_DISABLE(&hdma_usart1_tx);

//开端发送数据

HAL_UART_Transmit_DMA(&huart1,buffer,length);

// while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1); /* 放在此处可以确保每次发送彻底,但会占用时刻 */

}

串口中止接纳处理函数如下:

/*

* 称号: router_parse

* 功用: 接纳路由器数据的解析,在回调函数中调用

* 输入: 闲暇中止时串口1接纳的数据长度

* 输出: 无

*/

void router_parse(uint16_t buffer_len)

{

char *p_start = NULL,*p_end = NULL;

/* 只提取一帧NMEA数据,$最初,\n结束 */

p_start = strchr(usart1_rx_buffer,‘$’);

if(p_start != NULL)

{

p_end = strchr(p_start,‘\n’);

if(p_end != NULL)

{

memcpy(router_rx_buffer, p_start, (p_end – p_start + 1)); /* 保存数据 */

router_rx_flag = 1;

}

}

}

剖析进程

从前一向以为是send_to_router函数中的

//等候上一次的数据发送结束

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

这一句的问题,即因为某种原因导致DMA缓存中数据未发送彻底,但DMA状况却被释放了,成果重新开端了新一轮的发送,导致前次数据的后半部分被掩盖。但无论如何调试,都无法证明这个猜测,DMA外设没有出过任何反常。

今日仔细观察了一下,“Getckey”和“Get ok\r\n”和”$Mickey\r\n“,为什是第2次发送的内容的后半部掩盖了第一次发送的内容,一般不该该是前半部分”(美元符号,此处会排版犯错)Mic”吗?问题的原因或许与状况位无关。所以我再审视了一下send_to_router函数:void send_to_router(unsigned char *buffer,unsigned int length)突然间想到,入参仅仅一个指针,发送缓存区在log_printf函数中

staTIc char tx_buffer[256]={“”};

收拾一下,整个发送进程流程如下:

log_printf(“Get ok\r\n”);时,“Get ok\r\n”被装进了tx_buffer,顺便一个发送长度8字节。

send_to_router函数中,HAL_UART_Transmit_DMA(&huart1,buffer,length);敞开了这个8个字节的发送。

8个字节或许只完成了“Get”的发送, log_printf(“%s”,router_rx_buffer);(即log_printf(“$Mickey\r\n“);)现已开端履行。

”$Mickey\r\n“被装进tx_buffer,顺便一个发送长度9字节。

send_to_router函数中,因为上一次数据还没有发送彻底,进入DMA状况等候循环。可是DMA发送指针char *buffer本来指向的那个地址的内容” ok\r\n“现已被”ckey\r\n“替代,所以就变成了”Getckey\r“。因为显现原因,只看到”Getckey“。

处理办法

把while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);这一句放到缓存区tx_buffer装载过程之前即可:

/*

* 称号: log_printf

* 功用: 在串口1上打印出日志内容

* 输入: 格式化输出的字符串

* 输出: 无

*/

void log_printf(const char *format ,。。。 )

{

va_list arg;

staTIc char tx_buffer[256]={“”};

//等候上一次的数据发送结束

while(HAL_DMA_GetState(&hdma_usart1_tx) == HAL_DMA_STATE_BUSY) osDelay(1);

//把数据处理后放进缓冲区

va_start(arg, format);

vsprintf((char *)tx_buffer, format, arg);

va_end(arg);

//开端发送数据

send_to_router((u8 *)tx_buffer,strlen(tx_buffer));

}

至于send_to_router函数中的该代码,保存或删去都可以。

后言

好久从前就开端运用STM32的DMA串口发送功用,套路基本上便是从前的博文《iar中运用DMA+printf+uart1》所描绘的那样。后来开端用STM32CubeMX了,把之前的例程略微做了一些修正,调试成功之后,就一向沿用至今。期间,这个问题困扰了我好久,虽然在写代码时略微留意一下就可防止其产生,但做技能的人都理解:千里之堤,溃于蝼蚁,放过任何一个小细节都或许在将来引发严重灾祸。很幸亏今日可以找到问题的原因。

再回去看来一遍《iar中运用DMA+printf+uart1》,其实这个问题的答案很早就写在里边了。。。

找个时刻,我会专门写一篇运用DMA串口Normal形式发送的博文,还是以Cube来创立工程。到时,再用一个例程完好复现和处理这个问题。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/347584.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部