做了一个项目,使用STM32F103VBT6来做GPS终端,在调试过程中发现两个问题,记录下来以便今后参考!
-
问题一:
给电路板上电,CAN模块正常收发,然后断电,此时因为有电池原因CPU不断电,正常工作。但硬件上CAN模块断电,此硬件设计没问题,就是这种方式。再次给电路板上电,CAN模块不能收发,但此时CPU正常,量CAN收发器电压正常! -
解决方法:
百度了一下,发现有不少人遇到类似问题,他们大多是因为开启了错误中断,在CANH和CANL短接或者其他原因造成CAN模块收发有误,在错误帧没有得到处理的时候CAN模块会因为错误中断而进入死循环。 解决链接:https://blog.csdn.net/u014515202/article/details/54135882
我把错误中断使能禁止 CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE);(库函数)发现还是不行,,后来查阅STM32数据手册发现就算用户不去禁止,他默认也是关闭的
之前的中断错误被排除了,查看数据手册中有这么一段
当CAN收发器断电后,STM32 CAN模块会进行发送错误计数,当TEC大于255时CAN模块进入离线状态,此时并不用产生错误中断就可以让CAN模块停止发送和接收。
后来看到一篇专门讲出错管理的一篇文章:https://blog.csdn.net/flydream0/article/details/8161418
于是修改了程序
void CAN_Mode_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
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;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
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);
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_ABOM=ENABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=DISABLE; //不使能非自动重传模式
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;//模式设置: CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//设置波特率250Kbps
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=CAN_BS1_8tq; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=CAN_BS2_7tq; //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=8; //分频系数(Fdiv)为brp+1
CAN_Init(CAN1, &CAN_InitStructure); //初始化CAN1
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //接收中断允许.
CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE); //禁止错误中断
}
CAN_InitStructure.CAN_ABOM=ENABLE; //软件自动离线管理
CAN_ITConfig(CAN1,CAN_IT_ERR,DISABLE); //禁止错误中断
修改以上两个语句,问题得到解决。
- 问题二:
之前学程序时候参考了一份非常有价值的文章
1、https://blog.csdn.net/flydream0/article/details/8148791
2、https://blog.csdn.net/bonson2004/article/details/68942442
程序编写完之后验证时发现过滤器根本不起作用,又是一个坑,以后写程序得先看一遍官方数据手册是很有必要的!
发现STM32的CAN过滤器在配置时必须要进入初始化,才能对其进行配置。
/***********************************************************
函数名称:CANFilterConfig_List_Extend(u8 FGrop,u32 Ext_Id1,u32 Ext_Id2)
函数功能:设置过滤器与屏蔽寄存器 列表模式
入口参数:FGrop 过滤器组,Ext_Id1、Ext_Id2 需要过滤的扩展ID
出口参数:无
备 注:32位列表模式下,屏蔽寄存器也被当作标识符寄存器用,即两个寄存器各作为过滤值用
***********************************************************/
void CANFilterConfig_List_Extend(u8 FGrop,u32 Ext_Id1,u32 Ext_Id2)
{
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN1->FMR |= 1; //过滤器组工作在初始化模式
CAN_FilterInitStructure.CAN_FilterNumber = FGrop; //设置过滤器组0,范围为0~13
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; //设置过滤器组0为标识符列表模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //设置过滤器组0位宽为32位
//设置标识符寄存器
CAN_FilterInitStructure.CAN_FilterIdHigh=((Ext_Id1<<3)>>16)&0xffff ; //设置标识符寄存器高字节
CAN_FilterInitStructure.CAN_FilterIdLow=((Ext_Id1<<3)&0xffff)|CAN_Id_Extended;//设置标识符寄存器低字节,CAN_FilterIdLow的ID位可以随意设置,在此模式下不会有效。
//设置屏蔽寄存器,这里当标识符寄存器用
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=((Ext_Id2<<3)>>16)&0xffff; //设置屏蔽寄存器高字节
CAN_FilterInitStructure.CAN_FilterMaskIdLow=((Ext_Id2<<3)&0xffff)|CAN_Id_Extended; //设置屏蔽寄存器低字节
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //此过滤器组关联到接收FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活此过滤器组
CAN_FilterInit(&CAN_FilterInitStructure); //设置过滤器
CAN1->FMR &=~1; //过滤器组正常工作
}
重要的两句:CAN1->FMR |= 1; //过滤器组工作在初始化模式
CAN1->FMR &=~1; //过滤器组正常工作
实测可以进行过滤|