基于QT的CAN通讯数据实时波形显示(连载五)========“CAN帧的处理”

前述工作:

    前期完成:(1)正确接收can帧并显示;(2)每次接收55个。

    通讯协议:CAN帧通讯协议如下图所示,8000为报头(后面数据不可能出现8000,所以以此为报头),10ms发送5帧(5帧为一个数据帧包)。由于仅仅显示波形,所以只有14个具体参数需要处理。QT程序定时器100ms执行一次receive函数。接收到55个左右(非完整的数据帧包)。

    处理要求:(1)将10ms,20ms到1000ms的数据帧包的每个参数放入对应的数组中,即第1个参数放入第1个数组,第2个参数放入第2个数组,,,一共14个数组。每个数组存放1s的数据,即100个数。(2)依数据第1帧中的ms数作为x轴,以1s存放的100个数作为y轴,进行绘图,即每秒绘制的曲线包含100个点。另第1个参数、第2个参数和第3个参数的曲线放入一个图表中,第4个参数、第5个参数和第6个参数的曲线放入一个图表中,第7个参数、第8个参数和第9个参数的曲线放入一个图表中,第10个参数、第11个参数和第12个参数的曲线放入一个图表中,第13个参数和第14个参数放入一个图表中,共5个图表,14条曲线。

    处理估计难点:(1)接收到的第1帧数据不一定为含有报头的帧。(2)接收的55帧左右的最后1帧不一定为CRC校验帧。(3)由于(2)的原因,头一帧的尾和后一帧的头的数据帧需要连接起来

第一部分:处理方法选取

    处理方法考虑到有3种:

   题外注:周末两天一直在考虑CAN帧的处理方法与逻辑,基本方法就几种,但是其中的逻辑有的就是想不明白,想着想着就断了,甚至有的就走不通。白天想,夜里想,脑子里一直在转着处理逻辑。明白了为啥码农的头发会变少了,估计都是一天24小时转没的。本来是搞电力电子与电力传动的,结果慢慢走上了程序员的道路,并且越走越远,想着能慢慢回头,编程序这东西太累人了。以前编代码也是这种情况,晚上睡不着觉,脑子里一直转程序,转不明白的话就是睡不着。现在也慢慢的放开了,转不了就慢慢的转,也不是个急功夫。有些轮子可以直接拿过来,但是有些轮子必须自己造,这个是避免不了的。本来想着做出来一个牛b的程序,什么功能都能具有,包含什么错误帧判断啥的,最后还是决定放弃了。程序只要满足自己的要求就行,方法用啥都行。性能方面只要没要求,可以用最笨的方法去实现,如果性能需要提高了,再说提高性能的事。做程序最怕好大喜功,贪多嚼不烂的。做程序的底线是功能满足并且不出错,特别是自己用的软件时。不用考虑太多,考虑太多就麻烦了(当然如果不考虑会发生危险就另说了)。比如现在做的CAN帧显示,错与不错都仅仅是个显示问题,可以不用考虑那么多,在做之后去找bug,可以去快速迭代,完善程序。比如以前做的控制继电器、断路器的大功率设备,合上开关就有可能炸管子的,这时必须把所有的逻辑考虑全面,一个逻辑问题都不能放过。具体问题具体分析。做逻辑很累,想不明白的时候更累。安慰自己一下:慢慢想就好。

第一种方法

    采用和《QT串口动态实时显示大量数据波形曲线(一)》中一致的数据处理方法。每次接收帧数包包含帧数个数整数倍的数据。1个帧数包包含5帧,所以每次接收10帧或者20帧,或者50帧。这时需要改变ReceiveNum = VCI_Receive(nDeviceType,nDeviceInd,nCANInd,Receive,100,400)函数的100。这里改变100等于50,每次接收的最大帧数为50个。然后将第二次接收到的50帧接到前50帧后面。为了解决末尾帧不是帧包最后一帧的问题,这样做造成的后果为:第二次接收到50帧之后才能处理前面的50帧,画出曲线的时间延迟了500ms。这里感觉不太满足要求,所以将50减小,比如改为10帧。这样就能将时间延迟减小为10ms。此时又存在一个问题,时间定时器必须10ms进入receive函数一次。QT中的定时器和单片机不一样的地方就在这里:单片机中断为强制进入中断程序,即:程序执行完成与否不影响中断程序的入口执行。没有执行的程序将不再执行,所以如果定时器中断里的执行时间比较长的话,后面的程序将不再执行。比如时间定时器中断为10ms一次,那定时器里面的程序需要15ms执行完毕,程序肯定会10ms从程序头开始执行,后5ms就不会执行。而QT中为程序执行完之后再从程序头开始执行。所以当程序执行时间长时,定时器不再是10ms一次(测试过)。考虑到后面程序还存在画图程序,同时又不用线程这样的好东西(主要是还不会),10ms的时间定时器肯定不会10ms执行,这样can的缓冲区会存在大量的帧,程序最终将越来越慢。

第二种方法

    采用经典的FIFO方式。将ReceiveNum = VCI_Receive(nDeviceType,nDeviceInd,nCANInd,Receive,100,400)中100不变,每次接收55帧左右的帧数。然后采用接收指针和处理指针的方式。

    (1)首先取一个大的buffer,比如1200个uint8单元的缓存,存放到1200个时自动从第一个再次开始存储。形成一个环形的buffer。

    (2)接收多少个,处理多少个。比如接收53帧数据,那么就处理53帧数据。这时困难就来了,开始时不是帧包的第一帧,即第一帧不是含8000的头帧,需要判断哪一帧是第一帧。一个帧包结束时,不一定是帧包的尾帧,即最后一帧不一定是含CRC校验的帧,所以要处理这次帧和下次帧的结合问题。这两个问题还是比较好处理的地方,另外还有一个问题就是里面的帧怎么取出来,将每个对应的量放在对应参数的缓存里。同时还要保证每个位置都对。如果每个CAN帧都是正确的,不丢帧,这个问题好解决,如果丢帧那就麻烦了,怎么解决丢帧问题。这个逻辑想了两天没有考虑出来。因为一次接收53帧,怎么在不知道帧包是否完整,53帧帧尾是哪帧,怎么和后面的50多帧连接起来的情况下,判断一个帧包,并将里面的对应数据放到固定的数组缓存里。所以最后此种方法也放弃了。

第三种方法

    最终在凌晨想出来最好的方法,既能考虑到第一次接收的第一帧不一定为8000头帧的情况,又方便两次接收帧相互连接,还能判断出来每次的帧正确与否的方法。先看CAN帧的接收程序:

    ReceiveNum = VCI_Receive(nDeviceType,nDeviceInd,nCANInd,Receive,100,400);
    if(ReceiveNum>0)
    {
        for (int i = 0; i < ReceiveNum; i++)
        {
            CANID = Receive[i].ID;
            for (int j = 0; j < 8; j++)
            {
               gnDataBuffer[j] = Receive[i].Data[j];
            }
        }      
    }

    假设ReceiveNum等于1,按照程序中逻辑,仅仅接收1帧,此时1帧的8个uint8放入buffer中。如果接收更多时,假设ReceiveNum等于2,按照程序中的逻辑,第2帧中的8个uint8将覆盖第1帧放入的8个uint8。即最后只能得到最后一帧的8个uint8。那么逻辑就在这里了,每次判断接收的8个uint8是什么数据

    ReceiveNum = VCI_Receive(nDeviceType,nDeviceInd,nCANInd,Receive,100,400);
    if(ReceiveNum>0)
    {
        for (int i = 0; i < ReceiveNum; i++)
        {
            CANID = Receive[i].ID;
            for (int j = 0; j < 8; j++)
            {
               gnDataBuffer[j] = Receive[i].Data[j];
            }
        此位置放入数据判断程序,并处理数据。
        }      
    }

    将数据判断和处理程序放入上面程序中汉字的位置。那么就可以每次接收1帧就判断一次。为了后续程序的编写,将接收到的8个uint8抛出,放入其他线程中(只能学习这个了),然后在其他位置处理和画图。

方法总结

    哪种方法不重要,重要的是能考虑到每个方法的弊端,可能出现的问题,同时选定方法的便捷性。只要能用最简单的逻辑,最少的bug的方法就可以。

第二部分:展望

    (1)画图必须在线程中进行,所以数据必须抛出。

    注:由于QT中最好不用全局变量,采用信号和槽函数来处理,在一个class定义的变量不能在另一个中使用,只能使用抛出emit函数。

    (2)抛出后,必须对数据进行对应放置,并且考虑到帧丢失、第一次接收的第一帧问题、每次接收的帧头和帧尾连接问题。

    (3)线程和线程中绘图问题。

所以《基于QT的CAN通讯数据实时波形显示(连载六)》加入内容:数据共享(QT操作问题),线程(QT操作问题),数据处理(处理CAN帧问题,与QT本身无关,至于项目的CAN帧数据有关)。

    注:由于小伙伴需要源代码的时间不同,登录邮箱界面太多麻烦,所以建立了一个订阅号,如果有问题或者需要源码,可添加订阅号,留言后会发送源代码或者有任何问题可留言,将积极解决提出的问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值