原创 stm32库函数学习篇--SysTick

2012-10-30 14:06 7942 16 19 分类: MCU/ 嵌入式 文集: stm32库函数学习

   半个月没有碰我的stm32开发板了,生疏了不少。这次除了学习SysTick以外,还自己花了点心思琢磨怎样建立keil工程比较方便。下面就是我今天使用的工程目录,非常简洁,以后就用这个吧,看着舒心。

20121019152842212001.gif

而接下来这个是windows管理器下的目录,相信大部分人都和我一样吧,不多说。

20121019153612664001.gif
 

还要提一下,在使用库函数时,很多人喜欢每建立一个工程就将那个文件夹复制一遍。我觉得没有必要这样,将从ST官网上下载的函数包独立放在一个地方就行了,只要在工程里指定包含路径即可,毕竟修改库函数还是挺少见的。当然如果有必要修改库函数的话就不能这样。

 

言归正传,开始SysTick的探讨。

实现功能:定时1s中断,取反led灯。

3.5版的库抛弃了2.0版以前的大部分函数,对这个定时器的配置方式作了较大的更改。在我们看来,新版的库反而不如旧版的库操作方便了。但是意法半导体的工程师们这样做肯定有他们的道理。个人觉得这样做更加凸显示出嘀嗒定时器的使用场合。因为这个是M3核内的定时器,设计的目的主要是用于操作系统的节拍时钟,估计意法半的设计师们有意告诉我们如果不跑操作系统,那就不要使用SysTick。

改版以后,我们如果要使用SysTick,需要做的事情很简单了。

 

 

 

我们看一看3.5版的库自带模板的main.c里面的说明。

 

/* Setup SysTick Timer for 1 msec interrupts.
     ------------------------------------------
    1. The SysTick_Config() function is a CMSIS function which configure:
       - The SysTick Reload register with value passed as function parameter.
       - Configure the SysTick IRQ priority to the lowest value (0x0F).
       - Reset the SysTick Counter register.
       - Configure the SysTick Counter clock source to be Core Clock Source (HCLK).
       - Enable the SysTick Interrupt.
       - Start the SysTick Counter.
   
    2. You can change the SysTick Clock source to be HCLK_Div8 by calling the
       SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8) just after the
       SysTick_Config() function call. The SysTick_CLKSourceConfig() is defined
       inside the misc.c file.

    3. You can change the SysTick IRQ priority by calling the
       NVIC_SetPriority(SysTick_IRQn,...) just after the SysTick_Config() function
       call. The NVIC_SetPriority() is defined inside the core_cm3.h file.

    4. To adjust the SysTick time base, use the following formula:
                           
         Reload Value = SysTick Counter Clock (Hz) x  Desired Time base (s)
   
       - Reload Value is the parameter to be passed for SysTick_Config() function
       - Reload Value should not exceed 0xFFFFFF
   */
  if (SysTick_Config(SystemCoreClock / 1000))
  {
    /* Capture error */
    while (1);
  }

上面说得很清楚,我们只要调用SysTick_Config()函数,系统就为我们做了大量的事情。

1.该函数的参数就是预装值

2.中断设置成最低级别,并将计数寄存器清零。

3.配置SysTick的时钟为HCLK。(还可以是HCLK/8

4.使能嘀嗒定时器的中断

5.开始计数。

这么说来,我们只要调用了SysTick_Config()函数,连NVIC都不用去配置了,系统已经直接打开了中断,我们只要去填写SysTick_Handler( )就行了,而且该函数的参数就是预装值。多方便!

但是方便的同时也造成了不方便。不方便之处就是,一旦使用了SysTick,就只能用中断来定时,不能采用查询方式。固件库并没有提供我们改变工作方式的接口,如果要使用查询,那就得直接操作寄存器了,这就是麻烦之处。这正好说明了,ST的工程师们不希望我们随便来使用SysTick 。但还他们还是够意思的,后面至少告诉了我们怎样去改变中断优先级,怎样改变计数的时钟源,还有怎样去改变预装值。

 

 

所以上面这条语句

 if (SysTick_Config(SystemCoreClock / 1000))
  {
    /* Capture error */
    while (1);
  }

的作用显而易见了。

 

在if条件里调用SysTick_Config(),该函数是一定会执行的,一旦执行,就会进行我们上面讨论的初始化。另外,无论系统的时钟(HCLK)是多少,都将定时器的定时为1ms,SystemCoreClock其实就是HCLK,在我们的例子中就是72MHz。

 

 

看看SysTick_Config()的实现,就知道这条语句为什么要这么写

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */
                                                              
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

 

 

 

下面是main函数的代码

//main.c

#include "stm32f10x.h"

GPIO_InitTypeDef GPIO_InitStructure;

__IO uint32_t TimingDelay;

void rcc_cfg()
{
 ;
}

void gpio_cfg()
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void Delay(__IO uint32_t nTime)
{
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

int main(void)
{
   rcc_cfg();
   gpio_cfg();

    if (SysTick_Config(SystemCoreClock / 1000))
  {
    /* Capture error */
    while (1);
  }

  /* Infinite loop */
  while (1)
  {
    /* Set PA8 */
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
 
 Delay(1000);

    /* Reset PA8 */
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
 
    Delay(1000);
  }
}

 

 

下面是中断函数源码

//system_stm32f10x.c

extern __IO uint32_t TimingDelay;
void SysTick_Handler(void)
{
if (TimingDelay != 0x00)
    {    
 TimingDelay--;
 }
}

注意红色显示的语句,使用外部变量的方法。

文章评论3条评论)

登录后参与讨论

用户377235 2015-10-4 17:20

厉害!!

用户438376 2013-4-24 20:45

很不错

用户402268 2012-11-19 17:19

学习了,讲的不错
相关推荐阅读
用户423038 2012-12-26 09:35
利用序列的DTFT来分析被采样模拟信号的频谱----我的一点理解
       假设被采样的模拟信号为x(t)=sin(Ω0t+∅),其周期为T0,频率 为f0;        采样周期为Ts,  则采样后得到的序列为x(n)=sin(w0n+∅), ...
用户423038 2012-12-26 09:34
时域抽取基2FFT算法C程序注解
/*********************************************************************    简介:此程序包是通用的快速傅里叶变换C语...
用户423038 2012-12-26 09:33
由DFT来分析模拟信号频谱的过程之我的理解
   所谓信号的频谱,就是信号的傅里叶变换,就是信号的频域特性。           我们知道,连续时间信号的傅里叶变换所得信号的频谱函数是模 拟角频率Ω的连续函数;而对连续时间信号...
用户423038 2012-12-26 09:33
因果实序列可以完全由其奇分量或偶分量恢复
        首先,任意实序列都可以分解成奇序列和偶序列之和。 即x[n]=xe[n]+xo[n],其中,xe[n]=(x[n]+x[-n])/2,xo[n]=(x[n]-x[-n])/2。...
用户423038 2012-12-26 09:31
(*(volatile unsigned long *)用法
           对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语...
用户423038 2012-12-26 09:29
傅里叶变换的物理意义
        傅里叶变换的实质是将一个信号分离为无穷多多正弦/复指数信号的加成,也就是说,把信号变成正弦信号相加的形式——既然是无穷多个信号相加,那对于非周期信号来说,每个信号的加权应该都是零—...
我要评论
3
16
关闭 站长推荐上一条 /2 下一条