DSP28377D CAN发送与中断接收实战:从寄存器配置到避坑排查

发布时间:2026/10/15 18:41:58
DSP28377D CAN发送与中断接收实战:从寄存器配置到避坑排查 简介这份资源面向嵌入式开发初学者与DSP工程师聚焦TI DSP28377DTMS320C28x系列的CAN总线通信实现解决发送与中断接收的代码落地问题适用于工业自动化、汽车电子等实时通信场景。压缩包共217个文件约818KB以79个h头文件、30个c源文件、38个obj目标文件、36个d依赖文件及16个mk编译脚本为主另含asm汇编、cmd链接命令、ccxml与project工程配置等构成完整CCS工程结构。内容涵盖CAN模块选择、波特率设置、GPIO引脚复用、消息帧构建与邮箱填充、中断使能与服务例程、错误标志处理等关键环节并配有详细注释便于理解程序流程。已有3258人学习下载适合希望快速掌握DSP28377D CAN通信配置与中断收发机制的开发者参考实践。1. DSP28377D 的 CAN 发送与中断接收从寄存器到可复现的最小工程如果你手头正拿着一块 DSP28377D 的控制板想让它通过 CAN 总线和另一台设备稳定通信却卡在“发送能出去、接收收不到”或者“中断进不去”这类问题上那这篇笔记就是写给你的。DSP28377D 属于 C2000 系列里集成度较高的一颗芯片片上有两个 CAN 模块CANA、CANB支持标准帧和扩展帧邮箱数量足够应付大多数工业控制场景。但它的 CAN 配置不像某些 MCU 那样“填几个结构体就完事”从时钟使能、GPIO 复用、位时序计算到中断向量表映射每一步都有容易翻车的地方。我见过不少开发者发送调通了就以为大功告成结果接收端一上中断就卡死或者邮箱配置冲突导致数据被覆盖。这篇内容会从最小可运行工程的角度把发送、中断接收、避坑和验证串成一条线适合刚接触 C2000 CAN 的工程师也适合已经能发但收不稳、想搞清楚中断和邮箱机制的人。2. CAN 模块初始化时钟、GPIO 与位时序怎么定2.1 为什么初始化顺序不能随便调DSP28377D 的 CAN 模块挂在系统时钟树上初始化顺序如果搞反最常见的结果就是寄存器写不进去或者模块完全不工作。我一般会按这个顺序走先使能 CAN 模块时钟再配置 GPIO 复用为 CAN 功能然后让 CAN 模块进入初始化模式接着设置位时序参数最后退出初始化模式并使能模块。这个顺序不是随便定的因为 CAN 模块只有在初始化模式下才能修改位时序和邮箱配置而进入初始化模式的前提是模块时钟已经稳定。时钟使能涉及CpuSysRegs.PCLKCR0.bit.CAN_A或CAN_B这类寄存器位具体位名以你用的头文件为准。GPIO 复用则要查数据手册的 GPIO 复用表CANA 通常对应 GPIO30/31 或 GPIO70/71 这类引脚不同封装可能不一样。这里有个血泪经验如果你用的是某款控制板原理图上标了 CAN 引脚但代码里 GPIO 复用没配对现象就是发送引脚一直隐性示波器上什么都看不到。// 使能 CANA 模块时钟 EALLOW; CpuSysRegs.PCLKCR0.bit.CAN_A 1; EDIS; // 配置 GPIO 复用为 CANA 功能 EALLOW; GpioCtrlRegs.GPAMUX2.bit.GPIO30 1; // CANA_TX GpioCtrlRegs.GPAMUX2.bit.GPIO31 1; // CANA_RX EDIS;上面这段代码里EALLOW/EDIS是 C2000 保护寄存器的标准操作少了它写不进去。GPIO 复用值1代表外设功能具体是哪个值要查你芯片封装对应的复用表不同系列可能不同。时钟和 GPIO 配完后CAN 模块本身还没开始工作接下来要进入初始化模式。2.2 位时序参数一个算错就通信失败位时序是 CAN 初始化里最容易出玄学问题的地方。DSP28377D 的 CAN 位时序由CAN_BTR寄存器控制包含波特率预分频器BRP、同步跳转宽度SJW、时间段 1TSEG1和时间段 2TSEG2。采样点位置由TSEG1和TSEG2的比例决定一般推荐采样点在 75% 到 87.5% 之间。如果采样点太靠前或太靠后短距离调试可能没事一旦线缆变长或者节点增多误码率就上来了。假设 CAN 模块时钟是 20MHz目标波特率 500kbps位时间 20 个时钟周期。可以取BRP1实际分频 2则 TQ 时钟为 10MHz一个位时间 20 个 TQ。设TSEG115、TSEG24、SJW4采样点 (1 15) / 20 80%比较稳妥。写入时注意寄存器值通常是“实际值减一”比如BRP1对应分频 2。// 进入初始化模式 HWREGH(CANA_BASE CAN_O_CTL) | CAN_CTL_INIT; // 等待初始化模式生效 while(!(HWREGH(CANA_BASE CAN_O_CTL) CAN_CTL_INIT)); // 配置位时序BRP1, SJW4, TSEG115, TSEG24 HWREGH(CANA_BASE CAN_O_BTR) (1 0) | (4 6) | (15 8) | (4 12);这段代码直接操作寄存器CAN_O_CTL和CAN_O_BTR是偏移地址宏具体值参考头文件。CAN_CTL_INIT是初始化模式位。写BTR时各字段位置要对照手册不同文档里位域命名可能略有差异。配置完位时序后还要设置邮箱方向、使能中断等这些放到下一章讲。这里先记住一个原则位时序没算对后面所有调试都是白费。2.3 邮箱配置发送和接收的边界在哪DSP28377D 的 CAN 模块有 32 个邮箱每个邮箱可以独立配置为发送或接收也可以配置为标准帧或扩展帧。我一般会把邮箱 0 到 15 分配给发送16 到 31 分配给接收这样中断服务程序里判断起来清晰。发送邮箱需要设置CAN_MBOX_ID、CAN_MBOX_DLC和CAN_MBOX_CTRL里的方向位。接收邮箱除了方向还要设置验收屏蔽寄存器决定哪些 ID 能触发接收。// 配置邮箱 0 为发送标准帧ID 0x123 HWREGH(CANA_BASE CAN_O_MBOX_ID(0)) 0x123; HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) CAN_MBOX_CTRL_TX | CAN_MBOX_CTRL_STD; // 配置邮箱 16 为接收标准帧ID 0x456 HWREGH(CANA_BASE CAN_O_MBOX_ID(16)) 0x456; HWREGH(CANA_BASE CAN_O_MBOX_CTRL(16)) CAN_MBOX_CTRL_RX | CAN_MBOX_CTRL_STD; // 使能邮箱 16 接收中断 HWREGH(CANA_BASE CAN_O_MBOX_CTRL(16)) | CAN_MBOX_CTRL_RXIE;邮箱配置里有个容易忽略的点CAN_MBOX_CTRL的TX和RX位是互斥的写错方向会导致邮箱不工作。另外接收邮箱的RXIE位使能后还要在模块级中断使能寄存器里打开对应中断否则中断服务程序永远不会被调用。邮箱 ID 的设置要注意标准帧只有 11 位扩展帧 29 位写超了会被截断。3. 发送与中断接收从轮询到中断的完整链路3.1 发送流程什么时候该等什么时候不该等CAN 发送有两种方式轮询发送和中断发送。轮询发送简单但会阻塞 CPU中断发送效率高但配置稍复杂。我一般建议发送用轮询因为发送完成通常很快而且发送中断优先级如果设得太高可能影响其他实时任务。发送流程是把数据写入邮箱数据寄存器设置 DLC然后置位发送请求位等待发送成功标志。// 向邮箱 0 写入 8 字节数据 HWREGH(CANA_BASE CAN_O_MBOX_DATA(0, 0)) 0x1122; HWREGH(CANA_BASE CAN_O_MBOX_DATA(0, 1)) 0x3344; HWREGH(CANA_BASE CAN_O_MBOX_DATA(0, 2)) 0x5566; HWREGH(CANA_BASE CAN_O_MBOX_DATA(0, 3)) 0x7788; // 设置 DLC 8 HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) (HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) ~0xF) | 8; // 置位发送请求 HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) | CAN_MBOX_CTRL_TXRQ; // 等待发送成功 while(HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) CAN_MBOX_CTRL_TXRQ);这段代码里CAN_O_MBOX_DATA是邮箱数据寄存器的偏移每个邮箱有 4 个 16 位寄存器对应 8 字节。DLC 设置时先清零低 4 位再写入避免影响其他位。发送请求位置位后硬件会自动发送发送成功后该位会被清零。如果总线上没有其他节点应答发送会失败TXRQ位可能一直不清这时候需要检查总线终端电阻和波特率是否匹配。3.2 中断接收向量表、使能和清除标志的顺序中断接收是这篇笔记的重点也是最多人翻车的地方。DSP28377D 的中断系统分三级外设级、PIE 级和 CPU 级。CAN 接收中断要依次使能这三级的对应位少一级都进不去。具体来说CAN 模块级要打开邮箱中断和模块中断PIE 级要打开对应组的通道CPU 级要打开全局中断。顺序上我一般先配邮箱中断再配 PIE最后开 CPU 全局中断。// 使能 CAN 模块级中断 HWREGH(CANA_BASE CAN_O_CTL) | CAN_CTL_MIE; // 使能邮箱 16 中断 HWREGH(CANA_BASE CAN_O_MBOX_CTRL(16)) | CAN_MBOX_CTRL_RXIE; // 配置 PIE 向量表 EALLOW; PieVectTable.CANA0_INT canA0ISR; EDIS; // 使能 PIE 组中断 PieCtrlRegs.PIEIER9.bit.INTx5 1; // 假设 CANA0 在 PIE 组 9 通道 5 // 使能 CPU 全局中断 IER | M_INT9; EINT; ERTM;这段代码里PieVectTable.CANA0_INT是中断服务函数的入口地址具体名称以头文件为准。PIE 组和通道号要查芯片的 PIE 中断映射表不同文档可能编号不同。IER | M_INT9使能 CPU 级第 9 组中断EINT开全局中断ERTM开实时调试中断。中断服务函数里必须清除中断标志否则会反复进入。__interrupt void canA0ISR(void) { // 读取接收数据 Uint16 data0 HWREGH(CANA_BASE CAN_O_MBOX_DATA(16, 0)); Uint16 data1 HWREGH(CANA_BASE CAN_O_MBOX_DATA(16, 1)); // 清除邮箱中断标志 HWREGH(CANA_BASE CAN_O_MBOX_CTRL(16)) | CAN_MBOX_CTRL_RXIE; HWREGH(CANA_BASE CAN_O_IF1CMD) CAN_IF1CMD_CLRINT; // 清除 PIE 应答 PieCtrlRegs.PIEACK.all PIEACK_GROUP9; }中断服务函数里读取数据后要清除邮箱中断标志和 PIE 应答位。CAN_O_IF1CMD是接口寄存器命令用于清除中断。PIEACK写对应组号表示应答。如果忘了清 PIEACK中断只会进一次之后就被挂起。这个坑我踩过不止一次现象就是“第一次能进中断后面再也不进了”。3.3 验收屏蔽为什么你的接收邮箱收不到指定 ID接收邮箱能不能收到数据取决于验收屏蔽寄存器的配置。DSP28377D 的每个接收邮箱都有对应的验收屏蔽寄存器决定哪些 ID 位参与比较。如果屏蔽位设为 1表示该位不关心设为 0表示必须匹配。我一般会把标准帧的 11 位 ID 全部设为必须匹配这样只有 ID 完全一致的报文才会触发接收。// 设置邮箱 16 的验收屏蔽标准帧 11 位全部匹配 HWREGH(CANA_BASE CAN_O_MBOX_ID(16)) 0x456; HWREGH(CANA_BASE CAN_O_MBOX_MASK(16)) 0x7FF; // 11 位全比较这里CAN_O_MBOX_MASK是验收屏蔽寄存器偏移0x7FF表示 11 位全部参与比较。如果写成0x000表示所有 ID 都接收适合调试阶段。但正式产品里不建议全接收否则总线上的无关报文会频繁触发中断增加 CPU 负担。另外扩展帧的屏蔽寄存器是 29 位写法类似但要注意 ID 寄存器的对齐方式。4. 避坑与排查CAN 调试中最容易翻车的五个点4.1 发送正常但接收中断进不去现象发送端示波器能看到波形接收端邮箱数据寄存器也有值但中断服务函数就是不执行。原因通常是三级中断没配全或者 PIE 向量表没映射。解决先检查PieVectTable是否指向了正确的函数再确认PIEIER和IER对应位是否置 1最后看EINT和ERTM是否执行。我一般会在中断服务函数第一行翻转一个 GPIO用示波器看有没有进中断比打印快得多。4.2 中断只进一次就卡死现象第一次接收能进中断之后再也不进。原因几乎都是忘了清 PIEACK 或者邮箱中断标志。解决在中断服务函数末尾写PieCtrlRegs.PIEACK.all PIEACK_GROUPx;同时清除邮箱的RXIE或接口寄存器中断标志。注意清除顺序先清外设标志再清 PIEACK反过来可能丢中断。4.3 波特率算错导致通信不稳定现象短距离能通线一长就丢包或者两个节点波特率看起来一样但就是不通。原因通常是采样点位置不对或者 BRP 分频算错。解决用示波器测一个位的时间反推实际波特率。如果和设定值差太多检查 CAN 模块时钟源是否和预期一致。我一般会把采样点设在 80% 左右SJW取 4 个 TQ这样对时钟偏差容忍度好一些。4.4 邮箱方向配反导致数据覆盖现象发送邮箱里写的数据过一会儿变成接收到的数据。原因是有邮箱被配成了接收但 ID 和发送邮箱冲突或者方向位写错。解决把发送和接收邮箱分组发送用 0-15接收用 16-31并在初始化时逐个确认CAN_MBOX_CTRL的方向位。如果用了扩展帧还要注意 ID 寄存器的两个 16 位寄存器拼接顺序。4.5 总线终端电阻缺失导致偶发失败现象实验室里两根线短接能通接到实际设备上就时好时坏。原因通常是 CAN 总线两端没有 120 欧姆终端电阻或者电阻功率不够。解决用万用表测 CANH 和 CANL 之间的电阻正常应该是 60 欧姆左右两个 120 欧姆并联。如果测出来是 120 欧姆说明只有一端有电阻如果是无穷大说明两端都没有。这个坑很隐蔽因为短距离调试时有没有电阻都能通一旦线缆变长就暴露。5. 进阶验证用回环模式和错误计数器定位问题5.1 回环模式不接总线也能验证收发逻辑DSP28377D 的 CAN 模块支持回环模式发送的数据不经过物理总线直接回送到接收邮箱。这个模式特别适合在没有其他节点的情况下验证发送和接收代码是否正确。配置方法是把CAN_CTL寄存器里的TEST位置 1再设置LBM位。回环模式下发送邮箱发出的报文会被自己接收如果接收中断能进说明邮箱配置和中断链路没问题。// 进入回环模式 HWREGH(CANA_BASE CAN_O_CTL) | CAN_CTL_TEST; HWREGH(CANA_BASE CAN_O_TEST) | CAN_TEST_LBM; // 发送一帧数据 HWREGH(CANA_BASE CAN_O_MBOX_DATA(0, 0)) 0xAA55; HWREGH(CANA_BASE CAN_O_MBOX_CTRL(0)) | CAN_MBOX_CTRL_TXRQ; // 等待接收中断在中断里读取邮箱 16 数据回环模式验证通过后再切回正常模式接总线。如果回环能收但正常模式收不到问题就在物理层或总线配置上不在代码逻辑。这个分步排查方法能省很多时间。5.2 错误计数器从寄存器值判断故障类型CAN 模块有两个错误计数器发送错误计数器TEC和接收错误计数器REC。正常通信时这两个值应该接近 0。如果TEC持续增长说明发送端有问题可能是总线没有应答或者位时序不匹配。如果REC增长说明接收端检测到错误。当TEC超过 255 时节点会进入总线关闭状态这时候需要重新初始化 CAN 模块才能恢复。// 读取错误计数器 Uint16 tec HWREGH(CANA_BASE CAN_O_ERRC) 0xFF; Uint16 rec (HWREGH(CANA_BASE CAN_O_ERRC) 8) 0xFF; // 如果 TEC 255需要恢复 if(tec 255) { HWREGH(CANA_BASE CAN_O_CTL) | CAN_CTL_INIT; // 重新配置位时序和邮箱 HWREGH(CANA_BASE CAN_O_CTL) ~CAN_CTL_INIT; }这段代码里CAN_O_ERRC是错误计数器寄存器低 8 位是TEC高 8 位是REC。如果发现TEC快速上升先检查总线上有没有其他节点应答再确认两个节点的波特率是否一致。我一般会在调试阶段定期打印这两个值比猜问题快得多。5.3 一个习惯先回环再总线先中断再轮询我调试 CAN 的习惯是先在回环模式下验证发送和中断接收确认代码逻辑没问题再切到正常模式用轮询方式接收确认物理层和总线配置没问题最后再开中断。这样分步走每一步只引入一个变量出问题时定位范围小。如果一上来就全开发送、接收、中断、总线搅在一起排查起来就是黑匣子。另外中断服务函数里尽量只做数据搬运和标志清除复杂处理放到主循环避免中断嵌套导致时序问题。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询