论多串口通信架构(方便多编程语言和不同硬件之间移植)
2016-03-15 13:58
513 查看
论多串口通信架构(方便多编程语言和不同硬件之间移植)
标签(空格分隔): 多串口 队列 多语言移植写此文的目的有二:
1、方便自己,觉得在以后的工程中,总是避不过多串口的问题,不像单串口时那么简单,考虑到可靠性,要使用队列,而且指令有首尾标志位时,也需要识别。如果只用一种语言写,在用另外一种语言或者另外一种硬件时,又要重新想结构。希望能写出一个架构,每次套用即可。
2、也是把经验分享给新手,节省时间。
下面以C语言为例来说明架构
1、文件层面上
UART_QUEUE.h | UART_QUEUE.c |
---|---|
变量定义:队列结构体、接收完整指令数组 函数声明:.c文件里的函数 | 1、初始化 : Uart_Init(UARTX) 初始化UARTX的寄存器,设置波特率,定义这个口的队列,接收\发送完整指令数组,还有所有串口初始化的公用部分。 2、队列初始化: Uart_Queue_Init(UARTX_queue) 将队列的队首队尾初始化 3、存入队列 : Uart_Queue_pushAchar(UARTX_queue,data) 将data存入UARTX_queue的队尾 4、取出队列: Uart_Queue_popAchar(UARTX_queue) 返回值是从队首取出的一个数据 5、计算队列长度: Uart_Queue_size(UARTX_queue) 若队列中没有数则不进行取数。 6、取出一条完整的指令 : Uart_Queue_getAcmd(&cmd_bufferX_R[],UARTX_queue) 返回值是指令的长度,若是没有读取到完整的指令则返回0 7、发送一个字节 : Uart_sendAchar(UARTX,data) 8、发送一个字符串 Uart_sendAcmd(UARTX,data) |
2、图解数据的流动
队列初始状态
队首在队尾后
队首在队尾前
3、程序流程图
Created with Raphaël 2.1.0https://www.zybuluo.comStarthttps://www.zybuluo.com串口初始化串口队列初始化串口中断Yes or No?存入串口队列一个数据获得一条完整的指令yesno4、代码模板
UART_QUEUE.h#define QUEUE_MAX_SIZE 40//串口接收缓存长度 #define CMD_MAX_BUFFER //一条指令的最大长度 typedef struct _QUEUE { qsize _head; //队首 qsize _tail; //队尾 qdata _data[QUEUE_MAX_SIZE]; //队列空间 } QUEUE;//串口数据接收队列结构体 typedef struct _SERIALCMD { uchar idata cmd_buffer_pointer; //cmd数组的计数指针,因为不一定调用一次取CMD函数就能取出一帧指令,所以这个变量必须是全局变量,在取出一帧后,清0. uint8 xdata cmd_buffer_R[CMD_MAX_BUFFER]//串口接收指令数组 uint8 xdata cmd_buffer_T[8];//串口指令发送数组 } SERIALCMD;//串口指令结构体
UART_QUEUE.c
#include "UART_QUEUE.h" QUEUE xdata UARTX_queue = {0,0,0}; //定义串口X队列 SERIALCMD xdata UARTX_cmd = {0,0,0};//定义串口X的指令结构体 /******************************** *名 称: Uart_Init *功 能: 串口初始化 *入口参数: 串口号 *出口参数: 无 *********************************/ Uart_Init(UARTX) { IO_init(); //串口对应的IO口初始化 switch(UARTX) { case UART1: /*设置串口模式,波特率等,使能中断*/ break; case ... } EA = 1; //开启总中断 } /******************************** *名 称: Uart_Queue_Init *功 能: 串口队列初始化 *入口参数: 串口队列 *出口参数: 无 *********************************/ Uart_Queue_Init(UARTX_queue) { UARTX_queue._head = UARTX_queue._tail = 0; //清空队列 } /******************************** *名 称: Uart_Queue_pushAchar *功 能: 存入串口队列一个数据 *入口参数: 串口队列 *出口参数: 无 *********************************/ Uart_Queue_pushAchar(UARTX_queue,data) { UARTX_queue._tail = (UARTX_queue._tail+1)%QUEUE_MAX_SIZE; //将UARTX_queue.tail限制在队列的长度范围内 if(UARTX_queue._tail!=UARTX_queue._head)//非满状态 UARTX_queue._data[(UARTX_queue._tail)%QUEUE_MAX_SIZE] = _data; } /******************************** *名 称: Uart_Queue_popAchar *功 能: 取出串口队列一个数据 *入口参数: 串口队列 *出口参数: 取出的数据 *********************************/ Uart_Queue_popAchar(UARTX_queue) { int data; if(UARTX_queue._tail!=UARTX_queue._head)//非空状态 { UARTX_queue._head = (UARTX_queue._head+1)%QUEUE_MAX_SIZE; data = UARTX_queue._data[UARTX_queue._head]; return data; } } /******************************** *名 称: Uart_Queue_size *功 能: 算出串口队列的长度 *入口参数: 串口队列 *出口参数: 队列长度 *********************************/ Uart_Queue_size(UARTX_queue) { return ((UARTX_queue._tail+QUEUE_MAX_SIZE-UARTX_queue._head)%QUEUE_MAX_SIZE); } /******************************** *名 称: Uart_Queue_getAcmd *功 能: 获取一帧完整的指令 *入口参数: 接收指令数组,串口队列 *出口参数: 指令长度 *********************************/ Uart_Queue_getAcmd(UARTX_cmd,UARTX_queue) { int cmd_data; while(Uart_Queue_size(UARTX_queue)>0) { //取一个数据 cmd_data = Uart_Queue_popAchar(UARTX_queue); if(UARTX_cmd.cmd_buffer_pointer == 0 && cmd_data != 帧首) //帧头出错,跳过 continue; /*此处自己添加获取帧长度的代码,根据协议,帧长度在一个帧的不同位置*/ if(UARTX_cmd.cmd_buffer_pointer<帧长度)//防止缓冲区溢出 { UARTX_cmd.cmd_buffer_R[UARTX_cmd.cmd_buffer_pointer] = cmd_data; UARTX_cmd.cmd_buffer_pointer++; } //得到完整的帧 if(UARTX_cmd.cmd_buffer_pointer==帧长度) { /*若有校验位的话,此处计算校验位,并检验*/ UARTX_cmd.cmd_buffer_pointer = 0; //清0,准备下一个帧计数 return 1; } } return 0;//没有形成完整的一帧 } /******************************** *名 称: Uart_sendAchar *功 能: 串口发送一个字节 *入口参数: 串口号,数据 *出口参数: 指令长度 *********************************/ Uart_sendAchar(UARTX,data) { switch(UARTX) { case UART1: /*此处是发送data的程序,不同的硬件不一样*/ break; case ... } } /******************************** *名 称: Uart_sendAcmd *功 能: 串口发送一个字符串 *入口参数: 串口号,串口发送数组UARTX_cmd.cmd_buffer_T[] *出口参数: *********************************/ Uart_sendAcmd(UARTX,&str) { uchar count=0; do { Uart_sendAchar(UARTX,*str) str++; count++; }while(count!=帧长); //因为指令中可能包含0x00.所以要用这个函数判断是否发送完一帧,否则会丢失0x00后的数据 /*若是发送帧长未知,则可以用如下程序*/ while(*str!='\0') { Uart_sendAchar(UARTX,*str); str++; } }
相关文章推荐
- 学习网站整理
- 如何扩展大规模Web网站的性能?
- 网站验证码
- ASP.net MVC 网站发布 navbar 背景图片丢失 ArcGIS Web 开发学习(五)
- 珠宝网站 今日金价 采集(伦敦实时交易价格)
- firefox浏览本地网站慢的问题
- 大型网站架构演化历程
- 网站的最大并发连接数
- 网站流量与性能分析指标:PV/UV/PR/IP/QPS/并发数/吞吐量/响应时间
- java分布式通信系统(J2EE分布式服务器架构)
- HBase应用场景、原理与基本架构
- 从零开始的Android新项目1 - 架构搭建篇
- 如何应对云爆发架构?四种方法替你解忧
- 苹果开源网站
- [国嵌攻略][145][块设备系统架构]
- Android之Jsoup解析Html抓包其他网站数据
- Android 控件架构
- 高并发服务器的设计--架构与瓶颈的设计GOOD
- Android系统架构
- Mvc设计模型与三层架构