您的位置:首页 > 运维架构 > 网站架构

论多串口通信架构(方便多编程语言和不同硬件之间移植)

2016-03-15 13:58 513 查看

论多串口通信架构(方便多编程语言和不同硬件之间移植)

标签(空格分隔): 多串口 队列 多语言移植

写此文的目的有二:

  1、方便自己,觉得在以后的工程中,总是避不过多串口的问题,不像单串口时那么简单,考虑到可靠性,要使用队列,而且指令有首尾标志位时,也需要识别。如果只用一种语言写,在用另外一种语言或者另外一种硬件时,又要重新想结构。希望能写出一个架构,每次套用即可。

  2、也是把经验分享给新手,节省时间。

下面以C语言为例来说明架构

1、文件层面上

UART_QUEUE.hUART_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?存入串口队列一个数据获得一条完整的指令yesno

4、代码模板

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++;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: