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()
( r- r# I c0 ?; F/ Y - { ~- E& D# t0 F! G/ @: \4 e
- ...........
9 _/ A _6 Q5 U/ h9 e/ v* B - LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);5 Y, f; G+ y- e4 g: X! h% j
- LL_SetSystemCoreClock(32000000);" m$ m+ |* k4 e9 O2 X# W
- #ifndef SYSTICK_IRQ6 M% Q* B# a3 j) K
- LL_Init1msTick(32000000); //使能systick但是不开启systick中断
' D2 V0 m8 ~: f - #else1 ]* K, H1 ]8 n5 @ J
- SysTick_Config(SystemCoreClock / 1000);//使能systick同时开启systick中断
/ l) X1 X% I7 a9 ^8 ]: Z - #endif
9 }+ _* @9 W. m, n! F - }
复制代码 但是这里 需要注意的是,是不是需要开启 systick 中断!!!! 1、如果只是想用systick来作为延时用,程序不想被中断打断,就只需要使能systick而不用开启systick中断,调用 LL_Init1msTick 即可 - void LL_Init1msTick(uint32_t HCLKFrequency)
; K X# R% g K* K! J8 W - ---> LL_InitTick(HCLKFrequency, 1000U);
; a0 N/ a: ?$ J x& d - ---> __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks) z8 [3 e! _9 F. B/ {8 ~
- {. M6 D8 ^* N. S/ z
- /* Configure the SysTick to have interrupt in 1ms time base */0 N$ O) W; b+ v( H- a5 j& `, q" W, {
- SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */& N4 Y# R1 ]% y7 C9 B$ j
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */# K0 }, P% {% H X e! l, [7 Q; t
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
, L1 i/ g" K: Y! I6 _1 H$ g3 |) | - SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */6 Y2 B- V/ S4 J- \- [; }4 O
- }
复制代码 ; x. M/ l" ?- l- Z7 N$ F
但是需要自己编写延时函数,不能使用HAL库提供的HAL_Delay()。原因如下:HAL_Delay的实现是依靠一个uwTickFreq变量,uwTickFreq是在HAL_IncTick中累加的,需要在 SysTick_Handler中断函数中周期调用,这样HAL_Delay才会有一个基准 - __weak void HAL_IncTick(void)
- X' U `. R0 E: T - {
1 S' B0 c6 d+ n I4 O - uwTick += uwTickFreq;
2 X' t# Q3 H- x% Y% {& v - }
& a' ~0 l" s* j - __weak uint32_t HAL_GetTick(void)( V! m" I: i+ R' u+ ~* D1 b! i* b; }# ]
- {
9 y7 L; f2 J' j( p - return uwTick;+ S: S& p/ A0 f- }7 `" L8 [9 l
- }
, O0 b$ c! `- C! K - __weak void HAL_Delay(uint32_t Delay)
4 W0 B3 \# f, H - {
, m9 a5 ~3 f. m/ B0 V - uint32_t tickstart = HAL_GetTick();( V& y" Z4 n' Z3 L1 Y. G( ^
- uint32_t wait = Delay;
2 V9 U2 h- W# E# ^& {. o" ]7 h. ? -
# i1 m' \0 _7 b1 t5 S) e7 ? - /* Add a period to guaranty minimum wait */3 a0 U, u& _( S: S
- if (wait < HAL_MAX_DELAY)7 D- D0 s) g L4 c( @5 B
- {+ ]$ t9 C1 @' k4 l
- wait += (uint32_t)(uwTickFreq);5 X5 Q: u1 c- q/ G! v: w& k
- }/ d# A1 q7 I1 V# O8 u; m
-
( T$ L/ S V3 v4 `5 Y. E2 j0 m9 `' N - while((HAL_GetTick() - tickstart) < wait); E/ p# V9 ]; |/ v
- { S/ ^. H6 }% ?- @
- }
$ ]/ \# x0 X2 _5 K. Y$ {+ U - }
复制代码 自定义的us延时 - void my_delay_us(uint32_t nus)8 u; ^! w* r: y: X+ A" q- _
- {
' B; A$ p; D) b* |( V - uint32_t temp; 2 c# F+ N$ P7 j% G, A
- uint32_t fac_us = SystemCoreClock/1000000; //为系统时钟的1/1000000 % O: i. {% d2 G( O! Y
- SysTick->LOAD = nus*fac_us; //时间加载 - s( d( w% o& k4 m# t
- SysTick->VAL = 0x00; //清空计数器
# U; \5 I( b9 E- O; D* V$ ~ - SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数
% Z! i- o0 ?3 z* f - do
0 Q9 }5 s& m0 p0 p( s - {& h, g- p! ]6 j- n6 \( y
- temp = SysTick->CTRL;. ?' f! E9 y1 S, o3 Z. G/ A' W
- }3 Z6 b5 H& f& E& F- J
- while((temp & 0x01) &&! (temp&(1 << 16))); //等待时间到达
5 s L* e" |' {8 O" O - SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; //关闭计数器
1 ]* d" ^. x6 c( H - SysTick->VAL = 0X00; //清空计数器
1 r ~& D: y* h/ z/ n8 m# O4 P9 x+ } - }
复制代码 + `! U. H, ~: D& M8 I' {/ ^3 S
2、如果想用systick座系统的时钟节拍,需要开启systick中断,可以直接调用 SysTick_Config 来配置,也可以使用 HAL_Init 来配置,HAL_Init 配置最终也会调用 SysTick_Config 函数 - HAL_Init(void)
1 b4 L" U; @$ U$ e% u - ---> HAL_InitTick(uint32_t TickPriority)
+ F- N' T3 D/ E2 ] - ---> SysTick_Config(uint32_t ticks)
; x6 r; M1 [; k2 K - {
+ A" r+ w* v7 ]1 k' Z8 t - if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
) r ^# N9 Q* B4 x' s6 Z& W - {
/ M, t6 l1 ]/ E* H6 N! o - return (1UL); /* Reload value impossible */% h' B1 ^+ u% L
- }. b5 X2 ?% X$ r! c$ i
-
6 A2 N! v* n' s% I3 ~$ T# q: y - SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */% y2 s/ J2 b& \9 l4 U
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */8 Y! B( g, I8 E6 ^ k( {* N5 u1 }
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */, C! {: W# N+ k4 o( m! |0 L
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
2 l' Q9 p! E$ o. S; P, B; ~ - SysTick_CTRL_TICKINT_Msk |
4 ]# U0 e) `3 e" M/ t - SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */: b- a. @: [0 e, w+ {
- return (0UL); /* Function successful */
9 M7 |# i3 l. U1 c - }
复制代码 v0 g5 c( k1 E! S/ c1 w
这样配置完成之后,还需要再systick的中断中调用 osSystickHandler 和 HAL_IncTick - void SysTick_Handler(void)+ S5 D7 H- b4 G$ A. W
- {0 H* i4 z% L9 {7 Z ~8 s
- osSystickHandler();//为OS提供系统时钟节拍
* X9 ?+ i7 u& ]3 g" p - HAL_IncTick();//为HAL库提供时钟基准
) Z. A$ ?* a9 e p - }
复制代码
: ]8 m7 p* R$ y+ q! B! ^) r; j 转载此文目的在于传递更多信息,版权归原作者所有,如涉及侵权,请联系小编删除。 文章出处: MCU开发加油站 7 h8 V5 n3 |: J
|