学习笔记STMF4 TIMER定时器(使用开发板立创天空星STMF4)

目录

                                                #定时器的介绍

             #怎么去理解定时器的预分频系数

        

                                            #使用定时器实现完成触发中断

  #定时器触发中断基本函数配置

#在使用TIMER  触发中断的时候为什么不需要配置EXTI中断这个选项

                                    

                                                #使用定时器完成输出PWM

#PWM基本知识介绍

#函数配置生成PWM


        这个系列所有笔记用来记录,笔者学习过程中,产生的疑惑,个人的理解,同时掺杂着个人理解,希望对各位读者姥爷有帮助,参考文章连接在最后

                                                #定时器的介绍

        这是一张,数据手册里面的定时器框图,里面是定时器这个外设的整体运作模式,比较重要。

         TIMER   定时器  单片机开发的一种常用外设,定时器类型分为   高级定时器  通用定时器  基本定时器  这三种,这里需要注意的是,只有高级定时器,通用定时器,具有四个输出通道,这四个通道对应四个引脚,总的来说就是一个定时器,可以作用四个引脚,让这四个引脚,使用定时器的功能,具体功能注释如下。

                               输入捕获(input captuer)测量输入PWM 频率 间隔  波形

                               输出比较(input compare)用于输出PWM

                               PWM输出(pwm generation) 用于输出PWM,与上者相同

                               单脉冲模式(one-pluse mode output)

        同时这里要注意,基本定时器,没有能力使用以上四个功能,主要用于驱动DAC,可以参考下文数据手册,读者姥爷们,那有的读者姥爷就要问了,定时器不同的类型,到底有什么具体的不同,具体参考中文数据手册,手册连接放在最后

        高/普 定时器,上面这个多功能描述,最为常用的定时器,作用其实是,输出比较输出PWM,定时器触发中断,本篇主要简单介绍,定时器,以及使用STMF4完成举例。

             #定时器预分频系数,周期相关介绍

        

        这一部分其实对应着时基单元,PSC:预分频系数 ,对timer时钟(CK_PSC)进行分频结果为cnt  CNT:计时器时钟(这里注意不是,定时器时钟)ARR:自动重装载值,当CNT的值达到ARR的值就会触发中断,具体计算公式如下

                                                CK_CNT=CK_PSC/(PSC+1)

        这里解释一下为什么PSC要+1,PSC预分频系数 16位寄存器取值0~65535之间,在软件中赋值结构体变量 PSC 后面通常是跟-1的,所以在公式中,给+1了(个人看法)所以就+1,这些东西就是 TIM_TimeBaseInitTypeDef,这个结构体变量需要配置的东西,需要注意的是,ARR就是TIM_Period,也就是自动重装载值,当CNT计数到达,ARR,会重头开始计数。

                                            #使用定时器实现完成触发中断

  #定时器触发中断基本函数配置

        首先,我们来看一下,timer.c文件中的介绍配置流程 ,然后我们按照这个流程进行,函数配置,

void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//EBABLE TIMER3 Clock

TIM_TimeBaseInitTypeDef TimerBaseInitStructure;//配置  timer  struct 变量
TimerBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;	
TimerBaseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;
TimerBaseInitStructure.TIM_Period  = 10000;
TimerBaseInitStructure.TIM_Prescaler  = 8400 - 1; 

TIM_TimeBaseInit(TIM3, &TimerBaseInitStructure);//初始化  timer

NVIC_InitTypeDef NVIC_InitStructure;//配置 inturputer control 管理器
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;

NVIC_Init(&NVIC_InitStructure);
	
TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);//开启  timer3 中断	
TIM_Cmd(TIM3,ENABLE);
}
void TIM3_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
        { // {}中为中断处理
                printf("IRQHandler!!!\r\n");
                
                // 反转LED灯
                if( flag == 0 )
                {
                        GPIO_SetBits(GPIOB, GPIO_Pin_2);
                        flag = 1;
                }
                else
                {
                        GPIO_ResetBits(GPIOB, GPIO_Pin_2);
                        flag = 0;
                }
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

        按照上述流程,这边配置好了,timer的初始化,然后配置,timer3 中断的响应函数,然后下面在配置,一下串口和板载LED

void uart1_init(uint32_t __Baud)
{
	GPIO_InitTypeDef GPIO_InitStructure;	

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);	

	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//IO口用作串口引脚要配置复用模式
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);

	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_9;//TX引脚
	GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;//IO口用作串口引脚要配置复用模式
	GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_10;//RX引脚
	GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
  
	USART_InitTypeDef USART_InitStructure;//定义配置串口的结构体变量

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//开启串口1的时钟

	USART_DeInit(USART1);//大概意思是解除此串口的其他配置

	USART_StructInit(&USART_InitStructure);
	USART_InitStructure.USART_BaudRate              = __Baud;//设置波特率
	USART_InitStructure.USART_WordLength            = USART_WordLength_8b;//字节长度为8bit
	USART_InitStructure.USART_StopBits              = USART_StopBits_1;//1个停止位
	USART_InitStructure.USART_Parity                = USART_Parity_No ;//没有校验位
	USART_InitStructure.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;//将串口配置为收发模式
	USART_InitStructure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //不提供流控 
	USART_Init(USART1,&USART_InitStructure);//将相关参数初始化给串口1
	
	USART_ClearFlag(USART1,USART_FLAG_RXNE);//初始配置时清除接受置位

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//初始配置接受中断

	USART_Cmd(USART1,ENABLE);//开启串口1
	
	NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义

	NVIC_InitStructure.NVIC_IRQChannel                    = USART1_IRQn;//中断通道指定为USART1
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;//主优先级为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority         = 1;//次优先级为1
	NVIC_InitStructure.NVIC_IRQChannelCmd                 = ENABLE;//确定使能
	NVIC_Init(&NVIC_InitStructure);//初始化配置此中断通道
		
}

void LED_GPIO_Init(void)
{

	//板载LED引脚初始化配置
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

	GPIO_InitTypeDef  GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd 	= GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_ResetBits(GPIOB,GPIO_Pin_2);
}

        这里基本配置完成之后,然后扔到main()里面去调用,然后实验现象是,串口每秒打印IRQHandler,同时板载LED每秒进行闪烁。

#include "board.h"
#include "bsp_uart.h"
#include <stdio.h>
#include  "button.h"
#include  "exti.h"
#include "timer.h"
extern uint8_t  flag;//
void TIM3_IRQHandler(void);//声明末尾定义的函数

int main(void)
{
	
	LED_GPIO_Init();
	board_init();
	uart1_init(9600);
	flag = 0;
	Timer_Init();
	
	while(1)
	{
		
	}
	

}
#在使用TIMER  触发中断的时候为什么不需要配置EXTI中断这个选项

       EXTI(External interrupt/event controller)外部中断/事件控制器,片上外设之一,能够检测外部输入信号边沿产生变化时(上升  下降  ),并由此产生中断,通常用于GPIO这种不能自己产生中断源 的片上外设,而timer定时器  这个片上外设本身可以产生 中断源,自然也就使用不到   exti 在此产生中断源进行配置  timer  产生中断源  nvic 在进行配置  在编写  中断响应函数  然后就能使用  ,所以timer定时器  配置使用不到  exti 这个片上外设  功能   使用 exti 的配置流程如下  本文实验中断流程如

 GPIO (电平发声变化)-> EXTI(产生中断源) ->NVIC(配置中断优先级)  ->IRQ(定义函数)

        TIMER(产生中断源) ->NVIC(配置中断优先级)  ->IRQ(编写中断响应函数)

       总结:TIMER 片上外设本身可以产生中断源  不需要在使用 EXTI 这个片上外设  在此产生中断源  所以不需要使用  EXTI 这个片上外设去产生中断源   EXTI这个片上外设 一般用于检测 GPIO

引脚出现电平 变化的时候  触发产生中断源  进行触发中断使用  

                                    

                                                #使用定时器完成输出PWM

#PWM基本知识介绍

         冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果基本相同。

        这句话描述的是物理学中的动量守恒原理,同时也是PWM能够生成指定电压的原理,特别是在信号处理或控制系统分析中的应用。当两个形状不同的窄脉冲(可以理解为短暂且强度大的力或者能量输入)对一个具有惯性的系统施加作用时,如果它们的总冲量(即在时间上的力与持续时间的乘积,等于物体动量的变化量)相等,那么最终系统的行为——比如位移、速度或加速度变化——将基本相似,尽管输入的脉冲形状不同。

        这反映了无论输入信号如何变化,只要总的动量转移是相同的,系统的响应将是类似的,因为系统的动态响应主要取决于冲量,而不是脉冲的具体形状。这也是工程设计中经常考虑的一种简化模型,PWM就像是BUCK电路,通过开关来控制电压稳定在指定的范围,而PWM是控制占空比,就是高电平的在整个周期内的占比,来控制整体输出电压,控制在指定范围输出,PWM(Pulse Width Modulation脉宽调制)

                                        频率:PWM的频率是整个周期的倒数。

                                        占空比:占空比是指一个周期内高电平所占的比例。

        单片机 高电平是 3.3V  低电平是   0V  那么问题来了,如果需要输出1.65V,那么就需要使用PWM这个模式输出电平,简单原理阐述,PWM输出不同电压电平,是利用高电平在一段时间周期里面的占比,这一段时间周期通常     ms为单位,从而显示出不同的电平,

                                                        50%   对应  3.3*0.5 =1.65V  

                                                        60%   对应 3.3*0.6 = 1.98V

        具体不同占空比,对应多少V电压就是这么换算的,

#函数配置生成PWM

        timer,外设输出PWM,也就是定时器框图的这一部分,一个定时器的OC(输出比较),有四个引脚可以使用,进行输出PWM,也就是 TIM_CH1 TIM_CH2 TIM_CH3 TIM_CH4 ,

void PWM_GPIO_Init(void)
{

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3);
	//开启复用模式 GPIOB5不在作为 普通GPIO引脚使用  而是作为timer 输出PWM通道使用 
	
}
void Time_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = 1000;
TIM_TimeBaseStruct.TIM_Prescaler = 500 - 1; 

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct); 

}
void Timer_OCInit(void)
{
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = ENABLE;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OC2Init(TIM2,&TIM_OCInitStruct);//输出通道2 Init
	
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  
//enable  CC2R 也就是 TIM_SetCompare2(timx,cc2r)	就是开启这个函数
	
TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	}
void pwm_breathing_lamp(void)
{
        uint32_t brightness = 0;// 当前亮度
        int step = 10;          // 亮度改变的步长
        
        // 逐渐增加亮度
        for(brightness = 0; brightness < 1000; brightness += step)
        {
                TIM_SetCompare2(TIM3, brightness); // 使用TIM3的Channel 2
                delay_ms(10);
        }
        
        // 逐渐减少亮度
        for(brightness = 1000; brightness > 10; brightness -= step)
        {
                TIM_SetCompare2(TIM3, brightness); // 使用TIM3的Channel 2
                delay_ms(10);
        }
}   
int main(void)
{
	board_init();
	uart1_init(9600);
	PWM_GPIO_Init();
	Time_Init();
	Timer_OCInit();
	while(1)
	{
		pwm_breathing_lamp();
	}
}

        【立创·天空星STM32F407VET6】入门手册 - 飞书云文档 (feishu.cn)

        链接:https://pan.baidu.com/s/12SM_KSvwXXyTqAvosVA-gQ 
        提取码:zhiy

        最后希望对你有所帮助!!!个人理解,如有失误,欢迎指出,核实立改

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值