STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码

1.通用定时器常用库函数

常用库函数:stm32f4xx_tim.c/.h

定时器初始化函数 void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

结构体的定义:

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第1张图片


 2.常用函数的介绍:  (函数原型)
1.定时器使能函数: void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

2.定时器中断使能函数:void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

3.状态标志位获取和清除

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//状态标志位的获取

void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//状态标志位的清除

ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//此函数功能是判断 TIMx 的中断类型 TIM_IT 是否产生中断

void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除定时器 TIMx 的中断 TIM_IT 标志位

FlagStatus TIM_GetFlagStatus();		//获取状态标志位
void TIM_ClearFlag();					//清除状态标志位

ITStatus TIM_GetITStatus();			//获取中断状态标志位
void TIM_ClearITPendingBit();			//清除中断状态标志位

4.补充的信息:

FlagStatus 返回值是中断标志位状态(读SR寄存器)

该函数用于检测串口中断标志位的状态。
在没有使能相应的中断函数时,通常使用该函数来判断标志位是否置位。


.ITStatus 返回值是中断发生与否的判断(读CR寄存器)

读取串口控制寄存器CR1,CR2,CR3的状态,获取中断发生的动作,返回SET或RESET。

除了可以判断中断标志位外,还能判断是否发生了中断。
 


3.芯片里面自带的  定时器有哪些:

定时器种类

位数

计数器模式

产生DMA请求

捕获/比较通道

互补输出

特殊应用场景

高级定时器

TIM1,TIM8)

16

向上,向下,向上/

可以

4

带可编程死区的互补输出

通用定时器(TIM2,TIM5

32

向上,向下,向上/

可以

4

通用。定时计数,PWM输出,

输入捕获,输出比较

通用定时器(TIM3,TIM4

16

向上,向下,向上/

可以

4

通用。定时计数,PWM输出,

输入捕获,输出比较

通用定时器(TIM9~TIM14

16

向上

没有

2

通用。定时计数,PWM输出,

输入捕获,输出比较

基本定时器

(TIM6,TIM7)

16

向上,向下,向上/

可以

0

主要应用于驱动DAC

1.      STM3 F4的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能特点包括:

 2.    16 /32 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。

3.      16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。

4.      4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:

                     输入捕获

                     输出比较

                     PWM 生成(边缘或中间对齐模式)

                     单脉冲模式输出

5.     可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。


4.芯片中断发生的条件  和 定时器的用法    和实现的中断的步骤 :

如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器):

 1.        更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

2.          触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

3.        输入捕获

4.       输出比较

5.       支持针对定位的增量(正交)编码器和霍尔传感器电路

6.      触发输入作为外部时钟或者按周期的电流管理

STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。

使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。

//定时器中断实现步骤
1.使能定时器时钟。
       RCC_APB1PeriphClockCmd();
2.初始化定时器,配置ARR,PSC。
      TIM_TimeBaseInit();
3.允许更新中断
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
4.  使能定时器。
      TIM_Cmd();
5.开启定时器中断,配置NVIC。
      NVIC_Init();
6.  编写中断服务函数。      
      TIMx_IRQHandler();     
 7.在中断服务函数中清除中断标志位
       TIM_ClearITPendingBit(TIM3,TIM_IT_Update); 

实列: (使用定时器  TIM 3    中断)

#include "stm32f4xx.h"

// Header:stm32f407ve-version
// File Name: 定时器初始化函数
// Author:dandy;
// Date:2021.11.2;
void timer3init()
{
	//定时器结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	//用到中断,所以要有中断结构体	
	NVIC_InitTypeDef NVIC_InitStructure;	
	//1使能定时器时钟   步骤1
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);   
	//自动重装载值   
	TIM_TimeBaseInitStructure.TIM_Period = 4999;    //5000 -》0.5s   ---》   0.0001s = 0.1ms 
	//定时器预分频	
	TIM_TimeBaseInitStructure.TIM_Prescaler=8399;    //  84000000 / 8400 = 10000 //频率的倒数正好是0.0001s 
	//向上计数模式
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 
	//时钟分频
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	//2初始化时钟    步骤2
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
	//3允许定时器3更新中断   步骤3
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	//4使能定时器3   步骤4
	TIM_Cmd(TIM3,ENABLE);
	//中断配置部分。
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
	//中断成员1
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
	//中断成员2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //响应优先级3
	//中断成员3
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	//5中断成员4   步骤5
	NVIC_Init(&NVIC_InitStructure);
}

//定时器3中断服务函数  步骤6
void TIM3_IRQHandler(void)
{
	//测试语句
	GPIO_ResetBits(GPIOE,GPIO_Pin_9);
	
	if(num % 2 == 0 )
	{
	GPIO_ResetBits(GPIOE,GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);
	//delay();
	GPIO_SetBits(GPIOE,GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);
	//delay();
	//清除中断标志位  步骤7
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
	}
	num++;
	if(num > 1000)
		num = 0 ;
}



//判断函数是否执行就用测试语句。
void TIM3_IRQHandler()
{
		//测试语句
	  //GPIO_ResetBits(GPIOE,GPIO_Pin_9);
		if(num % 2 == 0 )
		{
				GPIO_ResetBits(GPIOE,GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);
				num++;
				TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
		}
		else
		{
				GPIO_SetBits(GPIOE,GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10);
				num++;
				TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
		}
		if(num > 100000)
			  num = 0 ;
}


.5.定时器计数器模式的 选择   和计数器的时钟源  :

通用定时器可以向上计数、向下计数、向上向下双向计数模式。

①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。

②向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。

③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第2张图片

计数器时钟可以由下列时钟源提供:

1.     内部时钟(CK_INT)

2.      外部时钟模式1:外部输入脚(TIx)

3.      外部时钟模式2:外部触发输入(ETR)(仅适用TIM2,3,4)

4.      内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。


 6.PWM  模式(脉冲宽度调制)  (只有定时器  2  3   4  可以使用)

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第3张图片

定时器中断产生pwm
io口如何产生一个pwm ,无非就是做一个高低电平周期性的变化,这种思想很重要,确定频率就可以确定周期(T=1/f)也就是在一个周期内产生pwm的时间可以确定下来了,如何改变占空比?                   确定了时间,高电平的时间不就是想要的占空比么,比如要产生一个频率1khz,占空比为70%的pwm,根据频率我们知道了周期为1ms,产生一个占空比为70%的不就是0.7ms的时间给高电平么,(我们用定时器中断的方式,使0.1ms产生一次中断,计数中断次数,中断处理函数前七次中断都给高电平就ok了)

PWM输出的配置步骤:
1.     使能相应的GPIO口的时钟
2.     配置相应的GPIO口为复用功能推挽输出
3.     选择复用功能
4.     使能定时器的相应时钟,即RCC->APB1ENR的相应位置1
5.     TIMx_ARR 寄存器进行缓冲
6.     计数器在发生更新事件时不会停止计数(循环计数,循环定时)
7.     使能更新 (UEV)
8.    UG位置1重新初始化定时器计数器(TIMx_CNT)
9.    状态寄存器清零
9.    配置预分频值 
10.  配置自动重装载值 (用于控制脉冲的周期)
11.  CCMR1配置为PWM的模式
12.  CCR1影子寄存器有效
13.  CC1 通道配置为输出。
14.  配置OC1 有效电平
15.  捕获/比较 1 中断使能
16.  使能定时器中断中断通道,调用NVIC_EnableIRQ函数,调整抢占和响应的优先级,
17.  捕获/比较 1 输出使能
18.  使能定时器
19.  改变CCR1的值可以改变占空比

 


 7.代码:(图片加代码)(因为没有板子实践    只上过课可能有错误    望大家体谅!)

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第4张图片

 

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第5张图片

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第6张图片

 

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第7张图片

 STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第8张图片

 

代码:


void Timer3_Init()   
{
      //1.配置时钟  (填写寄存器 ) 84 名
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  /*使能定时器3 的时钟*/

	TIM_TimeBaseInitTypeDef   TIM_TimeBaseInitStrecture;     //定时器时基初始化结构体
	NVIC_InitTypeDef   NVIC_InitStructure;   //中断优先级配置结构体

	
	
	TIM_TimeBaseInitStrecture.TIM_Period = 4999;  /*重装载寄存器数值 0.0001 * 5000 =0.5s*/
	TIM_TimeBaseInitStrecture.TIM_Prescaler = 8399; /*预分配数值*/
	TIM_TimeBaseInitStrecture.TIM_ClockDivision = TIM_CKD_DIV1; /*时钟分频*/
	TIM_TimeBaseInitStrecture.TIM_CounterMode = TIM_CounterMode_Up; /*向上计数*/
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrecture); /*初始化*/


	TIM_ClearFlag(TIM3,TIM_FLAG_Update); /*清更新标志位*/
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); /*使能中断*/
	TIM_Cmd(TIM3,ENABLE); /*使能计数*/

	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;/*定时器1的中断通道使能*/
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/*定时器1的中断通道使能*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;/*抢占优先级*/
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;/*响应优先级*/
	NVIC_Init(&NVIC_InitStructure);/*配置中断分组,并使能中断*/

}

//定时器中断函数 : 固定名字  并且只要定义  不要声明  不要调用
void TIM3_IRQHander()
{
    if(num%2==0)
    {
        Openbeep();//打开蜂鸣器
        num++;
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//清除TIMx的中断待处理位:TIM3中断源 	
    }
    else
    {
        Closebeep();//关闭蜂鸣器
        num++;
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);//清除TIMx的中断待处理位:TIM3中断源 
    
    }

}


 


代码:(PWM)

//TIM2 PWM部分初始化 
//PWM输出初始化

void TIM2_PWM_Init()
{		 

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);  	//TIM2时钟使能    
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 	//使能PORTA时钟	
					 
	//此部分需手动修改IO口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	
	
	//复用不能写成下面,会出问题 (两个引脚不能同时 初始化)
	//GPIO_PinAFConfig(GPIOA,GPIO_PinSource8|GPIO_PinSource11,GPIO_AF_TIM1); //GPIO复用为定时器1
	
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2); //复用GPIOB_Pin10为TIM2, 
	
	//GPIO 引脚复用功能	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           //GPIO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Low_Speed;  	//速度低速
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOB,&GPIO_InitStructure);              //初始化P


	
	TIM_TimeBaseStructure.TIM_Prescaler=1000;  //定时器分频
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseStructure.TIM_Period=83r;   //自动重装载值
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);//初始化定时器1

 
 
 
	//初始化TIM1  PWM模式	 
	//PWM 模式 1–– 在递增计数模式下,只要 TIMx_CNT


8.补充知识:

STM32的优先级NVIC_PriorityGroupConfig的理解及其使用

我自己依据此图理解,应用思维导图画了一张方便理解:(如果看不清可通过ctrl+鼠标滑轮    放大看;)

前提条件1:组别优先顺序(第0组优先级最强,第4组优先级最弱):NVIC_PriorityGroup_0>NVIC_PriorityGroup_1>NVIC_PriorityGroup_2>NVIC_PriorityGroup_3>NVIC_PriorityGroup_4
前提条件2:“组”优先级别>“抢”占优先级别>“副”优先级别
前提条件3:同一组优先级别中,不同的抢占级别之间,其中一抢占级别正在做事,另外抢占级别不能打断他;(即”同一组优先级下的中断源间,没有中断嵌套“)
前提条件4:不同组优先级别间,依据优先级强弱,优先级别高的组的中断源可以打断优先级别低的组的正在做的事情;(即:不同组优先级间,可以中断嵌套)

通过定时器中断配置,每500ms中断一次,然后中断服务函数中控制LED实现LED1状态取反(闪烁)。

Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk;

arr:自动重装值

psc:时钟预分频数

定时器的寄存器:
TIMx计数器:TIMx_CNT
TIMx预分频器:TIMx_PSC
TIMx自动重载寄存器:TIMx_ARR
TIMx 控制寄存器 1:TIMx_CR1
TIMx DMA/中断使能寄存器:TIMx_DIER
6.定时器中断的实现步骤:
(1)使能定时器时钟:
RCC_APB1PeriphClockCmd();
(2)初始化定时器:配置ARR、PSC,TIM_TimeBaseInit();
(3)开启定时器中断:配置NVIC,NVIC_Init();
(4)使能定时器,TIM_Cmd();
(5)编写中断服务函数,TIMx_IRQHandler ();
注意:Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk;

计数器当前值寄存器CNT(图片):

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第9张图片

预分频寄存器TIMx_PS(图片):

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第10张图片

 自动重装载寄存器(TIMx_ARR)(图片):

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第11张图片

 控制寄存器(图片):

STM32F407 芯片的学习 day05 芯片自带的定时器 的知识与代码_第12张图片

 
 


 

你可能感兴趣的:(stm32f407,单片机技术学习,stm32,单片机,学习)