在嵌入式开发中,CAN(Controller Area Network)是一种高效、可靠的通信协议,广泛应用于汽车电子、工业自动化等领域。本文将以STM32G431为例,详细讲解如何配置和使用CAN接口实现主从通信。STM32G431是一款基于Cortex-M4内核的高性能单片机,支持多种通信接口,是开发者的理想选择。
项目概述我们将实现以下功能:
- STM32G431作为主控,通过CAN总线发送命令至从设备。
- 从设备接收到命令后进行反馈。
- 数据格式包括命令ID和数据载荷。
硬件连接- STM32G431开发板
- MCP2551 CAN收发器
- 终端电阻(120Ω)
- 电源与接地
硬件连接如下:
- STM32G431 的 CAN_TX 连接至 MCP2551 的 TXD。
- STM32G431 的 CAN_RX 连接至 MCP2551 的 RXD。
- MCP2551 的 CANH 和 CANL 接至总线。
- 总线两端分别连接120Ω终端电阻。
软件配置与代码实现软件采用STM32CubeMX生成初始化代码,使用HAL库实现CAN通信。
配置步骤- 在STM32CubeMX中启用FDCAN外设。
- 设置波特率为500kbps(可根据需求调整)。
- 生成初始化代码并导入至Keil或CubeIDE中。
示例代码以下为实现主机发送和从机接收的完整代码:
#include "main.h"
// 定义CAN句柄
FDCAN_HandleTypeDef hfdcan1;
// 初始化FDCAN
void MX_FDCAN1_Init(void) {
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = ENABLE;
hfdcan1.Init.TransmitPause = DISABLE;
hfdcan1.Init.ProtocolException = DISABLE;
hfdcan1.Init.NominalPrescaler = 1;
hfdcan1.Init.NominalSyncJumpWidth = 1;
hfdcan1.Init.NominalTimeSeg1 = 13;
hfdcan1.Init.NominalTimeSeg2 = 2;
if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) {
Error_Handler();
}
// 配置过滤器
FDCAN_FilterTypeDef filterConfig;
filterConfig.IdType = FDCAN_STANDARD_ID;
filterConfig.FilterIndex = 0;
filterConfig.FilterType = FDCAN_FILTER_MASK;
filterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
filterConfig.FilterID1 = 0x100;
filterConfig.FilterID2 = 0x7FF;
HAL_FDCAN_ConfigFilter(&hfdcan1, &filterConfig);
// 启动FDCAN
HAL_FDCAN_Start(&hfdcan1);
HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
}
// CAN发送数据
void CAN_SendData(uint32_t id, uint8_t* data, uint8_t length) {
FDCAN_TxHeaderTypeDef txHeader;
txHeader.Identifier = id;
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;
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, data) != HAL_OK) {
Error_Handler();
}
}
// CAN接收回调
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) {
if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {
FDCAN_RxHeaderTypeDef rxHeader;
uint8_t rxData[8];
HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rxHeader, rxData);
// 处理接收到的数据
if (rxHeader.Identifier == 0x200) {
// 具体逻辑处理
}
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_FDCAN1_Init();
uint8_t txData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
while (1) {
CAN_SendData(0x100, txData, 8);
HAL_Delay(1000);
}
}
注意事项- 波特率匹配:主机与从机的波特率必须一致。
- 总线终端电阻:无论调试还是应用环境中,总线两端必须有终端电阻。
- 数据接收处理:要确保接收逻辑与实际需求匹配,避免因数据丢失或格式不符导致的异常。
总结本文详细介绍了如何使用STM32G431的CAN接口实现主从通信,并通过实际代码演示了发送和接收的完整流程。在实际开发中,可以根据项目需求对数据格式和逻辑处理进行扩展。
|