这两天去面试,突然问我CAN的相关功能,但是做过一次早就忘记了,正好用HAL库重新做一遍,留下个记忆。
正常配置引脚,配置功能。
第一栏是配置时钟的,通过配置能设置波特率(主要功能,里面具体的TQ方面请自行查找),因为我的总线是42MHz的,直接分频42,这样TQ就是整数,方便设置波特率。因为低速和高速CAN的速率区分线就是125K,这样设置成125K可以同时应用在两种不同总线情况下(可以后续改)。最后一个是补偿机制的,相当于一个可设定频率的可调带宽滤波器,可以类比成系口袋的绳,越大容错越高,但是风险也越大(意外的杂波)。
第二栏是CAN总线的一些功能。第一个是时间戳,使能就能用时间戳;第二个是自动离线管理,当发送或接收错误超过一定值就离线了;第三个是自动唤醒,低功耗用的;第四个是报文自动重传,当发送失败了就一直发送到成功;第五个是FIFO锁,使能后满了就不收后边的报文,关闭就会覆盖原来的报文;第六个是报文发送优先级的功能,这个是配置邮箱中多个未发送报文的以ID的优先级发送还是以存进来的顺序发送。这栏功能根据自己的需求选,个人认为时间戳、自动离线、自动重传这三个作用比较大,我选择这三个启用。
第三栏是模式选择,CAN总线有正常模式、环回模式、静默模式和环回静默模式。正常模式不说了,环回是TX可以发到自己的RX上,RX接收不到外边的报文,用来自测试数据发送的。静默是只能接收,发送隐性位,像是做CAN分析仪的在监控的时候就可以用这个模式。环回静默就相当于两个都结合一下,对外只能发隐性位,自己发送的自己能接收,不能接收外部的报文。这几个功能取决于产品用途和调试阶段吧。
中断有四个,TX一般不用,自己看情况使用;RX0 RX1取决于用了那个FIFO,用0就勾0,用1就勾1;SCE是错误中断,自己发着玩没啥问题,实际产品肯定要在这里做功能的。
CAN.C里要去配置一下,默认生成的没有过滤器的设置,所以自己建一下,建ID和mask,内容要根据实际的来,看是标准帧还是扩展帧,还有掩码相关的部分也要自己配置。
#define CAN1_ID_H 0X0000
#define CAN1_ID_L 0X0000
#define CAN1_MASK_H 0X0000
#define CAN1_MASK_L 0X0000
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
CAN_FilterTypeDef CAN1_sFilterConfig; //建立一个CAN1的配置结构体
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 42;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_2TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
hcan1.Init.TimeTriggeredMode = ENABLE;
hcan1.Init.AutoBusOff = ENABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = ENABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
/*过滤器配置*/
CAN1_sFilterConfig.FilterIdHigh = CAN1_ID_H; //ID设置
CAN1_sFilterConfig.FilterIdLow = CAN1_ID_L;
CAN1_sFilterConfig.FilterMaskIdHigh = CAN1_MASK_H;//掩码设置
CAN1_sFilterConfig.FilterMaskIdLow = CAN1_MASK_L;
CAN1_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;//选择的FIFO,这个和中断有关系
CAN1_sFilterConfig.FilterBank = 0;//从0到13,共14个给1用
CAN1_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//这个还有个list 那个是完全符合的过滤
CAN1_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
CAN1_sFilterConfig.FilterActivation = ENABLE;
CAN1_sFilterConfig.SlaveStartFilterBank = 14;//共14个
while(HAL_CAN_ConfigFilter(&hcan1, &CAN1_sFilterConfig)!=HAL_OK);//配置函数
while(HAL_CAN_Start(&hcan1)!= HAL_OK);//can开始
while(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING)!=HAL_OK);//can中断
/* USER CODE END CAN1_Init 2 */
}
#define CAN2_ID_H 0X0000
#define CAN2_ID_L 0X0000
#define CAN2_MASK_H 0X0000
#define CAN2_MASK_L 0X0000
void MX_CAN2_Init(void)
{
/* USER CODE BEGIN CAN2_Init 0 */
CAN_FilterTypeDef CAN2_sFilterConfig;
/* USER CODE END CAN2_Init 0 */
/* USER CODE BEGIN CAN2_Init 1 */
/* USER CODE END CAN2_Init 1 */
hcan2.Instance = CAN2;
hcan2.Init.Prescaler = 42;
hcan2.Init.Mode = CAN_MODE_NORMAL;
hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan2.Init.TimeSeg1 = CAN_BS1_3TQ;
hcan2.Init.TimeSeg2 = CAN_BS2_4TQ;
hcan2.Init.TimeTriggeredMode = DISABLE;
hcan2.Init.AutoBusOff = DISABLE;
hcan2.Init.AutoWakeUp = DISABLE;
hcan2.Init.AutoRetransmission = DISABLE;
hcan2.Init.ReceiveFifoLocked = DISABLE;
hcan2.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN2_Init 2 */
/*过滤器配置*/
CAN2_sFilterConfig.FilterIdHigh = CAN2_ID_H;
CAN2_sFilterConfig.FilterIdLow = CAN2_ID_L;
CAN2_sFilterConfig.FilterMaskIdHigh = CAN2_MASK_H;
CAN2_sFilterConfig.FilterMaskIdLow = CAN2_MASK_L;
CAN2_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1;//这个用的fifo1
CAN2_sFilterConfig.FilterBank = 14;//上边是0-13 这个是14到27
CAN2_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
CAN2_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
CAN2_sFilterConfig.FilterActivation = ENABLE;
CAN2_sFilterConfig.SlaveStartFilterBank = 14;
while(HAL_CAN_ConfigFilter(&hcan2, &CAN2_sFilterConfig)!=HAL_OK);
while(HAL_CAN_Start(&hcan2)!= HAL_OK);
while(HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK);
/* USER CODE END CAN2_Init 2 */
}
里面有注释,两个都配一下,至此配置结束。