BAT32A239KK48FA 串口打印添加KFIFO

本文探讨了如何在使用中微半导体的串口时,从使用UART0的阻塞发送切换到UART1的中断发送,以及引入kfifo实现异步打印,以提高响应速度。作者提供了两种解决方案:阻塞式发送和使用kfifo队列,讨论了各自的优缺点。
摘要由CSDN通过智能技术生成

1.前言

最近使用中微半导的串口调试信息,由于使用的是串口1,使用的中断发送打印,中微的芯片包很贴心的给了printf的重定向,但是发送字符的函数是中断打印。

原本代码重定向函数(这里使用的是uart0,位置位于:retarget.c):

void _ttywrch(int ch)
{
  UART0_Send(ch);
  return;
}

int fputc(int ch, FILE *f)
{
  UART0_Send(ch);
  if(ch == '\n')
  {
    UART0_Send('\r');
  }
  return ch;
}
int fgetc( FILE *f)
{
  uint8_t ch;
  ch = UART0_Receive();
#if 1
  if(ch == 0x0D) // 回车键
  {
    UART0_Send('\r'); // echo
    UART0_Send('\n'); // echo
  }
  else {
    UART0_Send(ch); // echo
  }
#endif
  return ch;
}

这里把 UART0_Send改为UART1_Send.传入单个变量,长度改为1即可。

由于原本使用的发送函数是阻塞的,但uart1是中断发送,异步发送直接换的话,会造成打印错误!所以该怎么改呢?

2.改进

1.我直接阻塞

        既然你是中断打印,我直接把中断打印变成阻塞打印

volatile uint8_t uart1_send_over = 0; //定义一个flag
/***********************************************************************************************************************
* Function Name: UART1_Send
* @brief  This function sends UART1 data.
* @param  tx_buf - transfer buffer pointer
* @param  tx_num - buffer size
* @return status - MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS UART1_Send(uint8_t *const tx_buf, uint16_t tx_num)
{
    MD_STATUS status = MD_OK;

    if (tx_num < 1U)
    {
        status = MD_ARGERROR;
    }
    else
    {
			
        uart1_send_over = 1;
        gp_uart1_tx_address = tx_buf;
        g_uart1_tx_count = tx_num;
        SCI0->TXD1 = *gp_uart1_tx_address;
        gp_uart1_tx_address++;
        g_uart1_tx_count--;
		
		while(uart1_send_over );
    }
    return (status);
}
/***********************************************************************************************************************
* Function Name: uart1_callback_sendend
* @brief  This function is a callback function when UART1 finishes transmission.
* @param  None
* @return None
***********************************************************************************************************************/
static void uart1_callback_sendend(void)
{
    /* Start user code. Do not edit comment generated here */
	   uart1_send_over = 0;
    /* End user code. Do not edit comment generated here */
}

直接用uart1_send_over 标志位阻塞发送,这样就不会有问题了。

优点:简单加两三行解决问题。

缺点:没有发挥异步打印的优势。如果波特率很慢的时候,会造成响应很慢!

2.异步打印kfifo

        异步打印主要解决的问题就是生产者和消费者的问题。这让我想到了kfifo,kfifo是linux一个精美且强大的队列缓存机制,既然写不出比linux更强大的代码,那我直接就用。这里不谈原理,只谈使用。

        单片机由于是裸机,也没有做动态内存分配,打印串口只有一个,我直接使用静态kfifo,同时也不用考虑锁的问题,因为kfifo自身直接可以锁定单生产者消费者,简单粗暴。

        kfifo使用需要声明和初始化,值得注意的是这里声明的时候需要注意大小为2的幂次方(kfifo的宏直接让编译器检查防止笨蛋输入非2的幂次方数,这就是Linux的强大)

#define KFIFO_BUFFER_SIZE 1024

DECLARE_KFIFO(fifo, uint8_t,KFIFO_BUFFER_SIZE);

void init_fifo()
{
    	INIT_KFIFO(fifo);
}

       串口发送部分 改为

volatile uint8_t uart1_send_over = 0;
/***********************************************************************************************************************
* Function Name: UART1_Send
* @brief  This function sends UART1 data.
* @param  tx_buf - transfer buffer pointer
* @param  tx_num - buffer size
* @return status - MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS UART1_Send(uint8_t *const tx_buf, uint16_t tx_num)
{
       uint8_t c = 0;
        
        if(tx_num == 1)
		{
			kfifo_put(&fifo, *data);
		}
		else
		{
			kfifo_in(&fifo, data,len);
		}
        if(uart1_send_over == 0)
        {
            uart1_send_over = 1;
		   if(kfifo_get(&fifo, &c)>0)
			 {
				   SCI0->TXD1 = c;
			 }
         }

}
/***********************************************************************************************************************
* Function Name: uart1_callback_sendend
* @brief  This function is a callback function when UART1 finishes transmission.
* @param  None
* @return None
***********************************************************************************************************************/
static void uart1_callback_sendend(void)
{
    /* Start user code. Do not edit comment generated here */
	   uart1_send_over = 0;
    /* End user code. Do not edit comment generated here */
}
/***********************************************************************************************************************
* Function Name: uart1_interrupt_send
* @brief  UART1 Send interrupt service routine
* @param  None
* @return None
***********************************************************************************************************************/
void uart1_interrupt_send(void)
{
    uint8_t c;
		if(kfifo_get(&fifo, &c) > 0)
		{
		    SCI0->TXD1 = c;
	  }
		else
		{
			  uart1_callback_sendend();
		}
}

好了,那就可以愉快的异步打印了。

优点:响应快,无阻塞,只要不超缓冲区,随便打印。

缺点:需要额外开辟内存,内存小的不要使用哦。

附带kfifo移植包(我的主页资源里)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值