主题中讨论的其他器件: TM4C123、 DK-TM4C123G、 SN65HVD251、 SN65HVD233
我在使用 tm4c1294的 CAN 控制器模块时遇到问题。 我尝试修改了可用于 TIvAware 上的 tm4c123的 CAN 示例、但似乎无法使其正常工作。 我正在使用2 个 EK-TM4C1294XL、每个 EK-TM4C1294XL 连接到各自 CAN1模块(CAN1Rx PB0和 CAN1Tx PB1)上的 MCP2561 CAN 收发器。 我的问题是、当我使用示波器观察 CAN1tx 传输数据时、显然没有数据被传输。 CAN1Tx 管脚始终保持在3V3。 我收到消息错误 CAN_BUS_OFF 和 CAN_STATUS_EWARN。 下面是我的代码:
//
//
// ca.c -简单的 CAN 示例。
//
//版权所有(c) 2013-2017 Texas Instruments Incorporated。 保留所有权利。
//软件许可协议
//
//德州仪器(TI)仅提供和使用此软件
//专门用于 TI 的微控制器产品。 该软件归其所有
// TI 和/或其供应商、受适用版权保护
//法律。 您不能将此软件与"病毒"开源软件结合使用
//软件,以便形成一个更大的程序。
//
//此软件按“原样”提供,且存在所有故障。
//不作任何明示、暗示或法定的保证,包括但
//不限于对适销性和适用性的暗示保证
//此软件的特定用途。 TI 不得以任何方式进行
//情况,对特殊、偶然或从属事件负责
//任何原因造成的损害。
//
//这是 DK-TM4C123G 固件包的版本2.1.4.178的一部分。
//
//
#include
#include
#include
#include
#include "inc/hw_ca.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/fpu.h"
#include "driverlib/CAN.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "grlib/grlib.h"
#include "drivers/cfal96x64x16.h"
#include "utils/uartstdio.h"
#include "driverlib/interrupt.h"
//
//
//! \addtogroup example_list
//!
CAN 示例(CAN)
//!
//! 此示例应用程序利用 CAN 来回发送字符
//! 之间的差异。 它使用 UART 读取/写入字符
//! UART 终端。 它还使用板上的图形显示进行显示
//! 最后一个字符被转接/接收。 还包括错误处理。
//!
//! CAN 硬件设置:
//!
//! 要使用此示例、您需要连接两个 DK-TM4C123G 板
//! 一起工作。 这涉及连接 CANH 螺钉端子
//! 和 CANL 端子一起。 此外、还具有120 Ω 终端
//! 需要在 CANH 之间的网络边缘添加电阻器
//! 和 CANL。 在两个电路板设置中、这意味着连接一个120欧姆的电阻器
//! CANH 和 CANL 之间的差值。
//!
//! 请参阅下图了解可视性。 '--'代表导线。
//!
//! \逐字记录
//! CANH---+--- +--CANH
//! ||
//! .. ..
//! || 120欧姆|| 120欧姆
//! |||||
//! '-'-'
//! ||
//! CANL---------------- +--CANL
//! \n 逐字记录
//!
//! 软件设置:
//!
//! 设置硬件连接后、将两个板连接到计算机
//! 通过图形显示屏旁边的在线调试接口 USB 端口。
//! 将一个 UART 终端连接到每块配置为115、200波特、8-n-1模式的电路板。
//!
//! 您在一个终端中键入的任何内容都将显示在另一个终端和中
//! 反之亦然。 发送/接收的最后一个字符也将显示在上
//! 板上的图形显示。
//
//
//
//
//跟踪 TX 和 RX 中断次数的计数器
//发生,它应与传输的消息数相匹配/
//已收到。
//
//
volatile uint32_t g_ui32RXMsgCount = 0;
volatile uint32_t g_ui32TXMsgCount = 0;
//
//
//中断处理程序指示已接收消息的标志。
//
//
volatile bool g_BRXFlag = 0;
//
//
//一个全局变量,用于跟踪已抛出的错误标志,以便它们可以被抛出
//进行处理。 这是必要的、因为读取错误寄存器会被清除
//标记,因此有必要将它们保存在某个位置进行处理。
//
//
volatile uint32_t g_ui32ErrFlag = 0;
//
//
//针对正在发送/接收的数据的 CAN 消息对象
//
//
tCANMsgObject g_sCAN1RxMessage;
tCANMsgObject g_sCAN1TxMessage;
//
//
//消息标识符和对象
// RXID 设为0,以便接收所有消息
//
//
#define CAN1RXID 0
#define RXOBJECT 1
#define CAN1TXID 2.
#define TXOBJECT 2.
//
//
//保存发送字符的变量/检索
//
//
uint8_t g_ui8TXMsgData;
uint8_t g_ui8RXMsgData;
//
//
//图形显示上打印的文本的全局上下文
//
//
tContext g_sContext;
//
//
//驱动程序库遇到错误时调用的错误例程。
//
//
#ifdef 调试
无效
_error__(char * pcFilename、uint32_t ui32Line)
{
}
#endif
//
//
// CAN 0中断处理程序。 它会检查中断的原因、和
//保留已发送/接收的所有消息的计数
//
//
无效
CAN1IntHandler (空)
{
uint32_t ui32Status;
//
//读取 CAN 中断状态以查找中断原因
//
// CAN_INT_STS_Cause 寄存器值
// 0x0000 =无中断挂起
// 0x0001-0x0020 =导致中断的报文对象数
// 0x8000 =状态中断
//所有其它数字都是保留的,在本系统中没有意义
//
ui32Status = CANIntStatus (CAN1_base、CAN_INT_STS_CAUST);
//
//如果这是一个状态中断、则通过读取 CAN 来确认它
//控制器状态寄存器。
//
if (ui32Status = CAN_INT_INTID_STATUS)
{
//
//读取控制器状态。 这将返回状态字段
//可以指示各种错误的错误位。 请参阅
// API 文档,了解有关错误状态位的详细信息。
//读取此状态的操作将清除中断。
//
ui32Status = CANStatusGet (CAN1_base、CAN_STS_CONTROL);
//
//将错误标志添加到当前错误列表中。 要处理的数据
//因为在中需要太多的时间
//中断。
//
G_ui32ErrFlag |= ui32Status;
}
//
//检查原因是否是我们正在使用的消息对象 RXOBJECT
//用于接收消息。
//
否则、IF (ui32Status = RXOBJECT)
{
//
//到达这一点意味着 RX 中断发生在上
//消息对象 RXOBJECT、消息接收完成。
//清除报文对象中断。
//
CANIntClear (CAN1_BASE、RXOBJECT);
//
//递增计数器以跟踪已有多少消息
//已收到。 在实际应用中、这可用于将标志设置为
//指示何时接收到消息。
//
G_ui32RXMsgCount++;
//
//设置标志以指示接收到的消息正暂挂。
//
G_bRXFlag = true;
//
//由于接收到消息,因此清除所有错误标志。
//这是因为在收到消息之前它会触发
// RX 完成的状态中断。 通过清除这里的标志、我们可以看到
//防止发生不必要的错误处理
//
G_ui32勘误标志= 0;
}
//
//检查原因是否是我们正在使用的消息对象 TXOBJECT
//用于传输消息。
//
否则、如果(ui32Status = TXOBJECT)
{
//
//到达这一点意味着 TX 中断发生在上
//消息对象 TXOBJECT、消息接收完成。
//清除报文对象中断。
//
CANIntClear (CAN1_BASE、TXOBJECT);
//
//递增计数器以跟踪已有多少消息
//已发送。 在实际应用中、可以使用此设置
//指示消息何时传输的标志。
//
G_ui32TXMsgCount++;
//
//由于已发送消息,因此清除所有错误标志。
//这是因为在发送消息之前它会触发
// TX 完成的状态中断。 通过清除这里的标志、我们可以看到
//防止发生不必要的错误处理
//
G_ui32勘误标志= 0;
}
//
//否则,发生意外导致中断的情况。 这应该是
//永远不会发生。
//
其他
{
//
//可以在此处执行伪中断处理。
//
}
}
//
//
//配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。
//
//
无效
配置 UART (空)
{
// Uart0
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
UARTConfigSetExpClk (UART0_BASE、120000000、115200、
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));
UARTFIFODisable (UART0_BASE);
UARTEnable (UART0_BASE);
}
//
//
//将 CAN1设置为以500kHz 的频率发送和接收。
//中断打开
//使用 PE4/PE5
//
//
无效
InitCAN1 (空)
{
//
//对于此示例、CAN1与端口 E4和 E5上的 RX 和 TX 引脚一起使用。
//需要启用 GPIO 端口 E,以便可以使用这些引脚。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOB));
//
//配置 GPIO 引脚复用以选择这些引脚的 CAN1功能。
//此步骤选择可用于这些引脚的替代功能。
//
GPIOPinConfigure (GPIO_PB0_CAN1RX);
GPIOPinConfigure (GPIO_PB1_CAN1TX);
//
//启用 GPIO 引脚上的复用功能。 以上步骤选择
//可用的备用功能。 此步骤实际上启用
//这些引脚的替代功能、而不是 GPIO。
//
GPIOPinTypeCAN (GPIO_PORTB_BASE、GPIO_PIN_0 | GPIO_PIN_1);
//
//已为 CAN 设置 GPIO 端口和引脚。 CAN 外设
//必须启用。
//
SysCtlPeripheralEnable (SYSCTL_Periph_CAN1);
while (!SysCtlPeripheralReady (SYSCTL_Periph_CAN1));
//
//初始化 CAN 控制器
//
CANInit (CAN1_base);
//
//设置 CAN 总线的比特率。 此函数设置 CAN
针对标称配置的//总线时序。 您可以实现更多控制
//使用函数 CANBitTimingSet()代替 CAN 总线时序
//如果需要。
//在此示例中、CAN 总线设置为500kHz。
//
CANBitRateSet (CAN1_base、120000000、50000);
//
//在 CAN 外设上启用中断。 此示例使用静态
//分配中断处理程序,表示处理程序的名称
//位于启动代码的矢量表中。
//
CANIntRegister (CAN1_base、CAN1IntHandler);
CANIntEnable (CAN1_base、CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
//
//在处理器(NVIC)上启用 CAN 中断。
//
IntEnable (INT_CAN1);
//
//启用 CAN 以进行操作。
//
CANEnable (CAN1_base);
//
//初始化用于接收 CAN 消息的消息对象
//任何 CAN ID。 为了接收任何 CAN ID、ID 和掩码必须同时存在
//设置为0,并启用 ID 过滤器。
//
G_sCAN1RxMessage.ui32MsgID = CAN1RXID;
G_sCAN1RxMessage.ui32MsgIDMask = 0;
G_sCAN1RxMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER;
G_sCAN1RxMessage.ui32MsgLen = sizeof (g_ui8RXMsgData);
//
//现在将消息对象加载到 CAN 外设中。 加载后
// CAN 将在总线上接收任何消息,并将发生中断。
//使用消息对象 RXOBJECT 接收消息(这不是
//与 CAN ID 相同,在本例中可以是任何值)。
//
CANMessageSet (CAN1_base、RXOBJECT、&g_sCAN1RxMessage、MSG_OBJ_TYPE_RX);
//
//初始化将用于发送 CAN 的消息对象
//消息。 消息将是包含字符的1个字节
//从另一个控制器接收。 最初它将设置为0。
//
G_ui8TXMsgData = 0;
G_sCAN1TxMessage.ui32MsgID = CAN1TXID;
G_sCAN1TxMessage.ui32MsgIDMask = 0;
G_sCAN1TxMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
G_sCAN1TxMessage.ui32MsgLen = sizeof (g_ui8TXMsgData);
G_sCAN1TxMessage.pui8MsgData =(uint8_t *)&g_ui8TXMsgData;
}
//
//
// CAN 错误处理。 如果存在错误、则在收到消息时
//保存到 g_ui32ErrFlag、错误标志集。 将检查标志下方的内容
//并被清除。 如果是、则由用户来添加处理概念
//需要。
//
//有关错误标志的更多信息,请参阅的 CAN 部分
//微控制器数据表。
//
//注:只有一个板通电时,您可能会在设置过程中遇到错误
//打开。 这是由一个板发送信号而不是另一个板引起的
//板到那里以确认它。 不用担心这些错误、它们可能会是这样
//不予考虑。
//
//
无效
CANErrorHandler (空)
{
//
// CAN 控制器已进入总线关闭状态。
//
if (g_ui32勘误标志和 CAN_STATUS_BUS_OFF)
{
//
//此处处理错误条件
//
// UARTprintf ("错误:CAN_STATUS_BUS_OFF \n");
Debug_UART ("错误:CAN_STATUS_BUS_OFF \n"、strlen ("错误:CAN_STATUS_BUS_OFF \n");
//
//清除 CAN_STATUS_BUS_OFF 标志
//
G_ui32ErrFlag &=~(CAN_STATUS_BUS_OFF);
}
//
// CAN 控制器错误级别已达到警告级别。
//
if (g_ui32勘误表和 CAN_STATUS_EWARN)
{
//
//此处处理错误条件
//
//UARTprintf ("错误:CAN_STATUS_EWARN \n");
Debug_UART ("错误:CAN_STATUS_EWARN \n"、strlen ("错误:CAN_STATUS_EWARN \n");
//
//清除 CAN_STATUS_EWARN 标志
//
G_ui32勘误表&=~(CAN_STATUS_EWARN);
}
//
// CAN 控制器错误级别已达到错误被动级别。
//
if (g_ui32勘误标志和 CAN_STATUS_EPASS)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_EPASS 标志
//
G_ui32勘误表&=~(CAN_STATUS_EPASS);
}
//
//自上次读取此状态以来,已成功接收到消息。
//
if (g_ui32勘误标志和 CAN_STATUS_RXOK)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_RXOK 标志
//
G_ui32勘误表&=~(CAN_STATUS_RXOK);
}
//
//自上次读取此消息以来,已成功发送消息
//状态。
//
if (g_ui32勘误标志和 CAN_STATUS_TXOK)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_TXOK 标志
//
G_ui32勘误表&=~(CAN_STATUS_TXOK);
}
//
//这是最后一个错误代码字段的掩码。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_MSK)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_MSK 标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_MSK);
}
//
//发生了位填充错误。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_SALES)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_填 充标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_SALES);
}
//
//发生格式错误。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_FORM)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_FORM 标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_FORM);
}
//
//发生了确认错误。
//
if (g_ui32勘误标志和 CAN_STATUS_LEC_ACK)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_ACK 标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_ACK);
}
//
//总线保持1的位电平的时间比允许的时间长。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_BIT1)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_BIT1标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_BIT1);
}
//
//总线保持为0的位电平的时间比允许的时间长。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_BIT0)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_BIT0标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_BIT0);
}
//
//发生了 CRC 错误。
//
if (g_ui32勘误表和 CAN_STATUS_LEC_CRC)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_CRC 标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_CRC);
}
//
//这是 CAN 最后一个错误代码(LEC)的掩码。
//
if (g_ui32勘误标志和 CAN_STATUS_LEC_MASK)
{
//
//此处处理错误条件
//
//
//清除 CAN_STATUS_LEC_MASK 标志
//
G_ui32勘误表&=~(CAN_STATUS_LEC_MASK);
}
//
//如果 g_ui32ErrFlag 中仍有任何位被置位,则表示未处理
//已经发生。 打印 g_ui32ErrFlag 的值。
//
if (g_ui32勘误标志!=0)
{
// UARTprintf ("未处理的错误:%x \n"、g_ui32ErrFlag);
Debug_UART ("未处理错误:%x \n"、strlen ("未处理错误:%x \n"));
}
}
void debug_UART (char * p、uint16_t length)
{
uint16_t x = 0;
while (x < length)
{
while (UARTBusy (UART0_BASE));
UARTCharPutNonBlocking (UART0_BASE、*);
P++;
X++;
}
}
void sendCharUart0 (unsigned char _c)
{
while (UARTBusy (UART0_BASE));
UARTCharPutNonBlocking (UART0_BASE、_c);
}
//
//
//设置系统,初始化 UART、图形和 CAN。 然后轮询
//用于数据的 UART。 如果有任何数据发送、如果接收到任何数据
//将其打印到 UART。 如果有错误、请调用错误处理
//函数。
//
//
内部
main (空)
{
//
//为中断处理程序启用怠惰堆栈。 这允许使用浮点
//在中断处理程序中使用的指令,但代价是
//额外的堆栈用法。
//
ROM_FPULazyStackingEnable();
//
//将时钟设置为直接从晶体运行。
//
uint32_t freq = SysCtlClockFreqSet (
(SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480)、120000000);
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
SysCtlPeripheralEnable (SYSCTL_Periph_UART3);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);
while (!SysCtlPeripheralReady (SYSCTL_Periph_UART3));
while (!SysCtlPeripheralReady (SYSCTL_Periph_UART0));
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOA));
while (!SysCtlPeripheralReady (SYSCTL_Periph_GPIOD));
GPIOPinTypeGPIOOutput (GPIO_PORTD_base、GPIO_PIN_6);
GPIOPinWrite (GPIO_PORTD_BASE、GPIO_PIN_6、0);
//初始化 UART
ConfigureUART();
//初始化 CAN1
InitCAN1();
//打印欢迎消息
// UARTprintf ("\n 可示例应用\n"\n);
// UARTprintf ("键入可在另一个终端上显示的内容:\n\n");
debug_uart ("\ncan example app\n"、strlen ("\n can example app\n");
Debug_UART ("键入要在另一个终端上显示的内容:\n"strlen ("键入要在另一个终端上显示的内容:\n\n");
//轮询 UART 数据,输入内容后跨 CAN 发送
while (1)
{
//如果该标志被置位、则表示发生了 RX 中断、然后
//有一条消息可以从 CAN 读取
if (g_bRXFlag)
{
//
//重复使用之前用于配置的同一消息对象
//用于接收消息的 CAN。 用于存储的缓冲器
//还必须提供接收到的数据,所以设置缓冲区指针
//在消息对象中。
//
G_sCAN1RxMessage.pui8MsgData =(uint8_t *)&g_ui8RXMsgData;
//
//从 CAN 读取消息。 使用报文对象 RXOBJECT
//(与 CAN ID 不相同)。 中断清除
//标志未设置、因为中已清除此中断
//中断处理程序。
//
CANMessageGet (CAN1_base、RXOBJECT、&g_sCAN1RxMessage、0);
//
//清除挂起的消息标志,以便中断处理程序可以
//在下一条消息到达时再次设置它。
//
G_bRXFlag = 0;
//
//检查是否有某些消息的指示
//丢失。
//
if (g_sCAN1RxMessage.ui32Flags & MSG_OBJ_DATA_LOST)
{
// UARTprintf ("\n 检测到消息丢失\n"CAN);
DEBUG_UART ("\n 检测到消息丢失\n"、
strlen("\n 检测到信息丢失\n");
}
//将接收到的字符打印到 UART 终端
// UARTprintf ("%c"、g_ui8RXMsgData);
sendCharUart0 (g_ui8RXMsgData);
//
//将接收到的字符打印到显示屏上,
//用空格清除行
//
}
其他
{
//
//错误处理
//
if (g_ui32勘误标志!= 0)
{
CANErrorHandler();
}
//
//查看是否有要传输的新内容
//
while (UARTCharsAvail (UART0_BASE))
{
//
//从 UART 终端读取下一个字符
//
G_ui8TXMsgData = UARTCharGetNonBlocking (UART0_BASE);
//使用对象编号 TXOBJECT (不是)发送 CAN 消息
//与 CAN ID 相同、在这里也是 TXOBJECT
//示例)。 此函数将导致消息为
//立即传输。
CANMessageSet (CAN1_base、TXOBJECT、&g_sCAN1TxMessage、
MSG_OBJ_TYPE_TX);
}
}
}
}
有没有人知道会发生什么错误?
