提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
本次CAN调试基于STM32F767系列,用于记录调试过程种发现的问题和难记点
一、调试环境
- 系统:FreeRTOS
- 接口:Can1
- 开发板:野火STM32F767
- 案例:野火&正点原子
二、程序代码
1.初始化
下面先贴出配置代码:
MSP初始化包括CLK和引脚配置,开启FIFO0接收中断。
/**
* @brief CAN_MSP初始化
* @param hcan
* @retval 成功返回@HAL_OK ,故障返回@HAL_ERROR
*/
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
{
GPIO_InitTypeDef GPIO_InitTypeStruct;
CAN1_CLK_ENABLE();
CAN1_TX_GPIO_CLK_ENABLE();
CAN1_RX_GPIO_CLK_ENABLE();
/* CAN1_TX && CAN1_RX引脚结构体 */
GPIO_InitTypeStruct.Pin = CAN1_TX_PIN | CAN1_RX_PIN;
GPIO_InitTypeStruct.Alternate = CAN_AF;
GPIO_InitTypeStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitTypeStruct.Pull = GPIO_PULLUP;
GPIO_InitTypeStruct.Mode = GPIO_MODE_AF_PP;
HAL_GPIO_Init(CAN1_TX_GPIO_PORT,&GPIO_InitTypeStruct);
/* 开启中断:FIFO 0 message pending interrupt */
__HAL_CAN_ENABLE_IT(&CAN1_Handler,CAN_IT_FMP0);
/* 开启NVIC */
HAL_NVIC_SetPriority(CAN1_RX0_IRQn,5,5);//若要在RTOS中使用系统函数,则优先级要大于5,以被系统调度
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
}
CAN1配置初始化设置波特率,CAN模式和过滤器设置。
/**
* @brief CAN1模式初始化
* @param
* @param
* @param
* @param
* @retval 成功返回@HAL_OK ,故障返回@HAL_ERROR
*/
HAL_StatusTypeDef CAN1_Config_Init(void)
{
uint32_t id = 0x0302;
uint32_t mask = 0x0300;
/*
* CiA计算方式:(1+CAN_BS1)/(1+CAN_BS1+CAN_BS2)
* 波特率 = APB1Clock/(1+CAN_BS1+CAN_BS2)/CAN_Prescaler
*/
CAN_FilterConfTypeDef CAN_FilterConfStruct; /* 过滤器结构体 */
CAN1_Handler.Instance = CAN1; /* CAN1 */
CAN1_Handler.pTxMsg = &Can1TxMsg; /* 映射TX发送结构体缓冲数据*/
CAN1_Handler.pRxMsg = &Can1RxMsg; /* 映射RX发送结构体缓冲数据*/
CAN1_Handler.Init.Mode = CAN_MODE_NORMAL; /* 模式设置 */
CAN1_Handler.Init.Prescaler = 6; /* 配置 CAN 外设的时钟分频,可设置为 1-1024 */
/* CAN_SJW表示重新同步跳跃宽度,不参与波特率的计算,其值可以编程为1到4个时间单元,表示该总线对波特率范围的容差度 */
CAN1_Handler.Init.SJW = CAN_SJW_1TQ; /* 配置 SJW 极限值 CAN_SJW_1TQ */
CAN1_Handler.Init.BS1 = CAN_BS1_5TQ; /* 配置 BS1 段长度 CAN_BS1_5TQ*/
CAN1_Handler.Init.BS2 = CAN_BS2_3TQ; /* 配置 BS2 段长度 CAN_BS2_3TQ*/
CAN1_Handler.Init.TTCM = DISABLE; /* 是否使能 TTCM 时间触发功能 */
CAN1_Handler.Init.ABOM = ENABLE; /* 是否使能 ABOM 自动离线管理功能 */
CAN1_Handler.Init.AWUM = ENABLE; /* 是否使能 AWUM 自动唤醒功能 */
CAN1_Handler.Init.NART = DISABLE; /* 是否使能 NART 自动重传功能 */
CAN1_Handler.Init.RFLM = DISABLE; /* 是否使能 RFLM 锁定 FIFO 功能 */
CAN1_Handler.Init.TXFP = DISABLE; /* 配置 TXFP 报文优先级的判定方法 */
CAN1_Handler.Init.Prescaler =6; BTR-BRP 波特率分频器 定义了时间单元的时间长度 54/(1+5+3)/5=1 Mbps
if(HAL_CAN_Init(&CAN1_Handler) !=HAL_OK)
{
printf("\r\nCAN初始化失败\r\n");
return HAL_ERROR;
}
else
printf("OK\r\n");
/* ----------------- 过滤器部分 -------------------------*/
CAN_FilterConfStruct.FilterNumber = 0;
CAN_FilterConfStruct.FilterIdHigh = ((((uint32_t)id<<3)|
CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16; /* 要筛选的ID高位 */
CAN_FilterConfStruct.FilterIdLow = (((uint32_t)id<<3)|
CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; /* 要筛选的ID低位 */
CAN_FilterConfStruct.FilterMaskIdHigh = ((((uint32_t)mask<<3)|
CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16; /* 筛选器高16位每位必须匹配; 0xFFFF*/
CAN_FilterConfStruct.FilterMaskIdLow = (((uint32_t)mask<<3)|
CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; /* 筛选器低16位每位必须匹配; 0xFFFF*/
CAN_FilterConfStruct.FilterFIFOAssignment = CAN_FILTER_FIFO0 ; /* 筛选器被关联到FIFO0 */
CAN_FilterConfStruct.FilterMode = CAN_FILTERMODE_IDMASK; /* 工作在掩码模式 */
CAN_FilterConfStruct.FilterScale = CAN_FILTERSCALE_32BIT; /* 筛选器位宽32位 */
CAN_FilterConfStruct.FilterActivation = ENABLE; /* 激活滤波器0 */
CAN_FilterConfStruct.BankNumber = 14; /* 对于双CAN产品,BankNumber(14)起往后的过滤器组分配给CAN2 */
if(HAL_CAN_ConfigFilter(&CAN1_Handler,&CAN_FilterConfStruct) != HAL_OK)
{
printf("HAL_CAN_ConfigFilter故障 \r\n");
return HAL_ERROR;
}
return HAL_OK;
}
2.配置分析
主要分析CAN配置:
2.1波特率设置
此处程序波特率设置是1MHz
主要通过三个设置:
- SJW
- BS1
- BS2
公式如下:
CAN时钟:APB1 = 54MHz
CAN Baudrate = APB1Clock/(1+CAN_BS1+CAN_BS2) / CAN_Prescaler
= 54MHz / (1 + 5 + 3) /6
= 1MHz //1MHz为F767—can最大响应速度
计算原理如下:
CAN波特率计算重点在于位时序的分解
为了实现位同步,CAN 协议把每一个数据位的时序分解成如图所示的 SS 段、PTS 段、PBS1 段、PBS2段,这四段的长度加起来即为一个 CAN 数据位的长度。分解后最小的时间单位是 Tq,而一个完整的位由 8~25 个Tq组成。为方便表示,图 中的高低电平直接代表信号逻辑 0 或逻辑 1(不是差分信号)。
2.2过滤器设置
参考原文:https://blog.csdn.net/faihung/article/details/98849164
2.2.1过滤器的位宽
- 1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
- 2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
此处程序内用的32位过滤器
CAN_FilterConfStruct.FilterScale = CAN_FILTERSCALE_32BIT; /* 筛选器位宽32位 */
2.2.2 CAN ID的结构
如上图,ID分为两种,分别是标准ID和扩展ID。
以下我们以扩展ID作为分析:
扩展格式中ID0~ID17为Extension ID,而ID18~ID28为Base ID
如ID = 0x0x1800f001
用二进制表示为:0b 0001 1000 0000 0000 1111 0000 0000 0001
用括号分别区别为:0b 000[1 1000 0000 0]0[00 1111 0000 0000 0001]
基本ID[28:18](绿色部分) + IDE + 扩展ID(蓝色部分)[17:0] 组成一个扩展ID。