前言
前面我们实现的串口发送采用的是阻塞查询方式,在USB开发中如果使用该方式作为打印调试,则可能会由于阻塞影响时序。所以需要该为非阻塞方式,我们的思路是先将待发送数据写入到缓存中,然后载在主循环中进行发送。核心部分还是和串口接收FIFO实现一样,可以复用其代码。
代码
增加代码uart_debug.c/h
数据结构
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[1024];
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,
};
写数据到缓存区
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[s_ring_buffer_t.in_u32] = buffer[i];
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;
}
从缓存区读出数据
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[i] = s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];
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;
}
发送处理,主循环中调用该接口实现真正的发送,
制定了一次发送的最大长度len,这样做目的是避免一次发送过长,导致主循环在这里等待过长,配置len来调整。
int uart_debug_send(uint32_t len)
{
uint32_t i;
uint8_t buff[16];
uint32_t slen;
if(0 != (slen = uart_debug_pop(buff, sizeof(buff))))
{
uart_write(buff, slen);
}
return slen;
}
重定向printf的底层接口
int fputc(int ch, FILE *f)
{
uint8_t tmp = (uint8_t)ch;
/* Your implementation of fputc(). */
uart_debug_push(&tmp, 1);
return ch;
}
uart_debug.h
#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
uart_debug.c
#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[1024];
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[i] = s_ring_buffer_t.buffer_pu8[s_ring_buffer_t.out_u32];
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[s_ring_buffer_t.in_u32] = buffer[i];
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[16];
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;
}
测试
Main.c中
#include "uart_debug.h"
while (1)
{
printf("Hello World\r\n");
uart_debug_send(16);
}
串口调试助手看到打印如下
总结
使用FIFO,将数据先陷入缓存区,再统一下主循环中不断查询发送,这样实现了非阻塞的串口输出,方便后面调试打印使用。