1、简介
使用STM32F407IGHX单片机(C板)CAN1、CAN2短接,进行数据自收发。
2.CubeMax初始化配置
CAN通讯介绍:CAN总线与单片机。
1.rcc配置
2.sys配置
3.时钟树配置
4.CAN配置
需要注意是第六点,根据C板手册所示,CAN1输出接口为PD0、PD1,如下图所示:
CAN2配置跟CAN1一致,不需要单独配置引脚,C板CAN2输出引脚与默认配置一致。
5.触发按键配置
6.文件导出
3 Keil端程序书写
3.1.初始化配置
1.过滤器配置
要想使用CAN总线首先需要对过滤器进行配置。
/* USER CODE BEGIN 4 */ //CAN初始化 void CAN_ConfigFilter() { //过滤器配置 CAN_FilterTypeDef sFilterConfig;//建立过滤器结构体 sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; sFilterConfig.FilterBank = 0; sFilterConfig.FilterFIFOAssignment = CAN_FilterFIFO0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000;//32 位 ID 不使用过滤器 sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000;//32 位 MASK sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.SlaveStartFilterBank = 14; if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } sFilterConfig.FilterBank = 14; if(HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) { Error_Handler(); } } /* USER CODE END 4 */
2.CAN启动配置
在过滤器配置后进行CAN启动配置,先启动CAN1在启动CAN2,代码如下所示:
if(HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) { Error_Handler(); } //启动CAN if(HAL_CAN_Start(&hcan1)!= HAL_OK) { Error_Handler(); } if(HAL_CAN_Start(&hcan2)!= HAL_OK) { Error_Handler(); }
3.打开中断
在CAN启动后,进行CAN中断配置,代码如下所示:
//打开接收中断 if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING|CAN_IT_RX_FIFO1_MSG_PENDING)!= HAL_OK) { Error_Handler(); } if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING|CAN_IT_RX_FIFO1_MSG_PENDING)!= HAL_OK) { Error_Handler(); }
整个初始化函数代码如下所示:
//CAN初始化 void CAN_ConfigFilter() { //过滤器配置 CAN_FilterTypeDef sFilterConfig;//建立过滤器结构体 sFilterConfig.FilterActivation = CAN_FILTER_ENABLE; sFilterConfig.FilterBank = 0; sFilterConfig.FilterFIFOAssignment = CAN_FilterFIFO0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000;//32 位 ID 不使用过滤器 sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000;//32 位 MASK sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.SlaveStartFilterBank = 14; if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } sFilterConfig.FilterBank = 14; if(HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) { Error_Handler(); } //启动CAN if(HAL_CAN_Start(&hcan1)!= HAL_OK) { Error_Handler(); } if(HAL_CAN_Start(&hcan2)!= HAL_OK) { Error_Handler(); } //打开接收中断 if(HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING|CAN_IT_RX_FIFO1_MSG_PENDING)!= HAL_OK) { Error_Handler(); } if(HAL_CAN_ActivateNotification(&hcan2,CAN_IT_RX_FIFO0_MSG_PENDING|CAN_IT_RX_FIFO1_MSG_PENDING)!= HAL_OK) { Error_Handler(); } } /* USER CODE END 4 */
4.函数声明与主函数调用
在main.h中对上诉函数进行声明,如下所示:
/* USER CODE BEGIN Includes */ void CAN_ConfigFilter(); /* USER CODE END Includes */
声明完后,在主函数进行初始化,如下所示:
/* USER CODE BEGIN 2 */ CAN_ConfigFilter(); /* USER CODE END 2 */
5.定义数组、发送接收结构体
/* USER CODE BEGIN PV */ uint8_t txData[8],rxData0[8],rxData1[8]; CAN_TxHeaderTypeDef txHeader; CAN_RxHeaderTypeDef rxHeader0,rxHeader1; bool Pa0Pressed = false; uint16_t txID = 0x200; uint32_t txMailbox; /* USER CODE END PV */
6、按键触发
引用头文件
/* USER CODE BEGIN Includes */ #include "stdbool.h" /* USER CODE END Includes */
7. CAN配置
while (1) { if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 0 && !Pa0Pressed){ Pa0Pressed = true; txHeader.StdId = txID; txHeader.IDE = CAN_ID_STD; txHeader.RTR = CAN_RTR_DATA; txHeader.DLC = 8; *((uint32_t*)(txData)) = HAL_GetTick(); if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) != 0){ HAL_CAN_AddTxMessage(&hcan1,&txHeader,txData,&txMailbox); } } else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 1 && !Pa0Pressed){ Pa0Pressed = false; } HAL_Delay(100);
8 中断回调函数
/* USER CODE BEGIN 4 */ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { if(hcan->Instance==CAN2) { HAL_CAN_GetRxMessage(&hcan2,CAN_FILTER_FIFO0,&rxHeader0,rxData0);//获取数据 } } void HAL_CAN_RxFifo10MsgPendingCallback(CAN_HandleTypeDef *hcan) { if(hcan->Instance==CAN2) { HAL_CAN_GetRxMessage(&hcan1,CAN_FILTER_FIFO1,&rxHeader1,rxData1);//获取数据 } }