本帖最后由 kkhkbb 于 2018-3-19 09:11 编辑
# L5 D" q3 P) {* t5 e6 R6 b: m
7 u0 R5 n- @! q# A0 h2 t. R一、 概述 1、 时钟系统简介 (1)STM32时钟源分以下五类: - 高速内部时钟(HSI):RC振荡器,精度不高。
- 高速外部时钟(HSE):可接石英/陶瓷谐振器或者接外部时钟源。
- 低速内部时钟(LSI):RC振荡器,提供低功耗时钟。应用如WDG。
- 低速外部时钟(LSE):接外部低频率石英晶体。应用如RTC。
- 常闭不带复位:锁相环倍环输出(PLL):其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频倍数可调,但是其最大输出频率受限数值因芯片型号而异。
3 H# Y3 a- K% J$ W$ h! ?3 Y1 ~3 O8 n# a9 Q7 p
(2)系统时钟SYSCLK可来源于:HSI振荡器时钟、HSE振荡器时钟、PLL时钟。 2、SYTICK简介 在STM32中,SysTick是内核CM4中的一个24位的递减计数器,也称系统嘀答定时器。SysTick的最大使命,就是定期地产生异常请求,作为系统的时基。操作系统需要这种“滴答”来推动任务和时间的管理。 SysTick在设定初值并开启后,每经一个系统时钟周期,计数值减1,计数到0时,将从重载寄存器中自动重新装载定时初值并继续计数,同时内部的COUNTFLAG标志位置1,触发中断(中断允许情况下),中断响应属于NVIC异常,异常号为15,Systick中断优先级可设置。 3、SYTICK寄存器控制 STM32内部有4个寄存器控制SysTick定时器。分别为:控制寄存器STK_CSR、重载寄存器STK_LOAD、当前值寄存器STK_VAL和校准值寄存器STK_CALRB。下面分别对这4个寄存器做详细介绍。 (1)控制寄存器STK_CSR(地址:0xE000E010) 控制寄存器STK_CSR中有4个bit具有意义,其内容如图4_0、表4_0所示:
3 g$ n( Z) v4 `! a- l 图4_0 控制寄存器STK_CSR的格式 ENABLE(位0) | Systick使能位。 0:关闭Systick功能; 1:开启Systick功能。 | TICKINT(位1) | Systick中断使能位。 0:关闭Systick中断; 1:开启Systick中断,systick倒数到零时产生systick异常中断。 | CLKSOURCE(位2) | Systick时钟源选择位。 0:使用HCLK/8作为Systick时钟(外部时钟); 1:使用HCLK作为Systick时钟(内核时钟)。 | COUNTFLAG(位16) | Systick计数比较标志,如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。如果读取该位,该位将自动清零。 | 表4_0 控制寄存器STK_CSR的格式
+ x# R: g- h: i/ A* ^# L5 O(2)重载寄存器STK_LOAD(地址:0xE000E014) 图4_1 重载寄存器STK_LOAD的格式 重载寄存器STK_LOAD为24位的寄存器(0:23有效),最大计数0xFFFFFF。SysTick定时器递减至0时,重载寄存器中的值就会被重新装载,继续开始递减计数。 (3)当前值寄存器STK_VAL(地址:0xE000E018) 图4_2 当前值寄存器STK_VAL的格式 当前值寄存器STK_VAL为24位的寄存器,读取时返回当前计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志。 (4)校准值寄存器STK_CALRB(地址:0xE000E01C) 图4_3 校准值值寄存器STK_CALRB的格式 NOREF | 0:HCLK可用;& R! m* t: s: A
1:HCLK不可用。 | SKEW | 0:校准值是准确的10ms;
; \6 u: d* h* g6 G& l$ o1:校准值不是准确的10ms。 | TENMS | 该值是10ms定时的重装值。其值取决于SKEW,它可以是精确的10ms,也可以是接近10ms的值。如果该值为0,则表示无法使用校准功能,这很可能是因为时钟是系统的一个未知输入或者时钟可以动态调节。 |
二、实验原理- K0 t- U7 B) n+ o
通过STM32的三个GPIO口驱动三色LED的三个通道;设定GPIO为推挽输出;采用灌电流的方式与LED连接,输出高电平LED灭,输出低电平LED亮。通过系统定时器实现1s定时,每秒变换一次LED颜色。. g) v& Q4 T: M3 e q
6 R, y. F% K$ D* k X/ z
图4_4 驱动示意图 三、源代码 1.主函数 - /*
8 R8 O, l, k' ] - * Name : main
! k- n L, x2 V - * Description : ---
( l+ @. ~7 ~1 o - * Author : ysloveivy.; L- b$ N: x: k5 r* S, \6 @9 [
- *8 t" a# O. ?. t7 M
- * History2 X1 z' Z, h0 R' [0 q- ~* w
- * --------------------6 y, n7 O* V b4 `
- * Rev : 0.00
1 H6 Z3 b/ s4 U - * Date : 11/21/2015& Z, e9 |8 H* k Z) g; z1 f _2 P
- * J! F9 J1 N. m# I! B
- * create.
1 C" A: _6 ?9 Y' l, E - * --------------------$ q( P1 K p4 L2 J
- */
\$ ^5 }2 V" t- Y, i - int main(void)
* K# h, G: a9 ]* m2 p% }- m - {
7 B4 D, W* i. V - static int work_status = 0;
4 s2 h) }/ `$ K/ w - led.initialize();8 I3 ]- `7 `& r7 i& C
- systick.initialize();
) K, l5 w6 @& {- F$ @ - //每隔一秒三色灯进行交替循环闪烁8 Q' {8 o' y$ C0 C& ?4 g( W% L0 ^
- while(1){
& q! ~1 c0 }5 t7 _. ^ - if(systick.second_flag == 1){ //每隔一秒标志位置1,执行一次2 k5 C2 Y3 {. S @. H2 N
- systick.second_flag = 0;8 g/ `8 Z2 O+ A
- work_status += 1;
- q! q |9 b% F: X - if(work_status > 2)work_status = 0;
6 C/ j4 b0 B X8 \, K8 H" i - }
) G5 s$ `2 e" i6 ?+ \0 K3 Q, [ - switch (work_status){0 C* W% f( u4 z* ~( m
- case 0 :; }) e) r1 Q2 F4 ~$ a# E
- LED_RED_ON;8 ^. O) `2 G ]. I# E1 X8 G
- LED_GREEN_OFF;* b& W6 c! w6 F8 `: c Q8 Y
- LED_BLUE_OFF;5 ?: Z# R2 z0 m3 @: ]( L+ V8 V6 D1 _4 Z
- break;5 y t3 A9 w" {+ @) Y: E
- ( q5 V- q3 J( R, u6 X
- case 1 :
! H& u5 a$ Z8 } s8 A" f' _ - LED_RED_OFF;" i% F* k% J5 I% w4 \7 R
- LED_GREEN_ON;& l1 @8 T' U% Z- {
- LED_BLUE_OFF;
- Y9 ]$ d+ o+ Z; Z - break;+ c2 I, d2 [1 }7 G
- 0 l( q4 a0 c) I9 \
- case 2:
; u) w: C6 _$ g& F - LED_RED_OFF;5 C3 P$ w5 h) ^2 r# ^ O
- LED_GREEN_OFF;5 A. ~3 g5 @, ]+ S) w2 A
- LED_BLUE_ON;, F. u0 R8 D W: E! j
- break;
7 S8 x y: U& u/ U& t
) w+ g; C# c4 Z6 `- default:
复制代码 2.Systick初始化 以下是Systick初始化及中断设置函数,主要实现定标志位的时1s,改变一次标志位,使用LED显色状态变换一次。 - /*
2 Q c& }( m# E. m! K' C - * Name : initialize
3 |# X9 H9 {6 `% E - * Description : ---
2 d( t8 E. k7 ^7 o5 ] l( u* W - * Author : ysloveivy.
& y8 F. Z% _( h, H4 Z" J [ - *+ j7 z, J u+ |( o+ f
- * History
( L' u9 L) R3 k. M g: q% s5 \$ M - * -------------------
! Y% F1 ^* m5 X! X4 n" A - * Rev : 0.00
- A) l) [/ @ Q% s - * Date : 11/21/20152 s; a; G0 \$ V6 l, {" }
- *
( A% F3 f L( J w, |: } - * create.
" l0 S3 J2 v8 T* e6 C1 @% F% T - * -------------------9 o8 X9 s$ }0 U8 h2 F/ m
- */
[/ |8 P' j' z - static int initialize(void)& s s* k2 i* p" X4 V9 _# T1 J% j' \: w
- {, w8 S, x6 H) l1 ]$ E8 @
- //定时1ms
: U# i! @7 V' q - if(SysTick_Config(SystemCoreClock / 1000)){
/ x" ?3 i/ k7 L$ N' G - while(1); G, U9 U& ]7 E
- }1 U; Z* c+ V- D, m# r. f& F
- return 0;
8 B% Y7 e3 t/ m" ] - }
" P8 Y8 o& h5 \5 ~8 r: L - /*
8 Z1 l+ V7 M3 n! g8 a - * Name : SysTick_Handler
6 G3 \, N5 J* w& H" p - * Description : ---/ C$ M6 ~* B* f9 k
- * Author : ysloveivy.
9 v2 A2 B( i, Z, a( R( C - * History
5 N1 m; G+ {, \# D" h" U! W' b - * -------------------
% H& ~# p8 D, O, T! [9 P* F - * Rev : 0.00
2 O% ~; F0 }. m/ n8 D4 S5 x - * Date : 11/21/20159 v+ t" _0 `1 J# J0 f
- * 6 l, A1 U0 K# S- ] `+ K0 i
- * create.
$ g2 l: ?$ o) Z5 z: R' \) ? - * -------------------
0 |! p; v& v0 o9 Z5 `. M6 P - */& V- c$ W6 _8 s
- void SysTick_Handler(void) }% Y" x2 f4 u" s7 C
- {
( n# G6 ^' _! _0 U; q- h - static int counter = 0;, s2 ?1 r8 Q0 r
- . t$ {$ }- b% d# ?9 V/ {% M
- if((counter ++ % 1000) == 0){ //每次中断counter自加1,判断是否整秒
1 d. d7 g2 u. A- o2 v- E - systick.second_flag = 1;
) d" a- Y( n- g) _' k W9 c - }" U' y- d; f' @; S2 R
- }
复制代码 3.小知识 在上面有两个重要的函数 1.SysTick_Confing(uint32_t ticks) 该函数的作用是初始化systick,时钟为HCLK(CM3一般为72M,CM4一般为168M),并开启中断。 - __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)- ~( |+ l0 [9 t% m# F
- {
9 M; i/ W- ^9 L, [+ R - if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) //大于重载寄存器最大值0xFFFFFF' B8 l1 \6 m. ~2 K
- {2 t- q2 L% O0 N- P/ O
- return (1UL); //重新加载值不可能,返回错误
" }0 D/ q# E- Z% C6 ? - }( c% K- L6 o& Y* G
- SysTick->LOAD = (uint32_t)(ticks - 1UL); //计数范围0到ticks-1 " l" L' c& H5 g4 L5 U3 s
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
9 a# ?/ E1 d9 s8 J! |% g: Z - //设置优先级
( a$ K% ^6 v( l3 l9 ?) n0 I - SysTick->VAL = 0UL; //当前值初始化为0 6 a$ v+ P4 ~0 P; K
- //接下来设置控制寄存器,以位与的方式实现三个控制位的设置。
8 |6 K; K8 @' L O/ r8 I - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | //选择时钟源0 x) ?; ^" t2 ]+ a
- SysTick_CTRL_TICKINT_Msk | //开启中断
y$ N) d" {6 q% q' ~: F6 ~6 b - SysTick_CTRL_ENABLE_Msk; //使能定时器
: K+ e& g+ I6 e& {* V! n# X0 G - return (0UL); //初始化成功返回
* K' ]' g$ h% F% e& { J - }
复制代码 回头看看程序中的SysTick_Config(SystemCoreClock / 1000)语句,该函数中的SystemCoreClock为时钟频率已在库函数中宏定义。如在iCore3双核心板ARM的HCLK为168M(每秒168M次计数),则程序中SystemCoreClock / 1000即意味每1ms中断一次。 2.void SysTick_Handler(void) 该函数是中断函数,即每次SysTick中断产生时运行一次函数,其在启动文件中已有设置,在驱动文件中使用时无需再次声明。. r' Q/ m+ h5 v' Z4 u4 i
四、 实验现象 iCore3的双核心板上与ARM相连的三色LED(PCB上标示为ARM·LED),红色、绿色、蓝色每秒交替点亮。 五、 代码包下载链接 & G( } G% ]; H
|
你直接搜索【零基础学习STM32】可以找到我们所有的帖子。。
另外一个也是你啊