查看: 7955|回复: 11

【有奖征文】LM4F Launchpad上手系列4-Timer

  [复制链接]
  • TA的每日心情
    奋斗
    2013-2-28 11:51
  • 签到天数: 49 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2012-12-27 21:39:37 | 显示全部楼层 |阅读模式
    分享到:

    上海最近一直在下雨,天气也越来越冷,晚上睡觉会被冻醒;
    事情也是非常多,做完了一些,又会来一堆,不知不觉有很长时间没有前来更新。

    为了延续本教程的生命力,我觉得再忙也要抽时间来写心得,和大家分享。
    今天我们的主题是定时器,查询LM4F120H5QR的手册可以得知该芯片一共有12个定时器,
    其中6个是32/64bit的,另外六个是16/32bit的,可谓非常强大。

    我们参考官方的例程来看看定时器究竟该如何使用,首先我们创建主函数:
    1. //*****************************************************************************
    2. //
    3. // This example application demonstrates the use of the timers to generate
    4. // periodic interrupts.
    5. //
    6. //*****************************************************************************
    7. int
    8. main(void)
    9. {
    10.     //
    11.     // Enable lazy stacking for interrupt handlers.  This allows floating-point
    12.     // instructions to be used within interrupt handlers, but at the expense of
    13.     // extra stack usage.
    14.     //
    15.     ROM_FPULazyStackingEnable();

    16.     //
    17.     // Set the clocking to run directly from the crystal.
    18.     //
    19.     ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    20.                        SYSCTL_XTAL_16MHZ);

    21.     //
    22.     // Initialize the UART and write status.
    23.     //
    24.     ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    25.     GPIOPinConfigure(GPIO_PA0_U0RX);
    26.     GPIOPinConfigure(GPIO_PA1_U0TX);
    27.     ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    28.     UARTStdioInit(0);
    29.     UARTprintf("\033[2JTimers example\n");
    30.     UARTprintf("T1: 0  T2: 0");

    31.     //
    32.     // Enable the GPIO port that is used for the on-board LED.
    33.     //
    34.     ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    35.     //
    36.     // Enable the GPIO pins for the LED (PF1 & PF2).  
    37.     //
    38.     ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_1);


    39.     //
    40.     // Enable the peripherals used by this example.
    41.     //
    42.     ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    43.     ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    44.     //
    45.     // Enable processor interrupts.
    46.     //
    47.     ROM_IntMasterEnable();

    48.     //
    49.     // Configure the two 32-bit periodic timers.
    50.     //
    51.     ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    52.     ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
    53.     ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet());
    54.     ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, ROM_SysCtlClockGet() / 2);

    55.     //
    56.     // Setup the interrupts for the timer timeouts.
    57.     //
    58.     ROM_IntEnable(INT_TIMER0A);
    59.     ROM_IntEnable(INT_TIMER1A);
    60.     ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    61.     ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

    62.     //
    63.     // Enable the timers.
    64.     //
    65.     ROM_TimerEnable(TIMER0_BASE, TIMER_A);
    66.     ROM_TimerEnable(TIMER1_BASE, TIMER_A);

    67.     //
    68.     // Loop forever while the timers run.
    69.     //
    70.     while(1)
    71.     {
    72.     }
    73. }
    复制代码
    我们来分析一下上述代码,其中与串口有关的我们直接忽略,有兴趣的可以参考
    另外一篇与串口有关的文章。

    1. //
    2. // Enable the peripherals used by this example.
    3. //
    4. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    5. ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    复制代码
    首先对定时器0和定时器1进行初始化,然后对定时器进行配置:
    1. //
    2. // Configure the two 32-bit periodic timers.
    3. //
    4. ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    5. ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
    6. ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, ROM_SysCtlClockGet());
    7. ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, ROM_SysCtlClockGet() / 2);
    复制代码
    由上述代码可知,配置成周期性模式,定时器0的频率采用系统频率,换句话说就是1s触发一次中断,
    定时器1采用系统频率的一半,即半秒触发一次定时器中断。
    而后配置定时器中断,并初始化时钟,这里采用TIMER_TIMA_TIMEOUT将时钟配置成溢出产生中断,程序如下:
    1. //
    2. // Setup the interrupts for the timer timeouts.
    3. //
    4. ROM_IntEnable(INT_TIMER0A);
    5. ROM_IntEnable(INT_TIMER1A);
    6. ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    7. ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    复制代码
    与中断有关,必定需要联系到中断处理函数,我们先来看下定时器0中断的函数:
    1. //*****************************************************************************
    2. //
    3. // The interrupt handler for the first timer interrupt.
    4. //
    5. //*****************************************************************************
    6. void
    7. Timer0IntHandler(void)
    8. {
    9.     //
    10.     // Clear the timer interrupt.
    11.     //
    12.     ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    13.     //
    14.     // Toggle the flag for the first timer.
    15.     //
    16.     HWREGBITW(&g_ulFlags, 0) ^= 1;

    17.     //
    18.     // Use the flags to Toggle the LED for this timer
    19.     //
    20.     GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, g_ulFlags << 1);
    21.    
    22.     //
    23.     // Update the interrupt status on the display.
    24.     //
    25.     ROM_IntMasterDisable();
    26.     UARTprintf("\rT1: %d  T2: %d", HWREGBITW(&g_ulFlags, 0) ? 1 : 0,
    27.                HWREGBITW(&g_ulFlags, 1) ? 1 : 0);
    28.     ROM_IntMasterEnable();
    29. }
    复制代码
    这里主要是每次定时器中断时,对LED灯状态进行异或,同时向串口输入,定时器1中断处理程序类似:
    1. //*****************************************************************************
    2. //
    3. // The interrupt handler for the second timer interrupt.
    4. //
    5. //*****************************************************************************
    6. void
    7. Timer1IntHandler(void)
    8. {
    9.     //
    10.     // Clear the timer interrupt.
    11.     //
    12.     ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

    13.     //
    14.     // Toggle the flag for the second timer.
    15.     //
    16.     HWREGBITW(&g_ulFlags, 1) ^= 1;
    17.    
    18.     //
    19.     // Use the flags to Toggle the LED for this timer
    20.     //
    21.     GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, g_ulFlags << 1);
    22.    
    23.     //
    24.     // Update the interrupt status on the display.
    25.     //
    26.     ROM_IntMasterDisable();
    27.     UARTprintf("\rT1: %d  T2: %d", HWREGBITW(&g_ulFlags, 0) ? 1 : 0,
    28.                HWREGBITW(&g_ulFlags, 1) ? 1 : 0);
    29.     ROM_IntMasterEnable();
    30. }
    复制代码
    定时器使用初步就介绍到这里,有兴趣的话可以自己建立工程,做一下试验,别忘了修改startup文件,
    连接上串口的话会看到以下结果,结果可自行结合代码进行分析。
    1.png


    回复

    使用道具 举报

  • TA的每日心情
    开心
    2015-8-7 21:35
  • 签到天数: 340 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2012-12-27 21:46:31 | 显示全部楼层
    有时间学习一下……
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2020-9-28 10:10
  • 签到天数: 1018 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2012-12-27 21:46:35 | 显示全部楼层
    支持一个!!!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2013-2-1 15:36
  • 签到天数: 14 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2012-12-30 17:42:44 | 显示全部楼层
    问下 startup 文件是修改俩个中断服务函数就OK 了 吗?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2013-1-21 22:58
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-1-18 11:52:06 | 显示全部楼层
    教程有bug,关于两个定时器的时钟,1/2的频率就会是2倍的周期应该是2s,还有这个系统时钟只有1hz么?
    我也是新手哈!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2013-2-28 11:51
  • 签到天数: 49 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2013-1-18 12:35:26 | 显示全部楼层
     唯、你专属 发表于 2013-1-18 11:52
    教程有bug,关于两个定时器的时钟,1/2的频率就会是2倍的周期应该是2s,还有这个系统时钟只有1hz么?
    我也 ...

    没错,一个是按照芯片时钟频率走,另一个按照1/2的芯片时钟频率走,他这里面设置了溢出的值,经过计算是1s溢出,芯片工作在80MHz
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-4-22 19:47:31 | 显示全部楼层
    有谁在呀?
    可否请教下,最后的结果显示窗口该怎么操作???
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-6-26 11:59
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-4-27 20:27:12 | 显示全部楼层
    写的真好,能请教一个问题吗?有个地方我一直没搞懂
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, g_ulFlags << 1);
    这个写在定时器中断里面的,改变LED灯的状态,可是我不明白为什么可以改变LEd灯的状态
    g_ulFlags << 1,是中断标志左移一位
    可是前面有一句HWREGBITW(&g_ulFlags, 0) ^= 1;
    按我的理解是中断标志寄存器最后一位写0吧,那么在LED的IO口上不就一直是0了吗?不理解,求指点一下!!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-6-26 11:59
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-4-27 20:28:31 | 显示全部楼层
    GPL 发表于 2013-4-22 19:47
    有谁在呀?
    可否请教下,最后的结果显示窗口该怎么操作???

    那个不是串口调试助手吗
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-6-26 11:59
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-4-27 21:02:34 | 显示全部楼层
    亮瞎了,那个符号是异或,不是取反。。。。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-26 11:58 , Processed in 0.205563 second(s), 35 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.