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.

[参考译文] CCS/EK-TM4C129EXL:默认定时器.c 不能按预期工作

Guru**** 2457760 points
Other Parts Discussed in Thread: EK-TM4C129EXL

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/646875/ccs-ek-tm4c129exl-default-timers-c-is-not-working-as-expected

器件型号:EK-TM4C129EXL

工具/软件:Code Composer Studio

大家好、

我的任务是编写一个基于计时器的中断代码(我是这个代码的初学者)。 至于开始、我尝试编译了 TI 为 TM4C129exl 提供的 timers.c 代码。

但是、似乎没有触发计时器 IntHandlers (添加了几条 printf 线对此进行调试)。  我想知道我是否需要为此进行任何跳线设置或返工(我的跳线处于默认设置)。

已连接终端输出和代码:

//
//
// timers.c -计时器示例。
//
//版权所有(c) 2013-2017 Texas Instruments Incorporated。 保留所有权利。
//软件许可协议
//
//德州仪器(TI)提供此软件仅供
和//仅供 TI 的微控制器产品使用。 软件归
// TI 和/或其供应商所有,并受适用的版权
//法律保护。 您不能将此软件与"病毒"开源
//软件组合在一起以形成更大的程序。
//
//此软件按“原样”提供,且存在所有故障。
//对于

本软件,不作任何明示、暗示或法定的保证,包括但不限于对适销性和适用性的暗示保证//特定用途。 在任何
//情况下、TI 不对任何
原因造成的特殊、意外或必然//损害负责。
//
//这是 EK-TM4C129EXL 固件包的版本2.1.4.178的一部分。
////
*****************

#include 
#include 
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"#include
"driverlib/interrupt.h"
#include "driverlib/driverlib.rom"


#include "driverlib/driverlib"#driverlib.driver.h"#include"#driverlib/driverlib.driverlib#driverlib.driverlib.driver.h





//
//! \addtogroup example_list
//! 

计时器(计时器)

//! //! 此示例应用演示了如何使用计时器来生成 //! 周期性中断。 一个计时器设置为每秒中断一次和 //! 另一个中断每秒中断两次;每个中断处理程序将切换 //! 它自己的指示器通过 UART。 //! //! UART0、连接到虚拟串行端口、运行速度为115、200、8-N-1、 //! 用于显示来自此应用程序的消息。 //// ***************** // // ////系统时钟速率,单位为 Hz。 //// ************* uint32_t g_ui32SysClock; //********* // //包含 UART 上显示的中断指示符当前值的标志//。 //// ***************** uint32_t g_ui32Flags; //********* // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // //第一个定时器中断的中断处理程序。 //// ***************** void Timer0IntHandler (void) { UARTprintf ("调试:输入的 timer0\n"); char cone、cTwo; // //清除计时器中断。 // ROM_TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); // //切换第一个计时器的标志。 // HWREGBITW (&g_ui32Flags、0)^= 1; // //使用标志切换此计时器的 LED // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、g_ui32Flags); // //更新中断状态。 // ROM_IntMasterDisable(); Cone = HWREGBITW (&g_ui32Flags、0)? “1”:“0”; cTwo = HWREGBITW (&g_ui32Flags、1)? “1”:“0”; UARTprintf ("\RT1:%c T2:%c"、cone、cTwo); ROM_IntMasterEnable(); } //********* // //第二个计时器中断的中断处理程序。 //// ***************** void Timer1IntHandler (void) { UARTprintf ("调试:输入的 Timer1\n"); char cone、cTwo; // //清除计时器中断。 // ROM_TimerIntClear (Timer1_base、timer_TINA_TIMEOUT); // //切换第二个计时器的标志。 // HWREGBITW (&g_ui32Flags、1)^= 1; // //使用标志切换此计时器的 LED // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、g_ui32Flags); // //更新中断状态。 // ROM_IntMasterDisable(); Cone = HWREGBITW (&g_ui32Flags、0)? “1”:“0”; cTwo = HWREGBITW (&g_ui32Flags、1)? “1”:“0”; UARTprintf ("\RT1:%c T2:%c"、cone、cTwo); ROM_IntMasterEnable(); } //********* // //配置 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); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、g_ui32SysClock); } //************* // //此示例应用演示了如何使用计时器生成 //周期性中断。 //// ***************** int main (void) { // //将时钟设置为直接从频率为120MHz 的晶体运行。 // G_ui32SysClock = MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、120000000); // //初始化 UART 和写入状态。 // ConfigureUART(); UARTprintf ("\033[2JTimers 示例\n"); UARTprintf ("t1:0 t2:0"); // //启用用于板载 LED 的 GPIO 端口。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPION); // //为 LED (PN0和 PN1)启用 GPIO 引脚。 // ROM_GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_0 | GPIO_PIN_1); // //启用此示例使用的外设。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); ROM_SysCtlPeripheralEnable (SYSCTL_Periph_Timer1); // //启用处理器中断。 // ROM_IntMasterEnable(); // //配置两个32位周期定时器。 // ROM_TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE); ROM_TimerConfigure (Timer1_base、timer_CFG_PERIODICRACRACASE); ROM_TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32SysClock); ROM_TimerLoadSet (Timer1_base、timer_A、g_ui32SysClock / 2); // //设置计时器超时的中断。 // ROM_IntEnable (INT_TIMER0A); ROM_IntEnable (INT_TIMER1A); ROM_TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); ROM_TimerIntEnable (Timer1_base、timer_TINA_TIMEOUT); // //启用计时器。 // ROM_TimerEnable (TIMER0_BASE、TIMER_A); ROM_TimerEnable (Timer1_base、timer_A); // //在计时器运行时永久循环。 // while (1) { } }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我们不使用'129系列-您是否使用了:

    ROM_TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE);

    兼容您(以后)使用的:

    ROM_IntEnable (INT_TIMER0A);   另请注意、您已在计时器代码的其余部分中实现了这一"半计时器"目标!

    "TimerConfigure"不是针对"整个定时器"、而是针对"IntEnable"和所有其他定时器编码-目标(仅)半/子定时器?

    可以使用两个 TimerConfigure 函数将参数"TIMER_CFG_PERIODICRAC"更改为"TIMER_CFG_A_PERIODICRAR"、这样就可以解决您的问题!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我刚刚重试了计时器项目、并验证它在 EK-TM4C129EXL launchpad 上是否正常工作。 然后、我将我的 timers.c 文件替换为您发布的文件、它也正常工作。  只需仔细检查它是否不是编译的问题、您是否会对附加的.out 文件进行编程以查看它是否起作用?

    /cfs-file/__key/communityserver-discussions-components-files/908/timers.out

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Bob、

    您是否会对我的帖子(比您自己的帖子更早)进行审核-我认为、在这些帖子中发现并纠正了错误?

    作为"全宽定时器"的定时器配置(两个定时器)作为"半宽定时器!"的所有后续参考之间存在明显的"冲突"。     这是(不太可能)"正常/习惯"API 使用-是吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 CB1、

    在我的 LaunchPad 上、代码的工作方式与最初编写的代码相同、也可与您提供的校正配合使用。 正是这样、两个定义是相等的:

    #define TIMER_CFG_PERIODICRACRACe. 0x00000022 //全宽度周期计时
    器#define TIMER_CFG_A_PERIODICRACIODIE 0x00000022 // Timer A 周期性计时器
    

    也就是说、使用"TIMER_CFG_A_PERIODICRAR"会更清楚。 这是 TI 示例代码中的缺陷、而不是原始海报的故障。 这是一个很好的发现、但没有解释为什么示例不能在原始海报的 Launch Pad 上工作。 一如既往、感谢您的细心关注。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bob、(周五!)

    确实-你是对的-我不会期待这!

    在配置"B"半定时器时、这是否会导致"相同的宽松预期"?   在这种情况下、没有(幸运的)"保存定义重复"来拯救不谨慎的人!   它们会崩溃/烧坏!   因此(预期)"半定时器 A 和 B 之间的并行性"被(意外/不据称)违反!   这不是很好!

    作为一个长期用户(回到 LMI 天)、我检查了7到8年以前的 StellarisWare 版本-它们也是-完全定义的"CFG_PERIODICRACENT 和 CFG_A_PERIODICRACENT。"   因此-这不是"新到"的-虽然可以"原谅"不那么细心的用户"Timer-A"-但肯定会使" Timer_B"的无电用户陷入黑暗-不幸的是、这种定义的重复(甚至鼓励)提示了这种黑暗...

    感谢您在"挖掘"这一细节方面的帮助-并非所有"长期"工作都是非常细心的-我很难过地说、"证明"这一点...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Bob:

    一个问题、如何将二进制文件刻录到我的129exl 中。 对于 MSP430、我们可以使用 FET-Pro430实现此目的(请参阅 :www.youtube.com/watch。 是否有适用于129exl 的任何类似软件、或者我可以仅使用 CCS 轻松实现此目的(不编译我的当前代码、只将您的二进制文件刻录到 launchpad)。

    还随附了用于交叉检查的项目文件(我已将 timers.c 替换为 hello.c)。

    e2e.ti.com/.../5707.hello.7z

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    这可以通过 CCS 轻松实现。 连接到目标后、依次选择"Run"、"Load"和"Load Program"。 选择"Browse"并找到我发送的文件"timers.out"。 然后选择"OK"。 这应该会对我写入您的 LaunchPad 中的代码进行编程。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Bob 和 CB1_MOBILE、您好!

    我想现在我知道问题是什么。 似乎以前我没有在 startup_ccs.c 的矢量表中定义定时器处理程序 它现在照常工作。  在本机模式下、我们还可以使用计时器中断处理程序的静态分配、如下例所示。 也很有用。 非常感谢你们的帮助。 谢谢:)

    //
    //
    // timers.c -计时器示例。
    //
    //版权所有(c) 2013-2017 Texas Instruments Incorporated。 保留所有权利。
    //软件许可协议
    //
    //德州仪器(TI)提供此软件仅供
    和//仅供 TI 的微控制器产品使用。 软件归
    // TI 和/或其供应商所有,并受适用的版权
    //法律保护。 您不能将此软件与"病毒"开源
    //软件组合在一起以形成更大的程序。
    //
    //此软件按“原样”提供,且存在所有故障。
    //对于
    
    本软件,不作任何明示、暗示或法定的保证,包括但不限于对适销性和适用性的暗示保证//特定用途。 在任何
    //情况下、TI 不对任何
    原因造成的特殊、意外或必然//损害负责。
    //
    //这是 EK-TM4C129EXL 固件包的版本2.1.4.178的一部分。
    ////
    *****************
    
    #include 
    #include 
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"#include
    "driverlib/interrupt.h"
    #include "driverlib/driverlib.rom"
    
    
    #include "driverlib/driverlib"#driverlib.driver.h"#include"#driverlib/driverlib.driverlib#driverlib.driverlib.driver.h
    
    
    
    
    
    //
    //! \addtogroup example_list
    //! 

    计时器(计时器)

    //! //! 此示例应用演示了如何使用计时器来生成 //! 周期性中断。 一个计时器设置为每秒中断一次和 //! 另一个中断每秒中断两次;每个中断处理程序将切换 //! 它自己的指示器通过 UART。 //! //! UART0、连接到虚拟串行端口、运行速度为115、200、8-N-1、 //! 用于显示来自此应用程序的消息。 //// ***************** // // ////系统时钟速率,单位为 Hz。 //// ************* uint32_t g_ui32SysClock; //********* // //包含 UART 上显示的中断指示符当前值的标志//。 //// ***************** uint32_t g_ui32Flags; //********* // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // //第一个定时器中断的中断处理程序。 //// ***************** void Timer0IntHandler (void) { char cone、cTwo; // //清除计时器中断。 // TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); // //切换第一个计时器的标志。 // HWREGBITW (&g_ui32Flags、0)^= 1; // //使用标志切换此计时器的 LED // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、g_ui32Flags); // //更新中断状态。 // IntMasterDisable(); Cone = HWREGBITW (&g_ui32Flags、0)? “1”:“0”; cTwo = HWREGBITW (&g_ui32Flags、1)? “1”:“0”; UARTprintf ("\RT1:%c T2:%c"、cone、cTwo); IntMasterEnable(); }// ********* // //第二个计时器中断的中断处理程序。 //// ***************** void Timer1IntHandler (void) { char cone、cTwo; // //清除计时器中断。 // TimerIntClear (Timer1_base、timer_TINA_TIMEOUT); // //切换第二个计时器的标志。 // HWREGBITW (&g_ui32Flags、1)^= 1; // //使用标志切换此计时器的 LED // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_1、g_ui32Flags); // //更新中断状态。 // IntMasterDisable(); Cone = HWREGBITW (&g_ui32Flags、0)? “1”:“0”; cTwo = HWREGBITW (&g_ui32Flags、1)? “1”:“0”; UARTprintf ("\RT1:%c T2:%c"、cone、cTwo); IntMasterEnable(); }// ********* // //配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 //// ***************** void ConfigureUART (void) { // //启用 UART 使用的 GPIO 外设。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //启用 UART0。 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); // //为 UART 模式配置 GPIO 引脚。 // GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、g_ui32SysClock); } //************* // //此示例应用演示了如何使用计时器生成 //周期性中断。 //// ***************** int main (void) { // //将时钟设置为直接从频率为120MHz 的晶体运行。 // G_ui32SysClock = MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、120000000); // //初始化 UART 和写入状态。 // ConfigureUART(); UARTprintf ("\033[2JTimers 示例\n"); UARTprintf ("t1:0 t2:0"); // //启用用于板载 LED 的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPION); // //为 LED (PN0和 PN1)启用 GPIO 引脚。 // GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_0 | GPIO_PIN_1); // //启用此示例使用的外设。 // SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); SysCtlPeripheralEnable (SYSCTL_Periph_Timer1); // //启用处理器中断。 // IntMasterEnable(); // //配置两个32位周期定时器。 // TimerConfigure (TIMER0_BASE、TIMER_CFG_PERIODICASE); TimerConfigure (Timer1_base、timer_CFG_PERIODICRACRACASE); TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32SysClock); TimerLoadSet (Timer1_base、timer_A、g_ui32SysClock / 2); TimerIntRegister (TIMER0_BASE、TIMER_A、Timer0IntHandler);//--- TimerIntRegister (Timer1_base、timer_A、Timer1IntHandler);//--- // //设置计时器超时的中断。 // IntEnable (INT_TIMER0A); IntEnable (INT_TIMER1A); TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerIntEnable (Timer1_base、timer_TINA_TIMEOUT); // //启用计时器。 // TimerEnable (TIMER0_BASE、TIMER_A); TimerEnable (Timer1_base、timer_A); // //在计时器运行时永久循环。 // while (1) { } }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我将提交、这是使用弱定义进行中断的原因。

    Robert
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Robert、
    很抱歉、我无法理解您的意思。 您能详细说明吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    复制自 e2e.ti.com/.../2215479 定义#2215479

    由于原始开机自检已锁定、因此可能无法保持完全保真

    这种方法是通用的。 几乎每个编译器都支持它。 详细信息是特定于编译器的。 由于它涉及启动和中断、因此在任何情况下都不可移植、因此它特定于编译器这一事实并不重要。

    例如、我将使用 IAR

    想法是 将每个矢量设置为一个类似的已知例程

    1
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    void(* const__vector_table[155])(void) =
    {
        top_of_mem,                         /* The initial stack pointer (defined by linker)*/
        Reset_ISR,                          /* The reset handler */
        NMI_ISR,                /* The NMI handler */
        Fault_ISR,                          /* The hard fault handler */
        MPUFault_ISR,                   /* The MPU fault handler */
        BusFault_ISR,                       /* The bus fault handler */
        UsageFault_ISR,                     /* The usage fault handler */

    定义默认例程

    1
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    voidIntDefaultHandler(void)
    {
        unsigned intpsr_contents;
        volatileinti;
            /*  Program Status Register contains the current exception vector.*/
        psr_contents=__get_PSR();
        (void)SWO_putc('!',31u);
        SWO_fputhex((char)(psr_contents&0xFF), 31u);

    到目前为止、这对于每个编译器来说通常是相同的。 现在来了解编译器的细节。 在 IAR 中、我具有以下内容

    1
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    /*lint -e975 allow pragma, this is not quite C.  Need to control placement and
        weak definitions of symbols.                    */
    /*lint -efile(766,startup_wk.h) */
        /* Weakly link vectors to default routines so user can replace. */
    #pragma weak NMI_ISR=IntDefaultHandler
    #pragma weak Fault_ISR=IntDefaultHandler
    #pragma weak BusFault_ISR=IntDefaultHandler
    #pragma weak UsageFault_ISR=IntDefaultHandler
    #pragma weak SVCall_ISR=IntDefaultHandler
    #pragma weak DebugMonitor_ISR=IntDefaultHandler
    #pragma weak MPUFault_ISR=IntDefaultHandler
    #pragma weak PendSV_ISR=IntDefaultHandler
    #pragma weak SysTick_ISR=IntDefaultHandler
    #pragma weak GPIO_A_ISR=IntDefaultHandler               /* GPIO Port A */

    这会将 IntDefaultHandler 指定为每个中断例程的例程。 将其视为对它们进行重命名。 WEAK pragma 使它们成为弱定义、即它们是临时分配。 如果用户代码定义了一个名为 NMI_ISR 的例程、则它用于代替 IntDefaultHandler。 在 GCC 中、我可能会使用链接器来定义弱定义(我以前有过)。

    现在添加新中断很容易、只需使用适当的名称来定义例程。

    支持:

    • 易于添加或删除中断
    • 别忘了分配中断
    • 未使用的中断自动具有默认值。
    • 启动可重复使用

    缺点:

    •  在运行时测试之前、可能不会检测到缺少的中断例程。 请考虑排印错误。
    • 中断名称是公共符号

    清除为泥浆?

    Robert