基于环形队列的UART收发回显实验

描述

18.7

实验3:基于环形队列的UART收发回显

在实际项目开发中,由于有些串口不具备FIFO(如SCI1和SCI2)或FIFO的buffer比较小,这可能会在数据处理速度小于数据接收速度的时候,导致数据的丢失。因此我们可以设计一个队列来避免这一问题。在本实验中,我们使用环形队列来实现实验1的串口收发回显,将串口接收到的数据暂存在队列中,待完成一次接收后再将队列中的数据全部发出去。

队列是一种特殊的线性表,只允许在队列头(head)删除元素,在队列尾(tail)添加元素。当队列添加一个元素,队列尾向后移动,当队列删除一个元素,同样,删除一个元素,队列头向后移动,如图19_18。

led灯

图19-18 队列图示

由于存储空间是有限的,如果使用线性队列,删除元素后就会空出一段存储空间,这会造成很大的浪费。因此实际上我们更多使用环形队列。并不是说这段存储空间是环形的,而是头指针和尾指针到达存储空间末尾后会回到存储空间起点。因此在逻辑上这是循环的,如图19_19。

led灯

图19-19 环形队列

18.7.1

硬件设计

本实验使用到开发板的串口和LED灯,其原理图在本章实验1和前面的点亮LED灯章节有介绍,这里不进行赘述。

18.7.2

软件设计

18.7.2.1

新建工程

因为本节的UART实验例程与上一个实验例程的FSP配置以及UART相关的一些代码基本一致,因此我们可以直接以前面的“19_UART_Receive_Send”工程为基础进行修改。

对于e2 studio开发环境:拷贝一份我们之前的e2s工程模板“19_UART_Receive_Send”,然后将工程文件夹重命名为“19_UART_Circular_Queue”,最后再将它导入到我们的e2 studio工作空间中。

对于Keil开发环境:拷贝一份我们之前的Keil工程模板“19_UART_Receive_Send”,然后将工程文件夹重命名为“19_UART_Circular_Queue”,并进入该文件夹里面双击Keil工程文件,打开该工程。

FSP配置完全一致,因此我们省略掉这部分。

18.7.2.2

环形队列的实现

列表8:代码清单19-7:环形队列头文件内容

左右滑动查看完整内容

 

#defineDATA_LEN 300//队列缓存大小
typedefstruct
 {
 uint16_thead; //头指针
uint16_ttail; //尾指针
uint8_t data[DATA_LEN]; //队列数据
}Circular_queue_t;
 externCircular_queue_tCircular_queue;//环形队列全局变量
boolQueue_Init(Circular_queue_t*circular_queue); //初始化队列
boolQueue_isEmpty(Circular_queue_t*circular_queue);//判断队列是否为空
boolQueue_isFull(Circular_queue_t*circular_queue); //判断队列是否已满
boolQueue_Wirte(Circular_queue_t*circular_queue,uint8_t *string, uint16_
 →t len);//写数据
boolQueue_Read(Circular_queue_t*circular_queue, uint8_t*string,uint16_t␣
 →len); //读数据
uint16_tQueue_HadUse(Circular_queue_t *circular_queue); //返回队列中数据的长度
uint16_tQueue_NoUse(Circular_queue_t*circular_queue); //返回未使用数据的长度

 

环形队列相关函数的具体定义可以在例程的circular_queue.c中查看,这里就不赘述了。

18.7.2.3

串口中断回调函数

debug_uart4_callback串口中断回调函数的内容修改成如下所示。

列表9:代码清单19-8:串口中断回调函数

左右滑动查看完整内容

 

/*串口中断回调*/
voiddebug_uart4_callback(uart_callback_args_t* p_args)
{
switch(p_args->event)
 {
 caseUART_EVENT_RX_CHAR:
 {
/*接收到数据后马上写入队列中*/
 Queue_Wirte(&Circular_queue,(uint8_t*) &p_args->data, 1);
break;
 }
 caseUART_EVENT_TX_COMPLETE:
 {
 uart_send_complete_flag= true;
break;
 }
default:
break;
 }
 }

 

18.7.2.4

hal_entry入口函数

hal_entry入口函数的内容修改成如下所示。

列表10:代码清单19-9:hal_entry入口函数

左右滑动查看完整内容

 

voidhal_entry(void)
{
/* TODO: add your own code here */
uint8_t Read_Buffer[DATA_LEN];
uint16_t Read_Length;
 LED_Init();
// LED 初始化
Debug_UART4_Init(); // SCI4 UART 调试串口初始化
Queue_Init((Circular_queue_t*)&Circular_queue); //环形队列初始化
printf("这是一个串口环形队列例程
");
printf("打开串口助手发送数据 5 个及以上的数据,接收窗口会打印所发送的数据
");
while(1)
 {
if (Queue_isEmpty(&Circular_queue) == false) //判断队列中的数据不为空
{
 Read_Length = Queue_HadUse(&Circular_queue);
if( Read_Length >= 5)
// 如果队列中的数据大于等于 5 个,开始打印
队列中的所有数据
{
printf("Read_Length=%d: ", Read_Length);
memset(Read_Buffer, 0, DATA_LEN);
/* 读出 Read_Length 个数据 */
 Queue_Read(&Circular_queue, Read_Buffer, Read_Length);
printf("%s
", Read_Buffer);
  }
 }
 R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
 }
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
 R_BSP_NonSecureEnter();
#endif
 }

 

18.7.3

下载验证

保证开发板相关硬件连接正确,用Type-CUSB线连接开发板“USBTOUART”接口跟电脑。本次实验需要使用到串口调试助手,配置好串口参数并打开串口后,在调试助手的发送区域输入超过5个的任意字符并点击发送,即可在接收区看见返回字符,不一定马上全部返回全部的已发送的字符,可以多发送几次数据观察,数据并没有丢失。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分