找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2731|回复: 28
收起左侧

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

[复制链接]
ID:404263 发表于 2022-4-25 16:37 | 显示全部楼层 |阅读模式
如果说单片机串口的通信协议是以字符串的形式来通信的话,大佬们有没有好的处理方式,比如这个协议的字符长短是不固定的,模块会给我单片机下发GETxxxxxxx,SETXXXXXX,RESETxxxxxx,之类的一堆字符串,我之前的做法是识别开头的字符,结束就判断\r\n,但是感觉不同指令用不同的头码识别,这个好像不太高效,随着协议的增加,程序会变得十分臃肿,希望有大佬能指导一下这种字符串协议的该怎么写好
回复

使用道具 举报

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,那就更不用说了
只有你的程序有实际运行,的确是因为效率或者代码真的太大了,才会开始考虑优化算法
回复

使用道具 举报

ID:320097 发表于 2022-4-25 21:58 | 显示全部楼层
我觉得只要不产生BUG,程序能正常运行,硬件资源也够的话,不用考虑那么多
回复

使用道具 举报

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

使用道具 举报

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

纯瞎聊天

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

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

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

使用道具 举报

ID:1013784 发表于 2022-4-26 03:56 | 显示全部楼层
串口的协议头都是固定的,可以写个数组来保存这些数据,然后判断解析
回复

使用道具 举报

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

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

使用道具 举报

ID:401564 发表于 2022-4-26 10:22 | 显示全部楼层
dzbj 发表于 2022-4-26 00:29
纯瞎聊天

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

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

使用道具 举报

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

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

使用道具 举报

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

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

使用道具 举报

ID:624769 发表于 2022-4-26 11:57 | 显示全部楼层
dzbj 发表于 2022-4-26 00:29
纯瞎聊天

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

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

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

使用道具 举报

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了。
回复

使用道具 举报

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

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

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

使用道具 举报

ID:123289 发表于 2022-4-26 15:02 | 显示全部楼层
你对通讯协议的目的还未理解。
想想为什么要用协议呢?
回复

使用道具 举报

ID:47286 发表于 2022-4-26 15:43 | 显示全部楼层
188610329 发表于 2022-4-26 11:57
既然,你开了头,我现在又闲的快啥啥啥的, 就陪你瞎聊天一下.

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

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

还是闲聊

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

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

使用道具 举报

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

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

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

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

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

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

使用道具 举报

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

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

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

使用道具 举报

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

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

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

使用道具 举报

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 之类的),都不会影响串口接收,所以才说,没必要考虑效率问题,并且对于字符串的判断,如果楼主不会汇编,累死都无法提高太多效率。投入和收获极端不等。
回复

使用道具 举报

ID:47286 发表于 2022-4-26 17:53 来自手机 | 显示全部楼层
188610329 发表于 2022-4-26 11:57
既然,你开了头,我现在又闲的快啥啥啥的, 就陪你瞎聊天一下.

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

出个题

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

使用道具 举报

ID:47286 发表于 2022-4-26 18:50 来自手机 | 显示全部楼层
188610329 发表于 2022-4-26 16:47
额…… 51系列单片机,只要时钟频率支持35MHz以上的,如STC89, STC12, STC15等等, 当有且只有一个硬件串 ...

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

使用道具 举报

ID:401564 发表于 2022-4-26 19:15 | 显示全部楼层
dzbj 发表于 2022-4-26 15:58
有时钟模块 为所有其它模块提供时钟服务 从系统角度讲 时钟模块不断电而其它所有模块都可以断电 那么 在 ...

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

使用道具 举报

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,就剩一个尾巴了,这个是不是也是一种变相的提高效率呢?
但是,这个提升吧,其实远不如波特率翻一个倍有效。看你喜欢与否了。
回复

使用道具 举报

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

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

使用道具 举报

ID:47286 发表于 2022-4-26 20:25 | 显示全部楼层
188610329 发表于 2022-4-26 19:53
要说详细的话, A4纸能写4页。就简单说一下大概的宗旨吧,

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

收到

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

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

使用道具 举报

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 >= ??) 来分段处理。
回复

使用道具 举报

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 单片机教程网

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