嵌入式之家

 找回密码
 现在注册

QQ登录

只需一步,快速开始

搜索
热搜: ARM cortex
查看: 4101|回复: 2

Cortex-M3的SysTick定时器

[复制链接]

该用户从未签到

55

主题

168

帖子

1767

积分

金牌会员

Rank: 6Rank: 6

积分
1767
发表于 2016-4-8 14:07:31 | 显示全部楼层 |阅读模式
         SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。如下图所示为SysTic的相关寄存器:


         CM3允许为SysTick提供两个时钟源以供选择。第一个是内核的“自由运行时钟”FCLK。“自由”表现在它不来自系统时钟HCLK,因此在系统时钟停止时FCLK也继续运行。第二个是一个外部的参考时钟。但是使用外部时钟时,因为它在内部是通过FCLK来采样的,因此其周期必须至少是FCLK的两倍(采样定理)。很多情况下芯片厂商都会忽略此外部参考时钟,因此通常不可用。通过检查校准寄存器的位[31](NOREF),可以判定是否有可用的外部时钟源,而芯片厂商则必须把该引线连接至正确的电平。
       当SysTick定时器从1计到0时,它将把COUNTFLAG位置位;而下述方法可以清零之:
       1、读取SysTick控制及状态寄存器(STCSR)
        2、往SysTick当前值寄存器(STCVR)中写任何数据
SysTick的最大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。如欲使能SysTick异常,则把STCSR.TICKINT置位。另外,如果把向量表重定位到了SRAM中,还需要为SysTick异常建立向量,提供其服务例程的入口地址,如下段代码所演示:
                    MOV R0, #0xF ; 异常号:15
                    LDR R1, =systick_handler ; 加载服务例程的入口地址
                    LDR R2, =0xE000ED08 ; 加载向量表偏移量寄存器的地址
                    LDR R2, [R2] ; 读取向量表的首地址
                    STR R1, [R2, R0, LSL #2] ; 写入向量
       下面的代码演示启用SysTick的基本程序
                    ; 使能SysTick定时器,并且使能SysTick异常
                    LDR R0, =0xE000E010 ; 加载STCSR的地址
                    MOV R1, #0
                    STR R1, [R0] ; 先停止SysTick,以防意外产生异常请求
                    LDR R1, =0x3FF ; 让SysTick每1024周期计完一次。因为是从1023数到; 0,总共数了1024个周期,所以加载值为0x3FF
                    STR R1, [R0,#4] ; 写入重装载的值
                    STR R1, [R0,#8] ; 往STCVR中写任意的数,以确保清除COUNTFLAG标志
                    MOV R1, #0x7 ; 选择FCLK作为时钟源,并使能SysTick及其异常请求
                    STR R1, [R0] ; 写入数值,开启定时
        除此之外,SysTick定时器还提供了走完10ms所需要的格数(TENMS位段),作为时间校准的参考信息。在CM3处理器的顶层有一个24位的输入,芯片厂商可以写入一个10ms的加载值,写程序时就可以读取STCR寄存器中的TENMS位段来获取此信息。不一定每个芯片都实现了此功能,因此在使用时还需查阅芯片的数据手册。
      SysTick定时器还可以用作闹钟,作为启动一个特定任务的时间依据。例如,如果需要在300周期后执行一段代码,就可以在SysTick异常服务例程中设置执行那段代码的软件标志。使用SysTick时,清零CURRENT再编程RELOAD寄存器,以使它在300周期后产生异常,如下述代码所演示:
                    LDR r0, =15
                    LDR r1, =SysTickAlarm ; SysTick异常服务例程为SetupExcpHanler
                    BL SetupExcpHandler ; 调用前面章节讲到的子程来建立向量
                    LDR R0, =0xE000E010 ; SysTick寄存器组的基地址
                    MOV R1, #0 ; 编程前先除能SysTick
                    STR R1, [R0]
                    STR R1, [R0,#0x8] ; 清零CURRENT
                    LDR R1, =(300-12) ; 设置装载值。减去12是为了补偿中延迟
                    STR R1, [R0,#0x4] ; 写入RELOAD
                    LDR R4, =SysTickFired ; 在RAM中的一个变量,指示是计时到期
                    MOV R5, #0 ; 初始为0
                    STR R5, [R4]
                    MOV R1, #0x7 ; 使用FCLK,使能SysTick,使能SysTick异常
                    STR R1, [R0] ; 启动计时
                    LDR R4, =SysTickFired
                    WaitLoop
                    LDR R5, [R4] ; 循环查询软件标志
                    CMP R5, #0
                    BEQ WaitLoop
                    ... ; SysTickFired在服务例程中被置位,主程序可以继续执行
                   本例中使用以前讲到的SetupExcpHandler来建立向量表,但注意:必须重定位向量表到RAM中才行。
            SetupExcpHandler
                   ; 入口条件:R0 = 异常号
                   ; 入口条件:R1 = 异常服务例程
                   PUSH {R0, R2, LR}
                   LDR R2, =NVIC_VECTTBL
                   LDR R2, [R2] ; 读取向量表的地址
                   STR.W R1, [R2, R0, LSL #2] ; 表中[R2+R0<<2]的位置就是为该向量的
                   POP {R0, R2, PC} ; 快速返回
         因为计数器是从0开始计数的,所以它会立即把300-12加载入CURRENT。12是中断响应的最短延时,因此减去它用以补偿。但是如果有更高优先级的异常抢占或者阻塞了它,则中断延迟还是会有的。
        另外要注意的,减去12只适用于一次性(one shot)的闹钟操作,在这种情况下必须在SysTick服务例程中按停这个SysTick。进一步地,如果其它异常把它延迟得太久,就有可能会使SysTick异常被悬起两次。因此,对于单次处理时,还需要其它一些步骤来消灭二次触发:
  SysTickAlarm ; SYSTICK exception handler
                   PUSH {LR}
                   LDR R0, =0xE000E010 ; SYSTICK寄存器组的基地址
                   MOV R1, #0
                   STR R1, [R0] ; 除能SysTick,因为只使用一次
                   LDR R0, =0xE000ED04
                   LDR R1, =0x02000000 ; 手工清除NVIC中的SysTick悬起位
                   STR R1, [R0]
                   ... ; 执行所需的处理工作
                   LDR R2, =SysTickFired
                   LDR R1, [R2]
                   ORR R1, #1
                   STR R1, [R2] ; 设置软件标志,与主程序同步,以执行任务
                   POP {PC} ; 异常返回
         在服务例程的末尾处,通过设置SysTickFired标志,通知主程序定时已经到期,可以结束循环等待了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?现在注册

x
回复

使用道具 举报

  • TA的每日心情
    开心
    2020-6-18 22:00
  • 签到天数: 1 天

    [LV.1]初来乍到

    101

    主题

    192

    帖子

    1645

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    1645
    发表于 2016-4-8 15:29:57 | 显示全部楼层
    好多
    回复

    使用道具 举报

    该用户从未签到

    32

    主题

    81

    帖子

    771

    积分

    高级会员

    Rank: 4

    积分
    771
    发表于 2016-4-13 20:30:27 | 显示全部楼层
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 现在注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|嵌入式之家 ( 京ICP备14038168号-1 )

    GMT+8, 2025-5-2 15:38 , Processed in 0.025283 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表