STM32G474VET6-CAN FD使用经典模式+过滤报文ID

文章目录


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:通过掩码来匹配特定的位域。这个也是比较常用的。

相关推荐
小智学长 | 嵌入式2 小时前
单片机-STM32部分:13-1、蜂鸣器
stm32·单片机·嵌入式硬件
#金毛2 小时前
六、STM32 HAL库回调机制详解:从设计原理到实战应用
stm32·单片机·嵌入式硬件
sword devil9005 小时前
将arduino开发的Marlin部署到stm32(3D打印机驱动)
stm32·单片机·嵌入式硬件
GodKK老神灭5 小时前
STM32 变量存储
stm32·单片机·嵌入式硬件
sword devil9007 小时前
Arduino快速入门
stm32·单片机·嵌入式硬件
GodKK老神灭8 小时前
STM32实现循环队列
stm32·单片机·嵌入式硬件
A-花开堪折11 小时前
OpenMCU(六):STM32F103开发板功能介绍
stm32·单片机·嵌入式硬件
二块烧肉17 小时前
STM32 ADC
stm32·单片机·嵌入式硬件
茯苓gao1 天前
stm32 WDG看门狗
stm32·单片机·嵌入式硬件