STM32 滴答时钟 SysTick 的使用 STM32F103C8T6

 

      程序完成利用STM32F103C8T6 滴答时钟 SysTick进行定时,每隔1秒输出脚PC13的小灯闪烁一下。

注意,小灯每隔1秒闪烁只是转换状态,可以理解为定时或1个脉冲时间,但并不是频率,频率要2个

脉冲时间2秒,所以要测频率的话是0.5Hz,即频率=1/2秒= 0.5Hz 。

 

1  使用中断的方法

修改stm32f10x_it.c文件,增加下面内容:

extern void LED_PC13 ();             //外部引入函数声明  加在文件首部

void SysTick_Handler(void)          //中断入口
{

LED_PC13 ();                               //亮灯取反灭灯函数

}

 

下面是main.c

#include "stm32f10x.h"

//**********************************************************************************

void GPIO_CFG()                                                                   //亮灯引脚配置函数
{
GPIO_InitTypeDef GPIO_InitStructure;                                   //声明GPIO_InitStructure结构变量
// 原版创作,引用请指明出处 https://www.cnblogs.com/beiyhs/p/12438787.html   北有寒山
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能AHB预分频器到端口C的开关

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;                     //指定脚13输出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;       //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //设定端口最快输出50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure);                              //按以上参数设置C口

GPIO_SetBits( GPIOC, GPIO_Pin_13);                                 //置高GPIO_Pin_13,关闭LED
}

//*********************************************************************************
void LED_PC13(void)                                                             //亮灯取反灭灯函数
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13,                                  //指定修改PC13脚的位
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)))); //读PC状态后取反
}

//********************************************************************************* 

//*********************************************************************************
int main(void)
{
GPIO_CFG() ;                                           //亮灯脚PC13的设置函数

SysTick_Config(9000000);                        //重装值设9M,定时1秒
//SysTick_Config(9000);                            //重装值设9K,定时1毫秒
//SysTick_Config(9);                                  //重装值设9,定时1微秒
//NVIC_SetPriority (SysTick_IRQn, 0);      //设SysTick中断优先级最高,不会在中断时被别的中断打断
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);  //配置SysTick时钟=HCLK时钟/8
                                                                                                      //即72M/8=9MHz 即记数9M次耗时1秒
                                                                                                      //注意要放在SysTick_Config函数之后

                                                                                                       //如果屏蔽此句,默认使用的时钟是72M

                                                                                                      //将上面9000000 改为72000000仍可得到

                                                                                                      //1秒定时

while (1)
{ }
}

 说明:
 1.1  systick定时器的内部计数器是24位递减的,最大重装值0xFFFFFF,即16777215,设置时不能超此值。

 1.2  使用systick定时器,只需调用SysTick_Config(uint32_t ticks)函数即可,该函数可以自动完成重装载

        值的装载、时钟源选择、计数寄存器复位、中断优先级的设置(默认最低)、开中断、开始计数的工作。

        一次搞定,是不是很爽。函数是在core_cm3.h头文件中进行定义的。
 1.3  要修改时钟源,比如外部时钟,可以修改SysTick_CLKSourceConfig函数内部,也可按照SysTick_Config

       中默认设置FCLK不变。

 1.4 要修改中断优先级调用 NVIC_SetPriority函数,函数在core_cm3.h

 1.5 systick是cortex_m3的标配,不是外设。故不需要在RCC寄存器组打开他的时钟。

 1.6 每次systick溢出后会置位计数标志位和中断标志位,计数标志位在计数器重装载后被清除,而中断标志位

      也会随着中断服务程序的响应被清除,所以这两个标志位都不需要手动清除。

 

2  使用延时的方法

下面是下面是main.c

//*********************************************************************************

#include "stm32f10x.h"

//************************************************

void delay_ms(unsigned int ms)  //把ms换成us,下面9000换成9,就改成了us定时函数

{
unsigned int tmp = 0;

SysTick->LOAD = ms * 9000;    //  重装寄存器 设置 72MHz/9000=9MHz

SysTick->VAL = 0x00;               // 当前计数寄存器 清零

SysTick->CTRL = 0x01;            // 控制寄存器  使能systick,禁止中断,时钟频率AHB/8
do
   {
    tmp = SysTick->CTRL;         // 读取控制寄存器的值赋给tmp
   }

 while (!(tmp & (1<<16)));         // 就是读取tmp的第16位的值,这一位如果为0就表示计数器的值不是0(即

                                                 // 还在计数),如果是1就表示计数器已经自减到0了,计数结束。

                                                  //假设该值为0,还在计数,套上外面的!取反为1,继续做do的内容。

 SysTick->VAL = 0x00;             // 当前计数寄存器 清零
 
SysTick->CTRL = 0x00;          //失能systick
}

 

//*********************************************************************************
int main(void)

{

GPIO_CFG() ;                                           //亮灯脚PC13 设置   参照上面同名函数,不再贴出

while(1)

 {

  Delay_ms(1000);

  GPIO_SetBits(GPIOC,GPIO_Pin_13);
  Delay_ms(1000);
  GPIO_ResetBits(GPIOC,GPIO_Pin_13);

  }

}

//*********************************************************************************************************

说明: 上面的定时函数如果用到us级别时,误差还是不能忽视的,尤其是10us级别误差很大的这是因为

程序指令的执行、跳转都是要花费时间的,也是在us级别。如果是us级精确定时输出控制的话,可以考

虑使用PWM方式,毕竟设定一次即可,后面全是硬件自己控制。

 

posted @ 2020-03-07 22:10  北有寒山  阅读(4689)  评论(0编辑  收藏  举报