嵌入式硬件篇---CAN

发布于:2025-05-12 ⋅ 阅读:(16) ⋅ 点赞:(0)


前言

CAN(Controller Area Network)是一种高可靠性、多主机的串行通信协议,广泛应用于汽车电子、工业控制等领域。STM32F103RCT6内置了bxCAN控制器(Basic Extended CAN),支持CAN 2.0A/B标准。以下是详细协议解析及代码实现


1. CAN协议基础

1.1 物理层特性

差分信号线

CAN_H(高电平线)
CAN_L(低电平线)

终端电阻

终端电阻:120Ω(两端各一个,抑制反射)。

通信速率

通信速率:最高1 Mbps(常见波特率:125kbps、250kbps、500kbps)。

总线拓扑

总线拓扑:线性总线结构,支持多节点(最多110个节点)。

1.2 帧类型

帧类型 用途
数据帧 传输实际数据(核心帧类型)
远程帧 请求其他节点发送数据
错误帧 报告通信错误
过载帧 通知节点延迟响应

1.3 数据帧格式

[帧起始] [仲裁段] [控制段] [数据段] [CRC段] [ACK段] [帧结束]
仲裁段:
标准帧(11位ID):CAN 2.0A。
扩展帧(29位ID):CAN 2.0B。
数据段:0~8字节有效载荷。

2. STM32F103RCT6的CAN硬件配置

2.1 硬件连接

CAN信号 STM32引脚 说明
CAN_RX PA11 接收引脚
CAN_TX PA12 发送引脚
CAN_H 连接总线 高电平线
CAN_L 连接总线 低电平线
终端电阻 120Ω 接在总线两端

2.2 CubeMX配置

启用CAN1

模式

模式:Normal(正常模式)。

波特率

波特率:500kbps(时钟分频需匹配APB1时钟,默认36MHz)。

引脚分配

引脚分配:

CAN_RX → PA11
CAN_TX → PA12

过滤器配置(可选)

设置接收过滤器(如仅接收特定ID的帧)。

3. HAL库代码实现

3.1 CAN初始化

#include "stm32f1xx_hal.h"

CAN_HandleTypeDef hcan;

void MX_CAN_Init(void) {
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 9;          // 波特率 = 36MHz / (Prescaler * (1 + BS1 + BS2)) = 500kbps
  hcan.Init.Mode = CAN_MODE_NORMAL;  // 正常模式(非环回)
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_4TQ;  // BS1 = 4时间单位
  hcan.Init.TimeSeg2 = CAN_BS2_3TQ;  // BS2 = 3时间单位
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = ENABLE; // 自动重传
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;

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

3.2 发送CAN数据帧

void CAN_Send(uint32_t id, uint8_t *data, uint8_t len) {
  CAN_TxHeaderTypeDef tx_header;
  uint32_t tx_mailbox;

  tx_header.StdId = id;           // 标准ID(11位)
  tx_header.ExtId = 0;            // 扩展ID(未使用)
  tx_header.IDE = CAN_ID_STD;     // 标准帧
  tx_header.RTR = CAN_RTR_DATA;   // 数据帧
  tx_header.DLC = len;            // 数据长度(0~8)
  tx_header.TransmitGlobalTime = DISABLE;

  if (HAL_CAN_AddTxMessage(&hcan, &tx_header, data, &tx_mailbox) != HAL_OK) {
    Error_Handler();
  }
}

// 示例:发送8字节数据(ID=0x123)
uint8_t msg[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
CAN_Send(0x123, msg, 8);

3.3 接收CAN数据帧(中断模式)

CAN_RxHeaderTypeDef rx_header;
uint8_t rx_data[8];

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
  if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) {
    printf("Received ID: 0x%03X, Data: ", rx_header.StdId);
    for (uint8_t i = 0; i < rx_header.DLC; i++) {
      printf("%02X ", rx_data[i]);
    }
    printf("\n");
  }
}

// 主函数中启用接收中断
int main(void) {
  HAL_Init();
  MX_CAN_Init();
  HAL_CAN_Start(&hcan);
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
  while (1) { /* 其他任务 */ }
}

4. 过滤器配置(接收特定ID)

CAN控制器通过过滤器筛选接收的帧。以下配置仅接收ID=0x123的帧:

CAN_FilterTypeDef filter;

filter.FilterBank = 0;                      // 过滤器组0
filter.FilterMode = CAN_FILTERMODE_IDMASK;  // 掩码模式
filter.FilterScale = CAN_FILTERSCALE_32BIT; // 32位过滤
filter.FilterIdHigh = 0x123 << 5;           // ID高16位(左移5位对齐)
filter.FilterIdLow = 0x0000;                // ID低16位
filter.FilterMaskIdHigh = 0xFFFF;           // 掩码高16位(全匹配)
filter.FilterMaskIdLow = 0x0000;            // 掩码低16位
filter.FilterFIFOAssignment = CAN_RX_FIFO0; // 存入FIFO0
filter.FilterActivation = ENABLE;           // 启用过滤器

HAL_CAN_ConfigFilter(&hcan, &filter);

5. 波特率计算

CAN波特率由以下公式决定
波特率= Prescaler×(BS1+BS2+1)
APB1时钟:STM32F103默认36MHz。
BS1:TimeSeg1(例中为4)。
BS2:TimeSeg2(例中为3)。
Prescaler:分频系数(例中为9)。

6. 常见问题与调试

6.1 通信失败原因

波特率不匹配

波特率不匹配:确保所有节点波特率一致。

终端电阻缺失

终端电阻缺失:总线两端需接120Ω电阻。

ID冲突

ID冲突:避免多个节点使用相同ID发送

硬件连接错误

硬件连接错误:检查CAN_H/CAN_L是否接反。

6.2 逻辑分析仪抓包

使用CAN分析仪(如PCAN-USB)或示波器观察
差分信号电平(CAN_H - CAN_L应为2V(显性)或0V(隐性))。
帧结构:起始位、ID、数据等是否正常。

7. 完整示例:双机通信

节点A(发送数据)

uint8_t data[8] = {0xAA, 0xBB, 0xCC, 0xDD};
CAN_Send(0x123, data, 4); // 发送ID=0x123的4字节数据

节点B(接收数据)

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
  CAN_RxHeaderTypeDef rx_header;
  uint8_t rx_data[8];
  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);
  if (rx_header.StdId == 0x123) {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 收到数据后翻转LED
  }
}

总结

硬件配置

硬件配置:正确设置波特率、过滤器

数据收发

数据收发:使用HAL_CAN_AddTxMessage中断回调

调试工具

调试工具:逻辑分析仪、CAN分析仪是关键。

应用场景

应用场景:汽车ECU通信、工业传感器网络等。
通过上述代码,STM32F103RCT6可稳定实现CAN通信,适用于高可靠性要求的嵌入式系统。



网站公告

今日签到

点亮在社区的每一天
去签到