STM32单片机systick使用注意事项 前言 CM4内核的处理和CM3一样,内部都包含了一个SysTick定时器,SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。这样可以用systick来实现延时定时功能,不用再占用系统定时器。systick也多用做系统的时钟节拍,如freeRTOS等OS,再启动调度器的时候,就会将systick配置成其系统时钟,给系统提供心跳。 systick中有4个寄存器 CTRL LOAD VAL CALIB systick配置注意事项 使用CubeMX配置生成的代码中,会自动生成一个 SystemClock_Config() 的函数,用于配置单片机时钟,其中就会配置systick - void SystemClock_Config()
) F) p }& v% {) W) {) b - {
" d* {/ z' c8 m% k6 e - ...........
1 d5 q+ U' I7 j. O+ b7 p - LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
% T0 ], c8 U9 Q4 O, U7 U0 W - LL_SetSystemCoreClock(32000000);( E3 E6 V) x+ C- o
- #ifndef SYSTICK_IRQ: K/ A/ n. A: d4 {0 s& S! F& J# U
- LL_Init1msTick(32000000); //使能systick但是不开启systick中断6 M* L2 i; I4 k+ r, x' N
- #else- C; z! |+ X5 g7 i5 H
- SysTick_Config(SystemCoreClock / 1000);//使能systick同时开启systick中断
X, z, D9 ]6 O2 P - #endif
" i% n) e5 |0 N: p; I: L! r - }
复制代码 但是这里 需要注意的是,是不是需要开启 systick 中断!!!! 1、如果只是想用systick来作为延时用,程序不想被中断打断,就只需要使能systick而不用开启systick中断,调用 LL_Init1msTick 即可 - void LL_Init1msTick(uint32_t HCLKFrequency), C& M* i# M3 D: B& n
- ---> LL_InitTick(HCLKFrequency, 1000U);
$ u4 o8 |0 O' i3 X - ---> __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks). i# ]2 Q6 X T* ^+ U
- {( w P8 y' p# R& ?
- /* Configure the SysTick to have interrupt in 1ms time base */
4 Z/ q, V( m4 _: ]- g/ A) o - SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */8 q3 j: v3 W7 H" E& t6 e- x
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
# V* i7 i) h( Q8 |1 m6 E6 e3 ] - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |8 o; c: D; Y$ X' F c1 x) C4 S1 [
- SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */5 Q/ B! S* x. d9 P' a1 p# E- e
- }
复制代码 ) C; L8 [4 S. J) h6 }! Y7 C
但是需要自己编写延时函数,不能使用HAL库提供的HAL_Delay()。原因如下:HAL_Delay的实现是依靠一个uwTickFreq变量,uwTickFreq是在HAL_IncTick中累加的,需要在 SysTick_Handler中断函数中周期调用,这样HAL_Delay才会有一个基准 - __weak void HAL_IncTick(void)
$ p9 v7 N3 ?9 W/ }! Q - {
3 n) L. O9 ^% C9 ?& w; U$ ? - uwTick += uwTickFreq;
/ e% x7 I2 s2 Q* ~3 b0 N. u; m - }
4 h1 X& F2 _3 p& T2 x# z3 P9 u$ q9 s - __weak uint32_t HAL_GetTick(void)" B4 Y0 Q! a' P5 s4 n2 k
- {
8 U& z. R7 P7 i5 l9 k7 x) i M. P# Y s - return uwTick;
- u" D, [5 P6 W' X; A8 a - }
, |, s4 }0 X1 p - __weak void HAL_Delay(uint32_t Delay)
; T& X Y, p" e - {
4 x% M) l& s0 |4 [' n+ E6 b - uint32_t tickstart = HAL_GetTick();
* ]( f3 A5 O3 G8 } - uint32_t wait = Delay;% Q% B. N- ^ S3 N$ p+ p
- . F7 {( H; G+ _( I5 V
- /* Add a period to guaranty minimum wait */; T' _2 _: n% r5 [
- if (wait < HAL_MAX_DELAY)
2 ~! j t# F0 r I; [+ s4 E$ G$ A+ i% r - {
% _% F' E! Z+ {8 c - wait += (uint32_t)(uwTickFreq);( b$ V' R; N# \3 P9 i
- }7 V- L9 a8 r8 g# _
-
/ G) {$ T# M4 A - while((HAL_GetTick() - tickstart) < wait)
8 U$ s7 w2 X C - {
' {" C8 X8 t+ j6 l0 J - }% o* R4 N% R# p% P
- }
复制代码 自定义的us延时 - void my_delay_us(uint32_t nus)2 k9 U8 k, z3 M5 n
- {
5 \. i9 h3 k2 a, H$ `' i - uint32_t temp; 0 F+ p8 B* L. E9 D: l7 L
- uint32_t fac_us = SystemCoreClock/1000000; //为系统时钟的1/1000000 $ d; O0 e) r. r' Y
- SysTick->LOAD = nus*fac_us; //时间加载 # ~3 c8 U$ V0 N" r
- SysTick->VAL = 0x00; //清空计数器
0 v7 ^- w6 Z/ ]9 }, a% p - SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数 8 m1 ~' M8 d& ?, G$ o+ Y$ n% g
- do' i k J+ l1 T T! t, [
- {
2 R# D i6 K+ K# z- v - temp = SysTick->CTRL;5 R( D! ]8 m/ T3 E4 i3 w2 a
- }8 Z3 _$ j6 R4 T/ T. n
- while((temp & 0x01) &&! (temp&(1 << 16))); //等待时间到达 1 J. e7 O" }7 P8 X
- SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; //关闭计数器
' L, j) W9 R& v - SysTick->VAL = 0X00; //清空计数器
' {, t5 T5 j5 J( i - }
复制代码 , U0 _2 n: X% P! @9 D
2、如果想用systick座系统的时钟节拍,需要开启systick中断,可以直接调用 SysTick_Config 来配置,也可以使用 HAL_Init 来配置,HAL_Init 配置最终也会调用 SysTick_Config 函数 - HAL_Init(void)
9 h, j) j3 g+ o! J+ R+ H - ---> HAL_InitTick(uint32_t TickPriority)
) p1 q2 [ q' O5 ]+ ` - ---> SysTick_Config(uint32_t ticks)$ C& {, g3 f* U1 o% t
- {
, B( `" P* N$ \3 a2 d1 U2 { - if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
- F) b* K% }; G! }% H9 _; j% S" b+ i - {4 x! y4 L- d6 J; D- X
- return (1UL); /* Reload value impossible */8 V7 X* `' ~8 S* G
- }2 f, W, Q7 h# t0 t
-
+ x, p9 P5 j6 E% L+ @( ` - SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */$ i: C- e% n% A4 @6 M+ \
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
, Y: t& ~: l/ l/ d - SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
, l! L' s# j+ ?2 W; k( o; G4 Y - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |) x/ q8 f" U( q: e/ ^
- SysTick_CTRL_TICKINT_Msk |
6 d2 U7 t. W5 l' ? - SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */2 O( E: ?0 C; R, C
- return (0UL); /* Function successful */) B5 C, a4 \' Z5 h4 e& |: L8 y8 ]
- }
复制代码
7 V" R9 ~5 S( [8 r# `1 V 这样配置完成之后,还需要再systick的中断中调用 osSystickHandler 和 HAL_IncTick - void SysTick_Handler(void)9 r( D; O/ p2 P6 k
- {
8 a9 f$ b; N. }5 t6 Z/ L+ I0 S - osSystickHandler();//为OS提供系统时钟节拍: f) d* E8 _! o
- HAL_IncTick();//为HAL库提供时钟基准
! \, G# S/ \5 ]* o2 L - }
复制代码 / O/ r3 h2 {$ j; G
转载此文目的在于传递更多信息,版权归原作者所有,如涉及侵权,请联系小编删除。 文章出处: MCU开发加油站 ( i. I- V& {. f, l- o0 N
|