3、开发环境搭建:硬件平台选择(STM32/ARM/Linux)、软件工具链(编译器、调试器)、CANopenNode源码获取与编译、第一个Hello World程序
好,咱们正式开始动手了。
这一章,说白了就是“把家伙事儿备齐”。做嵌入式开发,最怕什么?最怕环境搭了三天,代码一行没写。我当年刚入行时,光装一个IDE就折腾了一整天,最后发现是杀毒软件把编译器给干掉了。嗯,这种坑,咱们今天尽量避开。
3.1 硬件平台怎么选?
CANopenNode是个开源协议栈,移植性很好。但作为教学,我建议你选一个“皮实”的平台。我个人习惯把平台分成三类:
| 平台类型 | 代表芯片/板卡 | 适合场景 | 我的评价 |
|---|---|---|---|
| STM32系列 | STM32F103 / F407 / H743 | 入门、工业控制、从站开发 | 资料最多,社区最活跃,首选 |
| ARM通用MCU | NXP LPC系列、TI Tiva C系列 | 特定项目、成本敏感 | 寄存器级移植,适合进阶 |
| Linux平台 | 树莓派、BeagleBone、i.MX6 | 主站开发、网关、复杂应用 | 调试方便,但实时性需注意 |
我个人建议:初学者先用STM32F407开发板。为什么?因为CANopenNode官方例程里就有STM32的移植,你拿来就能跑。我在项目中遇到过用STM32F103做从站,结果CAN过滤器配置搞反了,总线上一堆错误帧。后来换成F407,调试器直接看寄存器,十分钟就定位了问题。
3.2 软件工具链:编译器与调试器
工具链这块,我踩过的坑比硬件还多。咱们分两种情况说:
3.2.1 针对STM32/ARM MCU
- 编译器: 我推荐ARM GCC(gcc-arm-none-eabi)。免费、开源、性能不输IAR。你想想看,IAR一个License好几万,个人学习真没必要。
- 调试器: J-Link或ST-Link。J-Link速度快,但贵。ST-Link买开发板时基本都送,够用。
- IDE: 我习惯用VS Code + CMake。当然,如果你喜欢图形化,STM32CubeIDE也行,它集成了GCC和调试器,开箱即用。
3.2.2 针对Linux平台
Linux下就简单多了。你只需要:
sudo apt-get install gcc make cmake
sudo apt-get install can-utils # 用于调试CAN总线
编译器用系统自带的GCC就行。调试器?Linux下我一般用gdb,配合OpenOCD或者直接print大法。说实话,Linux平台开发CANopenNode,比MCU省心一半。
3.3 获取CANopenNode源码
源码在GitHub上,地址是:https://github.com/CANopenNode/CANopenNode。怎么拿?两种方式:
- 直接下载ZIP: 点页面上的“Code” -> “Download ZIP”。简单粗暴,但后续更新麻烦。
- 用Git克隆: 我推荐这种方式。因为CANopenNode还在更新,你随时可以
git pull拉取最新代码。
git clone https://github.com/CANopenNode/CANopenNode.git
cd CANopenNode
git checkout master # 或者选一个稳定版本,比如v4.0
克隆下来后,目录结构是这样的:
CANopenNode/
├── CANopen.h # 主头文件
├── CANopen.c # 核心实现
├── stack/ # 协议栈各层
├── driver/ # 硬件驱动层(需要你移植)
├── example/ # 示例代码
└── doc/ # 文档
嗯,这里要注意:driver/ 目录下是空的,只有模板文件。你需要根据你的硬件,实现CAN收发、定时器、EEPROM读写这几个接口。别怕,咱们后面会手把手教你填。
3.4 编译第一个程序
咱们先不急着写业务逻辑。先让代码能编译通过,这叫“Hello World”级别的验证。
3.4.1 在Linux上编译(最简单)
CANopenNode自带CMakeLists.txt。你直接:
mkdir build && cd build
cmake ..
make
如果一切顺利,你会看到一堆 .o 文件和一个静态库 libCANopen.a。我在项目中第一次编译时,卡在了“找不到socketCAN头文件”上。后来发现是没装 libsocketcan-dev。所以,如果你报错,先检查依赖:
sudo apt-get install libsocketcan-dev
3.4.2 在STM32上编译(需要移植)
对于STM32,我建议你直接用STM32CubeIDE新建一个工程,然后把CANopenNode的源文件加进去。具体步骤:
- 新建STM32工程,配置好时钟和CAN外设(波特率建议先设125kbps)。
- 把
CANopenNode/stack/和CANopenNode/driver/下的源文件复制到工程里。 - 实现三个驱动函数:
CANopenNode_canRead()、CANopenNode_canWrite()、CANopenNode_timer()。 - 在main函数里调用
CANopenNode_init()和CANopenNode_process()。
#include "CANopen.h"
int main(void) {
// 硬件初始化(时钟、GPIO、CAN、定时器)
HAL_Init();
SystemClock_Config();
MX_CAN_Init();
MX_TIM_Init();
// CANopen协议栈初始化
CANopenNode_init();
while(1) {
CANopenNode_process(); // 主循环,处理CAN报文
// 你的应用逻辑可以写在这里
}
}
编译通过后,下载到板子里。用USB-CAN分析仪(或者另一块板子)发一个NMT启动命令(COB-ID=0x000,数据=0x01),如果板子回复了心跳报文(COB-ID=0x700+NodeID),恭喜你,第一个程序跑起来了!
3.5 验证:你的第一个CANopen节点
程序跑起来后,怎么确认它活着?我教你一个土办法:
- 用
candump can0(Linux)或CAN分析工具抓总线数据。 - 正常情况,你会看到节点每隔一定时间(默认1000ms)发送一个心跳报文。比如Node-ID=1,心跳COB-ID就是0x701,数据字节表示节点状态(0x00=启动中,0x05=运行中,0x7F=预操作)。
- 如果看不到心跳,先检查CAN收发器有没有共地,终端电阻有没有接(120Ω,总线两端各一个)。
嗯,到这里,你的开发环境就算搭好了。虽然只是点亮了一个“心跳”,但这是CANopen通信的第一步。后面咱们会在这个基础上,添加对象字典、PDO、SDO……一步步把节点做完整。
下一章,咱们聊聊对象字典——CANopen的灵魂。准备好了吗?