[STM32F1] 在 STM32F103C8T6 上通过 CAN 接口与 PEAK 设备的 BusMaster 通信

[复制链接]
112|10
cr315 发表于 2026-2-19 15:34 | 显示全部楼层 |阅读模式
1. 硬件连接
确保 STM32F103C8T6 的 CAN 接口与 PEAK 设备(如 PCAN-USB)正确连接:

CAN_TX (PA12) → 连接到 PEAK 设备的 CAN_H
CAN_RX (PA11) → 连接到 PEAK 设备的 CAN_L
共地:STM32 和 PEAK 设备必须共地(GND 连接)。
终端电阻:CAN 总线两端需接 120Ω 终端电阻(如果 PEAK 设备已提供,则无需额外添加)。
2. STM32CubeMX 配置
使用 STM32CubeMX 初始化 CAN 接口:

CAN 配置:
Mode: Normal(标准模式)
Prescaler: 6(APB1 = 36MHz → CAN 时钟 = 36MHz / 6 = 6Mbps,但实际建议 500kbps 或 1Mbps)
Time Quanta (BS1 + BS2):
BS1: 8TQ
BS2: 7TQ
Sync Jump Width: 1TQ
Bit Rate: 500kbps(或 1Mbps,需与 BusMaster 配置一致)
Filters:
Bank 0: Mask Mode(接收所有 ID 或过滤特定 ID)
Filter ID: 0x000(默认接收所有)
Mask ID: 0x000(允许所有 ID 通过)
NVIC 配置:
启用 CAN RX0 中断(USBD_CAN_RX0_IRQn)。
生成代码:
使用 STM32CubeIDE 生成项目。
3. 示例代码
(1) 初始化 CAN
在 main.c 中初始化 CAN:

c
#include "stm32f1xx_hal.h"

CAN_HandleTypeDef hcan;

void CAN_Init(void) {
    CAN_FilterTypeDef filter;

    hcan.Instance = CAN1;
    hcan.Init.Prescaler = 6;  // 36MHz / 6 = 6Mbps (调整至 500kbps 或 1Mbps)
    hcan.Init.Mode = CAN_MODE_NORMAL;
    hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan.Init.TimeSeg1 = CAN_BS1_8TQ;
    hcan.Init.TimeSeg2 = CAN_BS2_7TQ;
    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();
    }

    // 配置 CAN 过滤器(接收所有 ID)
    filter.FilterBank = 0;
    filter.FilterMode = CAN_FILTERMODE_IDMASK;
    filter.FilterScale = CAN_FILTERSCALE_32BIT;
    filter.FilterIdHigh = 0x0000;
    filter.FilterIdLow = 0x0000;
    filter.FilterMaskIdHigh = 0x0000;
    filter.FilterMaskIdLow = 0x0000;
    filter.FilterFIFOAssignment = CAN_RX_FIFO0;
    filter.FilterActivation = ENABLE;

    if (HAL_CAN_ConfigFilter(&hcan, &filter) != HAL_OK) {
        Error_Handler();
    }

    // 启动 CAN
    if (HAL_CAN_Start(&hcan) != HAL_OK) {
        Error_Handler();
    }

    // 启用 CAN RX 中断
    if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
        Error_Handler();
    }
}
(2) 发送 CAN 数据
c
void CAN_SendMessage(uint32_t id, uint8_t* data, uint8_t len) {
    CAN_TxHeaderTypeDef txHeader;
    uint32_t mailbox;

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

    if (HAL_CAN_AddTxMessage(&hcan, &txHeader, data, &mailbox) != HAL_OK) {
        Error_Handler();
    }
}
(3) 接收 CAN 数据(中断回调)
在 stm32f1xx_it.c 中实现中断回调:

c
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
    CAN_RxHeaderTypeDef rxHeader;
    uint8_t rxData[8];

    if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxData) == HAL_OK) {
        // 处理接收到的数据
        // rxHeader.StdId: 接收到的 CAN ID
        // rxData: 接收到的数据 (0-8 字节)
        // rxHeader.DLC: 数据长度
    }
}
(4) 主函数调用
c
int main(void) {
    HAL_Init();
    SystemClock_Config();
    CAN_Init();

    uint8_t testData[] = {0x11, 0x22, 0x33, 0x44};

    while (1) {
        CAN_SendMessage(0x123, testData, 4);  // 发送 CAN 帧 (ID=0x123)
        HAL_Delay(1000);
    }
}
4. BusMaster 配置
打开 BusMaster,选择 CAN → Database → Channel Configuration。
设置 CAN 通道:
Channel: CAN1
Baud Rate: 500kbps(与 STM32 配置一致)
Controller Mode: Normal
发送测试数据:
使用 BusMaster 的 "Send" 窗口,发送一个标准帧(ID=0x123,数据=0x11 0x22 0x33 0x44)。
监控接收:
在 BusMaster 的 "Log" 窗口 查看是否收到 STM32 的回复。
公羊子丹 发表于 2026-2-20 13:07 | 显示全部楼层
楼主这教程太实用了!补充个小细节,F103C8T6的CAN_IO口一定要开复用推挽,我之前忘配模式,光接了线完全没数据,配成PA11上拉输入、PA12复用推挽就正常了。
周半梅 发表于 2026-2-20 13:08 | 显示全部楼层
我试了楼主的配置,发现波特率计算有个小地方要注意,APB1时钟如果是36MHz,想500kbps的话,分频器选9会更准,BS1=8、BS2=1的组合时序也更稳,你可以试试这个参数。
帛灿灿 发表于 2026-2-20 13:09 | 显示全部楼层
提醒下大家,PEAK的PCAN-USB虽然自带120Ω电阻,但如果总线上只有STM32和它两个设备,最好确认下设备端电阻是开启的,我上次就是电阻没开,总线一直收不到帧。
童雨竹 发表于 2026-2-20 13:10 | 显示全部楼层
哈哈,我之前用BusMaster和STM32通信,卡了半天发现是ID格式没对应,楼主用的标准11位ID,BusMaster里别选成29位扩展ID了,新手超容易犯这错。
万图 发表于 2026-2-20 13:11 | 显示全部楼层
楼主的中断回调写得很简洁,补充个小技巧,回调里可以加个判断hcan->Instance == CAN1,要是后期加了CAN2,能避免两个CAN的中断混在一起,程序更稳。
Wordsworth 发表于 2026-2-20 13:12 | 显示全部楼层
好奇问下楼主,你配置里开了自动重传,实际用的时候有没有遇到总线忙重传多次的情况?我做项目时会加个重传次数判断,防止一直占总线,想听听你的建议。
Bblythe 发表于 2026-2-20 13:13 | 显示全部楼层
我建议大家接CAN线的时候用屏蔽线,普通杜邦线容易受干扰,尤其是距离稍远的时候,屏蔽层单端接地,能减少杂波,我之前测过,用屏蔽线后误码率直接降为0。
Pulitzer 发表于 2026-2-20 13:14 | 显示全部楼层
补充个调试小方法,要是通信不通,先在CubeIDE里用断点看HAL_CAN_Init的返回值,再用BusMaster的总线状态监测,看是不是总线处于BusOff状态,能快速定位问题。
Uriah 发表于 2026-2-20 13:15 | 显示全部楼层
楼主的发送函数里没判断发送邮箱是否空闲,虽然自动重传能兜底,但高频率发送时,最好加个while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan)==0),防止丢帧。
Clyde011 发表于 2026-2-20 13:16 | 显示全部楼层
这配置亲测能用!我用NUCLEO-F103RB试的,只改了启动文件和引脚,完美和BusMaster通信,另外提一句,BusMaster里的数据库文件可以自己做,标上ID和数据含义,调试更方便。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1695

主题

7380

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0