前面使用Demo进行了串口的收发测试,为了后面方便的使用串口,我们需要进行一些封装,实现串口的收发接口。
核心思路是设计环形缓冲区的FIFO,串口接收中断中将数据写入FIFO,满则丢弃
用户接收API查询FIFO有数据就读出无数据就等待。
中断和用户API都会操作FIFO所以需要对FIFO进行临界段操作保护。
对于发送也可以类似,不过这里为了简单,发送就使用查询方式。
#include <stdint.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;
定时缓冲区存接收数据
uint8_t uart_ring_buffer[128];
实例化一个缓冲区
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,
};
Rx API中操作FIFO时临界段通过关中断实现
#include "bsp_api.h"
#define Alloc_Critical() FSP_CRITICAL_SECTION_DEFINE
#define Enter_Critical() FSP_CRITICAL_SECTION_ENTER
#define Exit_Critical() FSP_CRITICAL_SECTION_EXIT
void uart_rx_handler(const uint8_t *buffer, uint32_t length)
{
uint32_t i;
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;
}
else
{
/* full */
break;
}
}
}
Uart_ep.c中
#include "uart.h"
void user_uart_callback(uart_callback_args_t *p_args)
{
/* Logged the event in global variable */
g_uart_event = (uint8_t)p_args->event;
if(UART_EVENT_RX_CHAR == p_args->event)
{
uint8_t tmp = (uint8_t ) p_args->data;
uart_rx_handler(&tmp, 1);
}
}
uint32_t uart_read(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;
}
int uart_write(uint8_t *buff, uint32_t len)
{
uint32_t i;
for(i=0; i<len ;i++)
{
uart_sendbyte(buff[i]);
}
return 0;
}
uart_sendbyte在uart_ep.c中实现
void uart_sendbyte(uint8_t ch)
{
uint8_t tmp = ch;
fsp_err_t err = FSP_SUCCESS;
uint32_t local_timeout = (DATA_LENGTH * UINT16_MAX);
/* Reset callback capture variable */
g_uart_event = RESET_VALUE;
/* Writing to terminal */
err = R_SCI_UART_Write (&g_uart_ctrl, &tmp, 1);
if (FSP_SUCCESS != err)
{
return;
}
/* Check for event transfer complete */
while ((UART_EVENT_TX_COMPLETE != g_uart_event) && (--local_timeout))
{
/* Check if any error event occurred */
if (UART_ERROR_EVENTS == g_uart_event)
{
return;
}
}
return;
}
使用原来的uart_initialize
uint8_t buffer[128];
for(;;)
{
uint32_t len=0;
if((len = uart_read(buffer, sizeof(buffer))) >0)
{
uart_write(buffer, len);
}
}
上位机发送,开发板原样返回,收发数据一致说明功能OK
uart.c
#include <stdint.h>
#include "uart.h"
#include "bsp_api.h"
#define Alloc_Critical() FSP_CRITICAL_SECTION_DEFINE
#define Enter_Critical() FSP_CRITICAL_SECTION_ENTER
#define Exit_Critical() FSP_CRITICAL_SECTION_EXIT
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;
uint8_t uart_ring_buffer[128];
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,
};
void uart_rx_handler(const uint8_t *buffer, uint32_t length)
{
uint32_t i;
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;
s_ring_buffer_t.datalen_u32++;
s_ring_buffer_t.in_u32++;
s_ring_buffer_t.in_u32 %= s_ring_buffer_t.maxlen_u32;
}
else
{
/* full */
break;
}
}
}
uint32_t uart_read(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.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;
}
int uart_write(uint8_t *buff, uint32_t len)
{
uint32_t i;
for(i=0; i<len ;i++)
{
uart_sendbyte(buff);
}
return 0;
}
uart.h
#ifndef UART_H
#define UART_H
#include <stdint.h>
void uart_rx_handler(const uint8_t *buffer, uint32_t length);
uint32_t uart_read(uint8_t *buff, uint32_t len);
int uart_write(uint8_t *buff, uint32_t len);
extern void uart_sendbyte(uint8_t ch);
#endif
依赖底层的串口驱动,实现了基于循环缓冲区FIFO的串口驱动接口,方便后面应用层使用。
得益于官方完善的驱动和Demo可以很快速的实现。
这个点用内存空间大吗?其实可以上RTT,他带的shell更强大。