- Systick定时器
1、定时器概念
定时器:是芯片内部用于计数从而得到时长的一种外设。
定时器定时长短与什么有关???(定时器定时长短与频率及计数大小有关)
定时器频率换算单位:1GHZ=1000MHZ=1000 000KHZ = 1000 000 000HZ
在1MHZ下,1us计1个数;在100MHZ下,1us计100个数;
2、Systick定时器
Systick定时器,是一个简单的定时器,对于CM3,CM4内核芯片,都有Systick定时器。常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如uCOS/FreeRTOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做uCOS心跳时钟。
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
一共4个Systick寄存器
CTRL SysTick 控制和状态寄存器
LOAD SysTick 自动重装载除值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器
- STM32通用定时器
1、定时分类及时钟频率
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
2、通用定时器的计数模式
通用定时器可以向上计数、向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
3、定时器框架分析
4、通用定时器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();
三、函数说明
/**
* @brief Configures the SysTick clock source.
* @param SysTick_CLKSource: specifies the SysTick clock source.
* This parameter can be one of the following values:
* @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
* @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
* @retval None
*/
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
函数说明:SysTick时钟源配置
返回值:无
uint32_t SysTick_CLKSource:时钟源
SysTick_CLKSource_HCLK_Div8: HCLK/8 = 21MHZ
SysTick_CLKSource_HCLK: HCLK = 168MHZ
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. 第四个参数是用来设置时钟分频因子
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
函数说明:定时器的中断配置
返回值:无
TIM_TypeDef* TIMx:选择哪个定时器
uint16_t TIM_IT:中断方式
TIM_IT_Update (更新中断)
TIM_IT_CC1
TIM_IT_CC2
TIM_IT_CC3
TIM_IT_CC4
TIM_IT_COM
TIM_IT_Trigger
TIM_IT_Break
FunctionalState NewState:是否使能
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
函数说明:定时器使能
返回值:无
TIM_TypeDef* TIMx:选择哪个定时器
FunctionalState NewState:是否使能
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
函数功能:获取定时器中断标志位
返回值:SET或RESET
TIM_TypeDef* TIMx:选择定时器
uint16_t TIM_IT:中断事件
* @arg TIM_IT_Update: TIM update Interrupt source
* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
* @arg TIM_IT_COM: TIM Commutation Interrupt source
* @arg TIM_IT_Trigger: TIM Trigger Interrupt source
* @arg TIM_IT_Break: TIM Break Interrupt source
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
函数功能:清空定时器中断标志位
返回值:无
TIM_TypeDef* TIMx:选择定时器
uint16_t TIM_IT:中断事件
* @arg TIM_IT_Update: TIM update Interrupt source
* @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
* @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
* @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
* @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
* @arg TIM_IT_COM: TIM Commutation Interrupt source
* @arg TIM_IT_Trigger: TIM Trigger Interrupt source
* @arg TIM_IT_Break: TIM Break Interrupt source
四、定时器应用
智能公交一体机,定时器每隔固定时间向服务器发送自己的定位
交通红绿灯定时1S将数字进行倒数
Systick延时
#include "delay.h"
int my_us = 21; //1us计21个数
int my_ms = 21000; //1ms计21000个数
void Delay_Init(void)
{
//SysTick时钟源配置 168MHZ/8 = 21MHZ;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
}
//int nus最大值:798915
void delay_us(int nus) //1000000
{
u32 temp = 0x00; //u32 == unsigned int
//设置重载值寄存器
SysTick->LOAD = my_us*nus-1;
//设置VAL为0
SysTick->VAL = 0x00;
//启动定时器,VAL开始计数
SysTick->CTRL |= (0x01<<0);
//查询状态位是否为1
do
{
temp = SysTick->CTRL;
//判断定时器是否开启 判断CTRL第16是否为1
}while( (temp &(0x01<<0)) && !(temp & (0x01<<16)) );
//关闭定时器,完成一次的计数,从而达到延时
SysTick->CTRL &= ~(0x01<<0);
}
//int nms最大值:798
void delay_ms(int nms) //1000000
{
u32 temp = 0x00; //u32 == unsigned int
//设置重载值寄存器
SysTick->LOAD = my_ms*nms-1;
//设置VAL为0
SysTick->VAL = 0x00;
//启动定时器,VAL开始计数
SysTick->CTRL |= (0x01<<0);
//查询状态位是否为1
do
{
temp = SysTick->CTRL;
//判断定时器是否开启 判断CTRL第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);
}
}
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f4xx.h"
void Delay_Init(void);
void delay_us(int nus);
void delay_ms(int nms);
void delay_s(int ns);
#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
void delay(int n)
{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<20000; j++);
}
int main(void)
{
int key_count = 0;
//设置NVIC分组(一个工程只能设置一个分组)
//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
while(1)
{
delay_s(1);
LED0_CH;
}
}
Systick中断
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
u32 delay_connt = 0;
void delayms(int nms);
int main(void)
{
int key_count = 0;
//设置NVIC分组(一个工程只能设置一个分组)
//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
//SystemCoreClock = 168000000 1ms产生一次中断
SysTick_Config(SystemCoreClock/1000);
//GPIO_ResetBits(GPIOE, GPIO_Pin_14);
while(1)
{
delayms(1000);
LED0_CH;
}
}
void delayms(int nms)//假设填入100
{
//时间赋值给delay_connt
delay_connt = nms;
while(delay_connt);
}
//SysTick中断 1ms
void SysTick_Handler(void)
{
if(delay_connt!=0)
{
delay_connt--;
}
}
time定时器
#include "tim.h"
/**************************************
函数说明
TIM3挂在APB1, TIM3频率:84MHZ
TIM3为16位定时器
**************************************/
void Tim3_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//1、能定时器时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitStruct.TIM_Prescaler = 83; //84分频 84MHZ/84 = 1MHZ
TIM_TimeBaseInitStruct.TIM_Period = (1000-1); //ARR的值,在1MHZ计1000个数,用时1ms
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式:向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
//2、初始化定时器,配置ARR,PSC。
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; //中断通道,中断通道在stm32f4xx.h文件当中查找
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能通道
//3、启定时器中断,配置NVIC。
NVIC_Init(&NVIC_InitStruct);
//4、设置 TIM3_DIER 允许更新中断
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
//5、使能定时器。
TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler(void)
{
//判断标志位是否置1
if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
}
//清空标志位
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
#ifndef __TIM_H
#define __TIM_H
#include "stm32f4xx.h"
void Tim3_Init(void);
#endif
#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<20000; j++);
}
int main(void)
{
int key_count = 0;
//设置NVIC分组(一个工程只能设置一个分组)
//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
Tim3_Init();
while(1)
{
delay_s(1);
LED0_CH;
}
}