什么是systick:
这是一个24位的系统节拍定时器system tick timer,systick,具有自动重载和溢出中断功能,所有基于cortex_m3处理器的微控制器都可以由这个定时器获得一定的时间间隔。
作用:
在单任务引用程序中,因为其架构就决定了它执行任务的串行性,这就引出一个问题:当某个任务出现问题时,就会牵连到后续的任务,进而导致整个系统崩溃。要解决这个问题,可以使用实时操作系统(rtos).
因为rtos以并行的架构处理任务,单一任务的崩溃并不会牵连到整个系统。这样用户出于可靠性的考虑可能就会基于rtos来设计自己的应用程序。这样systick存在的意义就是提供必要的时钟节拍,为rtos的任务调度提供一个有节奏的“心跳”。
微控制器的定时器资源一般比较丰富,比如stm32存在8个定时器,为啥还要再提供一个systick?原因就是所有基于arm cortex_m3内核的控制器都带有systick定时器,这样就方便了程序在不同的器件之间的移植。而使用rtos的第一项工作往往就是将其移植到开发人员的硬件平台上,由于systick的存在无疑降低了移植的难度。
systick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。
要注意的是,当处理器在调试期间被喊停(halt)时,则systick定时器亦将暂停运作。
时钟的选择:
用户可以在位于cortex_m3处理器系统控制单元中的系统节拍定时器控制和状态寄存器(systick control and status register ,scsr)选择systick 时钟源。如将scsr中的clksource位置位,systick会在cpu频率下运行;而将clksouce位清除则systick会以cpu主频的1/8频率运行。
3.5版本的库函数与以往的有所区别
不存在stm32f10x_systick.c文件,故原来的一些函数也不存在,比如systick_setreload(u32 reload);systick_itconfig(functionalstate newstate);等
在3.5版本的库函数中与systick相关的函数只有两个
第一个,systick_config(uint32_t ticks),在core_cm3.h头文件中进行定义的。
第二个,void systick_clksourceconfig(uint32_t systick_clksource),在misc.c文件中定义的。
systick_config(uint32_t ticks),在core_cm3.h
主要的作用:
1、初始化systick
2、打开systick
3、打开systick的中断并设置优先级
4、返回一个0代表成功或1代表失败
注意:
uint32_t ticks即为重装值,
这个函数默认使用的时钟源是ahb,即不分频。
要想分频,调用void systick_clksourceconfig(uint32_t systick_clksource),
但是要注意函数调用的次序,先systick_config(uint32_t ticks),
后systick_clksourceconfig(uint32_t systick_clksource)
函数说明:
/**
* @briefinitialize and start the systick counter and its interrupt.
*
* @param ticks number of ticks between two interrupts
* @return1 = failed, 0 = successful
*
* initialise the system tick timer and its interrupt and start the
* system tick timer / counter in free running mode to generate
* periodical interrupts.
*/
static __inline uint32_t systick_config(uint32_t ticks)
{
if (ticks > systick_load_reload_msk)return (1);
/* reload value impossible */重装载值必须小于0xff ffff,为什么,这是一个24位的递减计数器。
systick->load= (ticks & systick_load_reload_msk) - 1;
/* set reload register */设置重装载值,systick_load_reload_msk定义见后面
nvic_setpriority (systick_irqn, (1ctrl= systick_ctrl_clksource_msk |
systick_ctrl_tickint_msk |
systick_ctrl_enable_msk;
/* enable systick irq and systick timer */
return (0);
/* function successful */
}
#endif
与systick相关的寄存器定义
/** @addtogroup cmsis_cm3_systick cmsis cm3 systick
memory mapped structure for systick
@{
*/
typedef struct
{
__io uint32_t ctrl; /*!< offset: 0x00systick control and status register */
__io uint32_t load; /*!< offset: 0x04systick reload value register */
__io uint32_t val; /*!< offset: 0x08systick current value register */
__iuint32_t calib; /*!< offset: 0x0csystick calibration register */
} systick_type;
与systick寄存器相关的寄存器及位的宏定义
/* systick control / status register definitions */控制/状态寄存器
#define systick_ctrl_countflag_pos 16 /*!《 systick ctrl: countflag position */
#define systick_ctrl_countflag_msk (1ul 《《 systick_ctrl_countflag_pos)
/*!《 systick ctrl: countflag mask */ 溢出标志位
#define systick_ctrl_clksource_pos 2 /*!《 systick ctrl: clksource position */
#define systick_ctrl_clksource_msk (1ul 《《 systick_ctrl_clksource_pos)
/*!《 systick ctrl: clksource mask */时钟源选择位,0=外部时钟;1=内核时钟
#define systick_ctrl_tickint_pos 1 /*!《 systick ctrl: tickint position */
#define systick_ctrl_tickint_msk (1ul 《《 systick_ctrl_tickint_pos)
/*!《 systick ctrl: tickint mask */异常请求位
#define systick_ctrl_enable_pos 0 /*!《 systick ctrl: enable position */
#define systick_ctrl_enable_msk (1ul 《《 systick_ctrl_enable_pos)
/*!《 systick ctrl: enable mask */使能位
/* systick reload register definitions */
#define systick_load_reload_pos 0 /*!《 systick load: reload position */
#define systick_load_reload_msk (0xfffffful 《《 systick_load_reload_pos)
/*!《 systick load: reload mask */
/* systick current register definitions */
#define systick_val_current_pos 0 /*!《 systick val: current position */
#define systick_val_current_msk (0xfffffful 《《 systick_val_current_pos)
/*!《 systick val: current mask */
/* systick calibration register definitions */
#define systick_calib_noref_pos 31 /*!《 systick calib: noref position */
#define systick_calib_noref_msk (1ul 《《 systick_calib_noref_pos)
/*!《 systick calib: noref mask */
#define systick_calib_skew_pos 30 /*!《 systick calib: skew position */
#define systick_calib_skew_msk (1ul 《《 systick_calib_skew_pos)
/*!《 systick calib: skew mask */
#define systick_calib_tenms_pos 0 /*!《 systick calib: tenms position */
#define systick_calib_tenms_msk (0xfffffful 《《 systick_val_current_pos) /*!《 systick calib: tenms mask */
/*@}*/ /* end of group cmsis_cm3_systick */
void systick_clksourceconfig(uint32_t systick_clksource)
作用:
选择systick的时钟源,ahb时钟或ahb的8分频
库函数中默认使用的是ahb时钟(在systick_config()函数中设置),即72mhz
函数说明:
/**
* @brief configures the systick clock source.
* @param systick_clksource: specifies the systick clock source.
* this parameter can be one of the following values:
* @arg systick_clksource_hclk_div8: ahb clock divided by 8 selected as systick clock source.
* @arg systick_clksource_hclk: ahb clock selected as systick clock source.
* @retval none
*/
void systick_clksourceconfig(uint32_t systick_clksource)
{
/* check the parameters */
assert_param(is_systick_clk_source(systick_clksource));
if (systick_clksource == systick_clksource_hclk)
{
systick-》ctrl |= systick_clksource_hclk;
}
else
{
systick-》ctrl &= systick_clksource_hclk_div8;
}
}
systick时钟源的定义:
/** @defgroup systick_clock_source
* @{
*/
#define systick_clksource_hclk_div8 ((uint32_t)0xfffffffb)//将控制状态寄存器的第二位置0,即用外部时钟源
#define systick_clksource_hclk ((uint32_t)0x00000004)//将控制状态寄存器的第二位置1,即用内核时钟
#define is_systick_clk_source(source) (((source) == systick_clksource_hclk) || \
((source) == systick_clksource_hclk_div8))
与systick相关的寄存器的说明
systick寄存器说明在《cortex-m3权威指南》(chap8.systick定时器章节)有说明
systick使用实践
systick定时时间的设定:
重装载值=systick 时钟频率(hz)x想要的定时时间(s)
如果时钟频率为:ahb的8分频;ahb=72mhz那么systick的时钟频率为72/8mhz=9mhz
若要定时1秒,则重装载值=9000000x1=9000000,调用函数:systick_config(9000000x1);
若要定时1毫秒,重状态值=9000000x0.001=90000,调用函数:systick_config(9000000/1000);
systick的中断处理函数
在startup_stm32f10x_hd.s启动文件中有定义。
dcd systick_handler ; systick handler
根据需要直接编写中断处理函数即可:
void systick_handler (void)
{ ;}
注意:
如果在工程中,加入了stm32f10x_it.c,而又在主函数中编写中断函数,则会报错。
因为在stm32f10x_it.c文件中,也有这个中断函数的声明,只是内容是空的。
/**
* @brief this function handles systick handler.
* @param none
* @retval none
*/
void systick_handler(void)
{
}
中断优先级的修改
在调用systick_config(uint32_t ticks)之后,调用 void nvic_setpriority(irqn_type irqn, uint32_t priority)。这个函数在core_cm3.h头文件中。
具体内容如下:
/**
* @brief set the priority for an interrupt
*
* @param irqn the number of the interrupt for set priority
* @param priority the priority to set
*
* set the priority for the specified interrupt. the interrupt
* number can be positive to specify an external (device specific)
* interrupt, or negative to specify an internal (core) interrupt.
*
* note: the priority cannot be set for every core interrupt.
*/
static __inline void nvic_setpriority(irqn_type irqn, uint32_t priority)
{
if(irqn 《 0) {
scb-》shp[((uint32_t)(irqn) & 0xf)-4] = ((priority 《《 (8 - __nvic_prio_bits)) & 0xff); } /* set priority for cortex-m3 system interrupts */
else {
nvic-》ip[(uint32_t)(irqn)] = ((priority 《《 (8 - __nvic_prio_bits)) & 0xff); } /* set priority for device specific interrupts */
}
下面以一个实例来说明:
利用systick来实现以1秒的时间间隔,闪亮一个led指示灯,指示灯接在gpioa.8,低电平点亮。
#include “stm32f10x.h”
//函数声明
void gpio_configuration(void);//设置gpioa.8端口
u32 t;//定义一个全局变量
int main(void)
{
// systick_clksourceconfig(systick_clksource_hclk_div8);
systick_config(9000000);
systick_clksourceconfig(systick_clksource_hclk_div8);
gpio_configuration();
while(1);
}
//gpioa.8设置函数
void gpio_configuration(void)
{
gpio_inittypedef gpio_initstruct;//定义一个端口初始化结构体
rcc_apb2periphclockcmd(rcc_apb2periph_gpioa, enable);//打开gpioa口时钟
gpio_initstruct.gpio_mode=gpio_mode_out_pp;//设置为推挽输出
gpio_initstruct.gpio_speed=gpio_speed_50mhz;//设置输出频率50m
gpio_initstruct.gpio_pin=gpio_pin_8;//指定第8脚
gpio_init(gpioa,&gpio_initstruct);//初始化gpioa.8
gpio_setbits( gpioa, gpio_pin_8);//置高gpioa.8,关闭led
}
//systick中断函数
void systick_handler(void)
{
t++;
if(t》=1)
{
if(gpio_readinputdatabit(gpioa, gpio_pin_8)==1)
{gpio_resetbits( gpioa, gpio_pin_8);}
}
if(t》=2)
{
if(gpio_readinputdatabit(gpioa, gpio_pin_8)==0)
{gpio_setbits( gpioa, gpio_pin_8);}
t=0;
}
}
模拟后的结果
1、8分频后结果
总结:
1、要使用systick定时器,只需调用systick_config(uint32_t ticks)函数即可,
函数自动完成:重装载值的装载,时钟源选择,计数寄存器复位,中断优先级的设置(最低),开中断,开始计数的工作。
2、要修改时钟源调用systick_clksourceconfig(uint32_t systick_clksource),也可按照systick_config()中默认设置fclk不变。
3、要修改中断优先级调用
void nvic_setpriority(irqn_type irqn, uint32_t priority)
应用说明:
1、因systick是一个24位的定时器,故重装值最大值为2的24次方=16 777 215,
要注意不要超出这个值。
2、systick是cortex_m3的标配,不是外设。故不需要在rcc寄存器组打开他的时钟。
3、每次systick溢出后会置位计数标志位和中断标志位,计数标志位在计数器重装载后被清除,而中断标志位也会随着中断服务程序的响应被清除,所以这两个标志位都不需要手动清除。
4、采用使用库函数的方法,只能采用中断的方法响应定时器计时时间到,如要采用查询的方法,那只能采用设置systick的寄存器的方法,具体操作以后再做分析。
光纤通信的现状及其未来发展与应用
有机肥检测仪都包含哪些种类
浅谈连接器接线端子焊接技术热失效问题
OTP语音芯片具有什么特点?
单晶硅的用途_单晶硅的化学式
STM32知识:什么是SYSTICK 作用是什么
LoRa模块网络组成和架构原理是怎样的?
光纤通信技术在水利系统中的应用
适用于Altera FPGA的电源解决方案
AC-DC芯片220V转12V200MA电源芯片AH8665
Altera Stratix IV GT 100G开发方案
Vivo X60 Pro Plus的预计发布日期已经到来
用FPGA迎接AI时代而不是专用芯片
真无线蓝牙耳机对比评测:国庆出游必不可少的四款机型!
努比亚Z18是怎么做到如此极致的屏占比的
台积电与联发科股价均创下新高
采用PLC实现异步电动机的综合控制方案
详解GaN和SiC器件测试的理想探头
手机镜头与摄像模组业务双向发力 舜宇光学5月销量持续增长
液晶电视的可视角度