找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4156|回复: 28
打印 上一主题 下一主题
收起左侧

一个关于单片机串口通信协议的问题

[复制链接]
跳转到指定楼层
楼主
ID:404263 发表于 2022-4-25 16:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
如果说单片机串口的通信协议是以字符串的形式来通信的话,大佬们有没有好的处理方式,比如这个协议的字符长短是不固定的,模块会给我单片机下发GETxxxxxxx,SETXXXXXX,RESETxxxxxx,之类的一堆字符串,我之前的做法是识别开头的字符,结束就判断\r\n,但是感觉不同指令用不同的头码识别,这个好像不太高效,随着协议的增加,程序会变得十分臃肿,希望有大佬能指导一下这种字符串协议的该怎么写好
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:390416 发表于 2022-4-25 18:24 | 只看该作者
参考MODBUS 协议,以时间间隔作为一串数据的结束和下一次数据的开始
回复

使用道具 举报

板凳
ID:624769 发表于 2022-4-25 19:10 来自触屏版 | 只看该作者
没必要纠结这个效率,当你定义指令以字符串方式来收发时,表示你已经不在意这个效率了,能识别即可,
回复

使用道具 举报

地板
ID:401564 发表于 2022-4-25 20:25 | 只看该作者
上位机和下位机之间串口通讯基本都是这种样子的呀,有的还是固定长度的呢,长度不够的话,还得加上0x00或者0xff补齐再发送,有的后面还会跟上一堆结束符,比如说3个0xff或者是3个0x00之类的
就连数据,有的上位机都是要求发送ASCII字符串的,比如255就不会发送0xff,而是分开发送"2" "5" "5"
效率和程序代码大小并不是任何时候都要做到极致的
比如STC8A,它有64K程序空间,那省下来的几百个字节的内存,一点意义都没有
STM有的代码空间有512K,那就更不用说了
只有你的程序有实际运行,的确是因为效率或者代码真的太大了,才会开始考虑优化算法
回复

使用道具 举报

5#
ID:320097 发表于 2022-4-25 21:58 | 只看该作者
我觉得只要不产生BUG,程序能正常运行,硬件资源也够的话,不用考虑那么多
回复

使用道具 举报

6#
ID:47286 发表于 2022-4-26 00:20 | 只看该作者
你自己编个协议不就行了 所谓协议就是呼叫和应答双方能明白的约定 和硬件链路无关  你认为分别用不同前缀导致效率下降 你完全可以自己定义 1=GET 2=SET 3=RESET 然后结果就是1xxxxxxx 2XXXXXX 3xxxxxx 只要接收方能解释 你写100个字符和写1个没区别 这就是约定 和英语用缩写是一个意思
回复

使用道具 举报

7#
ID:47286 发表于 2022-4-26 00:29 | 只看该作者
188610329 发表于 2022-4-25 19:10
没必要纠结这个效率,当你定义指令以字符串方式来收发时,表示你已经不在意这个效率了,能识别即可,

纯瞎聊天

虽然大家都认为这个效率是无需考虑的 但我个人还是偏执的认为能节省一点还是好一点

假设57600bps的速率 我理解就是1秒内有57600个1 假设8个1产生一次接收中断 那就是每隔大约0.14ms会中断一次 如果用查询法ADC转换 还是次低速 大约就是这么久得到结果 但因为时序起点不对位 等待ADC结果的时候有可能被打断 如果用中断法 串口中断高于ADC中断 也会打断 速率越高打断的次数就越多

我这算法不一定对 而且打断是必然 只是偏执吧 总希望尽量少 感觉 可能 也许 会好一点 只是感觉 实际使用里好象也没什么影响 哈哈
回复

使用道具 举报

8#
ID:1013784 发表于 2022-4-26 03:56 | 只看该作者
串口的协议头都是固定的,可以写个数组来保存这些数据,然后判断解析
回复

使用道具 举报

9#
ID:404263 发表于 2022-4-26 08:06 | 只看该作者
dzbj 发表于 2022-4-26 00:20
你自己编个协议不就行了 所谓协议就是呼叫和应答双方能明白的约定 和硬件链路无关  你认为分别用不同前缀导 ...

主要是很多模块协议是固定的,如果是我自己把两个程序都写了肯定是怎么简单怎么来,但是实际项目中如果需要用别人的模块,协议只能按着他们的来
回复

使用道具 举报

10#
ID:401564 发表于 2022-4-26 10:22 | 只看该作者
dzbj 发表于 2022-4-26 00:29
纯瞎聊天

虽然大家都认为这个效率是无需考虑的 但我个人还是偏执的认为能节省一点还是好一点

串口通讯本身就不是追求非常的速度和一直在接收的状态,除非是大容量的存储
更多的时候就是接收一数据而已,你要是一直以57600的速率,一直在接收,什么算法在这都没用,程序都卡
因为你一直在进入中断,主程序根本就没有多少时间去干活
所以,你会看到9600这个设置是最常用的
回复

使用道具 举报

11#
ID:47286 发表于 2022-4-26 10:29 | 只看该作者
Y_G_G 发表于 2022-4-26 10:22
串口通讯本身就不是追求非常的速度和一直在接收的状态,除非是大容量的存储
更多的时候就是接收一数据而 ...

明白 你说的是 所以会有网关这种东西 专心处理通讯问题的模块
回复

使用道具 举报

12#
ID:213173 发表于 2022-4-26 10:43 | 只看该作者
cokesu 发表于 2022-4-26 08:06
主要是很多模块协议是固定的,如果是我自己把两个程序都写了肯定是怎么简单怎么来,但是实际项目中如果需 ...

如果所采用的模块其通信协议是供方固定的,那只能按模块供方的通信协议编程。如果采用多种不同模块(不可能太多),是会给编程带来麻烦,也没有一招天下通吃的处理方法。只能根据具体应用来规划适合的方式。串口函数本身只要能准确收发字节数据即可,帧字节长度不同也不是问题。至于数据的含义则是由解析函数来完成。总之任何合规的通信协议都有其特征,以此辨识解析也不是什么难事。
回复

使用道具 举报

13#
ID:624769 发表于 2022-4-26 11:57 | 只看该作者
dzbj 发表于 2022-4-26 00:29
纯瞎聊天

虽然大家都认为这个效率是无需考虑的 但我个人还是偏执的认为能节省一点还是好一点

既然,你开了头,我现在又闲的快啥啥啥的, 就陪你瞎聊天一下.

虽然,我也喜欢追求效率,但是不太喜欢做无用功,何为无用功呢? 对于字符串的解析来讲,你无论如何优化解析方案,效率能提高 1/10 就烧高香了。但是,你如果把传输的 ASCII 变成 HEX 其他什么都不干,效率至少提高 1/2,基于这一点,对于已经选择了 字符串方式传输的这个原则,个人觉得,再考虑优化已经没什么大的意义了,这就类似,我会去团购小作坊生产的雨刮片,而不会去砍价4S店的雨刮器一样。要么不弄,要么弄到极致。
回复

使用道具 举报

14#
ID:624769 发表于 2022-4-26 12:24 | 只看该作者
Y_G_G 发表于 2022-4-26 10:22
串口通讯本身就不是追求非常的速度和一直在接收的状态,除非是大容量的存储
更多的时候就是接收一数据而 ...

没别的意思,实在太无聊了,上海现在这情况,你应该也能理解,就当我找你唠嗑吧。

前段时间折腾光立方(很没技术含量,但能逗娃的东西),为了折腾"极致"以 STC15W104 为核心,HC595为驱动,看看可以做到什么程度,STC15W104 是没有串口的, 就用软件模拟串口,这个效率对比硬件串口来讲,大约是硬件串口的 1/10 的效率吧,毕竟每个位都要中断。光立方(3D8)的上位机软件,传输速率是 57600/115200 二选一,   由于我的光立方,阵列标准和这个上位机软件的阵列标准不符,收到上位机的数据后需要重排, 上位机的功能还挺多,除了LED阵列的控制,还有亮度,模式的控制,所以,接受到串口数据后,判断处理工作也算比较多。一下子感觉,对于没有硬件串口的STC15W104来说,还挺有挑战的。一顿的摩拳擦掌,做好准备,单片机处理速度跟不上,需要反复优化,打算和效率大战300回合。结果三下五除二,随便写一个重排代码,合并到模拟串口里面边收边重排,57600波特率毫无压力,再尝试115200依然毫无压力……。然后降低晶振速度到22118400,依然毫无压力。然后……,又没事干了……

我只想说,模拟串口115200都能游刃有余,在不停的接收数据的同时,处理各种其他工作。硬件串口57600的话,真没啥可以让系统干不了活得情况,我觉得,按现在单片机效率,57600应该属于比较标准的速率了,没必要再去9600了。
回复

使用道具 举报

15#
ID:401564 发表于 2022-4-26 13:40 | 只看该作者
188610329 发表于 2022-4-26 12:24
没别的意思,实在太无聊了,上海现在这情况,你应该也能理解,就当我找你唠嗑吧。

前段时间折腾光立方 ...

串口通讯本身就不是说一定要很高速率的,除了大容量传输以外
所以,很多模块,上位机什么的,大多都是默认9600的,当然,更高的速率也可以,只是没必要而已
至于你说的把数据变成HEX格式收发,如果是自己DIY点小玩意还可以
如果是有协议的模块,那是肯定不行,像GPS模块,人家协议就是发送字符串,那你程序就得这样接收
回复

使用道具 举报

16#
ID:123289 发表于 2022-4-26 15:02 | 只看该作者
你对通讯协议的目的还未理解。
想想为什么要用协议呢?
回复

使用道具 举报

17#
ID:47286 发表于 2022-4-26 15:43 | 只看该作者
188610329 发表于 2022-4-26 11:57
既然,你开了头,我现在又闲的快啥啥啥的, 就陪你瞎聊天一下.

虽然,我也喜欢追求效率,但是不太喜欢做 ...

明白 是你说的那样 单一字符效率再怎么提也就那样 整体提高作用会更大 是这意思吧

还是闲聊

雨刮片那东西 一直感觉最好的还是进口SWF 国产的各种品牌包括SWF(也许是假货)寿命都不好 你们那边暖和可能感觉不大 我这边冬天会刮冰雪 这种情况下国产的倒是耐搞 比进口的不爱坏 可老蹦啊 刮起来呼啦呼啦的 我听说咱的刮片也出口啊 咋就买不到又便宜又好的呢 进口刮片比国产刮片好的性能不值贵出了那价格

有一阵子大众4s可以单独买刮片自己换 那个用着还行
回复

使用道具 举报

18#
ID:47286 发表于 2022-4-26 15:48 | 只看该作者
188610329 发表于 2022-4-26 12:24
没别的意思,实在太无聊了,上海现在这情况,你应该也能理解,就当我找你唠嗑吧。

前段时间折腾光立方 ...

“然后降低晶振速度到22118400”

你。。。。。。你。。。。。。。没降速的时候开的多大啊 那东西总共也没多高

我是在11.0592下搞搞优化啥的 开到22.1148 嗯。。。。。呃。。。。。。我那些优化都是无用功

我这是个病 早年落下的病 Intel就是不换核一点一点累主频 然后自己超频玩 然后我就习惯在低频折腾了
回复

使用道具 举报

19#
ID:47286 发表于 2022-4-26 15:58 | 只看该作者
Y_G_G 发表于 2022-4-26 13:40
串口通讯本身就不是说一定要很高速率的,除了大容量传输以外
所以,很多模块,上位机什么的,大多都是默认96 ...

有时钟模块 为所有其它模块提供时钟服务 从系统角度讲 时钟模块不断电而其它所有模块都可以断电 那么 在所有模块都上电的时候 都先发送申请时间指令 这就相当于短时间内集中发包 如果速率高 每个模块占用信道时间短 会比速率低好很多的 57600发25位的时间比9600发25位短太多了

当然 这也不是必须 可以每个模块设置尝试次数 我只是想表达一下意思 总觉得通讯可靠性不降低的情况下 速率高些还是有益处吧
回复

使用道具 举报

20#
ID:47286 发表于 2022-4-26 16:04 | 只看该作者
cokesu 发表于 2022-4-26 08:06
主要是很多模块协议是固定的,如果是我自己把两个程序都写了肯定是怎么简单怎么来,但是实际项目中如果需 ...

如果这样 基本就是没啥优化空间了 人家就那么发 你不那么收就没法解析

可以每个模块再配一个自己的小模块 目的就是转换通讯 把人家的协议转换成你自定义的 这么做从硬件上基本就是个浪费 但如果模块多 种类多 范围较大 对管理来说就有好处 可以统一通讯协议 便于后期开发乃至上位机开发 通常在技术论坛讨论的都是技术成本 但假设是个项目 实际上要考虑人工成本 管理成本 还有运维成本 硬件系统贵一点其它费用可能下来好多也不一定
回复

使用道具 举报

21#
ID:624769 发表于 2022-4-26 16:47 | 只看该作者
dzbj 发表于 2022-4-26 15:48
“然后降低晶振速度到22118400”

你。。。。。。你。。。。。。。没降速的时候开的多大啊 那东西总共 ...

额…… 51系列单片机,只要时钟频率支持35MHz以上的,如STC89, STC12, STC15等等, 当有且只有一个硬件串口的,在有外接电源的情况下,我一般频率定义在 29.4912MHz, 主要原因有两个,一个是没必要用低频率节省那所谓的功耗,二是,这个速率用串口模式二的话,可以省下一个定时器,直接用系统时钟64分频作波特率发生器,产生比较常用的460800波特率,当然如果,电池供电,或者需要对接的设备,串口速率不支持那么高的话,我会用  7.3728MHz的频率,产生115200的波特率。
对于多串口,或者没有串口必须软件模拟的,即必须定时器来产生波特率的,如果外接电源,我大多会用 33.1776MHz, 电池供电的话,多用5.5296MHz,是不是做事很极端?
效率的极端优化,我大多是在折腾(或者说在试验某个功能,或者说通过这个过程,更深度的理解某个工作原理),实际做出东西,如果不是在决定的频率下,无法及时处理得话,相对于效率的优化,我更倾向于压缩代码的大小,减小内存的使用,这方面的优化,说到底,是为了让低端的单片机运行原本高端单片机才能运行的功能。比如,用STC15W102(128字节内存 + 2K的flash) + HC595 x 4 驱动16x16点阵屏 搞个 蛇身长度 最长可以达到250个点阵的贪吃蛇游戏出来。查了各种站点,各种信息,大多数人第一步,内存这关就过不了,目前为止,貌似只有我一个人搞出来了……

哎呀,扯远了,总之……, 既然串口传输的内容是 字符串, 说明,对效率其实没有要求,而波特率就算是57600,或者115200, 也不会说处理速度跟不上传输速度, 如果说问题出现在接受完整的指令再处理指令,会占用太多的内存影响整个系统的运行,那么,需要改变的是,一边接收,一边处理指令。而不是说琢磨如何优化对指令的判断的效率优化,只要对指令的判断,不要垃圾的太离谱(比如在串口中断里 while 之类的),都不会影响串口接收,所以才说,没必要考虑效率问题,并且对于字符串的判断,如果楼主不会汇编,累死都无法提高太多效率。投入和收获极端不等。
回复

使用道具 举报

22#
ID:47286 发表于 2022-4-26 17:53 来自触屏版 | 只看该作者
188610329 发表于 2022-4-26 11:57
既然,你开了头,我现在又闲的快啥啥啥的, 就陪你瞎聊天一下.

虽然,我也喜欢追求效率,但是不太喜欢做 ...

出个题

把光立方用2812 然后不断混色变 串口助手不断发指令 串口不断回复当前三色值
回复

使用道具 举报

23#
ID:47286 发表于 2022-4-26 18:50 来自触屏版 | 只看该作者
188610329 发表于 2022-4-26 16:47
额…… 51系列单片机,只要时钟频率支持35MHz以上的,如STC89, STC12, STC15等等, 当有且只有一个硬件串 ...

你说一边接受一边处理 能举例么 数据流都没完怎么处理 不理解啊
回复

使用道具 举报

24#
ID:401564 发表于 2022-4-26 19:15 | 只看该作者
dzbj 发表于 2022-4-26 15:58
有时钟模块 为所有其它模块提供时钟服务 从系统角度讲 时钟模块不断电而其它所有模块都可以断电 那么 在 ...

总觉得通讯可靠性不降低的情况下 速率高些还是有益处吧
就单个产品而言,自然是有好处的
但就开发而已,如果不是大容量传输的话,没有多大必要
很多上位机或者模块都是以字符的形式发送的,有的还是固定的"帧头,数据部分,帧尾"一大堆的,这就说明这个时候在速度上是没有特别高的要求的,可靠性反正更重要了
单片机的串口一般就是发送一些指令,小容量数据之类,在速度上要求不高
而且有很多的模块,上位机都不是自己的,别人做出来都是默认9600速率的
很多人感觉串口影响到主函数了,那是因为很多人在中断中使用while等待发送完成了,或者是发送的时候是先发送数据,然后就是while等待发送完成了,这就给人一种串口速率低影响到了主程序的错觉了
回复

使用道具 举报

25#
ID:624769 发表于 2022-4-26 19:53 | 只看该作者
dzbj 发表于 2022-4-26 18:50
你说一边接受一边处理 能举例么 数据流都没完怎么处理 不理解啊

要说详细的话, A4纸能写4页。就简单说一下大概的宗旨吧,

串口接受按57600波特率,大约200us能接受一个字节,串口中断 把数据从SBUF 里取出来,放入缓冲池,再给接收计数,就能退出中断也就几us,有大把的时间,回归到主程序进行别的操作,主程序里面判断,接收了的长度。
下面打比方,接收满5个(主程序里面判断 if(Rev_Cnt >=5){执行字头判断}) 来区分是 GET, WRITE, SET, 还是RESET,等等,  这个字符判断,也许比较费时,需要耗费上百us,( 其实也就串口接受一个字节的时间) 先做掉,然后做一个记号, Order_Type = ??; 这个就可以作为后续指令解读来用了,节约了后面处理的时间(算是优化的一种吧)。有必要的话,还要整理一下缓冲池,把已经分析完的字头部分的内存释放。
继续打比方,接受还在继续, 在主程序里面 if((Rev_Cnt>=15)&&(Order_Type= 0x01)){开始处理第二步骤工作}  当然,这部分也可以用 switch 看你喜欢吧。
依次类推,缓慢推进,等到上位机发送的数据全部完成后,单片机这里,工作其实已经处理的7788,就剩一个尾巴了,这个是不是也是一种变相的提高效率呢?
但是,这个提升吧,其实远不如波特率翻一个倍有效。看你喜欢与否了。
回复

使用道具 举报

26#
ID:47286 发表于 2022-4-26 20:22 | 只看该作者
Y_G_G 发表于 2022-4-26 19:15
总觉得通讯可靠性不降低的情况下 速率高些还是有益处吧
就单个产品而言,自然是有好处的
但就开发而已, ...

感谢耐心回复 你的意思记下了 目前搞的东西还不多 以后做得多了也许就明白了
回复

使用道具 举报

27#
ID:47286 发表于 2022-4-26 20:25 | 只看该作者
188610329 发表于 2022-4-26 19:53
要说详细的话, A4纸能写4页。就简单说一下大概的宗旨吧,

串口接受按57600波特率,大约200us能接受一 ...

收到

刚才回复完也想了一下可能性 大概也是类似你说的意思 把相同的内容归类处理 但这也中断内的时间开销会增加很多吧

我自己那个协议就有类似的情况 多槽就遇到内存占用大的问题 PC上可以用多少内存申请多少 用完释放 C51里只能按最大开内存 即便不用也得占着 看过一些动态内存的范例 感觉好麻烦
回复

使用道具 举报

28#
ID:624769 发表于 2022-4-26 20:37 | 只看该作者
dzbj 发表于 2022-4-26 20:25
收到

刚才回复完也想了一下可能性 大概也是类似你说的意思 把相同的内容归类处理 但这也中断内的时间 ...

中断内的开销 也就增加一个 Rev_Cnt++; 但是,同时可以节约掉一个 if(SBUF == 0x00) Rev_End = 1;  严格来讲,节约了一个if判断,中断内时间的开销反而更少。
差别是,主程序的指令判断, 从原来的 if(Rev_End==1)  分解成若干个 if(Rev_Cnt >= ??) 来分段处理。
回复

使用道具 举报

29#
ID:47286 发表于 2022-4-26 21:09 | 只看该作者
188610329 发表于 2022-4-26 20:37
中断内的开销 也就增加一个 Rev_Cnt++; 但是,同时可以节约掉一个 if(SBUF == 0x00) Rev_End = 1;  严格 ...

收到 回头我按这思路试试 看能写出个啥来

"用STC15W102(128字节内存 + 2K的flash) + HC595 x 4 驱动16x16点阵屏 搞个 蛇身长度 最长可以达到250个点阵的贪吃蛇游戏出来。"

这种事换我干 呵呵 只能堆料 现在随便写个啥8k都感觉紧张 呃。。。。。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表