基于TMS320F28335的CAN总线通信程序,包含CAN初始化、多邮箱配置、中断收发、错误处理、CANopen协议
一、TMS320F28335 eCAN模块特性
| 特性 | 说明 |
|---|---|
| 邮箱数量 | 32个邮箱(16个TX,16个RX) |
| 波特率 | 最高1Mbps |
| 协议 | CAN 2.0B(标准和扩展帧) |
| 邮箱类型 | 可配置为TX或RX |
| 中断 | 接收/发送/错误中断 |
| 过滤 | 接收屏蔽寄存器 |
推荐配置:
- 波特率:500kbps
- 邮箱数量:8个发送,8个接收
- 中断模式:邮箱接收中断
- 时钟:30MHz(系统时钟60MHz,分频)
二、硬件连接
DSP28335 CAN引脚:
GPIO30 → CANRXA
GPIO31 → CANTXA
外部电路:
DSP CAN → CAN收发器(TJA1050) → CAN总线
↓ ↓
3.3V 5V供电
必须加收发器:DSP CAN是TTL电平,需要收发器转为差分信号
三、程序架构
CAN_Driver/
├── can.c # CAN驱动
├── can.h # 头文件
├── can_config.c # 配置函数
├── can_isr.c # 中断服务
└── can_example.c # 示例程序
四、CAN驱动头文件
c
// can.h
#ifndef CAN_H
#define CAN_H
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
// CAN邮箱数量
#define CAN_MAILBOX_NUM 32
#define CAN_TX_MAILBOX_START 16
#define CAN_RX_MAILBOX_START 0
// CAN状态
typedef enum {
CAN_STATE_UNINIT = 0,
CAN_STATE_READY,
CAN_STATE_BUS_OFF,
CAN_STATE_ERROR
} CAN_State_t;
// CAN邮箱方向
typedef enum {
CAN_MAILBOX_DIR_RX = 0,
CAN_MAILBOX_DIR_TX
} CAN_MailboxDir_t;
// CAN帧类型
typedef enum {
CAN_FRAME_STD = 0, // 标准帧
CAN_FRAME_EXT // 扩展帧
} CAN_FrameType_t;
// CAN接收邮箱配置
typedef struct {
Uint16 mailbox_num; // 邮箱号 0-31
Uint32 msg_id; // 消息ID
CAN_FrameType_t frame_type; // 帧类型
Uint16 acceptance_mask; // 验收掩码
Uint16 data_len; // 数据长度
} CAN_RxMailboxConfig_t;
// CAN发送邮箱配置
typedef struct {
Uint16 mailbox_num; // 邮箱号 0-31
Uint32 msg_id; // 消息ID
CAN_FrameType_t frame_type; // 帧类型
Uint16 data_len; // 数据长度
Uint16 tx_priority; // 发送优先级
} CAN_TxMailboxConfig_t;
// CAN接收消息结构
typedef struct {
Uint32 msg_id; // 消息ID
CAN_FrameType_t frame_type; // 帧类型
Uint16 data_len; // 数据长度
Uint8 data[8]; // 数据
Uint16 timestamp; // 时间戳
Uint16 mailbox_num; // 邮箱号
} CAN_RxMsg_t;
// CAN发送消息结构
typedef struct {
Uint32 msg_id; // 消息ID
CAN_FrameType_t frame_type; // 帧类型
Uint16 data_len; // 数据长度
Uint8 data[8]; // 数据
Uint16 mailbox_num; // 邮箱号
} CAN_TxMsg_t;
// CAN错误计数
typedef struct {
Uint16 rx_error_count;
Uint16 tx_error_count;
Uint16 bus_off_count;
Uint16 error_passive_count;
} CAN_ErrorCount_t;
// CAN句柄
typedef struct {
CAN_State_t state;
CAN_ErrorCount_t error_count;
Uint16 baud_rate; // 波特率 kbps
Uint16 interrupt_enable; // 中断使能
void (*rx_callback)(CAN_RxMsg_t* msg); // 接收回调
void (*error_callback)(Uint16 error_code); // 错误回调
} CAN_Handle_t;
// 函数声明
void CAN_Init(Uint16 baud_rate);
void CAN_ConfigMailbox(CAN_MailboxDir_t dir, Uint16 mailbox_num,
Uint32 msg_id, CAN_FrameType_t frame_type);
Uint16 CAN_SendMessage(Uint16 mailbox_num, Uint8* data, Uint16 len);
Uint16 CAN_ReceiveMessage(Uint16 mailbox_num, CAN_RxMsg_t* msg);
void CAN_SetRxCallback(void (*callback)(CAN_RxMsg_t*));
void CAN_EnableInterrupt(Uint16 mailbox_num, Uint16 enable);
void CAN_ErrorHandler(void);
Uint16 CAN_GetStatus(void);
void CAN_BusOffRecovery(void);
// 波特率配置函数
void CAN_SetBaudRate(Uint16 baud_rate);
// 中断服务函数
interrupt void CAN_ISR(void);
#endif
五、CAN初始化配置
c
// can_config.c
#include "can.h"
// CAN句柄
CAN_Handle_t can_handle = {0};
// CAN初始化
void CAN_Init(Uint16 baud_rate)
{
// 1. 使能eCAN时钟
EALLOW;
SysCtrlRegs.PCLKCR0.bit.ECANAENCLK = 1; // 使能eCAN-A时钟
EDIS;
// 2. 配置GPIO为CAN功能
EALLOW;
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 3; // CANRXA
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 3; // CANTXA
EDIS;
// 3. 初始化CAN控制寄存器
// 进入初始化模式
ECanaRegs.CANMC.bit.CCR = 1; // 改变配置请求
while(ECanaRegs.CANES.bit.CCE != 1) {} // 等待配置使能
// 4. 配置位定时参数
CAN_SetBaudRate(baud_rate);
// 5. 配置接收屏蔽寄存器
// 全局接收屏蔽
ECanaMboxes.MBOX0.MSGID.all = 0x00000000; // 不屏蔽
// 6. 退出初始化模式
ECanaRegs.CANMC.bit.CCR = 0;
while(ECanaRegs.CANES.bit.CCE != 0) {} // 等待配置禁用
// 7. 初始化邮箱
CAN_InitMailboxes();
// 8. 初始化中断
CAN_InitInterrupts();
can_handle.state = CAN_STATE_READY;
can_handle.baud_rate = baud_rate;
}
// 设置波特率
void CAN_SetBaudRate(Uint16 baud_rate)
{
Uint16 brp, tseg1, tseg2, sjw;
// 系统时钟 = 150MHz (假设SYSCLKOUT=150MHz)
// CAN时钟 = SYSCLKOUT / (BRP + 1)
// 波特率 = CAN时钟 / ((TSEG1 + TSEG2 + 1) * (BRP + 1))
switch(baud_rate) {
case 1000: // 1Mbps
brp = 14; // 150/(15)=10MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 500: // 500kbps
brp = 29; // 150/(30)=5MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 250: // 250kbps
brp = 59; // 150/(60)=2.5MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
case 125: // 125kbps
brp = 119; // 150/(120)=1.25MHz
tseg1 = 5; // 5+1=6
tseg2 = 2; // 2+1=3
sjw = 1;
break;
default: // 500kbps
brp = 29;
tseg1 = 5;
tseg2 = 2;
sjw = 1;
}
// 配置位定时寄存器
ECanaRegs.CANBTC.bit.BRP = brp;
ECanaRegs.CANBTC.bit.TSEG1 = tseg1;
ECanaRegs.CANBTC.bit.TSEG2 = tseg2;
ECanaRegs.CANBTC.bit.SJW = sjw;
}
// 初始化邮箱
void CAN_InitMailboxes(void)
{
Uint16 i;
// 1. 初始化所有邮箱
for(i = 0; i < CAN_MAILBOX_NUM; i++) {
// 清空邮箱控制寄存器
ECanaMboxes.MBOX[i].MSGCTRL.all = 0x00000000;
// 清空消息ID
ECanaMboxes.MBOX[i].MSGID.all = 0x00000000;
// 清空数据
ECanaMboxes.MBOX[i].MDL.all = 0x00000000;
ECanaMboxes.MBOX[i].MDH.all = 0x00000000;
// 默认配置为接收邮箱
if(i < CAN_TX_MAILBOX_START) {
// 接收邮箱
ECanaRegs.CANME.all &= ~(1 << i); // 禁用邮箱
ECanaRegs.CANMD.all &= ~(1 << i); // 设置为接收
} else {
// 发送邮箱
ECanaRegs.CANME.all &= ~(1 << i); // 禁用邮箱
ECanaRegs.CANMD.all |= (1 << i); // 设置为发送
}
}
// 2. 配置邮箱方向寄存器(CANMD)
// 邮箱0-15: 接收邮箱
// 邮箱16-31: 发送邮箱
ECanaRegs.CANMD.all = 0xFFFF0000;
// 3. 使能邮箱
ECanaRegs.CANME.all = 0x00000000; // 先禁用所有邮箱
// 4. 配置接收屏蔽
// 使用接收屏蔽寄存器0-2
ECanaRegs.CANLAM0.all = 0xFFFFFFFF; // 全局接收
ECanaRegs.CANLAM1.all = 0xFFFFFFFF;
ECanaRegs.CANLAM2.all = 0xFFFFFFFF;
}
// 配置单个邮箱
void CAN_ConfigMailbox(CAN_MailboxDir_t dir, Uint16 mailbox_num,
Uint32 msg_id, CAN_FrameType_t frame_type)
{
if(mailbox_num >= CAN_MAILBOX_NUM) return;
// 1. 禁用邮箱
ECanaRegs.CANME.all &= ~(1 << mailbox_num);
// 2. 设置邮箱方向
if(dir == CAN_MAILBOX_DIR_RX) {
ECanaRegs.CANMD.all &= ~(1 << mailbox_num); // 接收
} else {
ECanaRegs.CANMD.all |= (1 << mailbox_num); // 发送
}
// 3. 配置消息ID
if(frame_type == CAN_FRAME_STD) {
// 标准帧
ECanaMboxes.MBOX[mailbox_num].MSGID.all = msg_id & 0x7FF; // 11位ID
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.IDE = 0; // 标准帧
} else {
// 扩展帧
ECanaMboxes.MBOX[mailbox_num].MSGID.all = msg_id & 0x1FFFFFFF; // 29位ID
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.IDE = 1; // 扩展帧
}
// 4. 使能邮箱
ECanaRegs.CANME.all |= (1 << mailbox_num);
}
// 设置接收回调
void CAN_SetRxCallback(void (*callback)(CAN_RxMsg_t*))
{
can_handle.rx_callback = callback;
}
六、CAN发送接收函数
c
// can.c
#include "can.h"
// 发送消息
Uint16 CAN_SendMessage(Uint16 mailbox_num, Uint8* data, Uint16 len)
{
Uint32* pData = (Uint32*)data;
if(mailbox_num < CAN_TX_MAILBOX_START || mailbox_num >= CAN_MAILBOX_NUM) {
return 0; // 邮箱号错误
}
if(len > 8) len = 8; // CAN最多8字节
// 1. 等待邮箱就绪
if(ECanaRegs.CANTRS.all & (1 << mailbox_num)) {
// 邮箱正在发送,等待完成
while(ECanaRegs.CANTRS.all & (1 << mailbox_num)) {}
}
// 2. 设置数据长度
ECanaMboxes.MBOX[mailbox_num].MSGCTRL.bit.DLC = len;
// 3. 写入数据
if(len > 0) {
ECanaMboxes.MBOX[mailbox_num].MDL.all = pData[0];
}
if(len > 4) {
ECanaMboxes.MBOX[mailbox_num].MDH.all = pData[1];
}
// 4. 触发发送
ECanaRegs.CANTRS.all = (1 << mailbox_num);
// 5. 等待发送完成
Uint32 timeout = 10000; // 超时计数
while((ECanaRegs.CANTA.all & (1 << mailbox_num)) == 0) {
timeout--;
if(timeout == 0) {
can_handle.error_count.tx_error_count++;
return 0; // 发送超时
}
}
// 6. 清除发送确认标志
ECanaRegs.CANTA.all = (1 << mailbox_num);
return len;
}
// 接收消息(查询方式)
Uint16 CAN_ReceiveMessage(Uint16 mailbox_num, CAN_RxMsg_t* msg)
{
if(mailbox_num >= CAN_TX_MAILBOX_START) {
return 0; // 不是接收邮箱
}
// 1. 检查是否有新消息
if((ECanaRegs.CANRMP.all & (1 << mailbox_num)) == 0) {
return 0; // 无新消息
}
// 2. 读取消息ID
if(ECanaMboxes.MBOX[mailbox_num].MSGID.bit.IDE) {
// 扩展帧
msg->frame_type = CAN_FRAME_EXT;
msg->msg_id = ECanaMboxes.MBOX[mailbox_num].MSGID.all & 0x1FFFFFFF;
} else {
// 标准帧
msg->frame_type = CAN_FRAME_STD;
msg->msg_id = ECanaMboxes.MBOX[mailbox_num].MSGID.bit.STDMSGID;
}
// 3. 读取数据长度
msg->data_len = ECanaMboxes.MBOX[mailbox_num].MSGCTRL.bit.DLC;
// 4. 读取数据
Uint32* pData = (Uint32*)msg->data;
pData[0] = ECanaMboxes.MBOX[mailbox_num].MDL.all;
pData[1] = ECanaMboxes.MBOX[mailbox_num].MDH.all;
// 5. 清除接收标志
ECanaRegs.CANRMP.all = (1 << mailbox_num);
// 6. 记录邮箱号和时间戳
msg->mailbox_num = mailbox_num;
msg->timestamp = ECanaRegs.CANTSC.all; // 时间戳计数器
return msg->data_len;
}
// 发送扩展帧
Uint16 CAN_SendExtFrame(Uint32 id, Uint8* data, Uint16 len, Uint16 mailbox_num)
{
if(mailbox_num < 16) mailbox_num = 16; // 使用发送邮箱
// 配置为扩展帧
ECanaMboxes.MBOX[mailbox_num].MSGID.all = id & 0x1FFFFFFF;
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.IDE = 1; // 扩展帧
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.AME = 0; // 不使用接收屏蔽
return CAN_SendMessage(mailbox_num, data, len);
}
// 发送标准帧
Uint16 CAN_SendStdFrame(Uint16 id, Uint8* data, Uint16 len, Uint16 mailbox_num)
{
if(mailbox_num < 16) mailbox_num = 16; // 使用发送邮箱
// 配置为标准帧
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.STDMSGID = id & 0x7FF;
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.IDE = 0; // 标准帧
ECanaMboxes.MBOX[mailbox_num].MSGID.bit.AME = 0; // 不使用接收屏蔽
return CAN_SendMessage(mailbox_num, data, len);
}
七、CAN中断配置
c
// can_isr.c
#include "can.h"
// 中断向量表
#define CAN_ISR_VECTOR INT14 // CAN-A中断向量
// 中断服务函数
interrupt void CAN_ISR(void)
{
Uint16 int_flag;
CAN_RxMsg_t rx_msg;
// 1. 读取中断标志
int_flag = ECanaRegs.CANGIF0.all;
// 2. 邮箱中断
if(int_flag & 0x00000001) { // 邮箱0-15中断
// 检查哪个邮箱有中断
for(int i = 0; i < 16; i++) {
if(ECanaRegs.CANRMP.all & (1 << i)) {
// 读取消息
CAN_ReceiveMessage(i, &rx_msg);
// 调用回调函数
if(can_handle.rx_callback != NULL) {
can_handle.rx_callback(&rx_msg);
}
// 清除中断标志
ECanaRegs.CANRMP.all = (1 << i);
}
}
}
// 3. 发送完成中断
if(int_flag & 0x00000002) { // 发送完成中断
// 清除发送确认标志
ECanaRegs.CANTA.all = ECanaRegs.CANTA.all;
}
// 4. 错误中断
if(int_flag & 0x00000004) { // 错误中断
CAN_ErrorHandler();
}
// 5. 唤醒中断
if(int_flag & 0x00000008) { // 唤醒中断
// 总线唤醒
ECanaRegs.CANGIF0.bit.WUIF = 0; // 清除标志
}
// 6. 总线关闭中断
if(int_flag & 0x00000010) { // 总线关闭
can_handle.state = CAN_STATE_BUS_OFF;
can_handle.error_count.bus_off_count++;
if(can_handle.error_callback != NULL) {
can_handle.error_callback(0x10);
}
ECanaRegs.CANGIF0.bit.BOIF = 0; // 清除标志
}
// 7. 错误被动中断
if(int_flag & 0x00000020) { // 错误被动
can_handle.error_count.error_passive_count++;
if(can_handle.error_callback != NULL) {
can_handle.error_callback(0x20);
}
ECanaRegs.CANGIF0.bit.EPIF = 0; // 清除标志
}
// 清除全局中断标志
ECanaRegs.CANGIF0.all = int_flag;
// 确认PIE中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
}
// 初始化CAN中断
void CAN_InitInterrupts(void)
{
// 1. 使能PIE中断
EALLOW;
PieVectTable.CANINTA = &CAN_ISR; // CAN-A中断
EDIS;
// 2. 使能CAN邮箱中断
// 邮箱0-15接收中断
ECanaRegs.CANMIM.all = 0x0000FFFF; // 使能邮箱0-15中断
// 3. 使能全局中断
ECanaRegs.CANGIM.all = 0x0000001F; // 使能所有中断
// 4. 配置PIE
PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // 使能INT9.1 (CAN-A)
// 5. 使能CPU INT9
IER |= M_INT9;
// 6. 使能全局中断
EINT;
ERTM;
}
// 使能/禁用邮箱中断
void CAN_EnableInterrupt(Uint16 mailbox_num, Uint16 enable)
{
if(mailbox_num >= CAN_MAILBOX_NUM) return;
if(enable) {
ECanaRegs.CANMIM.all |= (1 << mailbox_num);
} else {
ECanaRegs.CANMIM.all &= ~(1 << mailbox_num);
}
}
参考代码 DSP 28335 CAN总线通许程序 www.youwenfan.com/contentcsu/70113.html
八、错误处理
c
// can_error.c
#include "can.h"
// 错误处理函数
void CAN_ErrorHandler(void)
{
Uint16 error_status = ECanaRegs.CANES.all;
// 1. 检查错误状态
if(error_status & 0x0001) { // 接收错误
can_handle.error_count.rx_error_count++;
}
if(error_status & 0x0002) { // 发送错误
can_handle.error_count.tx_error_count++;
}
if(error_status & 0x0004) { // 错误被动
can_handle.state = CAN_STATE_ERROR;
}
if(error_status & 0x0008) { // 总线关闭
can_handle.state = CAN_STATE_BUS_OFF;
CAN_BusOffRecovery();
}
// 2. 调用错误回调
if(can_handle.error_callback != NULL) {
can_handle.error_callback(error_status);
}
}
// 总线关闭恢复
void CAN_BusOffRecovery(void)
{
// 1. 进入初始化模式
ECanaRegs.CANMC.bit.CCR = 1;
while(ECanaRegs.CANES.bit.CCE != 1) {}
// 2. 清除错误计数器
ECanaRegs.CANTEC = 0; // 发送错误计数器
ECanaRegs.CANREC = 0; // 接收错误计数器
// 3. 重新配置位定时
CAN_SetBaudRate(can_handle.baud_rate);
// 4. 退出初始化模式
ECanaRegs.CANMC.bit.CCR = 0;
while(ECanaRegs.CANES.bit.CCE != 0) {}
// 5. 重新使能邮箱
ECanaRegs.CANME.all = 0xFFFFFFFF;
can_handle.state = CAN_STATE_READY;
}
// 获取CAN状态
Uint16 CAN_GetStatus(void)
{
Uint16 status = 0;
// 组合状态信息
status = (can_handle.state << 8) |
(can_handle.error_count.rx_error_count & 0xFF);
return status;
}
九、CANopen协议实现(可选)
c
// canopen.c
#include "can.h"
// CANopen对象字典
typedef struct {
Uint16 index;
Uint8 subindex;
Uint32 value;
} CANopen_OD_Entry_t;
// CANopen协议函数
Uint16 CANopen_SendSDO(Uint16 node_id, Uint16 index, Uint8 subindex,
Uint8* data, Uint16 len, Uint8 expedited)
{
Uint8 sdo_data[8];
Uint32 sdo_cmd;
// 构建SDO命令
sdo_cmd = 0x600 + node_id; // 客户端发送SDO
sdo_data[0] = expedited ? 0x23 : 0x22; // 命令字节
sdo_data[1] = index & 0xFF;
sdo_data[2] = (index >> 8) & 0xFF;
sdo_data[3] = subindex;
// 复制数据
for(int i = 0; i < len && i < 4; i++) {
sdo_data[4 + i] = data[i];
}
return CAN_SendExtFrame(sdo_cmd, sdo_data, 8, 16);
}
Uint16 CANopen_SendPDO(Uint16 node_id, Uint8 pdo_num, Uint8* data, Uint16 len)
{
Uint32 pdo_cmd;
switch(pdo_num) {
case 1:
pdo_cmd = 0x200 + node_id;
break;
case 2:
pdo_cmd = 0x300 + node_id;
break;
case 3:
pdo_cmd = 0x400 + node_id;
break;
case 4:
pdo_cmd = 0x500 + node_id;
break;
default:
pdo_cmd = 0x200 + node_id;
}
return CAN_SendExtFrame(pdo_cmd, data, len, 16);
}
void CANopen_SendNMT(Uint8 node_id, Uint8 command)
{
Uint8 nmt_data[2];
nmt_data[0] = command;
nmt_data[1] = node_id;
CAN_SendExtFrame(0x000, nmt_data, 2, 16);
}
十、主程序示例
c
// main.c
#include "DSP2833x_Device.h"
#include "can.h"
// 全局变量
CAN_RxMsg_t rx_buffer[10];
Uint16 rx_index = 0;
// 接收回调函数
void CAN_RxCallback(CAN_RxMsg_t* msg)
{
if(rx_index < 10) {
rx_buffer[rx_index] = *msg;
rx_index++;
}
}
// 错误回调函数
void CAN_ErrorCallback(Uint16 error_code)
{
// 记录错误日志
// 可以保存到Flash或通过其他接口上报
}
int main(void)
{
// 1. 初始化系统
InitSysCtrl();
InitPieCtrl();
InitPieVectTable();
// 2. 初始化CAN,500kbps
CAN_Init(500);
// 3. 配置邮箱
// 邮箱0: 接收标准帧,ID=0x100
CAN_ConfigMailbox(CAN_MAILBOX_DIR_RX, 0, 0x100, CAN_FRAME_STD);
// 邮箱1: 接收扩展帧,ID=0x12345678
CAN_ConfigMailbox(CAN_MAILBOX_DIR_RX, 1, 0x12345678, CAN_FRAME_EXT);
// 邮箱16: 发送邮箱
CAN_ConfigMailbox(CAN_MAILBOX_DIR_TX, 16, 0x200, CAN_FRAME_STD);
// 4. 设置回调函数
CAN_SetRxCallback(CAN_RxCallback);
// 5. 主循环
while(1) {
// 发送测试数据
Uint8 tx_data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
CAN_SendStdFrame(0x200, tx_data, 8, 16);
// 处理接收到的数据
for(Uint16 i = 0; i < rx_index; i++) {
// 处理接收到的消息
ProcessCANMessage(&rx_buffer[i]);
}
rx_index = 0;
DELAY_US(1000000); // 延时1秒
}
}
// 处理CAN消息
void ProcessCANMessage(CAN_RxMsg_t* msg)
{
switch(msg->msg_id) {
case 0x100:
// 处理ID=0x100的消息
break;
case 0x12345678:
// 处理扩展帧
break;
}
}
十一、调试技巧
1、使用逻辑分析仪调试
c
// 添加调试引脚
#define DEBUG_PIN_SET() GpioDataRegs.GPASET.bit.GPIO0 = 1
#define DEBUG_PIN_CLR() GpioDataRegs.GPACLEAR.bit.GPIO0 = 1
// 在关键位置添加
DEBUG_PIN_SET();
CAN_SendMessage(16, data, 8);
DEBUG_PIN_CLR();
2、错误状态监测
c
void CAN_MonitorTask(void)
{
static Uint32 last_check = 0;
Uint32 current_time = GetTimerCount();
if(current_time - last_check > 1000) { // 1秒检查一次
Uint16 status = CAN_GetStatus();
if(status & 0xFF00) { // 检查状态位
printf("CAN状态异常: 0x%04X\n", status);
}
last_check = current_time;
}
}
十二、常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| 无法通信 | 波特率不匹配 | 检查两端波特率设置 |
| 接收不到数据 | 邮箱配置错误 | 检查邮箱方向和ID |
| 发送失败 | 邮箱被占用 | 等待发送完成或使用其他邮箱 |
| 总线错误 | 终端电阻缺失 | 总线两端加120Ω电阻 |
十三、编译配置
1、CCS工程配置
Include Paths:
- C:\ti\c2000\C28x_FPU_LIB
- ${PROJECT_ROOT}/include
Predefined Symbols:
_DEBUG
CPU1
2、链接器命令文件
cmd
MEMORY
{
PAGE 0: /* Program Memory */
PAGE 1: /* Data Memory */
}