这次,分享一下我的STC-FOC Lite电机中的CAN通讯部分实现。
CAN通讯在电机控制领域与PWM舵机控制信号几乎是一样常见的。
就像是舵机基本都是PPM(脉宽控制)一样,无刷的关节电机这一类,基本也都是CAN通讯方式的。
因为CAN通讯本身自带的高抗干扰,以及数据发送的灵活性,使其非常适合于电机控制领域。
当然,仅仅是数据通讯肯定是没有什么讲解的必要,因为CAN的底层都给封装好了,直接拿来用就可以传输数据了。
这次我来分享一些CAN的应用层面内容——如何实现数据同步。
一般的电机控制场景,基本都是多个电机挂载在同一条CAN总线上,如果现在驱动的是四轮小车,如果我们想要让后轮电机实现电子差速,那么这个差速必须要同步生效才能控制精准。
因为如果发送数据的速率比较慢或者电机比较多发完一圈时间比较长,这时候差速可能就会插入一个时间差。此时差速便不是很准确了,如果加上多次控制的累计误差,可能就会表现为小车往一个方向偏。
这种问题很显然是我们不想看到的,那么应该如何解决呢?
这里要介绍一个CAN的小知识,那就是CAN的滤波器
CAN的滤波器分为单滤波器和双滤波器,这里我们使用的是双滤波器
- // 通讯地址定义
- #define User_Can_ID 1 // 滤波器设置地址,除这个地址外不在允许接收其他地址的数据
- CanWriteReg(MR, 0x05); // 使能Reset模式,打开双滤波器功能
- CanWriteReg(ACR0, (u8)(User_Can_ID >> 3)); // 总线验收代码寄存器,过滤设备ID和广播ID
- CanWriteReg(ACR1, (u8)(User_Can_ID << 5));
- CanWriteReg(ACR2, 0x00); // 广播地址默认为0,不需要更改
- CanWriteReg(ACR3, 0x00);
复制代码
通过配置滤波器滤波CAN的ID字段,使得ID0的报文定义为广播字段,ID1(可以更改为其他的值)为接收字段。
这样,就只能接收ID1和ID0的报文,如果CAN总线上有主机发起给其他电机的数据,便可以不被接收。
同时,我们通过在ID1报文中添加一个同步标志位,如果标志位置1,则本次保存存入缓冲区而不解析,等待下次ID0报文中的同步指令匹配成功才进行解析。
这样,只要主机最后发送ID0报文的同步指令,就可以将所有电机的控制指令同步执行了。
下面这段程序就是程序中关于CAN处理的部分程序,已经添加了注释。
- // 数据解码
- void Can_Dat_Decoding(CAN_DataDef *can_dat)
- {
- if (can_dat->DLC == 8) // 数据长度必须是8,fifo频率超出了就不接收控制了
- {
- // ID非过滤字段
- if (can_dat->DataBuffer[Dat_SYNC] == 0x55) // 触发状态
- {
- Can_Get_Temp(can_dat);//获取缓冲区数据,进行解析
- }
- if (can_dat->ID == User_Can_ID && can_dat->DataBuffer[Dat_SYNC] != 0x55) // ID过滤
- {
-
- if (can_dat->DataBuffer[Dat_Ctrl] & Ctrl_Sync)
- {
- Can_Push_Temp(can_dat);//数据存入缓冲区
- }
- else
- {
- //指令处理部分
- }
- }
- }
- }
复制代码
|