更新博客缘由:
**一晃大约1年半没有更新过博客了,还是要督促下自己了。最近项目遇到问题,更新下,供大家参考也为自己留个纪念**
项目场景:
主机linux系统+从机单片机之间进行通信,通信方式采取I2C方式,时间为20ms一次。
I2C为主从模式,从机不具备主动上报功能,因此只有主机定期查询从机状态
问题描述
主机linux芯片功能强大,通过I2c挂载一个单片机,单片机用于做按键+显示功能。
1:主机通过下达write I2C数据控制单片机显示各种画面数据。
2:主机通过20ms轮询方式读取从机按键情况。
3:从机一个8个按键,通过一个I2C1_BUFR = I2C_read_data.I2C_BUFR[I2C_read_data.txIndex++];I2C_BUFR数组长度为8,但是通过大量测试发现,当按键速度过快以后,会发生“误触”的现象。
原因分析:
原因主要有两点:
1:i2c采取中断方式主机读取,按键通过while(1)循环20ms一次写入,也就是说中断是一直在读取数组,而按键是按的时候会写入,快速按,意味着快速写入。所以就存在着读取不完全就被按键提前写入的情况。
2:因为I2C的读取不能发送指令,只能直接发送读取和长度,无法区分读取的指令。那么就存在读取数据错乱的情况。字节越多,概率越高。此项为主要原因。
解决方案:
1:通过加锁的方案,而且这个加锁是在写入读取都要加锁的情况。也就是说,读的时候不能写(防止读错,误判),写的时候不能读。。初始状态弄好,不会出现死锁现象。
2:此项目为8个按键,刚好属于一个unsigned char 类型,刚好一个字节,也就是I2C读取的一个字节。这样不会出现误判,当读取的字节为0xFF时,意味着没有任何按键被按下。如图:
通过将8字节的数组转换成一个字节的数据,速度提升,准确率得到保证。
这个时候有人可能要问,大于8个按键怎么办?其实做这种通信的最好用双向通信方式,如串口,有问有答的方式,必须要确保发送的数据对方收到了,能够主动给回应的,而不是采取这种主从关系,不对等的方式。这个项目没办法,领导安排的只能这么做。
另外其实如果不进行大量数据频繁操作,是不需要回应的,就算是需要回应,采取多字节主机询问方式也不会出现太大问题。比如我现在这个项目,虽然我采取了一个字节的按键方式,但是我这个是带有升级功能的,升级功能必须包含回应,但是升级功能的回复,用的场景不多,数据不大,因此还是采取一次读取多个字节的方式。1是按键,2是升级功能的回复+版本查询的回复。
在这期间还尝试过字节对齐的方式,防止出错。如下:
unsigned int touch_key_sta_tmp[4] = {0};
unsigned char *touch_key_sta = (unsigned char *)&touch_key_sta_tmp[0];
在此有缘人遇到同样的问题可以参考下,如果你读完了,不妨点个赞哦。
爱你的“世外桃源”