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);//获取数据
}
}