目录:
概述:本篇博客针对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; /*定时器使能*/
}
/*
*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;
}