本人在学习CAN通信的过滤器配置的过程中,对位宽为16位的屏蔽码模型的寄存器设置一直产生错误。
1、在网上查找资料,包括CSDN中,参考他们的说明以及代码编写CAN外设的四种,发现除了 位宽为16位的屏蔽码模式一直有错误外,其他三种都可以正常实验。直到我发现了这个资料,按照资料所述,配置CAN过滤器的两个32位寄存器,发现能正常工作,另外将我编写的CAN初始化代码分享如下,里面包含了CAN过滤器的四种配置。
根据上述表中第四行所示,配置两个ID和他们对应的掩码,可以正常运行。
2、以下为CAN过滤器的16位标识符屏蔽模式(相当于两个屏蔽器,只能过滤标准帧,不能过滤扩展帧,因为扩展帧的ID为29位)的代码:
//选择机器5 筛选ID为:0x52-0x53 ,0x60-x063
// 机器5 16位标识符屏蔽模式(相当于两个屏蔽器,同上 只能过滤标准帧,不能过滤扩展帧)
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x060<<5;高16位 为ID1 0b0000 1100 0000 0000
CAN_FilterInitStructure.CAN_FilterIdLow=0x52<<5; // 低16位 为ID2 0b0000 1010 0100 0000
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xff9f;//高16位 为屏蔽1 0b1111 1111 1001 1111
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xffdf;// 低16位 为屏蔽2 0b1111 1111 1101 1111
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
注:代码中的 ID1对应屏蔽1,ID2对应屏蔽2。
3、以下是我所写的CAN初始化代码,基于stm32f103系列芯片。
使用了宏定义:#define Choice_MCU 5 // 可设置的值为1 2 3..... 分别选择机械1 2 3模式
来选择不同的CAN过滤器工作模式:
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE
NVIC_InitTypeDef NVIC_InitStructure;
#endif
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //TX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化IO
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式 //
CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理 //
CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)//
CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送 //
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的 //
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定 //
CAN_InitStructure.CAN_Mode= mode; //模式设置: mode:0,普通模式;1,回环模式; //
//设置波特率
CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=tbs2;//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1 //
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
#if Choice_MCU==1 //选择机器1 0x50~0x57
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x50<<5;32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xff1f;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xffff;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
#elif Choice_MCU==2 //选择机器2 0x51,0x55,0x59,0x5d
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x51<<5;32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xfe7f;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xffff;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
#elif Choice_MCU==3 //选择机器3 0x59 和 0x1800f001
// 机器3 32位标识符列表模式 2个ID
u32 ext_id =0x1800f001;
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; // 列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x059<<5; // 第一个ID高八位 标准帧
CAN_FilterInitStructure.CAN_FilterIdLow=0|CAN_Id_Standard;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((ext_id<<3)>>16) & 0xffff;// 第二个ID高八位 扩展帧
CAN_FilterInitStructure.CAN_FilterMaskIdLow=((ext_id<<3)& 0xffff) | CAN_Id_Extended;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
#elif Choice_MCU==4 //选择机器4 筛选ID为:0x50 0x53 0x57 0x63
// 机器4 16位标识符列表模式(16位不能过滤扩展帧,扩展帧必须是32位)
// 16位列表可以筛选4个ID(只能是标准帧),32为列表可以 筛选2个ID(可以是扩展帧)
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; //16位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x050<<5; // 第一个ID 0x050 0b0000 1010 0000 0000
CAN_FilterInitStructure.CAN_FilterIdLow=0x053<<5; // 第二个ID
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x057<<5;// 第三个ID
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x063<<5; // 第四个ID
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
#elif Choice_MCU==5 //选择机器5 筛选ID为:0x52-0x53 ,0x60-x063
// 机器3 16位标识符屏蔽模式(相当于两个屏蔽器,同上 只能过滤标准帧,不能过滤扩展帧)
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x060<<5;高16位 为ID1 0b0000 1100 0000 0000
CAN_FilterInitStructure.CAN_FilterIdLow=0x52<<5; // 低16位 为ID2 0b0000 1010 0100 0000
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xff9f;//高16位 为屏蔽1 0b1111 1111 1001 1111
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xffdf;// 低16位 为屏蔽2 0b1111 1111 1101 1111
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
#endif
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
#if CAN_RX0_INT_ENABLE
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif
return 0;
}
4、实验效果
硬件资源:4个stm32f03系列单片机,4个SN65HVD230(3.3V)CAN收发器 ,3个基于I2C的OLED和1个基于SPI的OLED,按键若干。
测试了上述代码中的1、2、4、5四种情况(图片中MCU从上到下),效果理想。
上传不了视频
CAN测试1
5、纠错
以下图片是我之前从CSDN等开源网站上查找到的各种资料,现在经我实验,发现是错误的。