本帖最后由 qinyunti 于 2024-7-24 23:48 编辑
前面我们实现了串口的收发测试,现在来基于FIFO实现好用的串口收发接口。FIFO的实现参考微信公众号”嵌入式Lee”的文章
https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag 超级精简系列之十三:超级精简的循环FIFO,C实现
Fifo.c源码如下
#include <string.h>
#include "fifo.h"
#define FIFO_PARAM_CHECK 0
/**
* in????? 0~(buffer_len-1)?
* out????? 0~(buffer_len-1)?
* in == out?????,?????,????len??????????
* ???in??,?????out???
* ????out??,?????in???
* in??out??[out,in)????????
* in??out??[out,buffer_len)?[0,in)????????
***********************************************************
* 0 buffer_len-1 buffer_len
* (1)?? in?out??0
* | |
* in(0)
* out(0)
* len = 0
* (2)??n???? in??n?out??0 ??in??out???
* | |
* out(0)������������>in(n) |
* len = n
* (3)??m????(m<n) in??n?out??m ??in??out???
* | |
* out(m)����>in(n)
* len = n-m
* (4)??????,?????,??in??out???
* | |
* out(m)��������������������������������>
* ��>in(k)
* len = k + buffer_len-m
*/
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
uint32_t space = 0; /* ?????????? */
/* ???? */
#if FIFO_PARAM_CHECK
if((dev == 0) || (buffer == 0) || (len == 0))
{
return 0;
}
if(dev->buffer == 0)
{
return 0;
}
#endif
/* ??len??????buffer?? */
if(len > dev->buffer_len)
{
len = dev->buffer_len;
}
/* ????????
* ??dev->len?????dev->buffer_len
*/
if(dev->buffer_len >= dev->len)
{
space = dev->buffer_len - dev->len;
}
else
{
/* ???????, ?????? */
dev->len = 0;
space = dev->buffer_len;
}
/* ???????, ??len???????????????? */
len = (len >= space) ? space : len;
if(len == 0)
{
return 0; /* ??????????,???? */
}
/* ??len??????????,?????? */
space = dev->buffer_len - dev->in; /* ??????in???????????? */
if(space >= len)
{
/* ??????in??????????? */
memcpy(dev->buffer+dev->in,buffer,len);
}
else
{
/* ??????in???????,????????? */
memcpy(dev->buffer+dev->in,buffer,space); /* ???tail?? */
memcpy(dev->buffer,buffer+space,len-space); /* ???????? */
}
/* ????????????? */
dev->in += len;
if(dev->in >= dev->buffer_len)
{
dev->in -= dev->buffer_len; /* ????? ?? dev->in %= dev->buffer->len */
}
dev->len += len; /* dev->len??dev->buffer->len,??%= dev->buffer->len */
return len;
}
uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len)
{
uint32_t space = 0;
/* ???? */
#if FIFO_PARAM_CHECK
if((dev == 0) || (buffer == 0) || (len == 0))
{
return 0;
}
if(dev->buffer == 0)
{
return 0;
}
#endif
/* ??????? */
if(dev->len == 0)
{
return 0;
}
/* ?????????????????? */
len = (dev->len) > len ? len : dev->len;
/* ??len??????????,?????? */
space = dev->buffer_len - dev->out; /* ??????out???????????? */
if(space >= len)
{
/* ??????out??????????? */
memcpy(buffer,dev->buffer+dev->out,len);
}
else
{
/* ??????out???????,????????? */
memcpy(buffer,dev->buffer+dev->out,space); /* ???tail?? */
memcpy(buffer+space,dev->buffer,len-space); /* ???????? */
}
/* ????????????? */
dev->out += len;
if(dev->out >= dev->buffer_len)
{
dev->out -= dev->buffer_len; /* ????? ?? dev->out %= dev->buffer->len */
}
dev->len -= len; /* ??dev->len ?????len,???? */
return len;
}
uint32_t fifo_getlen(fifo_st* dev)
{
#if FIFO_PARAM_CHECK
if(dev == 0)
{
return 0;
}
#endif
return dev->len;
}
void fifo_clean(fifo_st* dev)
{
#if FIFO_PARAM_CHECK
if(dev == 0)
{
return 0;
}
#endif
dev->len = 0;
dev->in = 0;
dev->out = 0;
}
Fifo.h源码如下
#ifndef FIFO_H
#define FIFO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* \struct fifo_st
* FIFO?????.
*/
typedef struct
{
uint32_t in; /**< ???? */
uint32_t out; /**< ???? */
uint32_t len; /**< ?????? */
uint32_t buffer_len; /**< ???? */
uint8_t* buffer; /**< ??,???? */
} fifo_st;
/**
* \fn fifo_in
* ?fifo????
* \param[in] dev \ref fifo_st
* \param[in] buffer ??????
* \param[in] len ??????
* \retval ??????????
*/
uint32_t fifo_in(fifo_st* dev, uint8_t* buffer, uint32_t len);
/**
* \fn fifo_out
* ?fifo????
* \param[in] dev \ref fifo_st
* \param[in] buffer ??????
* \param[in] len ?????????
* \retval ??????????
*/
uint32_t fifo_out(fifo_st* dev, uint8_t* buffer, uint32_t len);
uint32_t fifo_getlen(fifo_st* dev);
void fifo_clean(fifo_st* dev);
#ifdef __cplusplus
}
#endif
#endif
Uart.c中定义fifo实例
static uint8_t s_uart_rx_buffer[64];
static fifo_st s_uart_fifo_dev=
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx_buffer,
.buffer_len = sizeof(s_uart_rx_buffer),
};
串口接收中断中,将数据写入fifo
void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
uint8_t tmp;
switch (p_args->event)
{
case UART_EVENT_TX_COMPLETE:
g_data_transmit_flag = true;
break;
case UART_EVENT_TX_DATA_EMPTY:
g_data_transmit_flag = true;
break;
case UART_EVENT_RX_COMPLETE:
// Start Transmission
fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
//uart_send(rx_buffer,1);
break;
case UART_EVENT_RX_CHAR:
tmp = g_uart3_ctrl.p_reg->RDR_BY;
fifo_in(&s_uart_fifo_dev, &tmp, 1);
//uart_send(&tmp,1);
break;
default:
break;
}
}
临界段接口,中断中操作fifo无需临界段保护,uart_read再线程中调用,需要临界段保护。
#define CriticalAlloc()
#define EnterCritical() __disable_irq()
#define ExitCritical() __enable_irq()
串口读接口,从fifo中读数据
uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
uint32_t rlen;
CriticalAlloc();
EnterCritical();
rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
ExitCritical();
return rlen;
}
最终的uart.c如下
#include "hal_data.h"
#include <stdio.h>
#include <stdbool.h>
#include "r_uart_api.h"
#include "r_sci_b_uart.h"
#include "uart.h"
#include "blinky_thread.h"
#include "fifo.h"
#define CriticalAlloc()
#define EnterCritical() __disable_irq()
#define ExitCritical() __enable_irq()
static uint8_t s_uart_rx_buffer[64];
static fifo_st s_uart_fifo_dev=
{
.in = 0,
.len = 0,
.out = 0,
.buffer = s_uart_rx_buffer,
.buffer_len = sizeof(s_uart_rx_buffer),
};
volatile bool g_data_transmit_flag = false;
uint8_t rx_buffer[1];
void user_uart3_callback(uart_callback_args_t *p_args);
void user_uart3_callback(uart_callback_args_t *p_args)
{
uint8_t tmp;
switch (p_args->event)
{
case UART_EVENT_TX_COMPLETE:
g_data_transmit_flag = true;
break;
case UART_EVENT_TX_DATA_EMPTY:
g_data_transmit_flag = true;
break;
case UART_EVENT_RX_COMPLETE:
// Start Transmission
fifo_in(&s_uart_fifo_dev, rx_buffer, 1);
R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
//uart_send(rx_buffer,1);
break;
case UART_EVENT_RX_CHAR:
tmp = g_uart3_ctrl.p_reg->RDR_BY;
fifo_in(&s_uart_fifo_dev, &tmp, 1);
//uart_send(&tmp,1);
break;
default:
break;
}
}
int uart_init(void)
{
fsp_err_t err;
err = R_SCI_B_UART_Open(&g_uart3_ctrl, &g_uart3_cfg);
if (FSP_SUCCESS != err)
{
return -1;
}
else
{
// Start Transmission
err = R_SCI_B_UART_Read(&g_uart3_ctrl, (uint8_t * const)(rx_buffer), 1U);
if (FSP_SUCCESS != err)
{
return -1;
}
return 0;
}
}
uint32_t uart_send(uint8_t* buffer, uint32_t len)
{
g_data_transmit_flag = false;
for(uint32_t i=0;i<len;i++)
{
g_uart3_ctrl.p_reg->TDR_BY = buffer;
while((g_uart3_ctrl.p_reg->CSR_b.TEND == 0) || (g_uart3_ctrl.p_reg->CSR_b.TDRE == 0));
}
//fsp_err_t err = R_SCI_B_UART_Write(&g_uart3_ctrl, (uint8_t * const)(buffer), len);
//if (FSP_SUCCESS != err)
//{
// return 0;
//}
// Wait for event receive complete
//while (!g_data_transmit_flag)
//{
//}
return len;
}
uint32_t uart_read(uint8_t* buffer, uint32_t len)
{
uint32_t rlen;
CriticalAlloc();
EnterCritical();
rlen = fifo_out(&s_uart_fifo_dev, buffer, len);
ExitCritical();
return rlen;
}
Uart.h如下
#ifndef UART_H
#define UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
int uart_init(void);
uint32_t uart_send(uint8_t* buffer, uint32_t len);
uint32_t uart_read(uint8_t* buffer, uint32_t len);
#ifdef __cplusplus
}
#endif
#endif
测试
blinky_thread_entry.c中
#include "uart.h"
void blinky_thread_entry (void * pvParameters)
{
uart_init();
while(1)
{
static uint8_t rx_buffer[64];
uint32_t rlen = uart_read(rx_buffer,sizeof(rx_buffer));
if(rlen > 0)
{
uart_send(rx_buffer,rlen);
}
}
发送任意数据原样返回
以上实现了方便好用的串口收发接口,基于fifo接口简单非常方便。