STM32配置FDCAN通讯

STM32配置FDCAN通讯

由于总线上有设备不支持FDCAN,为了保持兼容性,将本机FDCAN配置为传统CAN运行。

CubeMX配置

开启SW调试接口
开启FDCAN2
开启外部时钟
STM32配置FDCAN通讯_第1张图片
外部晶振为12M,主频480M,FDCAN时钟来自PLL1Q
STM32配置FDCAN通讯_第2张图片
STM32配置FDCAN通讯_第3张图片
FDCAN2参数设置,参数设置的说明,在代码中有注释,
在此强调2点:
1 配置为传统CAN模式时要关闭自动重传,原子哥建议,不知为何,有待测试,CAN标准是支持自动重传的。
2 FDCAN支持仲裁段与数据段波特率不同,而传统模式二者相同,所以若配置为传统CAN时(如本例),数据段可以不配,即Data开始的4个参数可以采用默认值
波特率说明: 前面配置的FDCAN时钟频率为20MHz,Seg1+Seg2+1=40,20MHz/40=500KHz,为保持一致性,Data段配置也和仲裁段(Nominal)配成一样了。
STM32配置FDCAN通讯_第4张图片
开启中断
在这里插入图片描述

最后点Generate,生成工程

Keil代码

首先是定义变量

FDCAN_RxHeaderTypeDef RxHeader;
FDCAN_TxHeaderTypeDef TxHeader;
u8 RxData[8];
u8 TxData[8] = {'L', 'a', 'o', 'L', 'i', '1', '2', '3'};

下面这一段是CubeMX生成的CAN配置参数,我做了备注

void MX_FDCAN2_Init(void)
{
  /* USER CODE BEGIN FDCAN2_Init 0 */
  /* USER CODE END FDCAN2_Init 0 */

  /* USER CODE BEGIN FDCAN2_Init 1 */
  hfdcan2.Instance = FDCAN2;                      //用FDCAN2
  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 = 1;              //仲裁段时钟分频  FDCAN时钟基准为20MHz  传统CAN模式时只设置这一段即可
  hfdcan2.Init.NominalSyncJumpWidth = 8;          //同步跳转段的宽度 8
                                                  //时钟频率20M / (1 + TSG1 + TSG2) = CAN波特率
  hfdcan2.Init.NominalTimeSeg1 = 31;              //时间段1    31
  hfdcan2.Init.NominalTimeSeg2 = 8;               //时间段2    8
  
  hfdcan2.Init.DataPrescaler = 1;                 //数据段时钟分频,若工作于传统模式,不需要设置数据段参数
                                                  //                若工作于FDCAN模式,允许数据段与仲裁段波特率不同
  hfdcan2.Init.DataSyncJumpWidth = 8;             //8
  hfdcan2.Init.DataTimeSeg1 = 31;                 //31
  hfdcan2.Init.DataTimeSeg2 = 8;                  //8

  hfdcan2.Init.MessageRAMOffset = 0;              //消息偏移
  hfdcan2.Init.StdFiltersNbr = 1;                 //标准帧使用滤波器1
  hfdcan2.Init.ExtFiltersNbr = 1;                 //扩展帧使用滤波器1
  hfdcan2.Init.RxFifo0ElmtsNbr = 1;                   //接收FIFO0的元素编号1
  hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;  //接收FIFO0的元素长度8
  hfdcan2.Init.RxFifo1ElmtsNbr = 1;                   //接收FIFO1的元素编号1
  hfdcan2.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;  //接收FIFO1的元素长度8
  hfdcan2.Init.RxBuffersNbr = 1;                      //接收缓冲区编号1
  hfdcan2.Init.RxBufferSize = FDCAN_DATA_BYTES_8;     //接收缓冲区长度
  hfdcan2.Init.TxEventsNbr = 2;                       //发送事件编号
  hfdcan2.Init.TxBuffersNbr = 1;                      //发送缓冲区编号
  hfdcan2.Init.TxFifoQueueElmtsNbr = 2;               //发送FIFO队列元素编号
  hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; //发送模式 先入先出
  hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;       //发送元素长度8
  if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN FDCAN2_Init 2 */
  /* USER CODE END FDCAN2_Init 2 */

CAN滤波器的设置,本函数要自己写,然后放到自己的初始化代码中,在CubeMX生成的初始化代码的后面。

void FDCAN2_Config(void)
{
  FDCAN_FilterTypeDef sFilterConfig;
  
  HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
  
  sFilterConfig.IdType = FDCAN_STANDARD_ID;   //  配置为过滤标准帧
  sFilterConfig.FilterIndex = 0;              //  过滤器的索引号
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;  //  过滤方式为范围,即从FilterID1~FilterID2之间的值
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x0000;
  sFilterConfig.FilterID2 = 0x07ff;           //  标准帧为11位ID,即0x7ff,本例配置为接收所有帧
  if(HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig) != HAL_OK)
    Error_Handler();
  
  sFilterConfig.IdType = FDCAN_EXTENDED_ID;   //  配置为过滤扩展帧
  sFilterConfig.FilterIndex = 0;              //  过滤器的索引号
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM;  //  过滤方式为范围,即从FilterID1~FilterID2之间的值
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;
  sFilterConfig.FilterID1 = 0x00000000;
  sFilterConfig.FilterID2 = 0x01ffffff;       //  扩展帧为29位ID,即0x1fffffff,本例配置为接收所有帧
  HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig);
  
  TxHeader.Identifier = 0x123;
  TxHeader.IdType = FDCAN_STANDARD_ID;
  TxHeader.TxFrameType = FDCAN_DATA_FRAME;
  TxHeader.DataLength = FDCAN_DLC_BYTES_8;
  TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
  TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
  TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
  TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
  TxHeader.MessageMarker = 0x52;

  HAL_FDCAN_Start(&hfdcan2);
}

然后是发送代码,这个简单,即每延时200ms,发送一次数据

  while (1)
  {
    HAL_Delay(200);
    HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader, TxData);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

接收采用中断的方式,在FDCAN2_IT0中断内写入一句

void FDCAN2_IT0_IRQHandler(void)
{
  /* USER CODE BEGIN FDCAN2_IT0_IRQn 0 */

  /* USER CODE END FDCAN2_IT0_IRQn 0 */
  HAL_FDCAN_IRQHandler(&hfdcan2);
  /* USER CODE BEGIN FDCAN2_IT0_IRQn 1 */
  HAL_FDCAN_GetRxMessage(&hfdcan2, FDCAN_RX_FIFO0, &RxHeader, RxData);

  /* USER CODE END FDCAN2_IT0_IRQn 1 */
}

代码验证

打开CAN分析仪的界面,可以看到接收到的数据帧
STM32配置FDCAN通讯_第5张图片
在CAN分析仪发送数据后,可以在中断内接收到发来的数据
STM32配置FDCAN通讯_第6张图片
STM32配置FDCAN通讯_第7张图片

完整代码下载

https://download.csdn.net/download/13011803189/85054662

你可能感兴趣的:(嵌入式开发,stm32,can,fdcan,单片机,嵌入式)