文章目录
CAN协议
协议了解即可,主要了解,报文格式(比如标准格式的,数据帧:帧起始+仲裁段+控制段+数据段+CRC段+ACK段+帧结束),还是应用为主。
CUBEMAX生成
功能是:PE7 PE8 借助定时器2和6,分别以100ms和1s间隔闪烁。
接收/发送can报文
首先打开系统串口调试(可以直接将cubemax生成代码到项目工程里,后面直接更新生成即可)

GPIO配置:

时钟树配置:
配置主频72MHZ:
FDCAN时钟选择:

定时器2配置:

定时器6配置:
开启中断,以及设置中断抢占优先级为1,2 相应优先级都是默认为0:

定时时间计算:
Time = 72MHZ / ((PSC +1) (Count Period+1)) = 72MHZ / ((7199+1)*(9999+1)) = 1s*
CAN FD配置:

波特率计算:
baud = 72MHZ / ( (Nominal Sync Jump + Seg1+Seg2) 波特率分频系数 )
= 72Mbps/ ((1+9+8)8)
= 500 000bps
= 500kbps
再比如要1MHZ的话 那就是设置 波特率分频系数(Nominal Prescaler)为4,其它不变 就是如图。
这里我在程序中将波特率分频系数(Nominal Prescaler)为8 了 所以使用的是500kbps。
CAN代码
借助STM32CUBEMAX生成+编写接收/发送:
生成的肯定不能直接使用的:比如要自己编写Tim2 Tim6 的定时器中断服务函数,以及开启定时器计数,
tim.c
c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file tim.c
* @brief This file provides code for the configuration
* of the TIM instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim6;
/* TIM2 init function */
void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7199;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
/* TIM6 init function */
void MX_TIM6_Init(void)
{
/* USER CODE BEGIN TIM6_Init 0 */
/* USER CODE END TIM6_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */
htim6.Instance = TIM6;
htim6.Init.Prescaler = 7199;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 9999;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM6_Init 2 */
/* USER CODE END TIM6_Init 2 */
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
/* USER CODE END TIM2_MspInit 0 */
/* TIM2 clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* TIM2 interrupt Init */
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
else if(tim_baseHandle->Instance==TIM6)
{
/* USER CODE BEGIN TIM6_MspInit 0 */
/* USER CODE END TIM6_MspInit 0 */
/* TIM6 clock enable */
__HAL_RCC_TIM6_CLK_ENABLE();
/* TIM6 interrupt Init */
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
/* USER CODE BEGIN TIM6_MspInit 1 */
/* USER CODE END TIM6_MspInit 1 */
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */
/* USER CODE END TIM2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM2_CLK_DISABLE();
/* TIM2 interrupt Deinit */
HAL_NVIC_DisableIRQ(TIM2_IRQn);
/* USER CODE BEGIN TIM2_MspDeInit 1 */
/* USER CODE END TIM2_MspDeInit 1 */
}
else if(tim_baseHandle->Instance==TIM6)
{
/* USER CODE BEGIN TIM6_MspDeInit 0 */
/* USER CODE END TIM6_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM6_CLK_DISABLE();
/* TIM6 interrupt Deinit */
HAL_NVIC_DisableIRQ(TIM6_DAC_IRQn);
/* USER CODE BEGIN TIM6_MspDeInit 1 */
/* USER CODE END TIM6_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
tim.h
c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file tim.h
* @brief This file contains all the function prototypes for
* the tim.c file
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIM_H__
#define __TIM_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern TIM_HandleTypeDef htim2;
extern TIM_HandleTypeDef htim6;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_TIM2_Init(void);
void MX_TIM6_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __TIM_H__ */
fdcan.c
c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file fdcan.c
* @brief This file provides code for the configuration
* of the FDCAN instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "fdcan.h"
/* USER CODE BEGIN 0 */
FDCAN_RxHeaderTypeDef fdcan2_RxHeader;
FDCAN_TxHeaderTypeDef fdcan2_TxHeader;
/* USER CODE END 0 */
FDCAN_HandleTypeDef hfdcan2;
/* FDCAN2 init function */
void MX_FDCAN2_Init(void)
{
/* USER CODE BEGIN FDCAN2_Init 0 */
FDCAN_FilterTypeDef FDCAN1_RXFilter;
/* USER CODE END FDCAN2_Init 0 */
/* USER CODE BEGIN FDCAN2_Init 1 */
/* USER CODE END FDCAN2_Init 1 */
hfdcan2.Instance = FDCAN2;
hfdcan2.Init.ClockDivider = FDCAN_CLOCK_DIV1;
hfdcan2.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan2.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan2.Init.AutoRetransmission = DISABLE; //禁用自动重传功能。如果启用,则在检测到错误时会自动重发消息。
hfdcan2.Init.TransmitPause = DISABLE; //禁用传输暂停功能。如果启用,则在发送过程中不允许新的传输请求。
hfdcan2.Init.ProtocolException = DISABLE; //禁用协议异常处理。如果启用,则在检测到协议异常时会触发中断。
hfdcan2.Init.NominalPrescaler = 4*2; //波特率预分频器值为4*2
hfdcan2.Init.NominalSyncJumpWidth = 1; //同步跳转宽度为1个时间量子。
hfdcan2.Init.NominalTimeSeg1 = 9; //时间段1(Phase Segment 1)为9个时间量子。
hfdcan2.Init.NominalTimeSeg2 = 8; //时间段2(Phase Segment 2)为8个时间量子
//。这适用于CAN FD模式下的数据阶段,但在本例中由于使用的是经典CAN模式,这一项可能不会被使用。
hfdcan2.Init.DataPrescaler = 1; //设置数据波特率预分频器值为1
hfdcan2.Init.DataSyncJumpWidth = 1; //设置数据同步跳转宽度为1个时间量子。同样,这适用于CAN FD模式下的数据阶段。
hfdcan2.Init.DataTimeSeg1 = 1; // 设置数据时间段1为1个时间量子。同上,适用于CAN FD模式下的数据阶段
hfdcan2.Init.DataTimeSeg2 = 1; //设置数据时间段2为1个时间量子。同上,适用于CAN FD模式下的数据阶段。
//...............................................................
hfdcan2.Init.StdFiltersNbr = 2; //设置标准ID滤波器的数量为1。
hfdcan2.Init.ExtFiltersNbr = 1; //设置扩展ID滤波器的数量为0。
hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; //设置发送队列模式为FIFO操作模式。
if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN FDCAN2_Init 2 */
FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID; //设置接收滤波器的ID类型为标准ID(11位ID)
FDCAN1_RXFilter.FilterIndex= 0; //设置滤波器索引为0,表示这是第一个滤波器。
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_DUAL; //设置滤波器类型为(FDCAN_FILTER_DUAL)这个是指定俩个ID,只能接收和这俩id,其中之一,一样的报文。
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //设置滤波器配置为将匹配的消息存储到接收FIFO0中。
FDCAN1_RXFilter.FilterID1=0x11; //设置滤波器的第一个ID值为0x01。可以接收 0x11 的id消息
FDCAN1_RXFilter.FilterID2=0x12; //设置滤波器的第二个ID值为0x02。也可以接收 0x12 的id消息
if(HAL_FDCAN_ConfigFilter(&hfdcan2,&FDCAN1_RXFilter)!=HAL_OK) //滤波器初始化
{
Error_Handler();
}
FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID; //设置接收滤波器的ID类型为标准ID(11位ID)
FDCAN1_RXFilter.FilterIndex= 1; //设置滤波器索引为1,表示这是第二个滤波器。
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_DUAL; //设置滤波器类型为范围过滤器(FDCAN_FILTER_RANGE),意味着它将匹配一个ID范围内的所有消息。
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //设置滤波器配置为将匹配的消息存储到接收FIFO0中。
FDCAN1_RXFilter.FilterID1=0x13; //设置滤波器的第一个ID值为0x13。
FDCAN1_RXFilter.FilterID2=0x13; //设置滤波器的第二个ID值为0x13。只可以接收 0x13 的id消息
if(HAL_FDCAN_ConfigFilter(&hfdcan2,&FDCAN1_RXFilter)!=HAL_OK) //滤波器初始化
{
Error_Handler();
}
FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID; //设置接收滤波器的ID类型为扩展ID(11+18 = 29位ID)
FDCAN1_RXFilter.FilterIndex= 0; //设置滤波器索引为0,表示这是第一个滤波器。
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_RANGE; //设置滤波器类型为范围过滤器(FDCAN_FILTER_RANGE),意味着它将匹配一个ID范围内的所有消息。
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //设置滤波器配置为将匹配的消息存储到接收FIFO0中。
FDCAN1_RXFilter.FilterID1=0x12345672; //设置滤波器的第一个ID值为0x12345672。对于范围过滤器,这表示起始ID
FDCAN1_RXFilter.FilterID2=0x12345678; //设置滤波器的第二个ID值为x12345678。对于范围过滤器,这表示结束ID。这里两个ID相同,意味着只匹配ID为0x000的报文。
if(HAL_FDCAN_ConfigFilter(&hfdcan2,&FDCAN1_RXFilter)!=HAL_OK) //滤波器初始化
{
Error_Handler();
}
/* Configure global filter:这个函数是配置全局滤波器配置寄存器的,一定要写,否则配置了也没用
如果没有正确配置全局过滤器,可能会导致所有未匹配的消息(即那些不满足任何已定义滤波器规则的消息)按照默认规则处理,而不是被丢弃或重定向到指定的FIFO中。
而现在直接干涉,不匹配的直接丢弃,过滤器就生效了。*/
if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2,
FDCAN_REJECT, // 不匹配的标准帧丢弃
FDCAN_REJECT, // 不匹配的扩展帧丢弃
FDCAN_REJECT_REMOTE, // 拒绝标准帧的远程帧
FDCAN_REJECT_REMOTE) // 拒绝扩展帧的远程帧
!= HAL_OK)
{
Error_Handler();
}
HAL_FDCAN_Start(&hfdcan2); //启动FDCAN
//HAL_FDCAN_ActivateNotification(&hfdcan2,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0); //用来激活接收FIFO0新消息的中断通知。这个就是接收中断,开启了需要编写中断处理函数
/* USER CODE END FDCAN2_Init 2 */
}
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
if(fdcanHandle->Instance==FDCAN2)
{
/* USER CODE BEGIN FDCAN2_MspInit 0 */
/* USER CODE END FDCAN2_MspInit 0 */
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
// Error_Handler();
}
/* FDCAN2 clock enable */
__HAL_RCC_FDCAN_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**FDCAN2 GPIO Configuration
PB5 ------> FDCAN2_RX
PB6 ------> FDCAN2_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN FDCAN2_MspInit 1 */
/* USER CODE END FDCAN2_MspInit 1 */
}
}
void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{
if(fdcanHandle->Instance==FDCAN2)
{
/* USER CODE BEGIN FDCAN2_MspDeInit 0 */
/* USER CODE END FDCAN2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_FDCAN_CLK_DISABLE();
/**FDCAN2 GPIO Configuration
PB5 ------> FDCAN2_RX
PB6 ------> FDCAN2_TX
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5|GPIO_PIN_6);
/* USER CODE BEGIN FDCAN2_MspDeInit 1 */
/* USER CODE END FDCAN2_MspDeInit 1 */
}
}
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
// 其他,失败
uint8_t FDCAN2_Send_Msg(uint8_t* msg)
{
fdcan2_TxHeader.Identifier = 0x123;
fdcan2_TxHeader.IdType = FDCAN_EXTENDED_ID; //发送的是扩展帧;
fdcan2_TxHeader.TxFrameType = FDCAN_DATA_FRAME; //格式是数据帧,这里注意,CANFD是不存在遥控帧的
fdcan2_TxHeader.DataLength = FDCAN_DLC_BYTES_8; //发送字节数:8个字节
fdcan2_TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
fdcan2_TxHeader.BitRateSwitch = FDCAN_BRS_OFF; //代表:使用CANFD时数据段和其他段 波特率不一样
fdcan2_TxHeader.FDFormat = FDCAN_CLASSIC_CAN; //使用经典CAN模式
fdcan2_TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
fdcan2_TxHeader.MessageMarker = 0x52; //每条消息设置一个不同的 MessageMarker(如 0x01 表示发动机数据,0x02 表示刹车状态)
// MessageMarker 就是一个自己定义的消息 ID,用来区分不同发送消息的"身份证号码"
if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2,&fdcan2_TxHeader,msg)!=HAL_OK) return 1;
return 0;
}
//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到;
//其他,接收的数据长度;
uint16_t FDCAN2_Receive_Msg(uint8_t *buf, uint32_t *Identifier,uint16_t *len)
{
if(HAL_FDCAN_GetRxMessage(&hfdcan2,FDCAN_RX_FIFO0,&fdcan2_RxHeader,buf)!=HAL_OK)return 0;//接收数据
*Identifier = fdcan2_RxHeader.Identifier; //获取接收数据ID
*len=fdcan2_RxHeader.DataLength; //获取接收数据长度
return fdcan2_RxHeader.DataLength;
}
/* USER CODE END 1 */
fdcan.h
c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file fdcan.h
* @brief This file contains all the function prototypes for
* the fdcan.c file
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FDCAN_H__
#define __FDCAN_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern FDCAN_HandleTypeDef hfdcan2;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_FDCAN2_Init(void);
/* USER CODE BEGIN Prototypes */
uint8_t FDCAN2_Send_Msg(uint8_t* msg);
uint16_t FDCAN2_Receive_Msg(uint8_t *buf, uint32_t *Identifier,uint16_t *len);
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* __FDCAN_H__ */
main.c
c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fdcan.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t tx_buff[12]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC};
uint8_t tx2_buff[12]={'0','2','3','4','5','6','7','8'};
uint8_t rx_buff[12] = {'\0'};
uint32_t id = 0;
uint16_t len = 0;
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM6_Init();
MX_TIM2_Init();
MX_FDCAN2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6); // 这里一定要开启
HAL_TIM_Base_Start_IT(&htim2); // 这里也要写开启
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
FDCAN2_Send_Msg(tx_buff);
FDCAN2_Receive_Msg(rx_buff,&id,&len);
HAL_Delay(500);
//FDCAN2_Send_Msg(tx2_buff);
//FDCAN2_Receive_Msg(rx_buff,&id,&len);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 9;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
// 1S更新
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6){
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_7); //翻转LED灯的
}
if(htim->Instance == TIM2){
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_8); //翻转LED灯的
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
简单描述总结
发送配置:扩展帧,数据长度8字节,ID = 0x123,数据0x11,0x22 ······ 0x88 。
接收配置:设置2个标准id过滤器,以及1个扩展id过滤器。
2个标准的id过滤器都设置成双重ID模式。意思是:发送的id只要匹配设置的两个id中其中之一,即可被接收(代码里体现是:第一个过滤器能接收0x11或0x12标准的id报文,第二个过滤器只能接收0x13标准id的报文)。
1个扩展id设置成范围id模式,意思是:接收的id是在设置的id1和id2 之间的id 都是能够被接收的(代码里体现是:从id1:0x12345672到 id2:0x12345678之间的id 都可以接收)。
测试
测试1
助手发送标准帧id = 0x11,数据0x11······0x88

这里debug ,查看助手发送的数据,接收到数组里面,是10进制显示的,所以对应的是12 34 等等。

测试2
再发标准id = 0x12的数据,少发一个0x88,查看到:
【7】数据没有清除而已,可以看到长度是7,以及id为0x12了。
测试3
再发标准id = 0x13的数据,将少发的0x88改成0xAA,查看到:

【7】数据变成了0xAA = 170 可以看到长度是8,以及id为0x13了。
测试4
这里发一个 0x12345672 到0x12345678范围之间的一个扩展id,
发扩展id为:0x12345677,数据长度3个 ,内容是0x77 0x88 0x99



**0x77 = 119 0x88 = 136 0x99 = 153,接收的数据长度是3,以及id号0x12345677 = 305419895 **
测试5
测试一个标准id 为 0x14 内容无所谓(因为被过滤掉了),还有一个扩展帧不在0x12345672 到 0x12345678之间的 id ,如0x12345671。



DEBUG可以看到压根就没被接收到数组里面,里面数据还是测试4的数据,没被覆盖。
测试6
可以改动代码中的过滤器的模式,实现不一样的过滤:
c
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_DUAL;
//有如下选择:
#define FDCAN_FILTER_RANGE ((uint32_t)0x00000000U) /*!< Range filter from FilterID1 to FilterID2 */
#define FDCAN_FILTER_DUAL ((uint32_t)0x00000001U) /*!< Dual ID filter for FilterID1 or FilterID2 */
#define FDCAN_FILTER_MASK ((uint32_t)0x00000002U) /*!< Classic filter: FilterID1 = filter, FilterID2 = mask */
#define FDCAN_FILTER_RANGE_NO_EIDM ((uint32_t)0x00000003U) /*!< Range filter from FilterID1 to FilterID2, EIDM mask not applied */
FDCAN_FILTER_RANGE:匹配指定范围内的所有ID。
FDCAN_FILTER_DUAL:匹配两个特定的ID。
FDCAN_FILTER_MASK:通过掩码来匹配特定的位域。
FDCAN_FILTER_RANGE_NO_EIDM:范围过滤器,但不应用扩展ID掩码。
其中FDCAN_FILTER_MASK:通过掩码来匹配特定的位域。这个也是比较常用的。