4. 基础配置流程:从零开始配置一个CAN通信模块
好,咱们今天直接上手干活。前面几章聊了工具安装和界面,估计你已经等不及想看看DaVinci Config到底怎么把配置变成代码了。这一章我们就拿CAN通信模块开刀,走一遍完整的配置流程。
我个人习惯,学一个新工具时,先跑通一个最小闭环。别一上来就搞复杂的网络拓扑,先让一个节点能发能收,心里就有底了。
4.1 配置步骤概览:从项目创建到代码生成
整个流程其实就五步,我画了张图,你先有个整体印象。
说白了,这五步就是:建工程 → 配模块 → 配驱动 → 检查 → 生成。每一步都有坑,我一个个说。
4.2 第一步:创建工程
打开DaVinci Config Developer,点击File → New → DaVinci Project。这时候会弹出一个向导,让你选MCU型号和基础软件版本。
嗯,这里要注意。我刚开始用的时候,随便选了个基础软件版本,结果后面配CAN模块时发现有些寄存器地址对不上。折腾了半天才发现是版本不匹配。
创建完成后,你会看到左侧的工程浏览器里多了一个项目节点。展开它,里面有个BSW文件夹,所有基础软件模块的配置都在这里。
4.3 第二步:配置CAN模块
在BSW文件夹下找到Can模块,双击打开。你会看到一个配置编辑器,里面分了好几个选项卡。
我个人习惯,先配CanConfigSet。这里面定义了CAN控制器的硬件参数:
| 参数 | 说明 | 典型值 |
|---|---|---|
| CanControllerBaudRate | 波特率,单位kbps | 500 |
| CanControllerPropSeg | 传播段时间单元数 | 2 |
| CanControllerSeg1 | 相位段1时间单元数 | 3 |
| CanControllerSeg2 | 相位段2时间单元数 | 2 |
| CanControllerSyncJumpWidth | 同步跳转宽度 | 1 |
波特率怎么算?公式是:BaudRate = Fclk / ( (1 + PropSeg + Seg1 + Seg2) * Prescaler )。举个例子,如果时钟频率是40MHz,Prescaler设为4,那算出来就是500kbps。
配完控制器,接下来配CanHardwareObject。这就是CAN消息对象,每个对象对应一个CAN ID。你需要定义:
- CanIdType:标准帧(11位)还是扩展帧(29位)
- CanObjectType:接收还是发送
- CanIdValue:具体的CAN ID值
- CanDlc:数据长度,最大8字节
我记得有一次,客户要求同时支持标准帧和扩展帧。我一开始只配了标准帧的对象,结果扩展帧的消息全丢了。后来在CanHardwareObject里把两个类型都加上,问题就解决了。
4.4 第三步:配置CAN驱动
这一步很多人会忽略,但它很关键。CAN驱动层负责把模块配置映射到具体的硬件寄存器上。
在CanDrv模块里,你需要配置:
- 中断优先级:CAN接收中断的优先级,建议设高一点
- 时钟源:选择CAN模块的时钟,通常是系统时钟或外设时钟
- 引脚映射:CAN_TX和CAN_RX对应的GPIO引脚
这里有个容易踩的坑。引脚映射时,有些MCU的CAN模块有多个实例(比如CAN0、CAN1)。你得确认你配的引脚属于哪个实例。我曾经把CAN0的引脚配到了CAN1的实例上,结果怎么调都收不到数据。
4.5 第四步:验证配置
所有参数配完后,点击工具栏上的验证按钮(一个绿色对勾图标)。工具会检查配置的一致性,比如:
- 波特率参数是否在合理范围内
- 消息对象的CAN ID是否有冲突
- 引脚映射是否有效
- 中断优先级是否配置正确
如果验证通过,你会看到Validation successful的提示。如果有错误,工具会列出具体的问题和位置。双击错误信息,它会自动跳转到对应的配置项。
嗯,这里要提醒一下。验证通过不代表配置一定正确,它只检查了语法和一致性。逻辑上的错误(比如波特率算错了)它发现不了。所以,生成代码后最好还是用示波器或CAN分析仪验证一下。
4.6 第五步:生成代码
验证通过后,点击Generate Code按钮。工具会生成一堆源文件,包括:
| 文件 | 内容 |
|---|---|
| Can.c / Can.h | CAN驱动层代码,包含初始化和中断处理 |
| Can_Cfg.h | 配置头文件,包含波特率、消息对象等参数 |
| Can_PBcfg.c | Post-Build配置,运行时可以修改的参数 |
生成的文件默认放在工程目录下的generated文件夹里。你需要把这些文件复制到你的IDE工程中,并添加到编译列表里。
代码生成后,你可以在主函数里调用Can_Init(&Can_PBcfg)来初始化CAN模块。然后调用Can_Write发送消息,在Can_RxIndication回调函数里接收消息。