首先,让我们来了解一下CAN总线通信的基本原理。CAN(Controller Area Network)总线是一种常用于在电子设备之间进行通信的串行总线。它具有高速传输、抗干扰、可靠性强等特点,因此被广泛应用于汽车电子、工业控制、航空航天等领域。

在本文中,我们将使用STM32系列微控制器来实现两个设备之间的CAN总线通信。我们将使用两个STM32开发板作为示例设备,一个设备将充当CAN发送器,另一个设备将充当CAN接收器。

准备工作 在开始编写代码之前,我们需要确保我们已经安装了相应的开发工具和库,包括:

  1. STM32CubeMX,用于生成初始化代码。
  2. STM32Cube HAL库,用于提供驱动和函数库。
  3. Keil MDK-ARM或其他适用的IDE,用于编写和调试代码。
  4. 两个STM32开发板,其中一个充当发送器,另一个充当接收器。

步骤1:配置CAN硬件 首先,我们需要使用STM32CubeMX来配置CAN硬件。启动STM32CubeMX,选择适用于你的开发板的型号。然后,按照以下步骤进行配置:

  1. 打开"Configuration"窗口,在左侧的"Peripherals"选项卡中选择"CAN1"。
  2. 在右侧的"Parameter Settings"中,配置CAN通信的波特率、模式等。你可以根据自己的需求进行调整。在本示例中,我们将使用默认的波特率500Kbps和模式为Normal。
  3. 配置CAN的引脚。点击"Pinout & Configuration"选项卡,然后将CAN的引脚分配给你的开发板上的正确引脚。确保发送器和接收器的引脚分配正确。

完成配置后,点击"Project"菜单,选择"Generate Code"来生成初始化代码。

步骤2:发送器代码 在生成代码后,打开生成的工程,找到"main.c"文件并打开它。我们将在该文件中编写发送器代码。

首先,我们需要包含所需的头文件和定义一些变量。代码如下所示:

#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_can.h"

CAN_HandleTypeDef hcan1;

uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint32_t TxMailbox;

int main(void)
{
  HAL_Init();

  __HAL_RCC_CAN1_CLK_ENABLE();

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 2;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SJW = CAN_SJW_1TQ;
  hcan1.Init.BS1 = CAN_BS1_11TQ;
  hcan1.Init.BS2 = CAN_BS2_7TQ;
  hcan1.Init.TTCM = DISABLE;
  hcan1.Init.ABOM = DISABLE;
  hcan1.Init.AWUM = DISABLE;
  hcan1.Init.NART = DISABLE;
  hcan1.Init.RFLM = DISABLE;
  hcan1.Init.TXFP = DISABLE;

  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

  CAN_FilterTypeDef sFilterConfig;

  sFilterConfig.FilterIdHigh = 0x0000;
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;
  sFilterConfig.FilterMaskIdLow = 0x0000;
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
  sFilterConfig.FilterBank = 0;
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.SlaveStartFilterBank = 14;

  if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  CAN_TxHeaderTypeDef TxHeader;
  
  TxHeader.StdId = 0x123;
  TxHeader.ExtId = 0x01;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.DLC = 8;
  TxHeader.TransmitGlobalTime = DISABLE;

  while (1)
  {
    if (HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox) != HAL_OK)
    {
      Error_Handler();
    }
    
    HAL_Delay(1000);
  }
}

以上代码中,我们进行了一些初始化配置,包括时钟使能、CAN属性设置、过滤器配置等。然后,我们定义了一个CAN_TxHeaderTypeDef结构体来设置传输帧的参数。

在主循环中,我们通过调用HAL_CAN_AddTxMessage()函数将数据TxData发送到CAN总线上。在这个例子中,我们将数据发送到标准ID为0x123的帧中。发送完成后,等待1秒钟,然后进行下一个循环发送。

步骤3:接收器代码 接下来,我们将编写接收器代码。打开生成的工程,找到"main.c"文件并打开它。我们将在该文件中编写接收器代码。

首先,我们需要包含所需的头文件和定义一些变量。代码如下所示:

#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_can.h"

CAN_HandleTypeDef hcan1;
CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
  {
    Error_Handler();
  }
  
  // 在此处操作接收到的数据
}

int main(void)
{
  HAL_Init();

  __HAL_RCC_CAN1_CLK_ENABLE();

  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 2;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SJW = CAN_SJW_1TQ;
  hcan1.Init.BS1 = CAN_BS1_11TQ;
  hcan1.Init.BS2 = CAN_BS2_7TQ;
  hcan1.Init.TTCM = DISABLE;
  hcan1.Init.ABOM = DISABLE;
  hcan1.Init.AWUM = DISABLE;
  hcan1.Init.NART = DISABLE;
  hcan1.Init.RFLM = DISABLE;
  hcan1.Init.TXFP = DISABLE;

  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

  CAN_FilterTypeDef sFilterConfig;

  sFilterConfig.FilterIdHigh = 0x0000;
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;
  sFilterConfig.FilterMaskIdLow = 0x0000;
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
  sFilterConfig.FilterBank = 0;
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.SlaveStartFilterBank = 14;

  if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_CAN_Start(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
  {
    Error_Handler();
  }

  while (1)
  {
    // 主循环空闲
  }
}

以上代码中,我们也进行了一些初始化配置,与发送器代码类似。然后,我们定义了一个`

作者:MyM满满

物联沃分享整理
物联沃-IOTWORD物联网 » STM32 CAN总线通信详解

发表回复