news 2026/4/23 20:42:48

使用keil5烧录程序stm32完成CAN总线组网指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用keil5烧录程序stm32完成CAN总线组网指南

从零搭建STM32 CAN总线网络:Keil5烧录与多节点通信实战指南

你有没有遇到过这样的场景?在做一个分布式控制系统时,多个设备之间需要实时交换数据,但串口通信距离短、抗干扰差,以太网又太复杂、成本高。这时候,CAN总线就成了解决问题的“黄金方案”。

本文将带你一步步使用Keil5完成STM32固件烧录,并配置片上CAN控制器,最终实现多个STM32节点通过CAN总线稳定通信。整个过程不依赖复杂的操作系统或协议栈,适合嵌入式初学者和中级开发者快速上手。

我们不会堆砌术语,而是像一位老工程师手把手教你:怎么接线、怎么写代码、怎么调通第一个CAN帧,以及那些只有踩过坑才知道的“隐藏技巧”。


为什么是STM32 + Keil5 + CAN?

先说结论:这套组合在中小规模工业控制中几乎是“性价比之王”。

  • STM32多数型号自带硬件CAN控制器,无需外加协处理器;
  • Keil5(MDK)对ARM Cortex-M系列支持完善,调试体验流畅;
  • CAN总线支持多主、抗干扰强、传输距离远(最长可达1km),非常适合工厂、车载等复杂环境。

更重要的是,这三个技术点可以无缝衔接——你在Keil里写的代码,一键下载到STM32后就能驱动CAN收发器发送第一帧数据。

那么问题来了:如何让这一切真正跑起来?


第一步:用Keil5把程序烧进STM32

别小看这一步,很多初学者卡在这里——编译通过了,但板子没反应。其实关键不在代码,而在烧录配置是否正确

烧录的本质是什么?

简单说,就是把你写的C语言程序变成一串二进制机器码,写进STM32的Flash里,并让它从复位向量开始执行。

这个过程依赖三个要素:
1. 正确的工程设置(芯片型号、时钟)
2. 可靠的物理连接(ST-Link or J-Link)
3. 合理的启动模式(BOOT引脚)

实操流程(基于ST-Link + STM32F103C8T6)

  1. 硬件连接
    - ST-Link → STM32 板

    • SWDIO → PA13
    • SWCLK → PA14
    • GND → GND
    • 3.3V → 3.3V(可选供电)
  2. Keil5工程配置
    - Project → Options for Target → Debug

    • 选择ST-Link Debugger
    • Utilities → Settings
    • 勾选 “Use Memory Layout from Target Dialog”
    • 选择编程算法(如 STM32F1xx 64KB Flash)
  3. 关键检查项
    - ✅ BOOT0 = 0(从主Flash启动)
    - ✅ 目标板供电正常(推荐外部稳压源)
    - ✅ 没有短路或反接

⚠️ 常见坑点:如果你发现“No target connected”,大概率是电压不匹配或者SWD线路接触不良。不要强行烧录!

如何验证烧录成功?

最简单的办法是在main()函数开头点亮一个LED:

int main(void) { HAL_Init(); SystemClock_Config(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef gpio = {0}; gpio.Pin = GPIO_PIN_5; gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &gpio); while (1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(500); // 每半秒闪一次 } }

只要LED开始闪烁,说明程序已经成功运行 —— 你的开发链路打通了第一步!


第二步:让STM32说出“CAN语言”

现在轮到核心功能:配置STM32的CAN控制器。

STM32的CAN模块叫bxCAN(Basic Extended CAN),它不是软件模拟,而是独立运行的硬件外设。这意味着一旦初始化完成,发送和接收几乎不需要CPU干预。

CAN通信的核心参数:波特率怎么算?

这是最容易出错的地方。所有节点必须完全一致地配置位时间,否则谁也收不到谁的数据。

假设我们要设置500kbps波特率,APB1时钟为36MHz(常见于STM32F1系列),该怎么设置?

计算公式:
Bit Rate = APB1_CLK / (Prescaler × (1 + BS1 + BS2))

其中:
- Prescaler:分频系数
- BS1(Time Segment 1):传播段 + 相位缓冲段1
- BS2(Time Segment 2):相位缓冲段2
- 同步跳转宽度 SJW ≤ min(BS1, BS2)

示例配置(500kbps):
参数
APB1_CLK36 MHz
Prescaler9
BS18 Tq
BS27 Tq
总位时间1 + 8 + 7 = 16 Tq
实际波特率36,000,000 / (9×16) = 500,000 bps ✅

这些值对应HAL库中的结构体成员:

hcan.Init.Prescaler = 9; hcan.Init.BS1 = CAN_BS1_8TQ; hcan.Init.BS2 = CAN_BS2_7TQ; hcan.Init.SJW = CAN_SJW_1TQ;

💡 小贴士:采样点建议设在75%~85%之间(本例为(1+8)/16 ≈ 56%,偏低)。若通信不稳定,可适当增加BS1长度。


第三步:编写CAN初始化代码(基于HAL库)

下面是一段经过验证的CAN1初始化函数,适用于STM32F1系列:

CAN_HandleTypeDef hcan; void MX_CAN_Init(void) { hcan.Instance = CAN1; hcan.Init.Mode = CAN_MODE_NORMAL; // 正常模式 hcan.Init.AutoBusOff = ENABLE; // 自动离线恢复 hcan.Init.AutoWakeUp = DISABLE; hcan.Init.TimeTriggeredMode = DISABLE; hcan.Init.ReceiveFifoLocked = DISABLE; hcan.Init.TransmitFifoPriority = DISABLE; // 波特率设置(500kbps) hcan.Init.Prescaler = 9; hcan.Init.SJW = CAN_SJW_1TQ; hcan.Init.BS1 = CAN_BS1_8TQ; hcan.Init.BS2 = CAN_BS2_7TQ; if (HAL_CAN_Init(&hcan) != HAL_OK) { Error_Handler(); } // 配置过滤器:接收所有标准帧 CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; // ID掩码高位 sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; // 掩码全0 → 全部通过 sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; sFilterConfig.FilterActivation = ENABLE; if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) { Error_Handler(); } // 启动CAN并启用中断 if (HAL_CAN_Start(&hcan) != HAL_OK) { Error_Handler(); } if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { Error_Handler(); } }

🔍 关键解读:
-FilterMaskId=0表示“不管ID是多少都接收”,适合调试阶段。
- 使用FIFO0中断而非轮询,避免浪费CPU资源。
- 开启自动离线恢复(ABOM),防止总线异常导致节点锁死。

别忘了在NVIC中使能CAN中断:

HAL_NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);

并在中断服务函数中处理接收事件:

void USB_LP_CAN1_RX0_IRQHandler(void) { HAL_CAN_IRQHandler(&hcan); } // 回调函数(需定义) 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) { // 在这里处理收到的数据! if (rxHeader.StdId == 0x101 && rxData[0] == 0x01) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 点亮LED } } }

第四步:组网!构建一个多节点CAN系统

现在我们已经有能力发送和接收CAN帧了,下一步是让多个STM32节点互联通信

物理连接要点

  • 所有节点共用一对差分线:CAN_HCAN_L
  • 使用TJA1050MCP2551等CAN收发器芯片进行电平转换
  • 总线两端各加一个120Ω终端电阻,中间节点不接!
[Node A] -----(CAN_H/L)------ [Node B] │ 120Ω │ 120Ω │ (GND)

❗ 错误示范:有人为了“更可靠”在每个节点都加上120Ω电阻,结果总阻抗严重失配,通信失败。

软件层面的设计思路

  1. 统一波特率:所有节点必须使用相同的Prescaler、BS1、BS2。
  2. 规划ID空间:比如:
    - 0x100~0x1FF:传感器数据
    - 0x200~0x2FF:控制命令
    - 0x300~0x3FF:心跳包/状态上报
  3. 避免频繁重传:设置合理的NART(No Automatic Retransmission)策略。

发送一帧数据试试看

void send_temperature(float temp) { CAN_TxHeaderTypeDef txHeader; uint8_t txData[2]; uint32_t txMailbox; txHeader.StdId = 0x101; // 标准ID txHeader.RTR = CAN_RTR_DATA; // 数据帧 txHeader.IDE = CAN_ID_STD; // 标准帧 txHeader.DLC = 2; // 2字节数据 txHeader.TransmitGlobalTime = DISABLE; int value = (int)(temp * 10); // 25.3°C → 253 txData[0] = value >> 8; txData[1] = value & 0xFF; if (HAL_CAN_AddTxMessage(&hcan, &txHeader, txData, &txMailbox) != HAL_OK) { Error_Handler(); } }

当你调用send_temperature(25.3f),其他节点就会收到这条消息,并可根据ID做出响应。


实战案例:三节点温控系统

设想一个简单应用场景:

  • Node A:采集温度(每隔1秒发一次)
  • Node B:根据温度决定是否加热
  • Node C:HMI显示当前温度和状态

它们都连接在同一根CAN总线上,没有任何主控协调。

Node A(温度采集)

while (1) { float temp = read_ds18b20(); // 假设读取温度 send_temperature(temp); HAL_Delay(1000); }

Node B(加热控制)

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { ... if (rxHeader.StdId == 0x101) { float temp = ((rxData[0] << 8) | rxData[1]) / 10.0f; if (temp < 20.0f) { send_heater_cmd(HEATER_ON); // 发送加热指令 } } }

Node C(显示界面)

// 同时监听温度和加热状态 if (rxHeader.StdId == 0x101) update_temp_display(temp); if (rxHeader.StdId == 0x201) update_heater_icon(status);

整个系统去中心化,任何一个节点故障不影响其余部分运行,可靠性极高。


常见问题与调试技巧

Q1:为什么收不到任何消息?

  • ✅ 检查终端电阻是否只在两端接入
  • ✅ 所有节点波特率配置是否完全一致
  • ✅ CAN收发器VCC是否正常供电
  • ✅ 是否启用了接收中断并正确注册回调

Q2:偶尔丢帧怎么办?

  • 提高采样点位置(调整BS1/BS2比例)
  • 检查是否有强干扰源靠近通信线(如电机、继电器)
  • 使用屏蔽双绞线(STP)

Q3:节点突然“失联”?

  • 查看TEC(发送错误计数器)是否超过96(警告级别)
  • REC > 127 可能已进入“被动错误”状态
  • 加入状态监控任务定期打印CAN_ErrorCodeGet()

调试利器推荐

  • PCAN-ViewCANalyzer:抓取总线数据,分析通信流程
  • 逻辑分析仪:观察CAN_H/L波形质量
  • 串口透传:将CAN报文转发到串口,方便日志输出

写在最后:这套技术能走多远?

你可能会问:“这只是一个简单的CAN通信,有什么特别的?”

它的特别之处在于:简单、可靠、可扩展

  • 不需要RTOS也能实现实时通信;
  • 几个GPIO + 一片TJA1050就能组网;
  • 即使未来升级为CAN FD,底层架构依然可用。

无论是做毕业设计、工业改造,还是开发智能农业设备,这套“Keil5 + STM32 + CAN”的组合都能成为你手中的一张王牌。

掌握它,你就掌握了在复杂电磁环境中构建稳健通信系统的底层能力。

如果你正在尝试搭建自己的CAN网络,欢迎在评论区留言交流——我们一起解决每一个“收不到帧”的深夜难题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 9:58:40

网盘加速工具:告别龟速下载,免费实现高速下载提速

网盘加速工具&#xff1a;告别龟速下载&#xff0c;免费实现高速下载提速 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改&#xff08;改自6.1.4版本&#xff09; &#xff0c;自用&#xff0c;去推…

作者头像 李华
网站建设 2026/4/23 13:18:23

DLSS Swapper:解锁游戏性能优化的终极武器

DLSS Swapper&#xff1a;解锁游戏性能优化的终极武器 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 还在为游戏卡顿和画质不佳而烦恼吗&#xff1f;&#x1f914; 现代游戏对硬件的要求越来越高&#xff0c;但通过智…

作者头像 李华
网站建设 2026/4/23 11:35:30

DLSS Swapper完整使用指南:5步轻松优化游戏画质

DLSS Swapper完整使用指南&#xff1a;5步轻松优化游戏画质 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 还在为游戏画面模糊而困扰&#xff1f;想要不升级硬件就能获得更清晰的游戏体验&#xff1f;DLSS Swapper正是…

作者头像 李华
网站建设 2026/4/23 11:32:33

DLSS Swapper技术解析:智能DLSS版本管理的深度实践

DLSS Swapper技术解析&#xff1a;智能DLSS版本管理的深度实践 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper DLSS Swapper作为一款专业的DLSS动态链接库管理工具&#xff0c;通过智能化的版本控制系统&#xff0c;为…

作者头像 李华
网站建设 2026/4/23 11:20:55

终极指南:如何高效管理游戏DLSS技术版本

终极指南&#xff1a;如何高效管理游戏DLSS技术版本 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 还在为游戏更新后DLSS效果变差而困扰&#xff1f;想要自由控制游戏图形技术的版本升级与降级&#xff1f;DLSS Swapp…

作者头像 李华
网站建设 2026/4/23 17:53:30

DLSS Swapper:3个关键步骤让你的游戏性能提升50%

DLSS Swapper&#xff1a;3个关键步骤让你的游戏性能提升50% 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper DLSS Swapper作为一款专为NVIDIA RTX显卡用户设计的智能优化工具&#xff0c;能够通过精准的DLSS动态链接库…

作者头像 李华