【ST多款开发板返场测评】STM32F767 Nucleo-144 非阻塞串口打印实现
<div class='showpostmsg'><h1><b>前言</b></h1><p >前面我们实现的串口发送采用的是阻塞查询方式,在USB开发中如果使用该方式作为打印调试,则可能会由于阻塞影响时序。所以需要该为非阻塞方式,我们的思路是先将待发送数据写入到缓存中,然后载在主循环中进行发送。核心部分还是和串口接收FIFO实现一样,可以复用其代码。</p>
<p > </p>
<h1 ><b>代码</b></h1>
<p >增加代码uart_debug.c/h</p>
<p >数据结构</p>
<pre>
<code class="language-cpp">typedef struct
{
uint32_t datalen_u32;
uint32_t maxlen_u32;
uint32_t in_u32;
uint32_t out_u32;
uint8_t* buffer_pu8;
}ring_buffer_t;
static uint32_t uart_debug_pop(uint8_t *buff, uint32_t len);
static uint8_t uart_ring_buffer;
static ring_buffer_t s_ring_buffer_t=
{
.datalen_u32 = 0,
.maxlen_u32 = sizeof(uart_ring_buffer),
.in_u32 = 0,
.out_u32 = 0,
.buffer_pu8 = uart_ring_buffer,
};</code></pre>
<p > </p>
<p >写数据到缓存区</p>
<pre>
<code class="language-cpp">uint32_t uart_debug_push(uint8_t *buffer, uint32_t length)
{
uint32_t i;
uint32_t sendlen = 0;
Alloc_Critical();
Enter_Critical();
for(i=0;i<length; i++)
{
if(s_ring_buffer_t.datalen_u32 < s_ring_buffer_t.maxlen_u32)
{
s_ring_buffer_t.buffer_pu8 = buffer;
s_ring_buffer_t.datalen_u32++;
s_ring_buffer_t.in_u32++;
s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;
sendlen++;
}
else
{
/* full */
break;
}
}
Exit_Critical();
return sendlen;
}</code></pre>
<p > </p>
<p >从缓存区读出数据</p>
<pre>
<code class="language-cpp">static uint32_t uart_debug_pop(uint8_t *buff, uint32_t len)
{
uint32_t readlen = 0;
//uint32_t mask;
if(s_ring_buffer_t.datalen_u32 == 0)
{
return 0;
}
Alloc_Critical();
Enter_Critical();
uint32_t i;
for(i=0;i<len;i++)
{
if(s_ring_buffer_t.datalen_u32 > 0)
{
buff = s_ring_buffer_t.buffer_pu8;
s_ring_buffer_t.datalen_u32--;
s_ring_buffer_t.out_u32++;
s_ring_buffer_t.out_u32 %= s_ring_buffer_t.maxlen_u32;
readlen++;
}
else
{
break;
}
}
Exit_Critical();
return readlen;
}</code></pre>
<p > </p>
<p >发送处理,主循环中调用该接口实现真正的发送,</p>
<p >制定了一次发送的最大长度len,这样做目的是避免一次发送过长,导致主循环在这里等待过长,配置len来调整。</p>
<pre>
<code class="language-cpp">int uart_debug_send(uint32_t len)
{
uint32_t i;
uint8_t buff;
uint32_t slen;
if(0 != (slen = uart_debug_pop(buff, sizeof(buff))))
{
uart_write(buff, slen);
}
return slen;
}</code></pre>
<p > </p>
<p >重定向printf的底层接口</p>
<pre>
<code class="language-cpp">int fputc(int ch, FILE *f)
{
uint8_t tmp = (uint8_t)ch;
/* Your implementation of fputc(). */
uart_debug_push(&tmp, 1);
return ch;
}</code></pre>
<p >uart_debug.h</p>
<pre>
<code class="language-cpp">#ifndef UART_DEBUG_H
#define UART_DEBUG_H
#include <stdint.h>
uint32_t uart_debug_push(uint8_t *buffer, uint32_t length);
int uart_debug_send(uint32_t len);
#endif</code></pre>
<p >uart_debug.c</p>
<pre>
<code class="language-cpp">#include <stdio.h>
#include "uart.h"
#include "uart_debug.h"
#include "stm32f7xx.h"
#define Alloc_Critical()
#define Enter_Critical()
#define Exit_Critical()
typedef struct
{
uint32_t datalen_u32;
uint32_t maxlen_u32;
uint32_t in_u32;
uint32_t out_u32;
uint8_t* buffer_pu8;
}ring_buffer_t;
static uint32_t uart_debug_pop(uint8_t *buff, uint32_t len);
static uint8_t uart_ring_buffer;
static ring_buffer_t s_ring_buffer_t=
{
.datalen_u32 = 0,
.maxlen_u32 = sizeof(uart_ring_buffer),
.in_u32 = 0,
.out_u32 = 0,
.buffer_pu8 = uart_ring_buffer,
};
static uint32_t uart_debug_pop(uint8_t *buff, uint32_t len)
{
uint32_t readlen = 0;
//uint32_t mask;
if(s_ring_buffer_t.datalen_u32 == 0)
{
return 0;
}
Alloc_Critical();
Enter_Critical();
uint32_t i;
for(i=0;i<len;i++)
{
if(s_ring_buffer_t.datalen_u32 > 0)
{
buff = s_ring_buffer_t.buffer_pu8;
s_ring_buffer_t.datalen_u32--;
s_ring_buffer_t.out_u32++;
s_ring_buffer_t.out_u32 %= s_ring_buffer_t.maxlen_u32;
readlen++;
}
else
{
break;
}
}
Exit_Critical();
return readlen;
}
uint32_t uart_debug_push(uint8_t *buffer, uint32_t length)
{
uint32_t i;
uint32_t sendlen = 0;
Alloc_Critical();
Enter_Critical();
for(i=0;i<length; i++)
{
if(s_ring_buffer_t.datalen_u32 < s_ring_buffer_t.maxlen_u32)
{
s_ring_buffer_t.buffer_pu8 = buffer;
s_ring_buffer_t.datalen_u32++;
s_ring_buffer_t.in_u32++;
s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;
sendlen++;
}
else
{
/* full */
break;
}
}
Exit_Critical();
return sendlen;
}
int uart_debug_send(uint32_t len)
{
uint32_t i;
uint8_t buff;
uint32_t slen;
if(0 != (slen = uart_debug_pop(buff, sizeof(buff))))
{
uart_write(buff, slen);
}
return slen;
}
int fputc(int ch, FILE *f)
{
uint8_t tmp = (uint8_t)ch;
/* Your implementation of fputc(). */
uart_debug_push(&tmp, 1);
return ch;
}
</code></pre>
<h1 ><b>测试</b></h1>
<p >Main.c中</p>
<pre>
<code class="language-cpp">#include "uart_debug.h"
while (1)
{
printf("Hello World\r\n");
uart_debug_send(16);
}</code></pre>
<p >串口调试助手看到打印如下</p>
<p > </p>
<p > </p>
<p > </p>
<h1 ><b>总结</b></h1>
<p >使用FIFO,将数据先陷入缓存区,再统一下主循环中不断查询发送,这样实现了非阻塞的串口输出,方便后面调试打印使用。</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>前后台轮询?其实可以试试上个rtos</p>
<p>我觉得这种非阻塞的,适用于LOG存到Flash的。</p>
页:
[1]