当前位置: 首页 > article >正文

【STM32项目实战系列】基于STM32G474的FDCAN驱动配置

前言:本周工作中用到了CANFD的驱动,由于以前都是用到的CAN2.0,所以过程并不是特别的顺利,所以中间遇到几个比较小的问题导致自己卡住了一段时间,特此记录一下并完全奉上自己的配置的源码。


1,CANFD配置与简介

先简单介绍一下CANFD:

FDCAN(Flexible Data-Rate CAN,灵活数据速率 CAN)是 CAN-FD(CAN with Flexible Data-Rate)协议的实现,支持更高的传输速率和更大的数据负载。FDCAN 通信主要由 仲裁域(Arbitration Phase)数据域(Data Phase) 组成,它们在波特率和位定时参数上有所不同。

这里配置的FDCAN外设的时钟为100MHZ

1,相较于传统的CAN,CANFD仲裁域与数据域的波特率可以不同也可以相同,

  • 仲裁阶段:与传统 CAN 相同(≤ 1 Mbps)
  • 数据阶段:可以使用更高的速率(典型值 2 Mbps、5 Mbps,甚至 8 Mbps

2,数据传输特点:

  • 传输 更长的数据(64 字节),减少协议开销,提高带宽利用率。
  • 数据阶段 速率更快,提升整车网络通信性能。

3,仲裁域特点:

  • 低 ID 优先级高(0 优先级高于 1)。
  • 发送过程中,如果节点检测到比自己更低的 ID(更高优先级),则自动停止发送。
  • 传统 CAN 与 CAN FD 可以共存,但 如果 CAN FD 设备检测到传统 CAN 帧,会降级为传统 CAN 模式

4,波特率的计算方式

Baud_rate = FDCAN_Clock / (Prescaler * (Seg_1 + Seg_2 + Sync_Jump_Width))

  • FDCAN_Clock(FDCAN 时钟)
  • Prescaler(分频系数)
  • Phase Segment 1(相位段 1)
  • Phase Segment 2(相位段 2,用于接收器同步和误差修正)
  • Sync_Jump_Width(同步跳宽)

5,采样率的计算方式

  • sampling_rate = (Seg_1 + 1) / (1 + Seg_1 + Seg_2)


2,FDCAN代码生成

这里先用的CUBEMX生成的源驱动代码,但是烧录进板子里面发现无法使用,后面就有改了一下,同样的把这个源码也搬过来

fdcan.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 */

/* USER CODE END 0 */

FDCAN_HandleTypeDef hfdcan1;

/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{

  /* USER CODE BEGIN FDCAN1_Init 0 */

  /* USER CODE END FDCAN1_Init 0 */

  /* USER CODE BEGIN FDCAN1_Init 1 */

  /* USER CODE END FDCAN1_Init 1 */
  hfdcan1.Instance = FDCAN1;
  hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
  hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS;
  hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
  hfdcan1.Init.AutoRetransmission = DISABLE;
  hfdcan1.Init.TransmitPause = DISABLE;
  hfdcan1.Init.ProtocolException = DISABLE;
  hfdcan1.Init.NominalPrescaler = 5;
  hfdcan1.Init.NominalSyncJumpWidth = 1;
  hfdcan1.Init.NominalTimeSeg1 = 15;
  hfdcan1.Init.NominalTimeSeg2 = 4;
  hfdcan1.Init.DataPrescaler = 5;
  hfdcan1.Init.DataSyncJumpWidth = 1;
  hfdcan1.Init.DataTimeSeg1 = 2;
  hfdcan1.Init.DataTimeSeg2 = 1;
  hfdcan1.Init.StdFiltersNbr = 28;
  hfdcan1.Init.ExtFiltersNbr = 8;
  hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
  if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN FDCAN1_Init 2 */

  /* USER CODE END FDCAN1_Init 2 */

}

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(fdcanHandle->Instance==FDCAN1)
  {
  /* USER CODE BEGIN FDCAN1_MspInit 0 */

  /* USER CODE END FDCAN1_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();
    }

    /* FDCAN1 clock enable */
    __HAL_RCC_FDCAN_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**FDCAN1 GPIO Configuration
    PA11     ------> FDCAN1_RX
    PA12     ------> FDCAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* FDCAN1 interrupt Init */
    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
    HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
  /* USER CODE BEGIN FDCAN1_MspInit 1 */

  /* USER CODE END FDCAN1_MspInit 1 */
  }
}

void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{

  if(fdcanHandle->Instance==FDCAN1)
  {
  /* USER CODE BEGIN FDCAN1_MspDeInit 0 */

  /* USER CODE END FDCAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_FDCAN_CLK_DISABLE();

    /**FDCAN1 GPIO Configuration
    PA11     ------> FDCAN1_RX
    PA12     ------> FDCAN1_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

    /* FDCAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
    HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn);
  /* USER CODE BEGIN FDCAN1_MspDeInit 1 */

  /* USER CODE END FDCAN1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

fdcan.h

/* 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 hfdcan1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_FDCAN1_Init(void);

/* USER CODE BEGIN Prototypes */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __FDCAN_H__ */

改进后的代码,增加一个发送与接收CAN报文的接口与一些驱动接口。尝试之后就可以发送与接收到报文了,亲测有效。另外,当数据域设置成最大的时候,使用CAN工具设置数据域的那个波特率都是可以接受到报文的。

 fdcan.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 */
RxDataLen_t RxData_len[16] = {
    {SEND_BYTES_0, 0}, {SEND_BYTES_1, 1}, {SEND_BYTES_2, 2}, {SEND_BYTES_3, 3},
    {SEND_BYTES_4, 4}, {SEND_BYTES_5, 5}, {SEND_BYTES_6, 6}, {SEND_BYTES_7, 7},
    {SEND_BYTES_8, 8}, {SEND_BYTES_12, 12}, {SEND_BYTES_16, 16}, {SEND_BYTES_20, 20},
    {SEND_BYTES_24, 24}, {SEND_BYTES_32, 32}, {SEND_BYTES_48, 48}, {SEND_BYTES_64, 64}
};
/* USER CODE END 0 */

FDCAN_HandleTypeDef hfdcan1;

/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{

    FDCAN_FilterTypeDef sFilterConfig = {0};
    /* USER CODE BEGIN FDCAN1_Init 0 */

    /* USER CODE END FDCAN1_Init 0 */

    /* USER CODE BEGIN FDCAN1_Init 1 */
    /* USER CODE END FDCAN1_Init 1 */
    
    // 仲裁域波特率为1Mbps 80%  数据域波特率为5Mbps 75%
    // 波特率 Baud rate = FDCAN Clock / (Prescaler * (Seg_1 + Seg_2 + Sync_Jump_Width))
    // 采样率 sampling rate = (Seg_1 + 1) / (1 + Seg_1 + Seg_2)
    hfdcan1.Instance = FDCAN1;
    hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;  // 外设时钟分频
    hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS; // 使用FD BRS格式
    hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;  			 // 正常模式
    hfdcan1.Init.AutoRetransmission = DISABLE;     // 禁止自动重发
    hfdcan1.Init.TransmitPause = DISABLE;          // 禁止暂停传输
    hfdcan1.Init.ProtocolException = DISABLE;      // 禁用协议异常
    hfdcan1.Init.NominalPrescaler = 5;             // 仲裁域分频系数(1Mbps)
    hfdcan1.Init.NominalSyncJumpWidth = 1;         // 同步跳跃宽度
    hfdcan1.Init.NominalTimeSeg1 = 15;             // 时间段1
    hfdcan1.Init.NominalTimeSeg2 = 4;              // 时间段2
    hfdcan1.Init.DataPrescaler = 5;                // 数据域分频系数
    hfdcan1.Init.DataSyncJumpWidth = 1;            // 数据同步跳跃宽度
    hfdcan1.Init.DataTimeSeg1 = 2;                 // 数据时间段1
    hfdcan1.Init.DataTimeSeg2 = 1;                 // 数据时间段2
    hfdcan1.Init.StdFiltersNbr = 28;               // 标准过滤器数量
    hfdcan1.Init.ExtFiltersNbr = 8;                // 扩展过滤器数量
    hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;  // 发送FIFO操作模式
    if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
    {
        printf("Error_Handler:HAL_FDCAN_Init\r\n");
        Error_Handler();
    }

    sFilterConfig.IdType = FDCAN_STANDARD_ID;
	sFilterConfig.FilterIndex = 0;
	sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
	sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
	sFilterConfig.FilterID1 = 0x00;
	sFilterConfig.FilterID2 = 0x7FF;
	if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
	{
		Error_Handler();
	}
	
	sFilterConfig.IdType = FDCAN_EXTENDED_ID;
	sFilterConfig.FilterIndex = 0;
	sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
	sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
	sFilterConfig.FilterID1 = 0x00;
	sFilterConfig.FilterID2 = 0x1FFFFFFF;
	if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
	{
		Error_Handler();
	}
	
	/* Configure global filter on both FDCAN instances:
	Filter all remote frames with STD and EXT ID
	Reject non matching frames with STD ID and EXT ID */
	if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
	{
		Error_Handler();
	}
	
	/* Activate Rx FIFO 0 new message notification on both FDCAN instances */
	if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
	{
		Error_Handler();
	}
	
	if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0) != HAL_OK)
	{
		Error_Handler();
	}
	
	/* Configure and enable Tx Delay Compensation, required for BRS mode.
        TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
        TdcFilter default recommended value: 0 */
	HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
	HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);
	
	HAL_FDCAN_Start(&hfdcan1);

  /* USER CODE END FDCAN1_Init 2 */
}

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    if(fdcanHandle->Instance==FDCAN1)
    {
    /* USER CODE BEGIN FDCAN1_MspInit 0 */

    /* USER CODE END FDCAN1_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();
    }

    /* FDCAN1 clock enable */
    __HAL_RCC_FDCAN_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**FDCAN1 GPIO Configuration
    PA11     ------> FDCAN1_RX
    PA12     ------> FDCAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* FDCAN1 interrupt Init */
    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
    HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
  /* USER CODE BEGIN FDCAN1_MspInit 1 */
 

  /* USER CODE END FDCAN1_MspInit 1 */
  }
}

void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{

  if(fdcanHandle->Instance==FDCAN1)
  {
  /* USER CODE BEGIN FDCAN1_MspDeInit 0 */

  /* USER CODE END FDCAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_FDCAN_CLK_DISABLE();

    /**FDCAN1 GPIO Configuration
    PA11     ------> FDCAN1_RX
    PA12     ------> FDCAN1_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

    /* FDCAN1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
    HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn);
  /* USER CODE BEGIN FDCAN1_MspDeInit 1 */

  /* USER CODE END FDCAN1_MspDeInit 1 */
  }
}

// /* USER CODE BEGIN 1 */

/* FDCAN发送报文函数 */
HAL_StatusTypeDef FDCAN_SendMessage(uint32_t id, uint8_t Txdata[], FDCAN_DLC_T dataLength)
{
    FDCAN_TxHeaderTypeDef TxHeader = {0};
    TxHeader.Identifier = id;  // 设置CAN报文的ID  

    // 检查发送帧ID的有效性
	if(id < 0x800) {
		TxHeader.IdType = FDCAN_STANDARD_ID;
	}
    else {
        TxHeader.IdType = FDCAN_EXTENDED_ID;
        if(id > 0x1FFFFFFF) {
            printf("Error_Handler:id > 0x1FFFFFFF\r\n");
            return HAL_ERROR;
        }
    }

    // CAN发送格式的识别
    if (dataLength > FDCAN_DLC_BYTES_8) {
        TxHeader.FDFormat = FDCAN_FD_CAN;
    }
    else {
        TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
    }

    TxHeader.TxFrameType = FDCAN_DATA_FRAME;  // 数据帧 FDCAN_REMOTE_FRAME//FDCAN_DATA_FRAME
    // 数据长度(0-8字节,还有12,16,20,24,32,48,64)
    TxHeader.DataLength = dataLength; 
    TxHeader.BitRateSwitch = FDCAN_BRS_OFF;  // 不使用数据速率切换

    
    // 发送报文
    if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, Txdata) != HAL_OK)
    {
        printf("FDCAN send msg fail\r\n");
        return HAL_ERROR;  // 发送失败
    }

    return HAL_OK;  // 发送成功
}


// FDCAN1 中断接收回调函数
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
    FDCAN_RxHeaderTypeDef RxHeader = {0};
    uint8_t RxData[64] = {0};  // 支持最大64字节数据
    uint8_t len = 0;           // 接收到的数据长度

    // 从FIFO0中读取接收到的消息
    if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
    {
        Error_Handler();
    }

    for(int i = 0; i < (sizeof(RxData_len)/sizeof(RxData_len[0])); i++) {
        if (RxData_len[i].dataLength == RxHeader.DataLength) {
            len = RxData_len[i].datalen_num;
        }
    }

#if 1
    printf("id: %d, DataLength: %d\r\n", RxHeader.Identifier, len);
    printf("Received Data: ");
    for (uint8_t i = 0; i < len; i++)
    {
        printf("0x%02X ", RxData[i]);
    }
    printf("\n");
#endif

    // 可以根据需要检查其他中断标志位进行不同的处理
    // 如果接收FIFO0已满
    if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_FULL) != RESET)
    {
        // 处理FIFO满的情况
        printf("FIFO 0 is full\n");
    }
    // 如果接收FIFO0消息丢失
    if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_MESSAGE_LOST) != RESET)
    {
        // 处理消息丢失的情况
        printf("Message lost in FIFO 0\n");
    }
}

/* USER CODE END 1 */

  fdcan.h

/* 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 hfdcan1;

/* USER CODE BEGIN Private defines */
typedef enum {
  SEND_BYTES_0 = FDCAN_DLC_BYTES_0,
  SEND_BYTES_1 = FDCAN_DLC_BYTES_1,
  SEND_BYTES_2 = FDCAN_DLC_BYTES_2,
  SEND_BYTES_3 = FDCAN_DLC_BYTES_3,
  SEND_BYTES_4 = FDCAN_DLC_BYTES_4,
  SEND_BYTES_5 = FDCAN_DLC_BYTES_5,
  SEND_BYTES_6 = FDCAN_DLC_BYTES_6,
  SEND_BYTES_7 = FDCAN_DLC_BYTES_7,
  SEND_BYTES_8 = FDCAN_DLC_BYTES_8,
  SEND_BYTES_12 = FDCAN_DLC_BYTES_12,
  SEND_BYTES_16 = FDCAN_DLC_BYTES_16,
  SEND_BYTES_20 = FDCAN_DLC_BYTES_20,
  SEND_BYTES_24 = FDCAN_DLC_BYTES_24,
  SEND_BYTES_32 = FDCAN_DLC_BYTES_32,
  SEND_BYTES_48 = FDCAN_DLC_BYTES_48,
  SEND_BYTES_64 = FDCAN_DLC_BYTES_64
} FDCAN_DLC_T;

typedef struct {
  FDCAN_DLC_T dataLength;
  uint8_t datalen_num;
} RxDataLen_t;
/* USER CODE END Private defines */

/* USER CODE BEGIN Prototypes */

void MX_FDCAN1_Init(void);
HAL_StatusTypeDef FDCAN_SendMessage(uint32_t id, uint8_t Txdata[], FDCAN_DLC_T dataLength);

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __FDCAN_H__ */

参考文章:

CAN总线采样点原理与测试方法详解-CSDN博客

嵌入式Linux中的CAN(FD)总线——驱动配置 - 知乎 (zhihu.com)


http://www.kler.cn/a/572283.html

相关文章:

  • 江西省地标-DB36/T 1275-2020 绿色矿山建设标准
  • FastGPT 引申:信息抽取到知识图谱的衔接流程
  • 学到什么记什么(25.3.3)
  • 30秒从零搭建机器人管理系统(Trae)
  • python爬虫:pyspider的详细使用
  • 关于高精度力扣66
  • windows下使用Hyper+wsl实现ubuntu下git的平替
  • TCP协议(20250304)
  • VSCode详细安装步骤,适用于 Windows/macOS/Linux 系统
  • 点云配准技术的演进与前沿探索:从传统算法到深度学习融合(4)
  • 【2025小白版】计算复试/保研机试模板(个人总结非GPT生成)附代码
  • centos和ubuntu下安装redis
  • Linux笔记---缓冲区
  • 医疗行业网络安全:目前面临哪些挑战?
  • 基于Spring Boot的企业车辆管理系统设计与实现(LW+源码+讲解)
  • Stable Diffusion 反向提示词(Negative Prompt)深度解析
  • 小迪安全25天-php-文件管理包含,写入,删除,下载,上传,遍历,安全。
  • 宝塔找不到php扩展swoole,服务器编译安装
  • Android中的Content Provider是什么以及它有哪些用途
  • 软件工程中的各种图