本帖最后由 kkhkbb 于 2018-3-19 09:11 编辑
/ Z: U& U$ I, K
9 y6 \- d# E9 j+ @6 c$ r ]一、 概述 1、 时钟系统简介 (1)STM32时钟源分以下五类: - 高速内部时钟(HSI):RC振荡器,精度不高。
- 高速外部时钟(HSE):可接石英/陶瓷谐振器或者接外部时钟源。
- 低速内部时钟(LSI):RC振荡器,提供低功耗时钟。应用如WDG。
- 低速外部时钟(LSE):接外部低频率石英晶体。应用如RTC。
- 常闭不带复位:锁相环倍环输出(PLL):其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频倍数可调,但是其最大输出频率受限数值因芯片型号而异。
7 `1 b/ f) N* R/ Y$ e# ]3 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所示:
' v4 v J/ ~$ R7 G 图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的格式
) F3 d9 {; W! f' H(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可用;
' w# H3 b3 E$ R3 g& [. g1:HCLK不可用。 | SKEW | 0:校准值是准确的10ms;
# s# b7 g0 H' M% F7 k+ G1:校准值不是准确的10ms。 | TENMS | 该值是10ms定时的重装值。其值取决于SKEW,它可以是精确的10ms,也可以是接近10ms的值。如果该值为0,则表示无法使用校准功能,这很可能是因为时钟是系统的一个未知输入或者时钟可以动态调节。 |
二、实验原理3 V; `& F9 W( ]2 ?3 K
通过STM32的三个GPIO口驱动三色LED的三个通道;设定GPIO为推挽输出;采用灌电流的方式与LED连接,输出高电平LED灭,输出低电平LED亮。通过系统定时器实现1s定时,每秒变换一次LED颜色。
# w" n3 m5 V+ \% H; H
- W7 c* F0 k0 X
图4_4 驱动示意图 三、源代码 1.主函数 - /*
! s1 [) @0 N) x6 c& L1 Q - * Name : main
* q6 A0 ~8 q$ i4 }, ]% c - * Description : ---
5 N2 m! r1 }9 _: @5 L2 I - * Author : ysloveivy.! J3 k8 O" B: K9 S p
- *
" h9 H0 c6 c5 ~: R* h/ V - * History# i1 A2 P; q- X* t8 H
- * --------------------
. f% R! ^, h7 r# G - * Rev : 0.00
- e0 Z- e9 `+ S- A - * Date : 11/21/2015
& \: l! s1 x; l- { - * + [5 s- O* I( _. F2 W
- * create.* J- F5 u, J. A& v; m9 _+ m
- * --------------------
/ G9 L3 Q8 q7 P4 f" Z, u5 @* S - */0 N! _3 | r: B' b/ B: }
- int main(void)3 E2 k+ X# h* v i+ `
- {$ B, Z, _3 e/ s
- static int work_status = 0;
1 V, N. j" S. X7 S/ Q - led.initialize();
E- d1 a+ w3 O0 A) A/ c& N3 N. F - systick.initialize();
" k/ [0 e8 J. K# q2 U+ [$ A0 w* T - //每隔一秒三色灯进行交替循环闪烁
6 N, g6 H8 N5 S9 d/ l - while(1){
" y& H5 A2 x- c) B& ` - if(systick.second_flag == 1){ //每隔一秒标志位置1,执行一次$ L# A+ v q |+ T$ {; d0 A [
- systick.second_flag = 0;/ C) H# }" h# J9 k2 j3 Y# N
- work_status += 1;' _2 z; T9 C7 p
- if(work_status > 2)work_status = 0;
6 f' Z* K; H3 w5 H# \: Q9 V. M5 ] - }
$ T9 V2 U9 E2 u9 L - switch (work_status){
5 t/ T4 b0 Y0 C$ q# ]1 C( l. d - case 0 :
) m$ C( Y) D3 X9 h( Y. G* k - LED_RED_ON;" r3 E' F$ n8 R( u$ q) R! S' |
- LED_GREEN_OFF;& N0 h! D& L3 A! I5 }/ c" F
- LED_BLUE_OFF;0 A' x& U% I+ V3 i$ a9 j1 |
- break;
* U$ E5 V1 ^+ o p - 5 I9 m1 S9 H: x) k' ~- x
- case 1 :
) j# F" \" ?$ k - LED_RED_OFF;
$ v8 X9 A$ H1 m5 G8 ]3 c9 C - LED_GREEN_ON;
9 J9 k# f) e/ [ @ - LED_BLUE_OFF;) h. N% j, @6 q5 B5 w6 M" H: t
- break;7 L7 Q3 S/ i) q* S
- : f& K6 s5 c u' R9 S5 g
- case 2:, V+ ~9 U, x$ p" O* F o
- LED_RED_OFF;
: k9 i& a# Z, {7 j - LED_GREEN_OFF;
7 b$ }& K. i& T5 m2 I$ _. a - LED_BLUE_ON;
% R h! n' S$ ~9 { d( ?* @ - break;6 \' B8 k! n2 f
4 ?) @7 E. A! V2 j g" D8 u w- default:
复制代码 2.Systick初始化 以下是Systick初始化及中断设置函数,主要实现定标志位的时1s,改变一次标志位,使用LED显色状态变换一次。 - /*
2 K% U5 J2 K0 d0 n" }* B+ w - * Name : initialize
# @$ Y5 q G7 u) K+ L - * Description : ---! A8 N& T* P; [; j; m
- * Author : ysloveivy.
1 t: }9 x' B; |+ ~- n - *4 g, V1 G& d# s. ~6 v
- * History7 }4 y8 H: P q8 z8 a
- * -------------------
$ q8 A% e7 n* E: A) d) ]9 v9 }1 {- r% U - * Rev : 0.00, v- J- V! {# @# r! _8 X
- * Date : 11/21/2015
* H, ]0 W. e( V K2 l8 Y1 M - * ' X7 Y4 l8 O3 E$ A; \# ^
- * create.
+ p9 z1 J% f) {4 t1 ?9 k8 C - * -------------------* \% o1 o2 C' a' f
- */; U" g3 l+ f; D# [1 A' ^
- static int initialize(void)
7 U0 o! b! w" l8 z - {
1 P: X5 C. D' V; Q - //定时1ms
* \/ c* N Z3 w - if(SysTick_Config(SystemCoreClock / 1000)){
/ n. m, J& }! p' U - while(1); f$ {( C' t% \2 u, E
- }
; e }/ Z) X+ y5 t - return 0;
: x, o; b% x7 [) f4 [7 ? - }
2 b" y0 w6 \0 u7 q" Z h - /*6 C" W7 H4 S+ @! T% [5 D
- * Name : SysTick_Handler4 `4 L, ^+ M; C
- * Description : ---, T. M. [3 ^5 v" `% L2 f
- * Author : ysloveivy.) I1 q* v: i0 S* u8 f
- * History
$ f- t+ J- Y; b* m, i g6 i7 p - * -------------------3 q$ P: i! P. E) I/ w
- * Rev : 0.00
3 M! Q' D1 o: E; R7 e - * Date : 11/21/20156 ~# q2 `' i% K5 B% F) i; f
- * 4 B& F, R- H' v8 s/ `
- * create.( g; h: q5 ]+ S& W# r3 j; o
- * -------------------: M7 }" z c; ?% v5 r; Z4 i1 _3 W
- */
( ]" F( ^, {* y# Q2 z - void SysTick_Handler(void)' d8 t0 L) }- I- W
- {
7 x3 L* K/ a( `; r - static int counter = 0;% v" w# |6 ]) I" @/ R( ^
6 E5 g8 f6 G6 v# K1 ^- if((counter ++ % 1000) == 0){ //每次中断counter自加1,判断是否整秒
4 X6 V' M0 h9 o- N1 ]3 u - systick.second_flag = 1;
* P$ v$ J, A3 y - }) h9 O3 a$ U3 P# @. T( U9 b- c: s
- }
复制代码 3.小知识 在上面有两个重要的函数 1.SysTick_Confing(uint32_t ticks) 该函数的作用是初始化systick,时钟为HCLK(CM3一般为72M,CM4一般为168M),并开启中断。 - __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)2 n. |& D* J$ j2 o
- {7 t1 ~3 @9 ^0 e5 Q
- if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) //大于重载寄存器最大值0xFFFFFF
' Q5 l" u' m& j7 b3 h( H - {
8 E0 u! u; {) r7 A) M - return (1UL); //重新加载值不可能,返回错误 ( V$ `5 V5 N% l4 v% R
- }
! T: F( B9 k8 Q2 w3 ~# t8 ^. m& F! b - SysTick->LOAD = (uint32_t)(ticks - 1UL); //计数范围0到ticks-1
& h, {9 \% S) @% L - NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
, X: \, \) Y6 s9 l3 Y; i" N: m$ I - //设置优先级: x# G2 m) P7 D9 V4 ~- D, g
- SysTick->VAL = 0UL; //当前值初始化为0
. F$ A- m* n* _' m) z1 y - //接下来设置控制寄存器,以位与的方式实现三个控制位的设置。! O; u8 L3 n+ T _ w
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | //选择时钟源
( w' x; ~" ^7 X, x6 J: h' K! N. r - SysTick_CTRL_TICKINT_Msk | //开启中断
" I' r. @, b/ g X' r" m1 \ - SysTick_CTRL_ENABLE_Msk; //使能定时器
6 L( e& n; j, ^- D' I/ A4 t - return (0UL); //初始化成功返回
, _) g1 |2 ]' F: \% t - }
复制代码 回头看看程序中的SysTick_Config(SystemCoreClock / 1000)语句,该函数中的SystemCoreClock为时钟频率已在库函数中宏定义。如在iCore3双核心板ARM的HCLK为168M(每秒168M次计数),则程序中SystemCoreClock / 1000即意味每1ms中断一次。 2.void SysTick_Handler(void) 该函数是中断函数,即每次SysTick中断产生时运行一次函数,其在启动文件中已有设置,在驱动文件中使用时无需再次声明。
, I- b( F6 x/ h; R3 ~) K& R 四、 实验现象 iCore3的双核心板上与ARM相连的三色LED(PCB上标示为ARM·LED),红色、绿色、蓝色每秒交替点亮。 五、 代码包下载链接
A$ k# Z7 U( N) \. @, ] |
你直接搜索【零基础学习STM32】可以找到我们所有的帖子。。
另外一个也是你啊