通用串口通讯程序设计

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
||帧头段|===|数据段|===|校验码|===|帧尾段|| II 类时隙通讯:
||开始时隙 T(T1T2T3T4T5T6)|=|功能码|=|数据段|=|校验码|=|结束时隙 T(T1T2T3)| 注意:时隙只是纯粹的前后两帧数据的间隔时间,这期间坚决不能有数据产生。
1. 1 I 类通用型
帧头段 帧头段用于鉴别一串字节流中 1 帧数据起始位置,这个帧头段必须具有足够的特殊标识
效验码(CHK AREA)
CRC16 校验,多项式
(0xA001)
CRC16 低字 CRC16 高字


2Byte
帧尾段(EOF AREA)
EOF 帧尾
2Byte
帧内位置
0,1
2,3
4
5
6 …… N
N+1
N+2
N+3,N+4
取值范围 :(0x3A),@(0x40) 0x0 ≤ Len ≤ 0xFFFF 0x00 - 0xFF
‘U’(55H)、‘@’(40H)等等 只要保证帧头字节数据内容,在所有通讯数据字节流中,除帧头有意为之而出现,那就
是帧头。建议最好有两个字节及以上,这样数据出现与帧头一致的概率更加小,才做到独一 无二的特殊性。
第 2 页 共 13 页
表(1)类通用型(TYPE_A/V1.0)帧格式
I 类通用型(TYPE_A/V1.0)帧格式
(易分辨)。 什么样的特殊标识可作为帧头? 根据个人经验: ①具有监测通讯波特率功能特点:0B01010101(55H)、0B10101010(AAH)或 0B00000000
(00H)、0B11111111(FFH); ②利用 ASCII 码如 MODBUS ASCII 规约以冒号‘:’(3AH)作为帧头。也可以采用 ASCII
数据域长度 数据域长度信息是非常关键的数据。(当然,也有特殊类型通讯协议/规约不需要.) 数据域长度字段的值限定/定义数据域的字节个数信息。详见“表(1)、表(2)、表(3)”
帧格式数据域长度与数据域关系划分。
案例之一: 接收程序流程刚好将帧头、功能码/判断完毕,然后中断程序莫名原因(非法指令)引
两个字节帧头模式出现概率很低; 一个字节帧头模式出现概率很高。除非有对帧头特殊处理过程(补码替换(或取反模式), 这又涉及到识别哪个或哪几个字节是用补码(或取反)替换的?这里不做特殊处理扩展。 接着说普通简单做法—— 第一步:找帧头 一般通讯数据帧都是一帧一帧发送,只要接收到前面的数据帧传输正确,即使下一帧的 数据中有和帧头一样的数据(含帧头)也没有问题。 设置接收数据从开始就寻找接收到的第 1 个字节为帧头(if (data == SOF)判断(非单一 时隙式通讯模式)。当获取到帧头后,设值准备接收进度计数器(寄存器内部值)第 2 个字 节——功能码 (或 数据域长度);若不是帧头,接收进度计数器(寄存器内部值)不改变, 继续执行接收进度寄存器为“寻找帧头”。
N+3 0x0D
第 4 页 共 13 页
表(3)类通用型(TYPE_C/V1.0)帧格式
I 类通用型(TYPE_C/V1.0)帧格式
8*N 串二进制流
N 串字节流
校验/检查区域(CHECK AREA)
帧结构 帧头段(SOF AREA)
数据段(DATA AREA)
数据域
SOF
Function
Lenght
累加和校验算法简单,单片机的运算资源占用量小,累加最后只取最低字节就行,不是高字 节(至于原因后续再单独聊)。保存累加和的变量使用 1 个字节,简单好用。
CRC 校验,算法比较复杂。CAC 是对帧数据中每个字节的每二进制位(BIT)进行校验,具 有很高纠错率,只要数据帧中有一个数据的 1 个二进制位发生变化,都能检查出错误。
校验码 一帧数据在传输过程可能会被干扰,使得接收端获取的数据是错误的。为保证一帧数据的准 确性和完整性,就引入了校验功能,好的校验可以逆向还原一帧数据中的错误数据。 (密钥不在这里讨论!)
校验有很多方式,累加和校验、CRC 校验等。
第 7 页 共 13 页
(奇偶校验只针对 1 个字节校验,一般不做 2 字节以上数据帧校验)。
通用串口通讯程序设计
作者:和光同尘 版本:V1.0

做硬件开发近 20 载,花了近十年做基础开发,对硬件开发略知一二,接触的做国防/ 工业大项目的人才我就是和他们沟通中获取了很多思想;人生已过而立之年,不惑解疑,总 想写点什么。从一线研发(做了 4 年),开发(3 年),硬件开发主管(12 年),算起来人生 从不到弱冠之年(中专毕业)开始接触 MCS51、AVR 等 8 位处理器到 ARM v7 核、CoretxM 核的 32 位处理器,CPLD/FPGA、PLC…………啰嗦了!! 最近因为工作原因需要把一些自己感悟的记录下来,希望传递给入门的有心沉下心做基础健 壮扎实的初学者。
是帧头。建议最好有两个字节及以上,这样数据出现与帧头一致的概率更加小,才做到独一 无二的特殊性。
怎么设计帧头?怎么保障唯一性性(尽量接近唯一,发生重复概率越小,唯一性越高, 也就让接收数据识别性越高)。
数据域内的数据是很难满足(概率事件)不包含和帧头一样的数据不出现。
那么尽量避免除了帧头外其他部分也有这样的两个字节(简单通讯 1BYTE 帧头也可以) 的帧头出现,那会出现什么问题?
起没有及时读取/释放串口 BUF 中数据,就会在获取数据时得到错误的数据,这个错误的长 度数据可能导致创建的栈溢出,引发周边数据被篡改(注意所有字节变量定义区域选择,根 据单片机 RAM 资源,合理分配变量所处位置,尽量局部变量定义在 DATA、IDATA 区域,程 序执行效率也高些;数据栈定义在 XDATA 区域),数据栈溢出处理不好将是灾难性事件。在 接收数据域的数据之前切记一定要判断数据域长度信息(空闲中断除外)是否合法,不合法 的及时抛弃掉这帧数据,复位接收标识状态,准备新一帧的数据检查接入栈工作。
第 6 页 共 13 页
(状态机也就这个原理。状态机多了 PUSH\POP 栈流程。)
设计功能码,必须考虑兼容性和扩展性,对数据帧的功能进行划分,坚决杜绝想到一个算一 个,功能码也不能随意/随便/随心的安排,否则在以后增加数据帧的时候会很麻烦。
功能码长度:1 个字节(取值范围:0‐255) 一般 256 种功能分类够用;不够就扩展到两个字节。 编码规则(建议): 高四位二进制作为父类编码,低四位二进制父类中子类。这样就可以将系统数据通信帧 分为 16 个大类,每个大类下有 16 个可用的具体类,当你增加功能码的时候,就可以根据 你的设计来确定属于哪个大类了,然后再插入进去。这样在管理、维护这些通信数据时你会 发现很方便。 这个编码规范在 ARM 内核的中断系统和设计 uCOS II 任务优先级的时候都有使用到, 在设计项目的通信协议的时候就是运用了这些思想。
8*N 串二进制流
N 串字节流
校验/检查区域(CHECK AREA)
帧结构 帧头段(SOF AREA)
数据段(DATA AREA)
数据域(DATA AREA LENGHT)
SOF
Lenght
帧头
数据域长度
Function
DataBuf[N]
功能码
数据
字节数
2BYTE
2BYTE
1Byte
0Bytes To NBytes
I 类通用型(TYPE_B/V1.0)帧格式
8*N 串二进制流
N 串字节流
帧结构 帧头段(SOF AREA)
ຫໍສະໝຸດ Baidu
校验/检查区域(CHECK AREA) 数据段(DATA AREA)
SOF
ADDR
FUN
Lenght
数据域(DATA AREA LENGHT)
帧头
地址码
功能码
数据域长度
数据 DataBuf[N]
字节数
1BYTE
1BYTE
1BYTE
1BYTE
(2 - 4)Bytes
效验码(CHK AREA)
CRC16 校验,多项式(0xA001) CRC16 低字节 CRC16 高字节
帧尾段 (EOF AREA)
EOF 帧尾
2Byte
1Byte
帧内位置
0
1
2
3
4
5
……
N
N+1
N+2
取值范围 注:
:(0x3A)
第 5 页 共 13 页
1.2 接收程序编写考虑因素
数据“功能码”指针 数据包指针 FIFO 缓存读/写指针的互斥锁释放顺序 数据帧检查/校验 串口空闲 缓存数据帧存放时间/生命周期,超时识别 通讯数据吞吐量,(帧间隔时间,保证单片机有充分时间处理其他事情。)
帧头 只要保证帧头字节数据内容,在所有通讯数据字节流中,除帧头有意为之而出现,那就
这种校验方式占用单片机的运算资源量较大,目前有些单片机嵌入了硬件 CRC 模块(如 stm32 单片机)。
校验是通讯规约约定检验字节起点和结束位置。 建议:从帧头开始到数据域最后一个字节。也可以只检验数据域,这只是区别在单片机运算 量问题。建议从帧头开始校验,能保证整个帧数据的准确性。
帧尾 前面说了,帧尾在空闲中断中可以不用,RXNE 中断接收时其实也可以不用,当然也可以加 上,好处就是当你用串口助手查看数据流时,可以观察出一帧数据是否发送完整了。
第 1 页 共 13 页
正文
做嵌入式硬件开发一般都会用到通讯数据交互,这就涉及通讯协议/规约的设计。本文 从基础的串口(RS232、RS485 等)为模型进行讲解。 说道串口通讯,就是编写串口程序,简单的就是 1 个字节的发送,1 个字节的接收,但这不 能满足绝大多数实际工作业务需求,实际需要一串字节数据的交互,A 发送,B 接收……Z 接收;Z 机……B 机收到根据情况需要回复(ACK)A 机,这个过程就叫交互双向通讯(本文 不讨论多主机、1 主机相对复杂通讯机制。)。这种通讯就需要提前设计好通讯的规约(大家 约定好暗号——每个字节代表什么意思)。 接下来编写通信程序(发送/接收),如何写出一个健壮高效串口程序?是否健壮高效其实很 大一部分取决于通讯接收程序的架构。 通讯程序编写依据是——通讯规约,通讯帧的设计。 I 类通用型:
确保及时接收数据: ① 采用 DMA 模式(单片机若有); ② 设定串口通讯为最高有效优先级中断; ③ 接收程序在读取 BUF 数据时进可能先读取到临时/中转寄存器中,再做数据识别。
数据域 整个帧需要的最有用的数据。 接收/发送函数能处理各种类型的数据,建议参数类型定义成 void *DataPtr 是不错的选择。
帧内位置
0,1
2
3,4
5
6 …… N
N+1
N+2
N+3,N+4
取值范围 :(0x3A),=(0x3D) 0x00 - 0xFF 0x0 ≤ Len ≤ 0xFFFF
0x00 ~ 0xFF
0x00 ~ 0xFF
CR(0x0D),LF(0x0A)
注:
1.N 取值范围:0 To 65535 。 2.CRC 验证起止段:开始于帧头(SOF),结束于 CRC 验证码(低字节)前最后一个有效数据字节(DataBuf[N]),CRC 验证:多项式(0xA001).
(DATA AREA LENGHT)
帧头
功能码
数据域长度
DataBuf[N]
数据
字节数
2BYTE
1BYTE
2Byte
0Bytes To NBytes
效验码(CHK AREA)
CRC16 校验,多项式
(0xA001)
CRC16
CRC16
低字节
高字节
2Byte
帧尾段(EOF AREA)
EOF 帧尾 2Byte
0x00~0xF F
0x00~0xFF
0x00~0xFF
0x00~0xFF
0x00 ~ 0xFF
1.Databuf[N],N 取值范围:2(PC->H 型),4(H 型->PC)。
2.CRC 验证起止段:开始于帧头(SOF),结束于 CRC 验证码(低字节)前最后一个有效数据字节,CRC 验证:多项式(0xA001)。
特例 1: 串口空闲中断:帧头、帧尾都可以不用。建议,帧头保留,帧尾可以不需要。当单片机 没有串口空闲中断时考虑,也可能有其他考虑,所以帧头得保留。
功能码 功能码主要用于说明该数据帧的功能,也可作为函数指针的索引,一个索引值代表了一
个具体功能,据此可找到对应的功能函数。
比如: 设计一个函数指针数组,通过功能码进行索引,进而跳转到对应的功能函数执行程序。
0x00 ~ 0xFF
0x00 ~ 0xFF
0x0D
注:
1.N 取值范围:0 To 65535 。 2.CRC 验证起止段:开始于帧头(SOF),结束于 CRC 验证码(低字节)前最后一个有效数据字节(DataBuf[N])。CRC 验证:多项式(0xA001).
第 3 页 共 13 页
表(2)类通用型(TYPE_B/V1.0)帧格式
相关文档
最新文档