STM32 CAN总线通信详解
首先,让我们来了解一下CAN总线通信的基本原理。CAN(Controller Area Network)总线是一种常用于在电子设备之间进行通信的串行总线。它具有高速传输、抗干扰、可靠性强等特点,因此被广泛应用于汽车电子、工业控制、航空航天等领域。
在本文中,我们将使用STM32系列微控制器来实现两个设备之间的CAN总线通信。我们将使用两个STM32开发板作为示例设备,一个设备将充当CAN发送器,另一个设备将充当CAN接收器。
准备工作 在开始编写代码之前,我们需要确保我们已经安装了相应的开发工具和库,包括:
- STM32CubeMX,用于生成初始化代码。
- STM32Cube HAL库,用于提供驱动和函数库。
- Keil MDK-ARM或其他适用的IDE,用于编写和调试代码。
- 两个STM32开发板,其中一个充当发送器,另一个充当接收器。
步骤1:配置CAN硬件 首先,我们需要使用STM32CubeMX来配置CAN硬件。启动STM32CubeMX,选择适用于你的开发板的型号。然后,按照以下步骤进行配置:
- 打开"Configuration"窗口,在左侧的"Peripherals"选项卡中选择"CAN1"。
- 在右侧的"Parameter Settings"中,配置CAN通信的波特率、模式等。你可以根据自己的需求进行调整。在本示例中,我们将使用默认的波特率500Kbps和模式为Normal。
- 配置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满满