主题中讨论的其他器件:DK-TM4C123G、 EK-TM4C123GXL、 SN65HVD230
工具/软件:Code Composer Studio
我尝试运行以下代码以进行简单的 CAN 通信、如示例中所示。
每次我按下键盘上的某个键以将该键发送到另一个主板时、CANIFnDAn 寄存器中的值都会根据 ASCII 值发生变化
相应的按键。
这些是我面临的以下问题。
CANNWDAN 寄存器中相应报文位的 NEWDAT 位即使是数据也不会改变
每次按键时、CANIFnDAN 寄存器中的值都会发生变化。
CANSTS 寄存器中的 TXOk 位不变。
我需要有关错误原因或缺少任何步骤的建议
// // // CAN.c -简单的 CAN 示例。 // //版权所有(c) 2013-2016 Texas Instruments Incorporated。 保留所有权利。 //软件许可协议 // //德州仪器(TI)提供此软件仅供 和//仅供 TI 的微控制器产品使用。 软件归 // TI 和/或其供应商所有,并受适用的版权 //法律保护。 您不能将此软件与"病毒"开源 //软件组合在一起以形成更大的程序。 // //此软件按“原样”提供,且存在所有故障。 //对于 本软件,不作任何明示、暗示或法定的保证,包括但不限于对适销性和适用性的暗示保证//特定用途。 在任何 //情况下、TI 不对任何 原因造成的特殊、意外或必然//损害负责。 // //这是 DK-TM4C123G 固件包的版本2.1.3.156的一部分。 //// ***************** #include #include #include "inc/hw_ca.h" #include "include/hw_ints.h" #include "inc/hw_memmap.h" #include "driverlib/fpu.h" #include "driverlib/ca.h" #include "driverlib/pin_map.h" #include "driverlib/drivers.mdio.h"#include "drivers/drivers.mdio.mdio.h"#include "#include "#drivers.status./drivers.mdio.status.mdio.h"#include "#include "#include "#include "#include "#driverlib // //! \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 //! \end逐 字记录 //! //! 软件设置: //! //! 设置硬件连接后、将两个板连接到计算机 //! 通过图形显示屏旁边的在线调试接口 USB 端口。 //! 将一个 UART 终端连接到每块配置为115、200波特、8-n-1模式的电路板。 //! //! 您键入一个终端的任何内容都将显示在另一个终端和 //! 反之亦然。 发送/接收的最后一个字符也将显示在 //! 板上的图形显示。 //// ***************** // // //跟踪 TX & RX 中断次数 的计数器//发生,该计数器应与发送的消息数匹 配//接收的消息数匹配。 //// ***************** 易失性 uint32_t g_ui32RXMsgCount = 0; 易失性 uint32_t g_ui32TXMsgCount = 0; //********* // //中断处理程序的标志,指示已收到消息。 //// ***************** 易失性 bool g_BRXFlag = 0; //********* // //一个全局变量,用于跟踪已抛出的错误标志,以便 可以//进行处理。 这是必要 的、因为读取错误寄存器会清除//标志、所以有必要将它们保存在某个位置进行处理。 //// ***************** volatile uint32_t g_ui32 ErrFlag = 0; //********* // //正在发送/接收的数据的 CAN 消息对象 // tCANMsgObject g_sCAN0RxMessage; tCANMsgObject g_sCAN0TxMessage; //********* // //消息标识符和对象 // RXID 设置为0,因此接收所有消息 // ********* #define CAN0RXID 0 #define RXOBJECT 1 #define CAN0TXID 2 #define TXOBJECT 2 //********* // //保存字符的变量被发送/接收 // //************* uint8_t g_ui8TXMsgData; uint8_t g_ui8RXMsgData; //********* // //图形显示上打印的文本的全局上下文 // //********* tContext g_sContext; //********* // //屏幕行显示,以像素为单位的顶部偏移 // //********* #define SCREENLINE1 10 #define SCREENLINE2 20 #define SCREENLINE3 30 #define SCREENLINE4 40 #define SCREENLINE5 50 //********* // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // // CAN 0中断处理程序。 它检查中断原因、 并且//保持已发送/接收 的所有消息的计数// ********* void CAN0IntHandler (void) { uint32_t ui32Status; // //读取 CAN 中断状态以查找中断原因 // // CAN_INT_STS_Cause 寄存器值 // 0x0000 =无中断挂起 // 0x0001-0x0020 =导致中断的报文对象数 // 0x8000 =状态中断 //所有其它数字都是保留的,在本系统中没有意义 // ui32Status = CANIntStatus (CAN0_BASE、CAN_INT_STS_CAUST); // //如果这是一个状态中断、则通过读取 CAN 来确认它 //控制器状态寄存器。 // if (ui32Status = CAN_INT_INTID_STATUS) { // //读取控制器状态。 这将返回状态字段 //可以指示各种错误的错误位。 请参阅 // API 文档,了解有关错误状态位的详细信息。 //读取此状态的操作将清除中断。 // ui32Status = CANStatusGet (CAN0_BASE、CAN_STS_CONTROL); // //将错误标志添加到当前错误列表中。 要处理的数据 //因为在中需要太多的时间 //中断。 // G_ui32ErrFlag |= ui32Status; } // //检查原因是否是我们正在使用的消息对象 RXOBJECT //用于接收消息。 // 否则、IF (ui32Status = RXOBJECT) { // //到达这一点意味着 RX 中断发生在上 //消息对象 RXOBJECT、消息接收完成。 //清除报文对象中断。 // CANIntClear (CAN0_BASE、RXOBJECT); // //递增计数器以跟踪已有多少消息 //已收到。 在实际应用中、这可用于将标志设置为 //指示何时接收到消息。 // G_ui32RXMsgCount++; // //设置标志以指示接收到的消息正暂挂。 // G_bRXFlag = true; // //由于接收到消息,因此清除所有错误标志。 //这是因为在收到消息之前它会触发 // RX 完成的状态中断。 通过清除这里的标志、我们可以看到 //防止发生不必要的错误处理 // G_ui32ErrFlag = 0; } // //检查原因是否是我们正在使用的消息对象 TXOBJECT //用于传输消息。 // 否则、如果(ui32Status = TXOBJECT) { // //到达这一点意味着 TX 中断发生在上 //消息对象 TXOBJECT、消息接收完成。 //清除报文对象中断。 // CANIntClear (CAN0_BASE、TXOBJECT); // //递增计数器以跟踪已有多少消息 //已发送。 在实际应用中、可以使用此设置 //指示消息何时传输的标志。 // G_ui32TXMsgCount++; // //由于已发送消息,因此清除所有错误标志。 //这是因为在发送消息之前它会触发 // TX 完成的状态中断。 通过清除这里的标志、我们可以看到 //防止发生不必要的错误处理 // G_ui32ErrFlag = 0; } // //否则,发生意外导致中断的情况。 这应该是 //永远不会发生。 // 其他 { // //可以在此处执行伪中断处理。 // } } //********* // //配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 //// ***************** void ConfigureUART (void) { // //启用 UART 使用的 GPIO 外设。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //启用 UART0 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UART0); // //为 UART 模式配置 GPIO 引脚。 // ROM_GPIOPinConfigure (GPIO_PA0_U0RX); ROM_GPIOPinConfigure (GPIO_PA1_U0TX); ROM_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //使用内部16MHz 振荡器作为 UART 时钟源。 // UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、16000000); } //********* // //将 CAN0设置为以500kHz 的频率发送和接收。 //中断// 使用 PE4/PE5 // //********* 空 InitCAN0 (空) { // //对于此示例、CAN0与端口 E4和 E5上的 RX 和 TX 引脚搭配使用。 //需要启用 GPIO 端口 E,以便可以使用这些引脚。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB); // //配置 GPIO 引脚复用以选择这些引脚的 CAN0功能。 //此步骤选择可用于这些引脚的替代功能。 // GPIOPinConfigure (GPIO_PB4_CAN0RX); GPIOPinConfigure (GPIO_PB5_CAN0TX); // //启用 GPIO 引脚上的复用功能。 以上步骤选择 //可用的备用功能。 此步骤实际上启用 //这些引脚的替代功能、而不是 GPIO。 // GPIOPinTypeCAN (GPIO_PORTB_BASE、GPIO_PIN_4 | GPIO_PIN_5); // //已为 CAN 设置 GPIO 端口和引脚。 CAN 外设 //必须启用。 // SysCtlPeripheralEnable (SYSCTL_Periph_CAN0); // //初始化 CAN 控制器 // CANInit (CAN0_BASE); // //设置 CAN 总线的比特率。 此函数设置 CAN 针对标称配置的//总线时序。 您可以实现更多控制 //使用函数 CANBitTimingSet()代替 CAN 总线时序 //如果需要。 //在此示例中、CAN 总线设置为500kHz。 // CANBitRateSet (CAN0_BASE、SysCtlClockGet ()、50000); // //在 CAN 外设上启用中断。 此示例使用静态 //分配中断处理程序,表示处理程序的名称 //位于启动代码的矢量表中。 // CANIntEnable (CAN0_BASE、CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS); // //在处理器(NVIC)上启用 CAN 中断。 // IntEnable (INT_CAN0); // //启用 CAN 以进行操作。 // CANEnable (CAN0_BASE); // //初始化用于接收 CAN 消息的消息对象 //任何 CAN ID。 为了接收任何 CAN ID、ID 和掩码必须同时存在 //设置为0,并启用 ID 过滤器。 // G_sCAN0RxMessage.ui32MsgID = CAN0RXID; G_sCAN0RxMessage.ui32MsgIDMask = 0; G_sCAN0RxMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER; G_sCAN0RxMessage.ui32MsgLen = sizeof (g_ui8RXMsgData); // //现在将消息对象加载到 CAN 外设中。 加载后 // CAN 将在总线上接收任何消息,并将发生中断。 //使用消息对象 RXOBJECT 接收消息(这不是 //与 CAN ID 相同,在本例中可以是任何值)。 // CANMessageSet (CAN0_BASE、RXOBJECT、&g_sCAN0RxMessage、MSG_OBJ_TYPE_RX); // //初始化将用于发送 CAN 的消息对象 //消息。 消息将是包含字符的1个字节 //从另一个控制器接收。 最初它将设置为0。 // G_ui8TXMsgData = 0; G_sCAN0TxMessage.ui32MsgID = CAN0TXID; G_sCAN0TxMessage.ui32MsgIDMask = 0; G_sCAN0TxMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE; G_sCAN0TxMessage.ui32MsgLen = sizeof (g_ui8TXMsgData); G_sCAN0TxMessage.pui8MsgData =(uint8_t *)&g_ui8TXMsgData; } //********* // //设置 OLED 图形显示 // //********* void InitGraphics (void) { tRectangle sRect; // //初始化显示驱动程序。 // CFAL96x64x16Init(); // //初始化图形上下文。 // GrContextInit (&g_sContext、&g_sCFAL96x64x16); // //用蓝色填充屏幕的前24行以创建横幅。 // sRect.i16XMin = 0; sRect.i16YMin = 0; sRect.i16XMax = GrContextDpyWidthGet (&g_sContext)- 1; sRect.i16YMax = 9; GrContextForegroundSet (&g_sContext、ClrDarkBlue); GrRectFill (&g_sContext、&sRect); // //在横幅周围放置一个白色框。 // GrContextForegroundSet (&g_sContext、ClrWhite); GrRectDraw (&g_sContext、&sRect); // //将应用程序名称放在横幅中间。 // GrContextFontSet (&g_sContext、g_psFontFixed6x8); GrStringDrawCenter(&g_sContext,"CAN Example",-1, GrContextDpyWidthGet (&g_sContext)/ 2、4、0); // //刷新任何缓存的绘图操作。 // GrFlush (&G); } //********* // // CAN 错误处理。 当收到消息时、如果存在错误、 则//将其保存到 g_ui32ErrFlag 中、错误标志置1。 标志下方被选中 //并被清除。 如果需要的话 、由用户来添加处理功能//。 // //有关错误标志的更多信息、请参阅 //微控制器数据表的 CAN 部分。 // //注:只有一个板通电 时,您在设置过程中可能会遇到错误//打开。 这是由一个板发送信号而 没有另一个//板来确认的。 不要担心这些错误、 它们可以被//忽略。 //// ***************** void CANErrorHandler (void) { // // CAN 控制器已进入总线关闭状态。 // if (g_ui32勘误标志和 CAN_STATUS_BUS_OFF) { // //此处处理错误条件 // UARTprintf ("错误: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"); // //清除 CAN_STATUS_EWARN 标志 // G_ui32ErrFlag &=~(CAN_STATUS_EWARN); } // // CAN 控制器错误级别已达到错误被动级别。 // if (g_ui32勘误标志和 CAN_STATUS_EPASS) { // //此处处理错误条件 // // //清除 CAN_STATUS_EPASS 标志 // G_ui32ErrFlag &=~(CAN_STATUS_EPASS); } // //自上次读取此状态以来,已成功接收到消息。 // if (g_ui32勘误标志和 CAN_STATUS_RXOK) { // //此处处理错误条件 // // //清除 CAN_STATUS_RXOK 标志 // G_ui32ErrFlag &=~(CAN_STATUS_RXOK); } // //自上次读取此消息以来,已成功发送消息 //状态。 // if (g_ui32勘误标志和 CAN_STATUS_TXOK) { // //此处处理错误条件 // // //清除 CAN_STATUS_TXOK 标志 // G_ui32ErrFlag &=~(CAN_STATUS_TXOK); } // //这是最后一个错误代码字段的掩码。 // if (g_ui32勘误表和 CAN_STATUS_LEC_MSK) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_MSK 标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_MSK); } // //发生了位填充错误。 // if (g_ui32勘误表和 CAN_STATUS_LEC_SALES) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_填 充标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_SALES); } // //发生格式错误。 // if (g_ui32勘误表和 CAN_STATUS_LEC_FORM) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_FORM 标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_FORM); } // //发生了确认错误。 // if (g_ui32勘误标志和 CAN_STATUS_LEC_ACK) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_ACK 标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_ACK); } // //总线保持1的位电平的时间比允许的时间长。 // if (g_ui32勘误表和 CAN_STATUS_LEC_BIT1) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_BIT1标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_BIT1); } // //总线保持为0的位电平的时间比允许的时间长。 // if (g_ui32勘误表和 CAN_STATUS_LEC_BIT0) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_BIT0标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_BIT0); } // //发生了 CRC 错误。 // if (g_ui32勘误表和 CAN_STATUS_LEC_CRC) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_CRC 标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_CRC); } // //这是 CAN 最后一个错误代码(LEC)的掩码。 // if (g_ui32勘误标志和 CAN_STATUS_LEC_MASK) { // //此处处理错误条件 // // //清除 CAN_STATUS_LEC_MASK 标志 // G_ui32ErrFlag &=~(CAN_STATUS_LEC_MASK); } // //如果 g_ui32ErrFlag 中仍有任何位被置位,则表示未处理 //已经发生。 打印 g_ui32ErrFlag 的值。 // if (g_ui32勘误标志!=0) { UARTprintf ("未处理错误:%x \n"、g_ui32ErrFlag); } } //********* // //设置系统,初始化 UART、图形和 CAN。 然后轮询 // UART 以获取数据。 如果有任何数据发送、如果接收到任何数据 //将其打印到 UART。 如果出现错误、请调用错误处理 //函数。 //// ***************** int main (void) { // //为中断处理程序启用怠惰堆栈。 这允许使用浮点 //在中断处理程序中使用的指令,但代价是 //额外的堆栈用法。 // ROM_FPULazyStackingEnable(); // //将时钟设置为直接从晶体运行。 // ROM_SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz | SYSCTL_OSC_MAIN); // //初始化 UART // ConfigureUART(); // //初始化 CAN0 // InitCAN0(); // //打印欢迎消息 // UARTprintf ("\nCAN 示例应用\n"); UARTprintf ("键入要在另一个终端上显示的内容:\n\n"); // //轮询 UART 数据,输入内容后跨 CAN 发送 // while (1) { // //如果该标志被置位、则表示发生了 RX 中断、然后 //有一条消息可以从 CAN 读取 // if (g_bRXFlag) { // //重复使用之前用于配置的同一消息对象 //用于接收消息的 CAN。 用于存储的缓冲器 //还必须提供接收到的数据,所以设置缓冲区指针 //在消息对象中。 // G_sCAN0RxMessage.pui8MsgData =(uint8_t *)&g_ui8RXMsgData; // //从 CAN 读取消息。 使用报文对象 RXOBJECT //(与 CAN ID 不相同)。 中断清除 //标志未设置、因为中已清除此中断 //中断处理程序。 // CANMessageGet (CAN0_BASE、RXOBJECT、&g_sCAN0RxMessage、0); // //清除挂起的消息标志,以便中断处理程序可以 //在下一条消息到达时再次设置它。 // G_bRXFlag = 0; // //检查是否有某些消息的指示 //丢失。 // if (g_sCAN0RxMessage.ui32Flags & MSG_OBJ_DATA_LOST) { UARTprintf ("\n 检测到消息丢失\n"\n); } // //将接收到的字符打印到 UART 终端 // UARTprintf ("%c"、g_ui8RXMsgData); } 其他 { // //错误处理 // if (g_ui32勘误标志!= 0) { CANErrorHandler(); } // //查看是否有要传输的新内容 // while (ROM_UARTCharsAvail (UART0_BASE)) { // //从 UART 终端读取下一个字符 // G_ui8TXMsgData = ROM_UARTCharGetNonBlocking (UART0_BASE); // //使用对象编号 TXOBJECT (不是)发送 CAN 消息 //与 CAN ID 相同、在这里也是 TXOBJECT //示例)。 此函数将导致消息为 //立即传输。 // CANMessageSet (CAN0_BASE、TXOBJECT、&g_sCAN0TxMessage、 MSG_OBJ_TYPE_TX); } } }