您的位置:首页 > 其它

协议——如何制作一个简易的串口通信协议

2015-08-28 22:37 239 查看
=================================版权声明=================================

[b]版权声明:本文为博主原创文章 未经许可不得转载
[/b]

请通过右侧公告中的“联系邮箱(wlsandwho@foxmail.com)”联系我

未经作者授权勿用于学术性引用。

未经作者授权勿用于商业出版、商业印刷、商业引用以及其他商业用途。                

本文不定期修正完善,为保证内容正确,建议移步原文处阅读。 <--------总有一天我要自己做一个模板干掉这只土豆

本文链接:/article/5266600.html

耻辱墙:/article/5266550.html

=======================================================================

前几天收到个电话,说我给他们投了简历要我去面个试,这根本就是在撒谎,我只是刷新了简历还没有开始投递呢。

我一看距离也近两站路的样子,里面也有个同学好几年没见了,就花半天去参观一下吧。

然而并没有见到他。然后,没了。

对我来说笔试题得个二三四五十分已经不少了。

=======================================================================

吐槽完还是写点有意思的东西吧,算是一个梳理小结。

=======================================================================

点击上方耻辱墙,共同鄙视侵犯知识产权的非法转载小网站!

=======================================================================

本文仅面向“HelloWorld读者”,“Hello51读者”和“HelloARM读者”以及“HelloInternet读者”请关闭浏览器,因为你们会的更多。

本文内容基于RS232 DB9,只是用235三根线。

我并不了解嵌入式和单片机编程,本文有关嵌入式和单片机的内容纯属道听途说,并不可信。

本文内容并不包含具体实现细节。

本文只是写了一点我对串口通信协议的看法。

写此文的目的是不想再碰到只有两条简单格式就敢说是XXX协议的东西,天知道以后更改/扩展起来有多难。写此文纯粹是最近健忘,想把思路记下来,以便日后反思提高。

虽然我写了一个15页的详细协议实现,但是我不想去警署喝茶。本文内容不包含我在任何工作中写的任何文档或代码的内容。只是记录了我当时的想法以及现在的思考。

=======================================================================

做一个东西,要考虑很多事情,先来点大方向/显而易见的问题吧,便于启发思维,只是举几个最最容易想到的问题。

1 用16进制还是10进制/ANSI码?

  对PC来说没什么,随便一个处理器都能很快处理。

  对单片机或者嵌入式来说,如果不是很紧急的数据也没什么,慢慢发慢慢收就是了(通常是发),终归是能处理的。很幸运我遇到的都是不要求传输速度的。而且从调试和日志备份上讲,常人都是喜欢后者的。

2 串口用到了几根线?

  我只用过2、3、5三根线,据说其他的也很有用途,可是嵌入式和单片机的同事都不打算用,我干着急有何用呢。

3 数据用定长还是变长?

  仅次于咸豆腐脑和甜豆腐脑的问题。最明显的,定长老实忠厚,变长灵活乖张。

  定长的便于分析处理,趋近于一目了然,日后调试也方便,但是不便于扩展

  变长的便于扩展,但是需要根据当前数据包中附加信息来读取数据,例如有多少数据、每个数据的起始位置。

  个中滋味,自己体会。

4 间歇发送还是持续发送?

  当数据到来的时候,通过时间间隔来确定是不是完成了一次数据接收。如果两次数据包之间的间隔很短,会导致两个数据包连在一起,庆幸的是尽管如此但不会丢失数据——因为串行传送。如果发生了怎么处理?

5 如何保证串口通信是正常的?

  不管接收方是否正常接收,发送方始终都能通过打开的串口发送数据——即使没有连接串口线!那么该如何确保数据的准确和到达?

6 单片机/嵌入式是主动发送还是被动接收数据?

  这个也是仁者见仁智者见智,同时还要看到底要做什么。片上系统的性能必然不如PC机,把通信逻辑放在PC上,可以减轻片上系统的压力和编程难度。而且静默的设备也可以防止监听只能窥测。

=======================================================================

只要是会一点点网络编程的人一下子就会想到,这和UDP是有些相同的!

是的,在某些情形下是很相似。我也确实借鉴了一些网络设计的思想。

观众:所以你赶紧回家抱孩子去吧!

然而我并没有女朋友。

=======================================================================

我遇到的很简单,不需要发送速度——很久才能收发一个数据包(按秒算),也不需要即时响应——并不是做锅炉之类的东西(BOOM!:(),唯一要做的就是确保数据是真实有效的。

=======================================================================

据嵌入式的同事说,串口这东西要根据一个特定电平来确定一个数据的开始,我也不考虑是不是持续的,Windows的插件/类库为我保驾护航。

据嵌入式的同事说,发送和接受的数据要有特定的内容才能够在可怜而又有限的缓冲中搞到数据——你至少要确定哪里才是数据的头吧!数据结束的判定也是如此。

现在,我能够确定,数据包格式需要特定的数据来标识起始位置。

喜欢恶搞的可以2333开头,886结尾。然而这并不是好的实践,出来混总会遇到类似的数据——万一数据就是有一个2333怎么办?传送时间“23:33”的时候约定不传冒号也不是没可能的!

所以通常会用一些特殊符号来表示开头结尾,喜欢恶搞的人又可以用颜文字了!

开头  ヾ(o◕∀◕)ノ

结尾  ≧︿≦

开个玩笑,真要这么写,估计会名垂青史,另外还要注意嵌入式/单片机支持何种字符集,可别玩大了。

不过用“{{{”开头、“}}}”结尾还是可以的。

(太严肃并不好,严格要求自己倒是没什么问题。)

=======================================================================

设备采集/生成数据后发送给PC,PC收到。

设备采集/生成数据后发送给PC,PC未收到。

怎么办呢?有的设备会自备一块存储器,存储数据等待适当时机发送,例如PC请求缺失的数据时,这种设备会再次发送。

这就需要区当前获得的数据是那种情形,是即时的还是存储的。

现在,已经确定,数据包格式需要特定的标签来区分数据的性质。

=======================================================================

下面是数据包的数据部分了。没啥说的。不过要保证数据部分是正确无误的,还需要一个校验码来做验证。常见的有妇孺皆知的CRC。

不过累加求余也是可以的。看个人爱好和心情。

可能有人会说这个在物理设备上已经保证了,是的,串口设备会保证数据的准确。可是,如果数据由串口经过网络传输呢?通过RJ45网络发送串口数据的设备一搜一大堆。

这样可以原样转发,不需额外操作。

=======================================================================

这样基本上就能用了。

然而,怎样保证线路能用呢?

用心跳检测吧。无非就是一问一答,再问再答,不吭声就再问几次,还是不理睬就宣布“出局”。

可以参考这个/article/5266553.html

=======================================================================

曾经我以为这就行了,其实,最好能再用两个字节来表示下版本号。位置倒是无所谓,有个位置就好。这便于扩展升级、同时兼容不同的片上系统。

仪器更新换代,也可能不是同一批次的,但是PC端可以通过实现额外的协议来接收到来的所有数据。但是总得区分开。

=======================================================================

假如设备传送一个数据一次没成功,第二次传送也没成功,第三次、第四次都没成功,于是大家都放弃了这条数据。

要怎么实现呢?由谁来记录传送的次数?

片上系统?这无疑是给骆驼增加了一筐稻草。频繁的中断对片上系统来说并不好。

PC?如果PC接收几十甚至几百的串口数据,编程的难度会增加,而且也不利于后期调试。

我觉得模仿TTL来实现确认机制是个不错的做法,是的,借鉴计算机网络的知识——将计数放在确认包里,每到达一次就改变一次计数。

好处显而易见,大家都不用计数,极大的简化了模型,降低了难度。

=======================================================================

要注意的是心跳包和确认包是不同的。心跳包确保通信正常,确认包确保数据正常。

=======================================================================

现在扩大问题规模,考虑传送一批数据包时,怎样记录数据的发送接收情况。

首先传送一批数据,片上系统应该先向PC发送数据的规模。

然后发送利用上面说的确认机制来处理每个数据包

最后发送一个表示结束意义的东西来表示完成整个过程。

分三步走的批量发送意义在于

1 明确表示了传送的开始、传送的结束——这便于PC设置和处理事件

2 确保了遇到无效数据包时,确认机制能够让数据正常发送下去。

这里会发现,之前的确认包可能不够用、设计的不好,因为需要记录总包数、当前包数、当前包的TTL之类的信息。

所以,设计总是在不断的改进中得到完善。

=======================================================================

上文并不代表真正的工业设计实践,只是我的臆测瞎想,我也想有个瓢可以照着画,可现实是大家都掖着藏着,所以我只能自己造轮子。

=======================================================================

先写这么多吧。晚上该洗洗睡了。有空再补充。

=======================================================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: