This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
//以下是网友贴出的CAN示例代码:
// CAN实验程序解析
//头文件
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "driverlib/can.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"
#include "driverlib/fpu.h"
// 变量定义部分
// 一个计数器,用于记录所发送的数据包数
volatile
ui32 g_ulMsgCount_TX = 0;
// 一个计数器,用于记录所接收的数据包数
volatile
ui32 g_ulMsgCount_RX = 0;
// 用于指示在传输过程中是否出现错误以及错误类型
volatile
ui32 g_bErrFlag = 0;
//用于指示是否接收到数据包
volatile
ui32 g_bRXFlag = 0;
// 函数定义部分
// UART0的配置及初始化部分。*
// UART0模块用于通过计算机虚拟串口显示过程信息,主要包括InitConsole
//函数和一些UARTprintf语句。
void
InitConsole(
void
)
{
// 由于UART0使用PA0,PA1两个引脚,因此需要使能GPIOA模块
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
// 将PA0和PA1两个引脚的功能选择为执行UART0模块的功能
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
// 对PA0和PA1两个引脚配置为UART功能
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// UART的标准初始化
UARTStdioConfig(0,115200,50000000);
}
// 延时1s的函数
Void SimpleDelay(
void
)
{
//由于ROM_SysCtlDelay函数延时3个时钟周期,而ROM_SysCtlClockGet
//函数返回系统时钟的频率,因此最终的结果就是延时1s
ROM_SysCtlDelay(ROM_SysCtlClockGet()/3);
}
// CAN的中断函数
// 该函数寻找产生中断的原因,并且计算已发送/接收的数据包数目。
//由于要使用CAN0模块的中断函数,所以需要在startup_ccs.c文件的
//vector table(中断函数列表)中声明CANIntHandler。
void
CANIntHandler(
void
)
{
ui32 ulStatus;
// 通过CANIntStatus函数读取中断的状态
ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
// 如果是控制器状态中断,则说明出现了某种错误
if
(ulStatus == CAN_INT_INTID_STATUS)
{
//读取CAN模块所处的状态,并自动清除中断。
ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);
//将g_bErrFlag这个状态指示变量置1,以指示有错误发生
g_bErrFlag = 1;
}
// 检查是否是由message object 1引起的发送中断
else
if
(ulStatus == 1)
{
// 数据包发送已经完成,清除中断
CANIntClear(CAN0_BASE, 1);
//发送完一个数据包,计数器g_ulMsgCount_TX增加
g_ulMsgCount_TX++;
// 发送已经完成,清除所有的错误信息.
g_bErrFlag = 0;
}
// 检查是否是由于message object 2引起的接收中断
else
if
(ulStatus==2)
{
// 数据包接收已经完成,清除中断
CANIntClear(CAN0_BASE, 2);
// 接收完一个数据包,计数器g_ulMsgCount_RX增加
g_ulMsgCount_RX++;
// 设置Flag说明接收到的数据包正在等待处理
g_bRXFlag = 1;
// 发送已经完成,清除所有的错误信息.
g_bErrFlag = 0;
}
}
// main 函数
// 配置CAN模块,循环发送CAN格式数据包并通过LOOPBACK模式接收。
// 运行过程中的信息通过UART向计算机机传输。
int
main(
void
)
{
//使能FPU
FPUEnable();
FPULazyStackingEnable();
// 定义CAN的发送和接收对象
tCANMsgObject sCANMessage;
tCANMsgObject srCANMessage;
// 定义发送数据存储区和接收数据存储区
unsigned
int
uIdx;
//一个循环语句使用的变量
ui8 ucMsgData[4];
ui8 ucrMsgData[8];
// 禁用中断。在进行中断配置时要保证中断没被使用。
IntMasterDisable();
// 设置系统时钟为50MHz
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
// 由于CAN0使用PN0、PN1两个引脚,需要使能GPION对应的时钟
//信号
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
// 使能CAN0模块的时钟信号
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
//将PN0和PN1两个引脚的功能选择为执行CAN0模块的功能
GPIOPinConfigure(GPIO_PN0_CAN0RX);
GPIOPinConfigure(GPIO_PN1_CAN0TX);
// 对PN0和PN1两个引脚做有关CAN功能的配置
GPIOPinTypeCAN(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// CAN控制器的初始化
CANInit(CAN0_BASE);
// 利用CANBitRateSet函数将CAN的传输速率设置为1MHz
CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 1000000);
// 寄存器操作,将CAN0模块配置为运行于LOOPBACK模式
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
// 使能CAN0模块
CANEnable(CAN0_BASE);
// 使能CAN0模块的中断
IntEnable(INT_CAN0);
//设置可以引起CAN中断的中断源
CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
//初始化配置message object,即待发送的报文对象
//配置好报文对象后调用CANMessageSet函数进行设置,
//这样报文就可以自动被发送出去
// 待发送的数据为0
*(ui32 *)ucMsgData = 0;
// CAN message ID:使用1作为报文的ID
sCANMessage.ui32MsgID = 1;
// 没有MASK屏蔽
sCANMessage.ui32MsgIDMask = 0;
//使能发送中断
sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
//发送数据包大小为4个字节
sCANMessage.ui32MsgLen =
sizeof
(ucMsgData);
// 指向发送数据的指针
sCANMessage.pucMsgData = ucMsgData;
// 初始化配置用于接收的报文对象
// 同样也是用CANMessageSet函数可以将某个message object(报文对象)
//设置为如下的配置
// 可以接收任何ID的报文对象
srCANMessage.ui32MsgID = 0;
// 没有屏蔽
srCANMessage.ui32MsgIDMask = 0;
// 使能接收中断和ID过滤
srCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE|MSG_OBJ_USE_ID_FILTER;
// 允许最多8个字节的数据
srCANMessage.ui32MsgLen = 8;
//将message object 2设置为接收报文对象
ROM_CANMessageSet(CAN0_BASE,2,&srCANMessage,MSG_OBJ_TYPE_RX);
// 使能UART模块
InitConsole();
//使能中断
IntMasterEnable();
// 开始进入发送数据包的循环, 每秒将发送一个数据包。
while
(1)
{
// 将待发送的数据包内容通过UART传输并显示出来
UARTprintf(
"Sending msg: 0x%02X %02X %02X %02X"
,
ucMsgData[0], ucMsgData[1], ucMsgData[2], ucMsgData[3]);
// 将待发送的报文配置到message object 1中。
CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX);
// 等待1s
SimpleDelay();
// 通过g_bErrFlag变量查看是否出错
if
(g_bErrFlag)
{
UARTprintf(
" error - cable connected?\n"
);
}
else
{
// 如果没有出错,则显示已经发送的报文数目
UARTprintf(
" total count Transmit = %u\n"
, g_ulMsgCount_TX);
}
// 每次发送完毕,都将报文中的数据内容+1
(*(ui32 *)ucMsgData)++;
// 接收报文程序
// 通过g_bRXFlag判断是否有已经接收到是数据包
if
(g_bRXFlag)
{
// 建立指向报文数据的缓存区
srCANMessage.pucMsgData = ucrMsgData;
// 读取接收到的报文对象。
// 将message object中的信息读取到srCANMessage接收对象中
CANMessageGet(CAN0_BASE,2,&srCANMessage,0);
// 将g_bRXFlag置为0。
//等到下个报文到来时,中断函数会再次将它置1的
g_bRXFlag=0;
// 如果出现数据丢失等错误,则输出提示信息
if
(srCANMessage.ui32Flags & MSG_OBJ_DATA_LOST)
{
UARTprintf(
"CAN message loss detected\n"
);
}
// 通过UART输出接收到的报文信息
UARTprintf(
"Receive Msg ID=0x%08X len=%u data=0x"
,srCANMessage.ui32MsgID,srCANMessage.ui32MsgLen);
// 输出报文中的数据内容
for
(uIdx=0;uIdx<srCANMessage.ui32MsgLen;uIdx++)
{
UARTprintf(
"%02X"
,ucrMsgData[uIdx]);
}
// 输出所有已收到的报文数目
UARTprintf(
" total count Received = %u\n"
, g_ulMsgCount_RX);
}
}
return
(0);
}
// 寄存器操作,将CAN0模块配置为运行于LOOPBACK模式
//
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
//
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
CANIntHandler中断服务程序,说明CAN控制器没有发送报文成功。请问,这是为什么?看了好久的数据手册也没有找到答案,望TI的朋友们和各位坛友给我解惑,谢谢各位。
1.既然Tiva C芯片片内的CAN控制器工作于LOOPBACK模式,按照数据手册的介绍,报文应该没有送出芯片(即没有通过CAN收发器),而是直接再由CAN控制器接收,为什么外部的CAN调试设备可以接收到芯片发出的报文?
手册中是这样说的,回环模式下,接受输入被忽略,而没有说输出也被忽略。所以外部的CAN调试设备可以接收到芯片发出的报文
// 寄存器操作,将CAN0模块配置为运行于LOOPBACK模式
HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;
//
HWREG(CAN0_BASE + CAN_O_TST) = HWREG(CAN0_BASE + CAN_O_TST) | CAN_TST_LBACK;
因为在手册中只提到了一句,CAN_CTL_TEST置零后为正常模式,而没有说正常模式下是如何收发的。上面也没有介绍正常模式,只说明了有一种基本模式。而HWREG(CAN0_BASE + CAN_O_CTL) = HWREG(CAN0_BASE + CAN_O_CTL) | CAN_CTL_TEST;这句的意思就是开启测试模式下的正常模式,因此觉得,所谓的基本模式是不存在的。存在的是正常模式。
你的收发器是什么器件,高速收发器还是容错性的。
另外有没有用过示波器测下在MCU上的CAN 管脚有没有数据,然后再测下收发器的管脚有没有数据。
这样就比较容易定位是MCU有没有正常发送数据,或是收发器工作不正常。
谢谢
解决这个问题了。