c++ win32 获取串口高低电平_硬核分析串口通信协议

串口通信协议,基本上是每个单片机开发人员必会的协议,是所有通信协议里面最最常用的。但是很多人并没有去研究过细节,这篇文章干货满满,将带你深入串口协议的内部。

1、串口协议简介

什么是串口通信?

简而言之,串口通信就是通过一根导线(TX,只讨论发送,当然一定还包括GND),将需要的数据按bit流传送给接收端,既然是通信,参与的双方当然要制定数据的传输方式以及规范。

随便打开一个串口助手都可以看到,如果需要使用串口就需要配置端口、波特率、数据位、停止位、校验位、流控这些参数。

4f0e1e49128344e288298e0d541871b9.png

如果接收端和发送端的设置不同,就可能会导致数据异常。

端口:这个就不用解释了,使用串口芯片安装驱动后就可以在电脑上看到端口号了。

现在,我们从电平信号角度分析一下波特率、数据位、停止位、校验位、流控(由于用的比较少,暂不分析)的作用。

2、电平信号分析

打开串口工具,分别调整如下参数

①调整参数9600/8/N/1,发送十六进制数据55 AA

96f01a748b3bb80bdf6a40f7015f4cba.png

2e590649f2a52dc9128f785bb1bb16df.png

②调整参数115200/8/N/1发送十六进制数据55 AA

9dad757e07bc3ce6b289e0cf801edb7f.png

6083bcce05f1e5f7eed624ab29181c1d.png

③调整参数9600/7/N/1发送十六进制数据55 AA

60fbdb62c1ed9b2a2eb25dec10a7fd4f.png

④调整参数9600/8/O/1发送十六进制数据55 BA

5e3eb4ba1a9bbc9b70e19729582d4331.png

⑤调整参数9600/8/E/1发送十六进制数据55 BA

93816868931e8f601d7d77b41d1287b0.png

⑥调整参数9600/8/N/2发送十六进制数据55 AA

a4ffe0df8da87ca69df109117b8eaa96.png

其中B代表起始位,E代表停止位,很明显看出是先传输的低bit,再传输的高bit。

根据①②分析,调整波特率并不会影响整体波形形状,只有bit的持续时长不同,9600波特率时的一个bit大概占104us,115200波特率大概是9us,这是可以算出来的9600:1000ms/9600 = 104.1us,115200:1000/115200=8.6us。分析可知波特率越大,传输速度越快。

根据①③分析,调整数据位后,55本来应该是01010101但是数据位调整到7之后,55变成了1010101,AA本来是10101010变成了0101010,分析可知错误的数据位会将传输的字节从高位开始截断,可能导致数据丢失。一般来说除非特殊需求,否则不会调整数据位参数。

根据①④⑤分析,将校验位调整至奇校验(ODD)后,传输的bit多了一个奇校验位,就是说如果本来的8个bit的bit位按位加起来是偶数,则在最高位需要补一位1,否则补0,55传输变成了 (1)01010101,BA变成(0)10111010,同样偶校验(EVEN)、MASK校验(校验位始终为1)、SPACE校验(校验位始终为0)是相同的道理。

根据①⑥分析,将停止位设置为2后,传输的结束位(图片中的E)变成之前的2倍,分析可知,设置停止位,可改变数据传输完成后的停止位bit持续的时间。

3、为什么需要起始位和停止位?

波特率、数据位、校验位很好理解,都是为了实现不同的业务需求,但是起始位和停止位存在的意义是什么呢?

起始位:平时这根导线上是高电平,如果接收方检测到低电平了,说明要开始接受数据了,是发送方通知接收方开始接受的一种方式。(不考虑流控)

停止位:发送方通知接收方发送完成的一种方式。发送方发送完一个字节后,“暂停一会”再继续发送下一个字节。

这时帅气的小伙伴就要问了,起始位存在的意义可以理解,但是为什么需要停止位呢?不是提前都约定好了传输8个bit,接收方不能就接受到8个bit后认为一个字节传输结束就OK了吗?

能思考到这一步的小伙伴已经很棒了。如果我们是设计师,我们从设计的角度设计一下接收方接受数据的伪代码

//接收端接收数据线程
while(1) {
    //接收到起始位下降沿电平
    if((isGetStartFlag == 0) && getDownEdge()) {
        Delayus(52);
        //检测起始位低电平
        if(isLowPin()) {
            isGetStartFlag = 1;
            getBitIndex = 0;
        }
    }
 
     //已经接收到起始位
    if(isGetStartFlag) {
        Delayus(104);
  
        if(getHighOrLow() == high) {
            //接收到1bit
        }else {
            //接收到0bit
        }
        getBitIndex++;
        if(getBitIndex == 8) {
            //字节接收完成
            isGetStartFlag = 0;
            getBitIndex = 0;
        }
    }
}

按照这种伪代码逻辑,如果不存在停止位,会产生两个问题。

1、可能无法检查下降沿

如果上一个字节最后一次传输是0,而下一个字节的起始位也是0,那么下一个字节的起始位就检测不到下降沿,无法触发下一个字节的传输,就会丢失数据。这时帅气的小伙伴又要问了,那我不检查下降沿,只检查低电平不行吗?直接把getDownEdge换成isLowPin函数不就可以了吗,确实可以,这样又会引入第二个问题。

2、时钟同步问题

假设A跟B说,10分钟后你提醒我喝水,然后B就看着自己的表,10分钟后提醒A,这时A一看表,才过去9分钟。这种场景现实也会出现,造成的原因是A和B的表不同步或者有误差这个误差的引入就导致了A和B所指的“10分钟”不相同,在我们这个串口的场景里,就是发送方和接收方约定了9600波特率,也就相当于约定了104.1us传输一个字节,按照上面的伪代码,几个采集点应该是

61cafd2fd506abbe90c7092b04e1b902.png

但是由于误差,可能导致采集点偏移为

4affe9362087da662eef84ae444ad5be.png

这两个图能大致表达时钟不同步,导致接收设备的采集点后移,如果这时引入了停止位,第二个BYTE开始时,由于还是从下降沿开始采集,所以会重置上一个BYTE引入的误差。

7458d8695fd6493b50f49183ff8dae2f.png

4、总结

这篇干货基本把串口协议分析透彻了,大家在分析协议的时候,最好是从设计的角度去思考这样设计的作用,如果有什么分析不对的地方,欢迎大家指正。希望这篇文章能给你带来一点作用。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值