10.5 CAN通信项目:双机通信
# 10.5 CAN通信项目:双机通信
本实验通过STM32的CAN总线协议实现双机通信,MCU1(主节点)检测按键动作并发送计数值,MCU2(从节点)接收数据并在OLED实时显示。
核心功能:
- 主节点:按键触发CAN数据帧发送,OLED显示发送次数。
- 从节点:中断接收数据,OLED实时更新接收值。
# 10.5.1 CAN项目电路设计
# 硬件架构
- 主节点(MCU1):
- 按键接口:PC13
- CAN接口:PA12(TX)/PA11(RX) → TJA1040收发器
- 从节点(MCU2):
- OLED接口:PB8(SCL)/PB9(SDA)
- CAN接口:PA12(TX)/PA11(RX) → TJA1040收发器
- CAN总线:120Ω终端电阻,屏蔽双绞线连接。

# 10.5.2 STM32CubeMX配置
# 1. 基础配置(主/从节点相同)
- 工程设置:
- 芯片型号:STM32F103C8T6
- 主频:72MHz
- 调试接口:SWD
- GPIO配置:
- 按键引脚(PC13):
GPIO_Input
(无上下拉) - CAN引脚(PA11/PA12):
CAN_RX
/CAN_TX
- 按键引脚(PC13):
# 2. CAN参数配置
- 模式:Normal
- 波特率预分频:45
- 位时序:
- TimeSeg1 = 13TQ
- TimeSeg2 = 2TQ
- SyncJumpWidth = 1TQ
- 中断配置:启用CAN接收中断(FIFO0)

# 10.5.3 CAN项目软件设计
# 主节点代码(MCU1)
# 1. 初始化配置
// CAN过滤器配置(标准帧,ID=0x123)
CAN_FilterTypeDef filter;
filter.FilterIdHigh = 0x123 << 5; // 标准帧ID左移5位
filter.FilterMaskIdHigh = 0x7FF << 5; // 全匹配模式
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_32BIT;
filter.FilterFIFOAssignment = CAN_RX_FIFO0;
HAL_CAN_ConfigFilter(&hcan, &filter);
HAL_CAN_Start(&hcan); // 启动CAN
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2. 数据发送逻辑
// 定义发送帧头
CAN_TxHeaderTypeDef TxHeader;
TxHeader.StdId = 0x123; // 标准帧ID
TxHeader.IDE = CAN_ID_STD; // 标准帧
TxHeader.DLC = 4; // 数据长度4字节
// 主循环:检测按键并发送数据
while (1) {
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
HAL_Delay(50); // 消抖
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
keyPressCount++;
memcpy(txData, &keyPressCount, 4); // 数据拷贝
HAL_CAN_AddTxMessage(&hcan, &TxHeader, txData, &TxMailbox); // 发送
}
}
// OLED显示发送次数
sprintf(message, "TransmitData: %d", keyPressCount);
OLED_PrintString(0, 20, message, &font16x16, OLED_COLOR_NORMAL);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 从节点代码(MCU2)
# 1. 中断接收配置
// 启用接收中断
HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
// 中断回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, rxData) == HAL_OK) {
if (RxHeader.StdId == 0x123) {
memcpy(&receivedCount, rxData, 4); // 解析数据
}
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2. 数据显示逻辑
// 主循环:更新OLED显示
while (1) {
sprintf(message, "ReceiveData: %d", receivedCount);
OLED_PrintString(0, 20, message, &font16x16, OLED_COLOR_NORMAL);
HAL_Delay(100);
}
1
2
3
4
5
6
2
3
4
5
6
# 10.5.4 CAN项目下载验证
# 步骤与现象
- 硬件连接:
- CAN_H/CAN_L使用屏蔽双绞线连接主从节点,接入120Ω终端电阻。
- 烧录程序:
- 主节点烧录发送程序,从节点烧录接收程序。
- 功能验证:
- 按下主节点按键,OLED显示发送次数递增。
- 从节点OLED实时同步显示接收值。

关键说明:
- CAN总线需严格匹配终端电阻,避免信号反射。
- 帧标识符(0x123)需在主从节点中一致。
- 中断接收模式确保数据实时性,消抖逻辑防止误触发。