时钟滴答定时器(sysclk)用法详解

目录:

概述:本篇博客针对sysclk内核定时器(时钟滴答定时器)的常见用法进行总结,分别实现sysclk的定时、延时、计时功能,全部为代码,寄存器描述需参考《Cortex-M3 权威指南》。

平台:stm32f103奋斗开发板   开发环境:MKD5


1:sysclk的定时功能

2:sysclk的us/ms级延时功能

3:sysclk计时功能


1:sysclk的定时功能:LED1、LED2、LED3分别间隔不同的时间闪烁

main.c函数

/*
*FUNC:使用内核中的滴答定时器实现定时功能
*MCU:stm32f103
*DATE:2016/08/30
*/

#include "Sys_Driver.h"
#include "Led_Driver.h"
#include "RCC_Driver.h"

/*主函数*/
int main()
{
	SysTick_Init(INT_10MS,SysTick_CLKSource_HCLK_Div8);    /*内核滴答定时器配置*/
	RCC_PeriphClock_Config();                              /*外设时钟配置*/
	Led_Init();                                            /*LED灯初始化*/
	while(1)
	{
		/*任务1:led1每隔1s闪烁*/
		if(led1_flsh_times >= 100)
		{
			led1_flsh_times = 0;
			led1_on_off = !led1_on_off;
			if(led1_on_off == 1)
			{
				LED_ON(1);
			}
			else
			{
				LED_OFF(1)
			}
		}
		
		/*任务2:led2每隔2s闪烁*/
		if(led2_flsh_times >= 200)
		{
			led2_flsh_times = 0;
			led2_on_off = !led2_on_off;
			if(led2_on_off == 1)
			{
				LED_ON(2);
			}
			else
			{
				LED_OFF(2)
			}
		}
		
		/*任务3:led3每隔3s闪烁*/
		if(led3_flsh_times >= 300)
		{
			led3_flsh_times = 0;
			led3_on_off = !led3_on_off;
			if(led3_on_off == 1)
			{
				LED_ON(3);
			}
			else
			{
				LED_OFF(3)
			}
		}
	} //while(1)
}
sysclk配置函数:

#include "Sys_Driver.h"

/*
*SysTick_CLKSource:定时器时钟选择 SysTick_CLKSource_HCLK:系统时钟 SysTick_CLKSource_HCLK_Div8:系统时钟8分频
*/
void SysTick_Init(uint32_t ticks,uint32_t SysTick_CLKSource)
{
	/*定时器时钟选择配置*/
	if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
  }
	
	SysTick->LOAD  = ticks - 1;                  /*定时器重载值*/
	SysTick->VAL   = 0;                          /*定时器赋初值*/
	SysTick->CTRL  = SysTick_CTRL_TICKINT_Msk;   /*异常请求使能*/
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;    /*定时器使能*/
}

2:sysclk的us/ms级延时:流水灯

/*
*FUNC:使用内核中的滴答定时器实现:us/ms延时功能
*MCU:stm32f103
*DATE:2016/08/29
*/
#include "stm32f10x.h"

#define LED_ON(n) {if(n==1) GPIO_SetBits(GPIOB,GPIO_Pin_5);  \
                   if(n==2) GPIO_SetBits(GPIOD,GPIO_Pin_6);  \
                   if(n==3) GPIO_SetBits(GPIOD,GPIO_Pin_3);}
#define LED_OFF(n) {if(n==1) GPIO_ResetBits(GPIOB,GPIO_Pin_5); \
                    if(n==2) GPIO_ResetBits(GPIOD,GPIO_Pin_6); \
                    if(n==3) GPIO_ResetBits(GPIOD,GPIO_Pin_3);}

static uint32_t cnts_us = 0;   /*延时1us的计数值*/

/*
*SysTick_CLKSource:定时器时钟选择 SysTick_CLKSource_HCLK:系统时钟 SysTick_CLKSource_HCLK_Div8:系统时钟8分频
*/
void SysTick_Init(uint32_t SysTick_CLKSource)
{
	/*定时器时钟选择配置*/
	if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
  {
    SysTick->CTRL |= SysTick_CLKSource_HCLK;
		cnts_us = SystemCoreClock/1000000;
  }
  else
  {
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
		cnts_us = SystemCoreClock/(8*1000000);
  }
}

void delay_us(uint32_t cnts)
{
	uint32_t flag = 0;
	uint32_t ticks = cnts_us*cnts;
	SysTick->LOAD  = ticks - 1;                  /*定时器重载值*/
	SysTick->VAL   = 0;                          /*定时器赋初值*/
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;    /*定时器使能*/
	do
	{
		flag = SysTick->CTRL;
	}while(!(flag&(0x01<<16)));
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;    /*定时器禁止*/
	SysTick->VAL   = 0;                           /*定时器赋初值*/
}

/*定时器频率为HCLK时cnts<233 sysclk是24位计数器 定时器频率为HCLK时,计时最大233ms*/
void delay_ms(uint32_t cnts)
{
	cnts *= 1000;
	delay_us(cnts);
}

/*外设时钟初始化*/
void RCC_PeriphClock_Config()
{
	/*GPIOD和GPIOB口初始化*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD, ENABLE);
}
/*LED初始化*/
void Led_Init()
{
	GPIO_InitTypeDef GPIO_InitStruct;
	/*GPIOB5*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_5;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	
	/*GPIOD3/GPIOD6*/
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_3 | GPIO_Pin_6;
	GPIO_Init(GPIOD, &GPIO_InitStruct);
	GPIO_ResetBits(GPIOD,GPIO_Pin_3 | GPIO_Pin_6);
}

/*主函数*/
int main()
{
	SysTick_Init(SysTick_CLKSource_HCLK_Div8);    /*内核滴答定时器配置*/
	RCC_PeriphClock_Config();                     /*外设时钟配置*/
	Led_Init();                                   /*LED灯初始化*/
	while(1)
	{
		LED_ON(1);
		delay_ms(1000);
		LED_OFF(1);
		LED_ON(2);
		delay_ms(1000);
		LED_OFF(2);
		LED_ON(3);
		delay_ms(1000);
		LED_OFF(3);
	}
}


3:sysclk计时功能:

3.1:实现us级的定时功能,可得到一个算法的执行时间,考量算法的优劣;

/*
*FUNC:使用内核中的滴答定时器实现计时功能
*MCU:stm32f103
*DATE:2016/10/03
*/
#include "Sys_Driver.h"

uint16_t int_times = 0;
uint32_t start_cnts = 0;
uint32_t end_cnts = 0;
float count = 0;

/*得到当前计时器的计数值*/
uint32_t get_value(void)
{
	return SysTick->VAL;
}

/*计时函数,返回计时值,单位为us*/
float timing_func(uint32_t start,uint32_t end)
{
	if(int_times==0)
	{
		return (start - end)*(1.0/SystemCoreClock);
	}
	else if(int_times==1)
	{
		return (start+LODER_CNTS-end)*(1.0/SystemCoreClock);
	}
	else
	{
		return (start+LODER_CNTS-end+LODER_CNTS*(int_times-1))*(1.0/SystemCoreClock);
	}
}

/*主函数*/
int main()
{
	SysTick_Init(LODER_CNTS,SysTick_CLKSource_HCLK);       /*内核滴答定时器配置,为了提供计时的精确度,设置定时器不分频*/
	
	start_cnts = get_value();
	/*添加需要计时的主体代码,比如一个算法函数*/
	end_cnts = get_value();
	count = timing_func(start_cnts,end_cnts);
}

3.2:利用sysclk定时器,实现定时器超时判断,下面例程,主程序初始化一个定时器,while循环判断定时器是否超时,超时后点亮led灯,重新设置定时器,下一次超时,熄灭led灯;

main.c

/*
*FUNC:使用内核中的滴答定时器实现计时功能
*MCU:stm32f103
*DATE:2016/10/03
*/
#include "Sys_Driver.h"
#include "timer.h"
#include "led.h"

TIMER timer;
char flag = 0;

/*主函数*/
int main()
{
	SysTick_Init(INT_1MS,SysTick_CLKSource_HCLK);       /*内核滴答定时器配置,为了提供计时的精确度,设置定时器不分频*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	Led_Init();  /*led初始化*/
	timer_start(&timer,1000);   /*启动定时器,设置超时值为1000ms*/
	
	while(1)
	{
		if(timer_expired(&timer) == 1)
		{
			flag = !flag;
			if(flag==1)
				LED_ON;
			else
				LED_OFF;
			timer_reset(&timer);
		}
	}
}
time.c

#include "timer.h"

unsigned int clock_time = 0;

/*得到当前时间值*/
unsigned int get_current_time()
{
	return clock_time;
}

/*用一个给定的超时值启动定时器*/
void timer_start(TIMER *timer,int interval)
{
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;   //使能启动定时器,开始计时
	timer->start = get_current_time();
	timer->interval = interval;
}

/*关闭定时器*/
void timer_stop(void)
{
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;   //关闭定时器
}

/*定时器重新设置*/
void timer_reset(TIMER *timer)
{
	//timer->start = get_current_time();
	timer->start += timer->interval;
}

/*检查定时器是否溢出*/
int timer_expired(TIMER *timer)
{
	/*
	*1:计算得到的值需要类型转换成有符号型,在数学计算中,建议使用有符号型进行计算
	*2:关于clock_time变量会溢出导致计时不准确的问题,不用关心这个问题,比如:
	*定义三个16位无符号数:unsigned short int a=0xfffc;  unsigned short int b = a+5;  unsigned short int c = b-a;
	*计算结果为:a = 0xfffc; b = 0x0001; c = 0x0005;
	*/
	return (int)(get_current_time()-timer->start) >= (int)timer->interval;
}



总结:以上代码验证通过,有不足或者需要优化之处,望交流!






你可能感兴趣的:(stm32)