- Systick定时器
定时器:是芯片内部用于计数从而得到时长的一种外设。
定时器定时长短与什么有关???(定时器定时长短与频率及计数大小有关)
定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ
Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器。常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如uCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做uCOS心跳时钟。
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
一共4个Systick寄存器
CTRL SysTick 控制和状态寄存器
LOAD SysTick 自动重装载除值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器
SysTick 控制和状态寄存器---------CTRL
SysTick 重装载数值寄存器- LOAD
SysTick 当前值寄存器- VAL
- STM32通用定时器
STM32定时器分类:高级控制定时器、通用定时器、基本定时器
高级控制定时器:TIM1 TIM8
通用定时器:TIM2 TIM3 TIM4 TIM5 TIM9 TIM10 TIM11 TIM12 TIM13 TIM14
基本定时器:TIM6 TIM7
挂在APB1下的定时器:TIM2 TIM3 TIM4 TIM5 TIM6 TIM7 TIM12 TIM13 TIM14
挂在APB2下的定时器:TIM1 TIM8 TIM9 TIM10 TIM11
挂在APB1下的定时器时钟频率:42MHZ X 2 = 84MHZ
挂在APB2下的定时器时钟频率:84MHZ X 2 = 168MHZ
通用定时器的计数模式:
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
通用定时器3配置流程
通用定时器需要添加的库函数文件:stm32f4xx_tim.c
1、能定时器时钟。
RCC_APB1PeriphClockCmd();
2、初始化定时器,配置ARR,PSC。
TIM_TimeBaseInit();
3、启定时器中断,配置NVIC。
NVIC_Init();
4、设置 TIM3_DIER 允许更新中断
TIM_ITConfig();
5、使能定时器。
TIM_Cmd();
6、编写中断服务函数。
TIMx_IRQHandler();
函数说明:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
函数功能:定时器初始化
返回值:无
TIM_TypeDef* TIMx:选择定时器
TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct:定时器结构体
typedef struct
{
uint16_t TIM_Prescaler;
uint16_t TIM_CounterMode;
uint16_t TIM_Period;
uint16_t TIM_ClockDivision;
} TIM_TimeBaseInitTypeDef;
1. 第一个参数 TIM_Prescaler 是用来设置分频系数。
2. 第二个参数 TIM_CounterMode 是用来设置计数方式,上面讲解过,可以设置为向上计数,向下计数方式还有中央对齐计数方式,比较常用的是向上计数模式TIM_CounterMode_Up 和向
下计数模式 TIM_CounterMode_Down。
3. 第三个参数是设置自动重载计数周期值,这在前面也已经讲解过。
4. 第四个参数是用来设置时钟分频因子
下面是两个例子
例子一(通用定时器)
time.c
#include "tim.h"
/**********************************
定时器说明
TIM3 -- APB1 -- 84MHZ
TIM3 -- 16位定时器(65535)
***********************************/
void Tim2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//使能定时器时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// TIM_TimeBaseInitStruct.TIM_Prescaler = 84-1; //84分频, 84MHZ/84 = 1MHZ(1000 000HZ)
// TIM_TimeBaseInitStruct.TIM_Period = 1000-1; //计数周期1000,在1MHZ,计1000个数,用时1ms
// TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
// TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
// //初始化定时器,配置ARR,PSC。
// TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; //8400分频, 84MHZ/8400 = 10000HZ
TIM_TimeBaseInitStruct.TIM_Period = 2000-1; //计数周期10000,在10000HZ,计10000个数,用时1s
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
//初始化定时器,配置ARR,PSC。
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; //中断通道 可在stm32f4xx.h中查找
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能
//配置中断分组(NVIC),并使能中断。
NVIC_Init(&NVIC_InitStruct);
//设置 TIM3_DIER 允许更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
//使能定时器。
TIM_Cmd(TIM2, ENABLE);
}
//定时器中断服务函数
void TIM2_IRQHandler(void)
{
//判断中断标志位是否置为1
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
//清除中断标志位
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
main.c
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
void delay(int n)
{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<40000; j++);
}
int main(void)
{
//设置NVIC分组(一个工程只能有一个分组) 抢占优先级范围:0~3 响应优先级范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
Tim2_Init();
//(GPIOE, GPIO_Pin_14);
while(1)
{
GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
delay_ms(500);
delay_ms(500);
}
return 0;
}
led.c
#include "led.h"
/*************************************************
引脚说明:
LED0连接在PF9
PF9输出低电平(0),灯亮;PF9输出高电平(1),灯灭;
LED0 -- PF9
LED1 -- PF10
LED2 -- PE13
LED3 -- PE14
**************************************************/
void Led_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//打开GPIOE组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//打开GPIOF组时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //引脚9 10
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14; //引脚13 14
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //速度
GPIO_Init(GPIOE, &GPIO_InitStruct);
//LED0灯灭
GPIO_SetBits(GPIOF, GPIO_Pin_9); //引脚置1
//LED1灯灭
GPIO_SetBits(GPIOF, GPIO_Pin_10); //引脚置1
//LED2灯灭
GPIO_SetBits(GPIOE, GPIO_Pin_13); //引脚置1
//LED3灯灭
GPIO_SetBits(GPIOE, GPIO_Pin_14); //引脚置1
}
delay.c
#include "delay.h"
u32 my_us = 21; //1us可计21个数
u32 my_ms = 21000; //1us可计21000个数
void Delay_Init(void)
{
//时钟源选择,168MHZ/8 = 21MHZ
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //Systick时钟源选择 misc.c文件中
}
//nus取值范围:0~798915
void delay_us(int nus)
{
u32 temp = 0;
//设定重载值寄存器
SysTick->LOAD = my_us*nus - 1;
//设置计数为0
SysTick->VAL = 0x00;
//启动定时器
SysTick->CTRL |=(0x01<<0);
do
{
temp = SysTick->CTRL; //获取值,判断第16位
//判断是否使能定时器 //判断第16是否为1
}while( (temp & (0x01<<0)) && !(temp & (0x01<<16)));
//关闭定时器
SysTick->CTRL &= ~(0x01<<0);
}
//nus取值范围:0~798915
void delay_ms(int nms)
{
u32 temp = 0;
//设定重载值寄存器
SysTick->LOAD = my_ms*nms - 1;
//设置计数为0
SysTick->VAL = 0x00;
//启动定时器
SysTick->CTRL |=(0x01<<0);
do
{
temp = SysTick->CTRL; //获取值,判断第16位
//判断是否使能定时器 //判断第16是否为1
}while( (temp & (0x01<<0)) && !(temp & (0x01<<16)));
//关闭定时器
SysTick->CTRL &= ~(0x01<<0);
}
void delay_s(int ns)
{
int i;
for(i=0; i<ns; i++)
{
delay_ms(500);
delay_ms(500);
}
}
例子二(高级控制定时器)
time.c
#include "tim.h"
#include "delay.h"
/**********************************
定时器说明
TIM3 -- APB1 -- 84MHZ
TIM3 -- 16位定时器(65535)
***********************************/
void Tim3_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//使能定时器时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// TIM_TimeBaseInitStruct.TIM_Prescaler = 84-1; //84分频, 84MHZ/84 = 1MHZ(1000 000HZ)
// TIM_TimeBaseInitStruct.TIM_Period = 1000-1; //计数周期1000,在1MHZ,计1000个数,用时1ms
// TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
// TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
// //初始化定时器,配置ARR,PSC。
// TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_Prescaler = 8400-1; //8400分频, 84MHZ/8400 = 10000HZ
TIM_TimeBaseInitStruct.TIM_Period = 10000-1; //计数周期10000,在10000HZ,计10000个数,用时1s
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
//初始化定时器,配置ARR,PSC。
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; //中断通道 可在stm32f4xx.h中查找
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能
//配置中断分组(NVIC),并使能中断。
NVIC_Init(&NVIC_InitStruct);
//设置 TIM3_DIER 允许更新中断
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
//使能定时器。
TIM_Cmd(TIM3, ENABLE);
}
//定时器中断服务函数
void TIM3_IRQHandler(void)
{
//判断中断标志位是否置为1
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
if(GPIO_ReadInputDataBit(GPIOF, GPIO_Pin_9) == Bit_SET)
{
delay_s(2);
}
GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
//清除中断标志位
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
main.c
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
void delay(int n)
{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<40000; j++);
}
int main(void)
{
//设置NVIC分组(一个工程只能有一个分组) 抢占优先级范围:0~3 响应优先级范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
Tim3_Init();
//(GPIOE, GPIO_Pin_14);
while(1)
{
}
return 0;
}