F2800157开发板图形化配置 MCAN 报文收发笔记
📅 2026/7/18 21:29:53
👁️ 阅读次数
📝 编程学习
简介
CAN 总线是嵌入式开发中广泛使用的工业现场总线协议,TI 的 C2000 系列 MCU 内置了 MCAN 模块。手动配置 MCAN 的寄存器、引脚复用、Message RAM 和中断过去需要频繁查阅手册,过程繁琐且容易出错。借助 CCSTHEIA 的 SysConfig 图形化工具,可以直观完成 MCAN 初始化配置并自动生成驱动代码,让开发者聚焦应用逻辑。本文以 TMS320F2800157 为例,逐步演示用 SysConfig 配置 MCAN 实现经典 CAN 收发,涵盖创建驱动空工程、SysConfig 界面操作、MCAN 参数配置(波特率、时钟、中断、Message RAM、过滤器、GPIO 和 PIE 中断),最后补全收发代码并编译。
CAN(Controller Area Network)是 Bosch 提出的基于消息广播的串行通信协议,通过两根差分线实现多主架构通信,具备高可靠性和强实时性,广泛应用于汽车电子和工业控制。经典 CAN 支持 11 位标准 ID 或 29 位扩展 ID,数据帧最多 8 字节;CAN FD 在此基础上将数据段速率提升至 8 Mbps、有效载荷扩展到 64 字节。MCAN 是 TI C2000 系列集成的 CAN 外设模块,遵循 ISO 11898-1,兼容 CAN 2.0A/B 与 CAN FD,通过共享 Message RAM 灵活分配收发缓存。相比早期的 DCAN/eCAN,MCAN 在错误处理、过滤器和消息对象管理方面提供了更完善的硬件支持,配置灵活性也明显增强。
本文通过外接收发器和can卡完成总线的连通,进行收发测试
- 1. 创建工程
- 我这里选用的是带有驱动的空工程,直接导入就可以了,后面的弹出一路点就可以
- 2. 打开 SysConfig 界面
- 我这选择对应的开发板型号,然后出现第二张图的页面,对一些功能进行配置
- 3. 配置 MCAN 模块
- 3.1 添加 MCAN 实例
- 左边列表中找到MCAN,并点击添加,本实验采样的是标准的CAN;
- 所以取消默认的三个模式的勾选
- 3.2 波特率配置
- 这配置的波特率是500kbit,同时需要配置时钟
- 3.3 时钟配置
- 在左边选择时钟树,选择配置对应的时钟,我这里选择预分频系数3,将系统的120M转为40M的时钟信号,配合上面的参数得到CAN信号的波特率
- 3.4 中断配置
- 使能中断,并打开所有的中断源,将MCAN挂在中断线1上,并设置触发中断的条件,这里设置的是DRX触发中断,并将中断线1注册
- 3.5 Message RAM 配置
- 首先配置了接收的RX Buffer,标准的can接收的数据最大字节为8个,所以选择都是8
- 然后是TX Buffer设置2个专用缓存区,然后数据的大小也选择8个字节
- 3.6 过滤器配置
- 本文选择使用过滤器0,然后下面就会多一个滤波器0的折叠配置
- 这里因为本文使用的是RX Buffer,所以滤波的范围是不允许的,只能针对单一的ID进行接收,这里我写的2016,对应的16进制的ID:7E0
- 3.7 GPIO 引脚配置
- 这个地方对收发的引脚进行配置,可以选择,本文在实际的测试中发现GPIO21\20和GPIO12\13是可以正常使用的,但是GPIO30\31和GPIO4\5无法收发(暂时不知道是什么原因导致的)
- 3.8 PIE 中断配置
- 最后配置中断PIE勾选即可;然后中断处理函数的名称在这里可以INT_myMCAN0_1_ISR修改也可以就使用这个,中断处理函数内的内容需要自己添加
- 4. 生成代码并集成
- 4.1 Rx Buffer 接收代码补全
- 保存syscfg的配置后,在主函数下面添加中断处理函数
MCAN_RxBufElement g_rxMsg; volatile uint32_t g_txCount = 0U; // 发送计数 __interrupt void INT_myMCAN0_1_ISR(void) { uint32_t intrStatus; MCAN_RxNewDataStatus newData; intrStatus = MCAN_getIntrStatus(MCANA_DRIVER_BASE); MCAN_clearIntrStatus(MCANA_DRIVER_BASE, intrStatus); MCAN_clearInterrupt(MCANA_DRIVER_BASE, 0x2); if((MCAN_IR_DRX_MASK & intrStatus) == MCAN_IR_DRX_MASK) { MCAN_getNewDataStatus(MCANA_DRIVER_BASE, &newData); if((newData.statusLow & (1UL << 0U)) != 0U) { MCAN_readMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U, 0, &g_rxMsg); g_rxMsg.id = g_rxMsg.id >> 18U; // 提取真实 CAN ID g_rxCount++; } MCAN_clearNewDataStatus(MCANA_DRIVER_BASE, &newData); } else { // // 非DRX中断(TC发送完成、错误等),仅记录不中断运行 // } Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); }- 4.2 编译代码,检查配置
- 保存后编译代码,配置的代码就会自动生成,在主函数里,其中图形化配置的代码基本在board.c中,
// // Initialize device clock and peripherals // Device_init(); // // Disable pin locks and enable internal pull-ups. // Device_initGPIO(); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); // // PinMux and Peripheral Initialization // Board_init(); // // C2000Ware Library initialization // C2000Ware_libraries_init(); // // Enable Global Interrupt (INTM) and real time interrupt (DBGM) // EINT; ERTM;引脚配置代码
- 中断初始化等等
- 5.2 Tx Buffer 发送代码
- 添加的新的发送代码
volatile uint32_t g_txCount = 0U; // 发送计数 volatile uint32_t g_rxCanId = 0U; // 接收到的真实 CAN ID(已移位) // // ===== Tx Buffer 发送函数 ===== // void App_MCANSend(uint32_t canId, const uint8_t *data, uint32_t len) { MCAN_TxBufElement txMsg; uint32_t i; memset(&txMsg, 0, sizeof(txMsg)); txMsg.id = canId << 18U; // CAN ID 位于 bits[28:18] txMsg.dlc = (len > 8U) ? 8U : len; txMsg.rtr = 0U; txMsg.xtd = 0U; txMsg.fdf = 0U; for(i = 0U; i < txMsg.dlc; i++) { txMsg.data[i] = data[i]; } MCAN_writeMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U, &txMsg); MCAN_txBufAddReq(MCANA_DRIVER_BASE, 0U); g_txCount++; }- 5.3 保存并生成代码
- 编写 main.c(完整示例:接收 + 发送)
//############################################################################# // // FILE: empty_driverlib_main.c // // TITLE: Empty Project // // Empty Project Example // // This example is an empty project setup for Driverlib development. // //############################################################################# // // // $Copyright: // Copyright (C) 2026 Texas Instruments Incorporated - http://www.ti.com/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the // distribution. // // Neither the name of Texas Instruments Incorporated nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // $ //############################################################################# // // Included Files // #include "driverlib.h" #include "device.h" #include "board.h" #include "c2000ware_libraries.h" #include <string.h> MCAN_RxBufElement g_rxMsg; volatile uint32_t g_rxCount = 0U; volatile uint32_t g_txCount = 0U; // 发送计数 volatile uint32_t g_rxCanId = 0U; // 接收到的真实 CAN ID(已移位) // // ===== Tx Buffer 发送函数 ===== // void App_MCANSend(uint32_t canId, const uint8_t *data, uint32_t len) { MCAN_TxBufElement txMsg; uint32_t i; memset(&txMsg, 0, sizeof(txMsg)); txMsg.id = canId << 18U; // CAN ID 位于 bits[28:18] txMsg.dlc = (len > 8U) ? 8U : len; txMsg.rtr = 0U; txMsg.xtd = 0U; txMsg.fdf = 0U; for(i = 0U; i < txMsg.dlc; i++) { txMsg.data[i] = data[i]; } MCAN_writeMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U, &txMsg); MCAN_txBufAddReq(MCANA_DRIVER_BASE, 0U); g_txCount++; } // // Main // void main(void) { // // Initialize device clock and peripherals // Device_init(); // // Disable pin locks and enable internal pull-ups. // Device_initGPIO(); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); // // PinMux and Peripheral Initialization // Board_init(); // // C2000Ware Library initialization // C2000Ware_libraries_init(); // // Enable Global Interrupt (INTM) and real time interrupt (DBGM) // EINT; ERTM; uint8_t testData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; while(1) { // // 每 1 秒发送一帧 ID=0x7E0 的报文 // App_MCANSend(0x710U, testData, 8U); DEVICE_DELAY_US(1000000); } } __interrupt void INT_myMCAN0_1_ISR(void) { uint32_t intrStatus; MCAN_RxNewDataStatus newData; intrStatus = MCAN_getIntrStatus(MCANA_DRIVER_BASE); MCAN_clearIntrStatus(MCANA_DRIVER_BASE, intrStatus); MCAN_clearInterrupt(MCANA_DRIVER_BASE, 0x2); if((MCAN_IR_DRX_MASK & intrStatus) == MCAN_IR_DRX_MASK) { MCAN_getNewDataStatus(MCANA_DRIVER_BASE, &newData); if((newData.statusLow & (1UL << 0U)) != 0U) { MCAN_readMsgRam(MCANA_DRIVER_BASE, MCAN_MEM_TYPE_BUF, 0U, 0, &g_rxMsg); g_rxMsg.id = g_rxMsg.id >> 18U; // 提取真实 CAN ID g_rxCount++; } MCAN_clearNewDataStatus(MCANA_DRIVER_BASE, &newData); } else { // // 非DRX中断(TC发送完成、错误等),仅记录不中断运行 // } Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); } // // End of File //
编程学习
技术分享
实战经验