|
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()
3 {4 P7 k: G' N9 U4 d1 M' g; e - {
* [# a; l! q# U - ...........; x% Y3 q' x. b! Q
- LL_SYSTICK_SetClkSource(LL_SYSTICK_CLKSOURCE_HCLK);
- q* G% n0 @; Z% t! K1 g - LL_SetSystemCoreClock(32000000);% J# T2 a7 }# ]2 K+ R' U
- #ifndef SYSTICK_IRQ
5 ~3 |3 t5 R5 U8 g - LL_Init1msTick(32000000); //使能systick但是不开启systick中断
" V2 m* ^$ J+ Z0 |5 w% p: Q8 \ - #else
2 X0 ?. u* e! e5 N( D - SysTick_Config(SystemCoreClock / 1000);//使能systick同时开启systick中断$ a2 @: E# b6 C5 O4 P0 v7 n/ x) I
- #endif% E) c* f8 H0 k1 [* E: {
- }
复制代码 但是这里 需要注意的是,是不是需要开启 systick 中断!!!! 1、如果只是想用systick来作为延时用,程序不想被中断打断,就只需要使能systick而不用开启systick中断,调用 LL_Init1msTick 即可 - void LL_Init1msTick(uint32_t HCLKFrequency)
3 c2 T! s7 R5 U& R8 k - ---> LL_InitTick(HCLKFrequency, 1000U);$ D6 k$ } X* U* y8 m
- ---> __STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks)' D/ L$ U F- G2 r; A
- {
0 W8 f1 R9 U5 \/ `: ^' q - /* Configure the SysTick to have interrupt in 1ms time base */
8 a7 O0 r+ k4 O. \+ W - SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */
/ I% o1 M. ]) N; J, Q - SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
V e5 J2 w9 M Q- q0 f - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
( x) n* a5 z! S; ~3 i- V$ [: ~ - SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */
8 S6 p' E) ^: ?4 _( Y - }
复制代码
8 L" `. f. Y" p但是需要自己编写延时函数,不能使用HAL库提供的HAL_Delay()。原因如下:HAL_Delay的实现是依靠一个uwTickFreq变量,uwTickFreq是在HAL_IncTick中累加的,需要在 SysTick_Handler中断函数中周期调用,这样HAL_Delay才会有一个基准 - __weak void HAL_IncTick(void)
7 B0 B; {6 L6 |" e& _ - {
6 c7 ^4 A( B$ {" B) }! h: L - uwTick += uwTickFreq;+ b+ p) h/ z i# Z: L+ V7 N
- }, m2 ]' b$ j9 e1 W9 C- d
- __weak uint32_t HAL_GetTick(void)7 F2 g+ h/ D" t- h- P1 T
- {
' Y# I) p; u/ V- H2 d2 V - return uwTick;7 X6 _2 F a3 j7 J
- }6 | N1 J" w6 l
- __weak void HAL_Delay(uint32_t Delay)7 d6 q2 u# F f
- { A7 d8 k0 }8 I
- uint32_t tickstart = HAL_GetTick();! C1 F9 y% E) A7 X# W
- uint32_t wait = Delay;
4 ~$ X8 C; k& o. A$ x: a -
9 O) O; J3 c+ Q* U T0 A7 j" Y - /* Add a period to guaranty minimum wait */7 d% a h1 J! f1 b; Y5 K( v
- if (wait < HAL_MAX_DELAY)
# k- s- G B+ X% f9 b - {
8 l& j, f- @9 T2 I& R5 m" n - wait += (uint32_t)(uwTickFreq);
9 @9 p9 q8 [5 b - }0 v$ o, t; @( p4 i
-
4 U3 H! N# v+ ?% Q - while((HAL_GetTick() - tickstart) < wait)% L0 i# E3 H1 V3 v0 `% Z
- {
% S& |8 n; L* N, H, ]& S - } _) _+ A2 O% Y/ E5 `: o, `: N
- }
复制代码 自定义的us延时 - void my_delay_us(uint32_t nus)
* d& }4 {# V7 T9 V7 z) Y - { ) U7 V' F# ]& [& n$ i& O6 w
- uint32_t temp;
) v* X* ~, m; f* M! B. a8 g& ? | - uint32_t fac_us = SystemCoreClock/1000000; //为系统时钟的1/1000000
! w4 G) P' R# r5 _; x! V. U - SysTick->LOAD = nus*fac_us; //时间加载
4 v! C7 v3 I1 T - SysTick->VAL = 0x00; //清空计数器9 ?" X% d* u7 C0 x' l' l
- SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //开始倒数 + X" a. W% y) i
- do
6 ^/ w5 H, m# C9 v' b6 L6 H - {) ~( @8 x* h2 W3 Z, t; B1 Q& A
- temp = SysTick->CTRL;6 g' d6 j# n7 C- j3 u6 s
- }3 L6 A" ^1 F4 @
- while((temp & 0x01) &&! (temp&(1 << 16))); //等待时间到达
/ h1 {+ s. |' u9 ] - SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk; //关闭计数器7 u" h: W) [/ o+ j' ~" i, Z a* C
- SysTick->VAL = 0X00; //清空计数器
: h; t- y9 f# t( V5 r" \ - }
复制代码 2 X5 R& D1 o2 b% ?; x! h7 t4 R% T6 h
2、如果想用systick座系统的时钟节拍,需要开启systick中断,可以直接调用 SysTick_Config 来配置,也可以使用 HAL_Init 来配置,HAL_Init 配置最终也会调用 SysTick_Config 函数 - HAL_Init(void)' F$ _6 _3 u3 s, ?0 B
- ---> HAL_InitTick(uint32_t TickPriority)) T" D R- Y) f$ [) I8 \5 F
- ---> SysTick_Config(uint32_t ticks)" d2 L' U0 v" G' J" q$ G
- {" H c1 ?7 b) l( ^9 z
- if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)( h+ {& ?3 E0 `- ]5 |0 l6 f6 l/ x
- {
! Y7 w8 Z4 K# C/ Z; R/ H - return (1UL); /* Reload value impossible */
2 z7 X/ e) l! Z( K$ @: c" b. e# o - }
2 H4 s- I9 ^* Q! F3 y& J" x" S -
" G! H& j2 |, H( f3 ~- ~0 V - SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */3 M% u% u# u1 W# q9 u
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt *// |& {2 H# N" Y# C3 O2 f4 Y
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */& P! L% N$ D1 T7 k' z8 V, m
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |# {& n% h; y6 T! s2 s
- SysTick_CTRL_TICKINT_Msk |. a4 S; N# Z& D; w; y$ o
- SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
2 r0 N* B% \- I v# | - return (0UL); /* Function successful */- l1 _5 @9 x0 W9 p" E
- }
复制代码
3 c9 A- B; i2 P9 ^; L4 N! ~% V 这样配置完成之后,还需要再systick的中断中调用 osSystickHandler 和 HAL_IncTick - void SysTick_Handler(void)
# I% e$ w+ [1 N) U7 v' h7 x - {
8 o0 p. f# R& X5 n - osSystickHandler();//为OS提供系统时钟节拍8 S) X8 r: c4 y6 x9 a2 M5 Z
- HAL_IncTick();//为HAL库提供时钟基准
) c9 N$ G" k3 j) p. x2 L - }
复制代码 . m M' N! K% H1 w% j% y1 w
转载此文目的在于传递更多信息,版权归原作者所有,如涉及侵权,请联系小编删除。 文章出处: MCU开发加油站
% T1 q; v4 H. V |