你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

从滴答时钟了解STM32库操作

[复制链接]
kqh1120 发布时间:2015-1-7 12:50
3 [5 ?3 m+ |# T$ B
基于库函数的开发模式,与基于API(Application Programming Interface)的软件开发有着异曲同工之处,程序员通过调用 API 函数对应用程序进行开发,而又无需访问源码,或理解内部工作机制的细节,可以减轻编程任务。STM32的基于函数库的开发模式也是一样的道理,因此对于有单片机开发经验的工程师来说,学习STM32,很容易就可以上手。虽然可以不考虑库函数内部的细节,不考虑如何实现硬件寄存器的配置,但是深入了解库函数对于提高编程能力是很有好处的,下面以系统滴答时钟为例,详解其工作流程。
滴答时钟是STM32内部的一个24位定时器,其操作相对简单,配置寄存器较少。大体的工作流程是这样的,定时器首先要有时钟源,时钟源配置好之后,设置定时时间,然后定时器启动,当定时时间到时,置位标志位,重载定时器初值,系统可采用查询标志位和中断两种工作方式做出相应的响应,下面来看看程序如何实现延时功能。
//初始化配置函数
Void Delay_Init()
{
RCC_ClocksTypeDef RCC_ClocksStatus;
RCC_GetClocksFreq(&RCC_ClocksStatus);//获取时钟频率
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//时钟源配置为系统主时钟频率/8
SysTick_ITConfig(DISABLE);//不使能中断,采用查询方式
delay_fac_us = RCC_ClocksStatus.HCLK_Frequency / 8000000;// 1us的定时初值
}
//实现延时Nus的延时功能
void Delay_us(u32 Nus)
{
SysTick_SetReload(delay_fac_us * Nus);//载入初值
SysTick_CounterCmd(SysTick_Counter_Clear);//计数器清零
SysTick_CounterCmd(SysTick_Counter_Enable);//计数器开始计数
do
{
Status = SysTick_GetFlagStatus(SysTick_FLAG_COUNT);
}while (Status != SET);//不断查询标志位,当载入初值与计数器相等时,标志位置位。
SysTick_CounterCmd(SysTick_Counter_Disable);//关闭计数器
SysTick_CounterCmd(SysTick_Counter_Clear);//清零计数器
}
//实现闪灯
Delay_Init();
While(1)
{
LED1(ON);
Delay_us(500000);//延时500ms
LED1(OFF);
}
下面来看看库函数如何实现相应的寄存器配置。
void SysTick_ITConfig(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
SysTick->CTRL |= CTRL_TICKINT_Set;
}
else
{
SysTick->CTRL &= CTRL_TICKINT_Reset;
}
}
这个函数的作用是配置寄存器开启/关闭中断,FunctionalState是自定义的数据类型,是一个枚举类型,typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
枚举类型是一种基本数据类型而不是构造类型,它用于声明一组命名的常数,将变量的值一一列出来,变量的值只限于列举出来的值的范围内,因此当一个变量有几种可能的取值时,可以将它定义为枚举类型。
assert_param(IS_FUNCTIONAL_STATE(NewState));
这句话的作用是判断参数NewState的值是否正确,如果发现参数出错,它会调用函数assert_failed()向程序员报告错误。
void assert_failed(uint8_t* file, uint32_t line)
{
while (1)
{
}
SysTick->CTRL |= CTRL_TICKINT_Set;这句话就是用来配置寄存器的语句, SysTick是系统定义的一个结构体如下,SysTick->CTRL即为滴答时钟的控制寄存器。
$ c1 X7 i1 ~1 C  E
赞 收藏 评论2 发布时间:2015-1-7 12:50

举报

2个回答
kqh1120 回答时间:2015-1-7 12:50:48
typedef struct
8 t6 _" E* V2 u- R% x5 K: _, _2 _7 C* P) H4 i" l& R& E* |0 a( B
{
3 v3 e3 o0 t( F) s/ E
  K+ }5 W9 _$ x4 y: A9 i__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
4 Q7 q0 c( u- X! f" I8 [
: n6 I( h& J4 {1 a0 L__IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */4 L! X: x+ o8 T4 [8 `; a- v
5 K# N; L  o' n% R% z
__IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
- c+ S# G" p! s3 U; Y% Z2 F/ o- X& w0 T5 N  [
__I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
  E% k5 [2 O5 S0 y! R. S. [2 i, j, l' `, Z6 {' Z# v
} SysTick_Type; //声明一个SysTick_Type型的结构体。
* ~3 |0 G: y: h8 C2 m+ g0 R/ L1 _5 Z0 J/ Q, B
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */, b- d' F/ P9 @3 T  k3 T  u( ~
' e7 {3 o# N' ]) J% p. x$ S6 @( E& ]
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
" k8 t) H$ L$ u6 c& C* b. t
7 _7 p& n/ T1 s' C& u#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */% Z9 W1 a5 O; Z# L- \7 J
, W+ Q) h3 Y, C% h. s# _
定义一个SysTick_Type类型的结构体实例SysTick,而从根本上来说这是一个地址,就是STM32芯片内部分配给滴答时钟的实际地址0xE000E000UL+0x0010UL。# T* t) r' ~' r# p+ s$ s, n/ F
' `+ m6 ^4 t# A& ?; r( k
CTRL_TICKINT_Set是一个宏定义,定义如下
% j! i- {7 I7 |: \
2 ]- R* G2 Z: ~4 o5 B6 [7 \$ `/* CTRL TICKINT Mask */
: }. O/ M1 H- A
% E( ^  C' W  Z, d+ D( y#define CTRL_TICKINT_Set ((u32)0x00000002)( B) j; [+ H+ p, i2 Z+ [; h

9 m. p0 [# [# e#define CTRL_TICKINT_Reset ((u32)0xFFFFFFFD)7 d/ c* J) q' z# S8 l+ Z& }

4 p- y6 J+ m$ D* S5 C至此,SysTick->CTRL |= CTRL_TICKINT_Set;这句话的意义已经很清晰了,就是给地址0xE000E000+0x0010 +0x000赋一个0x00000002的值,对应滴答时钟的CTRL寄存器的第2位置1。即为开启中断的意思。. L% U% |0 B) c% Y. E7 N

  }+ u, m! N1 ~上面讲的是用查询的方式,下面再说下中断触发。只需调用下面这个函数即可完成中断的设置。2 I7 y# J4 j+ r& b0 a7 L

3 @; U( O) w; ^4 tSysTick_Config(uint32_t ticks);具体实现如下:) ?/ a& u" |: b2 H3 m3 `
+ j) ]* ]6 Y- ]/ t/ T; g
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
7 ?/ O3 r. Q, P- r# O$ M* e8 J5 s1 Z! z; s
{# }  ?! W! F. d/ w! N, B
, i4 F4 b1 Z- L
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1);
$ s( A: h% I1 ?+ j7 B  Z) c; o, |& M" E
SysTick->LOAD = ticks - 1;. I3 h8 @" c+ Q6 L2 W9 M* R! w
# N; D1 H0 A1 F( |+ Q' R! Y2 k8 L
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);: n" Z# H% m1 r2 Y
5 [0 O' k0 y+ s$ X, |1 m0 U
SysTick->VAL = 0;, w9 H# p& D) O  v; B  ^3 a6 _9 B; X; R

7 G6 X! ?; l7 d& \# I0 q% CSysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk |SysTick_CTRL_ENABLE_Msk;- k5 I8 d& ?- s/ i# `

9 {/ p5 J, }7 Rreturn (0);$ ?2 I2 F! c3 O4 ?6 F7 {' o

2 Z. Z3 h+ L6 c. H) v4 S3 Z}& e  M3 T; {7 w. u* {- Q
% K6 {& [1 h/ ?- u! ~
函数的参数为ticks,是要装入寄存器SysTick->LOAD的计数值,如果系统时钟为72M,把ticks赋值为SystemFrequency/10000,表示计数到720个时钟周期产生一次中断,而一个时钟周期的时间为(1/72)us,所以720x(1/72)=10us,也就实现了定时10us的功能。' l! s9 O  l5 r9 w8 d8 `+ v" m/ @
5 N2 f8 ^- y/ c( c. z
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);为SysTick中断设置优先级。将寄存器SysTick->VAL的值清0。然后使能中断,使能SysTick定时器,时钟源选择为AHB时钟。当定时时间到时,进入中断函数
  _) r! [! [: x
! S0 q+ @+ D4 k' dvoid SysTick_Handler(void), _) b2 x2 ~* e9 n. P

& C* f" ?0 t# c. S" e{3 G! Z; ?  ]4 ^: B5 s( o+ e! V
; R1 U# D, X) f) o
//具体函数实现由用户编写。5 Y% I) [+ n6 _, F& y
. `- ^& V  }/ P
}; v- @8 S- T& }& u( y$ L" ?

$ r2 x" z" O: h, [7 Y. v/ r通过对这样一个简单定时器的操作,我们可以初步了解到STM32库函数的使用方法
- E) s7 u. C1 q* @: M1 T( ^! Z, U# ^+ X$ H, N+ Q
AndyYau-268557 回答时间:2015-1-7 13:43:18
嗯,库函数比较简单直观
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版