STM32的第四天

  • 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;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值