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

相关推荐
qq_4017004116 小时前
STM32的HardFault错误处理技巧
stm32
WD1372980155717 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔17 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头17 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子19 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
XiangrongZ20 小时前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
xyx-3v21 小时前
SPI四种工作模式
stm32·单片机·嵌入式硬件·学习
BreezeJuvenile1 天前
实验二 呼吸灯功能实验
stm32·单片机·嵌入式系统·流水灯·实验
Truffle7电子1 天前
STM32【H7】理论——通信
stm32·单片机·嵌入式硬件
MAR-Sky1 天前
keil5使用STlink下载程序到stm32后不自动运行的解决办法
stm32·单片机·嵌入式硬件