完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
OS能够支持多任务,能够以周期性地完成上下文的切换,以并行的架构处理任务,单一任务的崩溃并不会牵连到整个系统。上下文周期性切换需要一个定时器能够打断程序执行,Systick定时器就可以提供必要的时钟节拍,为OS的任务调度提供一个有节奏的“心跳”。 SysTick定时器即系统滴答定时器,也称“心跳定时器”,它是一个24 位的倒计数定时器,计到0 时,将从重装载寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。 SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15),SysTick中断的优先级也可以设置。 它会根据节拍来工作,把整个时间段分成很多小小的时间片,而每个任务每次只能运行一个时间片的时间长度,超时就退出给别的任务运行,这样可以确保任何一个任务都不会霸占操作系统提供的各种定时功能,都与这个滴答定时器有关。 当启用时,定时器从重载值递减计数到零,在下一个时钟周期将重装载SYST_RVR 中的值,然后在后续时钟周期递减。将零值写入 SYST_RVR 会在下一次回调时禁用计数器。当计数器变为零时,COUNTFLAG 状态位设置为 1。读取 SYST_CSR 将 COUNTFLAG 位清除为 0。写入 SYST_CVR 将清除寄存器和 COUNTFLAG 状态位为 0,写入不会触发 SysTick 异常逻辑,读取该寄存器会在访问时返回其值。 01 SysTick寄存器 SysTick定时器主要由4个寄存器组成:
在CMSIS中系统控制寄存器结构体:typedef struct { __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */ __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */ __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */ __I uint32_t CALIB;/*!< Offset: 0x0C SysTick Calibration Register */ } SysTick_Type; 在ARM官方资料中4个寄存器的命名分别是SYST_CSR、SYST_RVR、SYST_CVR和SYST_CALIB,但是在CMSIS中进行了简化命名,更加清晰明了。 1.1 SysTick控制和状态寄存器(SYST_CSR) MM32F0130系列的SysTick的HCLK来源于AHB总线经过硬件4分频,FCLK直接来源于AHB时钟总线。 而下述方法可以清零: 读取 SysTick 控制及状态寄存器(STCSR) 往 SysTick 当前值寄存器(STCVR)中写任何数据 1.2 SysTick重装载寄存器(SYST_RVR) 1.3 SysTick当前值寄存器(SYST_CVR) CURRENT:读此寄存器返回系统定时器的当前值,给这个寄存器赋值,将使定时器归0,且清CTRL中的COUNTFLAG位。 1.4 SysTick当前值寄存器(SYST_CALIB) 校准值寄存器提供了这样一个解决方案:它使系统即使在不同的CM0产品上运行,也能产生恒定的SysTick中断频率。最简单的作法就是:直接把TENMS的值写入重装载寄存器,这样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick异常周期,则可以根据TENMS的值加以比例计算。 在系统定时器的四个寄存器中,SYST_CALIB为校准寄存器,这个是在出厂之前就已经配置好了的,我们不必考虑这个寄存器。 02 SysTick编程 SysTick配置需要遵循一定的流程: 1、 开始 2、 禁止SysTick 3、 设置重装值寄存器 4、 清除当前值寄存器 5、 使能SysTick 6、 完成 SysTick操作相关函数有:__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks); void SysTick_CLKSourceConfig(u32 systick_clk_source); void RCC_SystickDisable(void); void RCC_SystickEnable(u32 sys_tick_period); 下面的代码演示启用 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] ; 写入数值,开启定时器 在CMSIS库中有定义对应的配置函数:__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { /* Reload value impossible */ if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* set reload register */ SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set Priority for Systick Interrupt */ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* Load the SysTick Counter Value */ SysTick->VAL = 0UL; /* Enable SysTick IRQ and SysTick Timer */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Function successful */ return (0UL); } SysTick可以通过轮询或者中断方式进行操作,使用轮询的程序可以读取SysTick控制和状态寄存器,检查COUNTFLAG,如果该位置位,则表明SysTick计数已减到0。 中断方式延时参考程序:static __IO uint32_t TimingDelay; void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } void SysTick_Handler(void) { if (TimingDelay != 0x00) { TimingDelay--; } } int main(void) { //systick时钟为HCLK,中断时间间隔1ms if (SysTick_Config(SystemCoreClock / 1000)) { while (1); } while(1) { Delay(200);//200ms } } 轮询方式延时参考程序:void delay_init() { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div4); //选择外部时钟HCLK/4 //为系统时钟的1/4,实际上也就是在计算1usSysTick的VAL减的数目 fac_us=SystemCoreClock/4000000; //代表每个ms需要的systick时钟数,即每毫秒SysTick的VAL减的数目 fac_ms=(u16)fac_us*1000; } void delay_ms(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit) SysTick->VAL =0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达,看CTRL的第16位(COUNTFLAG)是否为1,看STRL的第0位(ENABLE)是否为1 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick->VAL =0X00; //清空计数器 } SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如时间测量、定时或者闹铃等。 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2249个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11703 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5930 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10965 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4577 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4302 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
981浏览 1评论
806浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 22:11 , Processed in 0.658372 second(s), Total 55, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号