STM32 Systick分析

发布者:czc天天最新更新时间:2021-11-29 来源: eefocus关键字:STM32  定时器 手机看文章 扫描二维码
随时随地手机看文章

前言:目前我觉得自己还没有能够深入用到这个SysTick的时候,只是要用到了delay_us()和delay_ms(),因为碰到了这个问题,所以想着提前了解一下,免得后来造成一脸懵逼的情况;毕竟没有社会经验的高手指点迷津,这里学习还是系统一点好;


systick是个啥?

是一个24位倒记数定时器;


systick的功能是什么


为操作系统提供硬件上的定时中断(滴答中断);

保证系统运行的时候不会让一个任务而占用整个系统;

可以制作精准的定时功能;

……

systick定时器的特点

可以工作在芯片睡眠状态下

此定时器被捆绑在NVIC(中断向量控制器)中,可以用于产生异常和中断;

……

编程涉及到的寄存器

SysTick_CTRL 控制寄存器

SysTick_LOAD 重载寄存器

SysTick_VAL 当前值寄存器

SysTick_CALRB 校准值寄存器

对四个寄存器及位的解释:

SysTick_CRTL

这里写图片描述

[0] : ENABLE systick使能位 0=关闭systick功能,1=开启systick功能

[1] : TICKINT systick中断使能位 0=关闭systick中断,1=开启systick中断

[2] : CLKSOURCE systick时钟源选择位 0=使用HCLK/8时钟源 1=使用HCLK时钟源

[16]: COUNTFLAG systick计数比较标志,如果计数器达到0,则读入为1;当读取或清除当前计数器值时,将自动清除为0;

[其它位] : 保留;


在不同的开发模式里,SysTick_CRTL有可能会被表示成STK_CRS,这里留意一下就好了;


SysTick_LOAD

这里写图片描述

[23:0] : systick定时器递减到0后,从SysTick_LOAD的值装载给SysTick_VAL(当前值寄存器),从而实现和C51单片机定时器的8位自动重装模式一样的效果;

[其它位]:保留


SysTick_VAL

这里写图片描述

[23:0] : 读取时返回当前倒计数的值,写它则使之清零,同时还会清除SysTick控制寄存器和状态寄存器中的COUNTFLAG标志;

[其它位]:保留


SysTick_CALRB(不做重要介绍因为不常用)

这里写图片描述

[31] :NOREF 外部参考时钟有无标志位 1=没有外部参考时钟(STCLK不可用); 0=外部参考时钟可用

[30] : SKEW 校准值是否为准确1ms标志位 1=准确 ; 0=不准确;

[23:0] : 校准值;(STM3210x使用手册中指出校准值固定为9000,而且当系统滴答时钟设定为9MHz(HCLK/8的最大值),将会产生1ms时间基准)


编程步骤


给SysTick_LOAD重载值;

清零SysTick_VAL;

通过配置寄存器SysTick_CTRL设置时钟输入(HCLK/8或HCLK)并且使能systick;

应用中的三个重要的函数

void delay_init(u8 SYSCLK); //初始化延迟函数

void delay_us(u32 nus); //延时n微妙

void delay_ms(u16 nms); //延时n毫秒


注意:这里又分为了两种情况:使用UCOSⅡ和不使用UCOSⅡ的情况

程序开始之前先解释一下:下面的延时函数代码支持UCOSⅡ下使用,它可以和UCOSⅡ共用systick定时器;在UCOSⅡ下系统不许有一个节拍,而这个节拍必须是固定的,不能被打断,否则就不准了;举个例子:比如每5ms一个节拍,那么直接由OS_TICK_PER_SEC = 200即可,stm32下systick提供这节拍;


由上可知:UCOSⅡ下的systick不能随意被更改;此时如果要sistick做delay_us和delay_ms的延时;

这事有一个时钟摘取的办法(以delay_us(50)为例):刚进入函数之后,先计算出需要延时的这段时间内systick需要建多少数,假设系统时钟为72MHz,那么systick每减1,就是1/9us,然后就是减了509次,然后就一直统计systick的计数变化,直到变化了509次,一旦检测到变化达到或者超过这个值,就说明延时了50us;栗子仅满足延时的时间小于UCOSⅡ的系统节拍的关系;


//初始化延迟函数

//当使用ucos的时候,此函数会初始化ucos的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init()  

{

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

u32 reload;

#endif

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟  HCLK/8

fac_us=SystemCoreClock/8000000; //为系统时钟的1/8  

 

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K    

reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出时间

//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右

fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延时的最少单位    

SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;    //开启SYSTICK中断

SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中断一次

SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;    //开启SYSTICK    

#else

fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数   

#endif

}


使用UCOSⅡ的情况下的delay_us()和delay_ms():



#ifdef OS_CRITICAL_METHOD //使用了ucos

//延时nus

//nus为要延时的us数.        

void delay_us(u32 nus)

{

u32 ticks;

u32 told,tnow,tcnt=0;

u32 reload=SysTick->LOAD; //LOAD的值      

ticks=nus*fac_us; //需要的节拍数    

tcnt=0;

told=SysTick->VAL;        //刚进入时的计数器值

while(1)

{

tnow=SysTick->VAL;

if(tnow!=told)

{     

if(tnow else tcnt+=reload-tnow+told;     

told=tnow;

if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.

}  

};     

}

//延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{

if(OSRunning==TRUE)//如果os已经在跑了     

{   

if(nms>=fac_ms)//延时的时间大于ucos的最少时间周期 

{

    OSTimeDly(nms/fac_ms);//ucos延时

}

nms%=fac_ms; //ucos已经无法提供这么小的延时了,采用普通方式延时    

}

delay_us((u32)(nms*1000)); //普通方式延时,此时ucos无法启动调度.

}


不使用UCONSⅡ的情况下:


//延时nus

//nus为要延时的us数.        

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;       //清空计数器  

}

//延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864 

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)));//等待时间到达   

SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //关闭计数器

SysTick->VAL =0X00;       //清空计数器       

#endif

关键字:STM32  定时器 引用地址:STM32 Systick分析

上一篇:IWDG和WWDG分析
下一篇:STM32处理器 RTC分析

推荐阅读最新更新时间:2024-11-09 11:11

STMCU应用过程中与电源相关的案例分享
我们在从事STM32单片机的应用开发及调试过程中,往往会碰到各类异常。其中有不少比例的问题跟电源有关。对于一个电子产品而言,电源部分很关键、很重要,但在实际开发调试中,我们偶尔会有意无意的忽视它。这里分享几个实际案例,以加强刺激,加深印象。 毕竟因为电源问题可能导致的异常很多很多,这里分享几个案例算是抛砖引玉,希望大家在调试中对电源方面加以重视。个人认为,往往电源出问题时导致的异常时并不太好分析。多数时候异常表现得更为诡异或没章法。 注:下面提到的案例中异常原因都与电源有关,但并不是说出现类似异常时一定是电源的原因。 下面主要分享五个基于STM32应用的案例。 案例1:STM32芯片的PLL无法正常工作。 有人使用STM3
[单片机]
STMCU应用过程中与电源相关的案例分享
STM32入门系列-GPIO结构
已经了解了STM32 GPIO的基本概念及引脚分类。现在来看下STM32 GPIO内部的结构是怎样的。IO端口位的基本结构如下图所示。 从图中可以看出GPIO内部结构还是比较复杂的,只要将这张GPIO结构图理解好,那么关于GPIO的各种应用模式将非常清楚。图中最右端I/O端口就是STM32芯片的引脚,其它部分都在STM32芯片内部。上图中我们将每部分都用红色数字标号了,按照顺序我们逐一讲解。 保护二极管 引脚内部加上这两个保护二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于VDD_FT或VDD时,上方的二极管导通吸收这个高电压,当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。 尽管S
[单片机]
<font color='red'>STM32</font>入门系列-GPIO结构
教室智能照明控制系统的设计说明
摘要:针对室内不同区域对于光照强度的不同要求,设计了一个利用STM32作为控制器的教室智能照明控制系统,能够依据室内照明强度以及室内人员分布情况对教室内光照强度进行实时,动态的调整。结果表明,该系统既可以保证教室内的光照强度充足,又不会造成电力浪费。 0. 引言 在学校的每个教室里,照明设备都是不可或缺的。然而,有时会见到某个空无一人的教室灯火通明,或者在白天室外阳光强烈,无需开灯的情况下,教室里的灯却开着。这些情况都造成了很大的浪费。因此,教室智能照明控制系统要能够依据室内光照强度以及室内人员分布情况对教室内光照强度进行实时,动态的调整,既使得教室内的光照强度充足,又不会造成电力浪费。 1. 系统的总体设计 教室智能照明
[单片机]
教室智能照明控制系统的设计说明
simulink开发STM32串口函数的步骤
配置环境:MATLAB2018b,STM32CubeMX-5.4.0,STM32MatTarget_5.4.0,Keil MDK5 单片机:STM32F103ZET6 CK_1****功能:单片机发送任意长度数组给上位机。 注意数组的输出数据类型要选择为uint8。不要删除两个getBuffPtr文件, 生成代码后将getBuffPtr的头文件和源文件分别复制到生成的Inc和Src文件夹中,先将源文件getBuffPtr添加到Keil的Application/User中,然后再编译下载。 注意:如果找不到getBuffPtr文件,请在STM32MatTarget的安装位置拷贝,默认的安装路径为:C:MATLABSTM32-MAT
[单片机]
simulink开发<font color='red'>STM32</font>串口函数的步骤
stm32复位电路设计 浅析stm32复位电路方法
说到复位,我们都不会陌生,系统基本都有一个复位按键。复位的种类有很多:上电复位、掉电复位、复位引脚复位、看门狗复位、软件复位等。本文探讨的就是在stm32中复位电路如何设计。 STM32介绍 STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex®-M0,M0+,M3, M4和M7内核在STM32F105和STM32F107互连型系列微控制器之前,意法半导体已经推出STM32基本型系列、增强型系列、USB基本型系列、互补型系列;新系列产品沿用增强型系列的72MHz处理频率。内存包括64KB到256KB闪存和 20KB到64KB嵌入式SRAM。新系列采用LQFP64、LQFP100和LFBGA10
[单片机]
<font color='red'>stm32</font>复位电路设计 浅析<font color='red'>stm32</font>复位电路方法
STM32独立看门狗详解
本文将介绍STM32的看门狗中的独立看门狗,并通过实例来喂狗、体验喂狗与不喂狗的区别。 ①STM32看门狗介绍之独立看门狗 ②使用STM32CUBEMX来配置工程文件 ③代码实现,按键按下喂狗、按键不按下不喂狗程序复位 ①STM32看门狗介绍之独立看门狗 看门狗定时器本质上是一个计数器、给计数器一个数值,在程序 运行后计数器的值开始递减,当计数器的值减到0是会将程序复位,若在减到0之前给计数器更新一下值“喂狗”则从最新的值开始递减; 用途: 1、这样做的好处就是程序跑飞、死机时,通过复位的方式使得程序又正常运行; 2、用于将系统从休眠或者空闲模式唤醒。 看门狗的种类: 独立看门狗IWDG 特点:专用时钟LSI、低功耗模式仍
[单片机]
<font color='red'>STM32</font>独立看门狗详解
为什么STM32的Flash地址要设置到0x08000000
我们言简意赅的普及下这个知识点,争取让大家不伤脑细胞 一、背景知识: M3,M4内核芯片上电复位后,要固定从0x0000 0000地址读取中断向量表,获取复位中断服务程序的入口地址后,进入复位中断服务程序,其中0x0000 0000是栈顶地址,0x0000 0004存的是复位中断服务程序地址。 ARM官方回复: Documentation – Arm Developer 二、引出问题: 既然ARM规定了M3,M4内核要从地址0x0000 0000读取中断向量表,而STM32设置Flash地址到0x0800 0000怎么办? STM32支持了个内存重映射功能,将地址0x0800 0000开始的内容重映射
[单片机]
为什么<font color='red'>STM32</font>的Flash地址要设置到0x08000000
关于STM32 ADC时采用DMA的一点疑问
手册上有这样的话:只有ADC1能够产生DMA请求,似乎是只有ADC通道1能采用DMA方式传输数据。 但是万利的开发板上的ADC例子,用的是ADC通道10,还用了DMA 方式传数据。 所以我猜测 “只有ADC1能够产生DMA请求”中提到的ADC1 并不是指ADC 通道1, 而是软件可配置的 ADC 通道的分类形式,可分为ADC1和ADC2. 我们可将 通道10(或其他)配置成ADC1 “模式”。通过函数 /* ADC1 regular channel10 configuration */ ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_5
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved