通过定时器和脉冲控制LED

目录

一、定时器

(一)定时器简介

(二)定时器类型

1、常见定时器

2、定时器的主要功能

3、常规定时器

(三)定时器配置

1、定时器标准外设库接口函数

2、定时器标准外设库配置

二、PWM

(一)PWM简介

1、介绍及其功能

2、占空比

(二)PWM的工作原理

1、产生PWM的定时器:

2、产生PWM的原因:

3、PWM的工作原理解释

(三)PWM标准外设库输出配置过程

三、实际应用

(一)关于定时器的题目

1、题目要求

2、代码

3、实物效果

(二)关于PWM的题目

1、题目要求

2、代码

3、Keil波形图​编辑

4、实物效果

四、总结


一、定时器

(一)定时器简介

        STM32定时器是STM32微控制器中的重要块,用于生成精确的时间基准。它可以用于测量时间间隔、产生脉冲、实现定时中断等功能。通过配置寄存器,用户可以灵活地控制定时器的工作模式和参数,实现各种实时控制和定时任务。        

(二)定时器类型

5d258fe9f7374c88abc6da56332f3977.png

1、常见定时器

  • SysTick定时器:

SysTick系统时钟位于Cortex-M3内核,是一个24位的递减计数器,主要用于:

1)精确延时,在多任务操作系统中为系统提供时间基准(时基);

2)任务切换,为每个任务分配时间片。

  • WatchDog定时器:

1)作用:当微控制器受到外部干扰或程序中出现不可预知的逻辑故障导致应用程序脱离正常的执行流程时(俗称程序跑飞),在一定的时间间隔内使系统复位,回到初始状态;

2)看门狗设计是用来监视MCU程序运行状态的,是确保系统可靠稳定运行的一种有效措施。

WatchDog又可以分为独立看门狗和窗口看门狗,区别如下:

54ec0a7c42a141e8ad49c9720bb3799b.png

独立看门狗:采用独立时钟,不受其他时钟和总线影响,可在停机和待机模式下工作。适用于独立于主程序之外、能够独立工作且对时间精度要求不高的场合。

窗口看门狗:计数值有一个上限时间和下限时间,低于下限时间或高于上限时间都会触发MCU复位。适用于精确计时窗口起作用的应用程序。

f726f9e0d36e4e3c8d5cd90b3b016898.png

  • 基本定时器(下方重点介绍):TIM6和TIM7。
  • 通用定时器(下方重点介绍):TIM2、TIM3、TIM4和TIM5。
  • 高级定时器(下方重点介绍):TIM1和TIM8。

2、定时器的主要功能

  • 计数:脉冲计数,使用使用微控制器内部的外部时钟(PCLK)来计数,是对固定周期的脉冲信号计数。
  • 定时:时间控制,通过对微控制器内部的时钟脉冲进行计数实现定时功能。
  • 输入捕获:对输入信号进行捕获,实现对脉冲的频率测量,可用于对外部输入信号脉冲宽度的测量,比如测量电机转速。
  • 输出比较:将计数器计数值和设定值进行比较,根据比较结果输出不同电平,用于控制输出波形,比如直流电机的调速。

3、常规定时器

STM32定时器分类比较表

533a0baefd454f488c122e02a0c37abf.png

(1)基本定时器

简介:

STM32有2个基本定时器TIM6和TIM7,可用作: 通用的16位计数或者 产生DAC触发信号,基本定时器的计数模式只有向上计数模式。

d0086469e2254f9fb9b92dfe4bfd4014.png

(2)通用定时器

简介:

        TIM2、TIM3、TIM4、TIM5为STM32的4个独立的16位通用定时器,具有定时、测量输入信号的脉冲长度(输入捕获)、输出所需波形(输出比较、产生PWM、单脉冲输出等)等功能。如下图为通用定时器内部结构框图。

e148772884ec4b50af51995cdff293de.png

        STM32F103系列微控制器的定时器功能十分强大,内部结构也比较复杂,STM32通用定时器TIMx(x=2,3,4,5)主要由时钟源、时钟单元、捕获和比较通道等构成,核心是可编程预分频驱动的16位自动装载计数器。通过对通用定时器内部结构进一步简化得到如下图所示的内部简化图:

cd68a59684d84fd78a4ccfbe1dd67814.png

通用定时器相关参数:

1)通用定时器的时钟源:

如下图为通用定时器框图中有关时钟源的部分:

6209c84251ff4715b72003be0ed5e385.png

当定时器使用内部时钟时,定时器的时钟源统称为TIMxCLK。虽然在系统默认的配置中,TIMxCLK的时钟频率都是72MHz,但其时钟来源并不相同。

  • 定时器TIM2~TIM7挂接在APB1上
  • 定时器TIM1和TIM8挂接在APB2上

若外部晶振的频率为8MHz,则系统默认的时钟频率为72MHz

  • APB1预分频器的分频系数设置为2,则PCLK1=36MHz;
  • APB2预分频系数设置为1,则PCLK2=72MHz,TIM1和TIM8的时钟频率TIMxCLK=72MHz;
  • Cortex系统时钟由AHB时钟(HCLK)8分频得到,即SysTick的频率为9MHz。

2)预分频器PSC:

如图为预分频器时序图:

24cb1e974d45489d9c6c87f928c3e85c.png

简介:

PSC参数代表预分频器(Prescaler)。预分频器用于将定时器的时钟频率分频,以便获得所需的计数频率。在定时器工作时,计数器将以预分频器所设定的频率递增,直到达到设定的自动重载值(ARR,Auto-Reload Register)为止,然后重新开始计数。

限制:可以以1~65535之间的任意数值对时钟源CK_PSC的时钟频率进行分频,输出CK_CNT脉冲供计数器CNT进行计数。

计数器计数频率计算公式:CK_CNT = CK_PSC / (PSC + 1)

3)计数器CNT:

如图为计数器时序图:

398f6d02cd1440d3a705cfbc35b5cd31.png

简介:

  • TIMxCNT是一个16位的寄存器,计数范围为1~65535,可以向上计数、向下计数或向下向上双向计数。
  • 要得到想要的计数值,需要对输入时钟频率进行分频。
  • 当计数值达到设定值时,便产生溢出事件,溢出时产生中断或DMA请求,然后再由自动装载寄存器进行重新加载或更新。
  • 计数器溢出中断属于软件中断,执行相应的定时器中断服务程序。、

计数器溢出频率计算公式:CK_CNT_OV = CK_CNT / (ARR + 1)                           

                                                                  = CK_PSC / (PSC + 1) / (ARR + 1)

4)自动装载寄存器ARR

定时器的定时时间主要取决于定时周期和预分频因子,这里ARR+1是因为计数器都是从0开始计数的。计算公式为:

定时时间=(ARR+1)×(预分频值PSC+1)/输入时钟频率  或者  

T=(TIM_Period +1)*(TIM_Prescaler +1)/TIMxCLK

例如下方实践中要求延时2秒闪烁及定时器设为2s,假设系统时钟为72MHz,通用定时器时钟TIMxCLK为72MHz,设置如下:

预分频系数PSC=6000-1;    ARR=4000-1;

则,定时时间=4000×36000/72000000=2s。

(3)高级定时器

92acfc2ca40c40c0b29a97a6dfe3e808.png

简介:TIM1和TIM8是STM32的2个16位的高级定时器,高级定时器相比基本定时器、通用定时器,功能更为强大   

功能: 高级定时器除了通用定时器的功能外,还支持更高级的特性,如相位锁定回路(PLL)、编码器接口、三角波生成等。

用途场景: 适用于需要更高级、复杂计时功能的应用,例如音频处理、电机控制、编码器接口等。重复计数器、死区生成、互补输出、刹车输入等功能。

(三)定时器配置

1、定时器标准外设库接口函数

简介:

STM32F103系列微控制器的定时器库函数存放在STM32标准外设库的stm32f10x_tim.c和stm32f10x_tim.h文件中,stm32f10x_tim.h头文件中声明了定时器有关的库函数以及相关的宏定义、结构体等。由于STM32的定时器功能较为强大,其库函数也较多,如下图所示:

ff07e9dcb6f94526a7fa396892bc0146.png

TIM_TimeBaseInit()库函数

用于定时器TIMx的参数初始化,函数原型:

void TIM_TimeBaseInit(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;   uint8_t TIM_RepetitionCounter; 
} TIM_TimeBaseInitTypeDef;  

其中

(1)typedef struct(第二行)是被定义在定义在stm32f10x_tim.h头文件中。

(2)uint16_t TIM_Prescaler(第四行),TIMx预分频寄存器TIMx_PSC的值,数值上等于TIMx计数器TIMxCNT的预分频系数减1

(3)uint8_t TIM_RepetitionCounter(第八行),为TIM1和TIM8高级定时器所特有。

(4)TIM_CounterMode(第五行):TIMx计数器TIMxCNT的计数模式分为向上计数和向下计数以及三种中央对其模式计数。

  • TIM_CounterMode_Up:向上计数模式,从0递增,计到TIMx_ARR计数器的自动装载值,并产生计数溢出脉冲
  • TIM_CounterMode_Down:向下计数模式,从TIMx_ARR计数器的自动装载值递减,计到0,并产生计数溢出脉冲
  • TIM_CounterMode_CenterAligned1:中央对齐模式1计数器交替地向上和向下计数,输出比较中断标志位,只在计数器向下计数时被设置;
  • TIM_CounterMode_CenterAligned2:中央对齐模式2计数器交替地向上和向下计数,输出比较中断标志位,只在计数器向上计数时被设置;
  • TIM_CounterMode_CenterAligned3:中央对齐模式3计数器交替地向上和向下计数,输出比较中断标志位,在计数器向下和向上计数时均可被设置。

(5) uint16_t TIM_Period(第六行);  下一个更新事件时装入自动重装载寄存器TIMx_ARR的周期值,数值上等于TIMx计数器TIMxCNT的计数周期减1。

  •   TIM_Period是一个16位无符号整型数据,取值范围为0~65535。    
  •  定时器定时时间主要取决于预分频因子TIM_Prescaler和定时周期TIM_Period

T=(TIM_Prescaler+1)*(TIM_Period+1)/TIMxCLK    

  • TIMxCLK为定时器TIMx的时钟频率,STM32F103的TIMxCLK默认设置为72MHz。

(6) uint16_t TIM_ClockDivision(第七行); 与TIMx_CR寄存器中bit[9:8]的CKD[1:0]对应,用于计数器工作模式时滤除高频干扰,有如下选择:

  • “00”——采样频率基准fDTS=定时器输入频率fCK_INT;
  • “01”——fDTS=fCK_INT/2;
  • “10”——fDTS=fCK_INT/4。

2、定时器标准外设库配置

3ca08e81ee7d4874a4bf2e8368af4da1.png

(1)步骤一:TIM2时钟使能

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

(2)步骤二:初始化定时器参数,设置自动重装值,分频系数,计数方式

定时器初始化使用TIM_TimeBaseInit()函数,如下所示:

void TIM_TimeBaseInit(TIM_TypeDef*TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
  • 第一个参数TIMx是具体定时器,x可为2~4
  • 第二个参数为TimeBaseInitStruct结构体指针。

下面以初始化通用定时器TIM2为例,进行以下配置:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定义TIM初始化类型结构体变量
TIM_TimeBaseStructure.TIM_Period = (36000-1); //设置自动重载计数周期值
TIM_TimeBaseStructure.TIM_Prescaler = (4000-1); //设置分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置为向上计数方式
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //初始化定时器TIM2
TIM_Cmd(TIM2,ENABLE); //使能TIM2定时器

(3)步骤三:设置TIM2允许更新中断

为了避免在初始化定时器时进入中断,需要在初始化过程中清除中断标志。中断在使用前必须先使能再使用,如使能定时器TIM2的更新模式中断,则调用库函数TIM_ITConfig(),函数原型为:

void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

其中:

  • 第一个参数TIMx是具体定时器,x可为2~4。
  • 第二个参数用来指明所使能定时器的中断类型。
  • 第三个参数为TIMx中断的状态,该参数可取值为ENABLE(使能)或者DISABLE(失能)。

(4)步骤四:TIM2中断优先级设置

如图为定时中断基本结构

de9bf9bcaabb4cbb812aa5b81c5fafc4.png

结合先前学习的中断编程,参考博客:中断编程入门-CSDN博客​​​​​​

对TIM2中断做如下所示的配置:

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

(5)步骤五:使能TIM2

使用TIM_Cmd()函数使能相应的定时器,其函数原型为:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) ;

其中:

  • 第一个参数TIMx是具体定时器,x可为2~4
  • 第二个参数为TIMx的状态,该参数可取值为ENABLE(使能)或者DISABLE(失能)

例如,使能定时器TIM2的更新中断,配置如下:              

 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);

(6)步骤六:编写中断服务函数

STM32标准外设库函数中用来读取中断状态的库函数为:

ITStatus TIM_GetITStatus (TIM_TypeDef* TIMx, uint16_t) ;

清除定时器相应中断标志位的函数为:

void TIM_ClearITPendingBit (TIM_TypeDef* TIMx, uint16_t TIM_IT) ;

 例如想要通过定时器设定某时间后GPIOA5引脚的灯反转,则中断服务函数如下所示:

void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)((1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))));TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

因此我们可以得到一个TIM2中断服务函数的模板以便以后使用时可以直接填入。

/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/

二、PWM

(一)PWM简介

PWM基本结构

473941e810a7467695cdc39a9054c6ac.png

1、介绍及其功能

        PWM(Pulse Width Modulation,脉冲宽度调制)是一种利用脉冲宽度即占空比实现对模拟信号进行控制的技术,即是对模拟信号电平进行数字表示的方法。

        广泛应用于电力电子技术中,比如PWM控制技术在逆变电路中的应用;PWM还应用于直流电机调速,如变频空调的交直流变频调速,除实现调速外,还具有节能等特性。

下图是一个周期为10ms(频率为100Hz)的PWM波形图

6d433b0f1d934e8080b5f94804e95270.png

2、占空比

占空比(Duty Cycle),是指在一个周期内,高电平时间占整个信号周期的百分比,即高电平时间与周期的比值: 占空比=Tp/T。

09bedc414b9e4f23bc2918b7171175c2.png87a2d36ed19e4563ba03a978d413ea3a.png

(二)PWM的工作原理

1、产生PWM的定时器:

  • 在STM32的定时器中除了TIM6和TIM7,其他定时器都可以用来产生PWM输出;
  • 高级定时器TIM1和TIM8可以同时产生多达7路的PWM输出;
  • 通用定时器能同时产生多达4路的PWM输出

2、产生PWM的原因:

  • STM32中每个定时器有4个输入通道:TIMx_CH1~TIMx_CH4;
  • 每个通道对应1个捕获/比较寄存器TIMx_CRRx,将寄存器值和计数器值相比较,通过比较结果输出高低电平,从而得到PWM信号;
  • 脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。

3、PWM的工作原理解释

e4bb10d81e884372a36ff9bcfde2ea41.png

  • 在PWM的一个周期内,定时器从0开始向上计数,在0-t1时间段,定时器计数器TIMx_CNT值小于TIMx_CCRx值,输出低电平;
  • 在t1-t2时间段,定时器计数器TIMx_CNT值大于TIMx_CCRx值,输出高电平;
  • 当定时器计数器的值TIMx_CNT达到ARR时,定时器溢出,重新从0开始向上计数,如此循环。

(三)PWM标准外设库输出配置过程

8c009a89bdfa4bc3a9fd8a2c7c4505c1.png

(1)步骤一:配置PWM输出通道,开启TIM2时钟

STM32规定了具体的引脚作为PWM输出引脚,选择不同的引脚时,还必须使用重定向功能(Remap)。

定时器TIM1的引脚复用功能映像:

048dc1dbe69544118087bea056f99172.png

 定时器TIM2的引脚复用功能映像:

2873e8d3cca34f3d9c9e3b8424237112.png

定时器TIM3的引脚复用功能映像:

59a941b8cd5f4f819af60dcaed901952.png

  • 使用定时器3的通道2(TIM2_CH1)作为PWM的输出引脚;
  • 对PA0引脚进行配置,配置PA0为复用推挽输出模式(GPIO_Mode_AF_PP)代码如下所示:
/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);	

(2)步骤二:初始化定时器TIM2

设置预分频系数PSC、自动重载计数值ARR、计数模式、时钟分割等,代码如下所示。下方实验中要求呼吸灯的周期为1~2s,且设置为向上计数法则如下配置。

	/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元

(3)步骤三:设置TIM2_CH1的PWM模式,使能TIM2的CH1输出

如下配置TIM2_CH1的PWM模式使能TIM2的CH1能够正常输出,配置情况如下所示:

    TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1

(4)步骤四:使能定时器TIM2

 最后使能TIM2,定时器开始运行:

TIM_Cmd(TIM2, ENABLE);

三、实际应用

(一)关于定时器的题目

1、题目要求

使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。

2、代码

(1)Timer.c

#include "stm32f10x.h"                  // Device header/*** 函    数:定时中断初始化* 参    数:无* 返 回 值:无*/
void Timer_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			//重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				//将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元	/*中断输出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update);						//清除定时器更新标志位//TIM_TimeBaseInit函数末尾,手动产生了更新事件//若不清除此标志位,则开启中断后,会立刻进入一次中断//如果不介意此问题,则不清除此标志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);					//开启TIM2的更新中断/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);				//配置NVIC为分组2//即抢占优先级范围:0~3,响应优先级范围:0~3//此分组配置在整个工程中仅需调用一次//若有多个中断,可以把此代码放在main函数内,while循环之前//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure;						//定义结构体变量NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;				//选择配置NVIC的TIM2线NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				//指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	//指定NVIC线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);								//将结构体变量交给NVIC_Init,配置NVIC外设/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/* 定时器中断函数,可以复制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/

(2)LED.c

#include "stm32f10x.h"                  // Device headervoid LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);
}

 (3)main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Timer.h"
#include "LED.h"int main(void)
{LED_Init();Timer_Init();	while (1){}
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)((1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5))));TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

3、实物效果

定时器控制LED

(二)关于PWM的题目

1、题目要求

采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整占空比变化到一个满意效果;使用Keil虚拟示波器,观察 PWM输出波形。

2、代码

(1)PWM.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

(2)main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"uint8_t i;			//定义for循环的变量int main(void)
{/*模块初始化*/PWM_Init();			//PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(15);			//延时500ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(15);		//延时500ms}}
}

3、Keil波形图dc479b7fcc764dfe8437bfbd654dda3f.png

4、实物效果

呼吸灯

四、总结

学习完定时器相关内容,就像掌握了一个闹钟。通过自己设定时间,当时间走完则自动运行预先选择做出的行动,为以后的单片机开发提供了一个新的思路。在学习了PWM之后,发现原来点灯也变得有趣起来了,可以通过赋予脉冲使得灯逐亮逐灭,为后续学习舵机等外设打好了基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/19926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

匿名函数(lambda)

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 匿名函数是指没有名字的函数&#xff0c;应用在需要一个函数&#xff0c;但是又不想费神去命名这个函数的场合。通常情况下&#xff0c;这样的函数只…

【Qt】Qt界面美化指南:深入理解QSS样式表的应用与实践

文章目录 前言&#xff1a;1. 背景介绍2. 基本语法3. QSS 设置方式3.1. 设置全局样式3.2. 从文件加载样式表3.3. 使用 Qt Designer 编辑样式 总结&#xff1a; 前言&#xff1a; 在当今这个视觉至上的时代&#xff0c;用户界面&#xff08;UI&#xff09;的设计对于任何软件产…

智能制造案例专题|与MongoDB一起解锁工业4.0转型与增长的无限潜力!

MongoDB 智能制造 数字化技术的洪流在各个产业链的主干和枝节涌现。在工业制造领域&#xff0c;能否通过数字化技术实现各生产要素、生产环节之间的紧密配合&#xff0c;高效规划、管理整个生产流程&#xff0c;是企业提升韧性、赢得竞争的关键。随着工业4.0的深入发展和智能…

高级Java开发者的自我修养:深入剖析JVM垃圾回收机制及面试要点

在探索Java虚拟机&#xff08;JVM&#xff09;的奥秘过程中&#xff0c;垃圾回收机制&#xff08;GC&#xff09;是一个不可或缺的话题&#xff0c;尤其在面对大型应用和系统优化时显得尤为重要。JVM的自动内存管理是Java编程语言中一项革命性的特性&#xff0c;它大大简化了程…

AI盒子在智慧加油站的应用

方案背景 为规范加油站作业&#xff0c;保障人民生命财产安全&#xff0c;《加油站作业安全规范》&#xff08;AQ 3010-2007&#xff09;中第五条规定&#xff1a;卸油作业基本要求&#xff0c;明确防静电、防雷电、防火、人员值守、禁止其他车辆及非工作人员进入卸油区。 痛点…

RocketMQ学习(2) 深入学习

RokcetMQ的介绍和基础知识见这篇博客——RocketMQ学习(1) 快速入门 本篇为上一篇的深入学习&#xff0c;很多基础知识不再赘述。 目录 消息重复消费问题(去重;幂等)布隆过滤器 重试机制死信消息 SpringBoot集成RocketMQ集成SpringBoot发送不同消息模式(同步消息)异步消息单向消…

使用el-tab,el-tab-pane循环使用循环后不显示下划线问题

在vue项目中使用element-UI el-tab里的el-tab-pane是循环出来的&#xff0c;但是循环出来后选中tab不显示下划线了 文章目录 问题问题展示效果问题代码问题原因 解决方案解决后效果解决方案1代码 解决方案2代码 问题 问题展示效果 问题代码 <el-tabs v-model"activeNa…

音量的对数表示与浮点数表示

音量用浮点数&#xff08;float&#xff09;和对数&#xff08;logarithmic scale&#xff09;表示各有特点和应用场景 浮点数&#xff1a;直接使用线性刻度表示音量&#xff0c;例如在0.0&#xff08;最小音量&#xff09;到1.0&#xff08;最大音量&#xff09;的范围内。对…

『 Linux 』缓冲区(万字)

文章目录 &#x1f9a6; 什么是缓冲区&#x1f9a6; 格式化输入/输出&#x1f9a6; 刷新策略&#x1fab6; 块缓冲(fully buffered)&#x1fab6; 无缓冲(unbuffered)&#x1fab6; 行缓冲(line buffered) &#x1f9a6; 现象解释&#x1f9a6; exit()与_exit()&#x1f9a6; 进…

list 的实现

目录 list 结点类 结点类的构造函数 list的尾插尾删 list的头插头删 迭代器 运算符重载 --运算符重载 和! 运算符重载 * 和 -> 运算符重载 list 的insert list的erase list list实际上是一个带头双向循环链表,要实现list,则首先需要实现一个结点类,而一个结点需要…

【代码随想录——回溯算法——四周目】

1.重新安排行程 1.1 我的代码&#xff0c;超时通不过 var (used []boolpath []stringres []stringisFind bool )func findItinerary(tickets [][]string) []string {sortTickets(tickets)res make([]string, len(tickets)1)path make([]string, 0)used make([]bool,…

JSON Web Token

JWT 什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一种用于在各方之间作为JSON对象安全地传输信息的开放标准&#xff08;RFC 7519&#xff09;。该信息经过数字签名&#xff0c;因此是可验证和可信的。JWT 可以使用HMAC算法或使用RSA的公钥/私钥对进行签名 JWT的…

win10键盘按乱了,如何恢复?

今天键盘被宝宝给按乱了&#xff0c;好不容易给重新调整回来&#xff0c;记录备忘&#xff1a; 1、win10的asdf和方向键互换了&#xff1a; 使用Fnw键来回切换&#xff0c;OK&#xff01; 2、键盘的win键失效&#xff0c;例如&#xff1a;按winD无法显示桌面。此时&#xf…

电动汽车电子系统架构

电动汽车的普及正在稳步发展&#xff0c;供应链的各个环节也在发生变化。它涵盖了制造电动汽车零件的原材料、化学品、电池和各种组件。与此同时&#xff0c;汽车充电基础设施也参与其中&#xff0c;它们正经历一个历史性的阶段&#xff0c;经过彻底的重新设计。它们的电气化以…

Wpf 使用 Prism 实战开发Day30

登录界面设计 一.准备登录界面图片素材&#xff08;透明背景图片&#xff09; 1.把准备好的图片放在Images 文件夹下面&#xff0c;格式分别是.png和.ico 2.选中 login.png图片鼠标右键&#xff0c;选择属性。生成的操作选择>资源 3.MyTodo 应用程序右键&#xff0c;属性&a…

如何修改开源项目中发现的bug?

如何修改开源项目中发现的bug&#xff1f; 目录 如何修改开源项目中发现的bug&#xff1f;第一步&#xff1a;找到开源项目并建立分支第二步&#xff1a;克隆分支到本地仓库第三步&#xff1a;在本地对项目进行修改第四步&#xff1a;依次使用命令行进行操作注意&#xff1a;Gi…

地质灾害位移应急监测站

地质灾害位移应急监测站是一种专门用于地质灾害预警和应急响应的设施&#xff0c;它能够实时监测和分析山体、建筑物、管道等的位移变化情况。以下是关于地质灾害位移应急监测站的详细介绍&#xff1a; 主要组成部分 传感器&#xff1a;安装于需要监测的位置&#xff0c;用于…

RK3588+FPGA+AI高性能边缘计算盒子,应用于视频分析、图像视觉等

搭载RK3588&#xff08;四核 A76四核 A55&#xff09;&#xff0c;CPU主频高达 2.4GHz &#xff0c;提供1MB L2 Cache 和 3MB L3 &#xff0c;Cache提供更强的 CPU运算能力&#xff0c;具备6T AI算力&#xff0c;可扩展至38T算力。 产品规格 系统主控CPURK3588&#xff0c;四核…

GUI 02:布局管理器相关知识,AWT 的 3 种布局管理器应用,以及嵌套布局的使用

一、前言 记录时间 [2024-05-31] 前置文章 GUI 01&#xff1a;GUI 编程概述&#xff0c;AWT 相关知识&#xff0c;Frame 窗口&#xff0c;Panel 面板&#xff0c;及监听事件的应用 本文讲述了 GUI 编程种布局管理器的相关知识&#xff0c;以及 AWT 的 3 种布局管理器——流式布…

【FPGA】Verilog语言从零到精通

接触fpga一段时间&#xff0c;也能写点跑点吧……试试系统地康康呢~这个需要耐心但是回报巨大的工作。正原子&&小梅哥 15_语法篇&#xff1a;Verilog高级知识点_哔哩哔哩_bilibili 1Verilog基础 Verilog程序框架&#xff1a;模块的结构 类比&#xff1a;c语言的基础…