STM32定时器详解_stm32通用定时器基本定时器-程序员宅基地

技术标签: stm32  STM32  嵌入式硬件  单片机  

目录

前言

一、定时器基本介绍

1. STM32定时器

2. 通用定时器功能和特点

3. 计数器模式

 4. 定时器工作原理

a.定时器框图

b.时钟产生器部分

c.时基单元

d.输入捕获通道

 e.输出比较通道(PWM)

二、定时器中断应用 

 1.内部时钟选择

2.计数器模式

3.定时器中断实验相关寄存器 

 4. 常用库函数 

5. 定时器中断实现步骤

6. 应用实例

三、定时器PWM输出实验 

1. 通用定时器PWM概述

 2. PWM模式

 3.相关寄存器介绍

4. 定时器输出通道引脚

5.定时器PWM库函数配置

6.实例

总结


前言


定时器作为微控制器不可缺少的外设,在STM32中也是如此。相信不少初学者学到定时器的时候对STM32的学习热情就大打折扣甚至想要放弃了,因为这一部分知识确实比较复杂。但是,如果你在之前对GPIO、串口通信、外部中断的学习中把这些外设掌握了的话,学习这个新知识并不难。

例本章共计1万余字,从STM32定时器的原理、寄存器介绍、定时器配置以及定时器的几个常用的功能(如定时器中断、定时器输出比较PWM波形、定时器输入捕获测电平长度、定时器编码器模式应用等)的使用方法来教大家掌握定时器这一外设。

一、定时器基本介绍

1. STM32定时器

1、上来说就是用来定时的机器,是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6),如下图所示:

这三种定时器的区别如下:

 即:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。

2. 通用定时器功能和特点

STM32的众多定时器中我们使用最多的是高级定时器和通用定时器,而高级定时器一般也是用作通用定时器的功能,下面我们就以通用定时器为例进行讲解,其功能和特点包括:

位于低速的APB1总线上(APB1)
16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。
16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数 为 1~65535 之间的任意数值。
4 个独立通道(TIMx_CH1~4),这些通道可以用来作为: 
        ① 输入捕获 

        ② 输出比较

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

        ④ 单脉冲模式输出

  • 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
  • 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器): 

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

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

        ③输入捕获 

        ④输出比较 

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

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

  • STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。   
  • 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。

3. 计数器模式

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

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

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

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

4. 定时器工作原理

a.定时器框图

下面就是STM32定时器的工作款图了,是学习STM32定时器必须要掌握的。很多学习者学会了通过库函数来配置定时器,实现了简单的应用却忽略了基本原理,这就对导致在复杂应用的设计上出现低级的错误。所以建议读者认真掌握定时器的工作框图,明白内在的原理

 框图可以分为四个大部分(用红色笔表示出),分别是:①时钟产生器部分,②时基单元部分,③输入捕获部分、④输出比较部分。

b.时钟产生器部分

在第一部分时钟选择上,STM32定时器有四种时钟源选择(图中蓝色笔标识),分别是:

①内部时钟(CK_INT)

②外部时钟模式:外部触发输入(ETR)

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

④外部时钟模式:外部输入脚(TIx)

这四种情况可由右图表示:

其中,内部触发输入口1~4除了ITR1/ITR2/ITR3/ITR4之外还有一种情况:用一个定时器作为另一个定时器的分频器。

外部捕获比较引脚有两种,分别是:

引脚1:TI1FP1或TI1F_ED

引脚2:TI2FP2

c.时基单元

时基单元就是定时器框图的第二部分,它包括三个寄存器,分别是:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)和自动装载寄存器(TIMx_ARR)。对这三个寄存器的介绍如下:

  • 计数器寄存器(TIMx_CNT)

向上计数、向下计数或者中心对齐计数;

  • 预分频器寄存器(TIMx_PSC)

可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值;

  • 自动装载寄存器(TIMx_ARR)

如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器;

如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。
 

d.输入捕获通道

  • IC1、2和IC3、4可以分别通过软件设置将其映射到TI1、TI2和TI3、TI4;
  • 4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值;
  • 当产生一次捕捉,相应的CCxIF标志位被置1;同时如果中断或DMA请求使能,则产生中断或DMA请求。
  • 如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。

e.输出比较通道(PWM)

  • PWM模式运行产生:

        定时器2、3和4可以产生4独立的信号

        频率和占空比可以进行如下设定:

                一个自动重载寄存器用于设定PWM的周期;

                每个PWM通道有一个捕捉比较寄存器用于设定占空时间。

                例如:产生一个40KHz的PWM信号:在定时器2的时钟为72MHz下,占空比为50% :

                        预分频寄存器设置为0 (计数器的时钟为TIM1CLK/(O+1)),自动重载寄存器设为                         1799,CCRx寄存器设为899。

  • 两种可设置PWM模式:

        边沿对齐模式

        中心对齐模式
 

 

二、定时器中断应用 

1.内部时钟选择

 除非APB1的分频系数是1,否则通用定时器的时钟等于APB1时钟的2倍。

默认调用SystemInit函数情况下:

SYSCLK=72M

AHB时钟=72M

APB1时钟=36M

所以APB1的分频系数=AHB/APB1时钟=2

所以,通用定时器时钟CK_INT=2*36M=72M

2.计数器模式

  • 向下计数模式:(时钟分频因子=1)

  • 向下计数模式:(时钟分频因子=1)

中央对齐计数模式:(时钟分频因子=1 ARR=6)

3.定时器中断实验相关寄存器 

  • 计数器当前值寄存器CNT

  •  预分频寄存器TIMx_PSC

  •  自动重装载寄存器(TIMx_ARR)

  •  控制寄存器1(TIMx_CR1)

  • DMA中断使能寄存器(TIMx_DIER)

4. 常用库函数 

定时器参数初始化:

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; 

 声明方式(一般):

TIM_TimeBaseStructure.TIM_Period = 4999; 
TIM_TimeBaseStructure.TIM_Prescaler =7199; 
TIM_TimeBaseStructure.TIM_ClockDivision =   TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode =   TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 

  定时器使能函数

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

 定时器中断使能函数

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

状态标志位获取和清除

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);
 
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

5. 定时器中断实现步骤

① 能定时器时钟。
       RCC_APB1PeriphClockCmd();

②  初始化定时器,配置ARR,PSC。

      TIM_TimeBaseInit();

③开启定时器中断,配置NVIC。
      void TIM_ITConfig();

      NVIC_Init();

④  使能定时器。

      TIM_Cmd();

⑥  编写中断服务函数。

      TIMx_IRQHandler();

6. 应用实例

下面是使用定时器中断的代码,我们设置为每500ms中断一次,中断服务函数控制LED实现LED状态取反。时间计算方法为:

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

//timer.c源文件
#include "timer.h"
#include "led.h"
 
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
 
	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
 
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}
//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
		LED1=!LED1;
		}
}

//timer.h头文件
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
 
void TIM3_Int_Init(u16 arr,u16 psc);
 
#endif
//main.c源文件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
 
 
 int main(void)
 {		
 
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms  
   	while(1)
	{
		LED0=!LED0;
		delay_ms(200);		   
	}	 
}	 

三、定时器PWM输出实验 

1. 通用定时器PWM概述

       PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。PWM的功能有很多种,比如控制呼吸灯、控制直流电机或者舵机等驱动原件等等,是单片机的一个十分重要的功能。

        在STM32单片机中,可以使用定时器的输出比较功能来产生PWM波:
       即PWM模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。其框图如下图所示:

         可见,横坐标是时间变量,纵坐标是CNT计数值,CNT计数值随着时间的推进会不断经历从0到ARR,清零复位再到ARR的这一过程。这之中还有一个数值是CCRx即比较值,通过比较值和输出配置可以使之输出高低电平逻辑,这样就产生了PWM波形。通过调节ARR的值可以调节PWM的周期,调节CCRx的值大小可以调节PWM占空比。

        我们以通道1为例,详细讲解PWM的工作过程,如下图所示:

从最左边进入的是时钟源,由内部时钟(CNT)或者外部触发时钟(ETRF)输入,进入输入模式控制器,通过OCMR1寄存器的OC1M[2:0]位来配置PWM模式,之后进入一个选择器,由CCER寄存器的CC1P位来设置输出极性,最后由CCER寄存器的CC1E位来使能输出,然后通过OC1来输出PWM波。

CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。

CCMR1: OC1M[2:0]位: 对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】

CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。

CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

2. PWM模式

PWM有PWM模式1和模式2两种模式,它们之间的区别用寄存器TIMx_CCMR1的OC1M[2:0]位来分析:

 表中红色框标识的地方就是PWM模式1和模式2的定义和区别,可以简单理解为:PWM模式1的情况下,当前值小于比较值为有效电平;PWM模式2的情况下,当前值大于比较值为有效电平。

理解这一点对之后的PWM配置十分重要。

下面是对PWM模式1以及向上计数配置情况的说明:

3.相关寄存器介绍

  • 捕获/比较寄存器1(TIMx_CCR1)

 这里以寄存器1举例,其它的三个寄存器(CCR2、CCR3、CCR4)都是一样的

  • 捕获比较模式寄存器1(TIMx_CCMR1)

可以看到,每个捕获/比较模式寄存器可以控制两个通道,这样的话每个定时器就对应两个捕获/比较模式寄存器。其最常用的位就是0C1M(OC2M)位了,这两个位是用来设置PWM模式的,有模式1和模式2两种,这就和前面所讲的对应上了。

  • 捕获/比较使能寄存器(TIMx_CCER)

 可以看到,位0(CC1E)和位1(CC1P)是捕获比较使能寄存器最常用的两个位,分别控制输出使能和输出极性,这就也和刚刚讲的对应上了。

  • 自动重装载寄存器(TIMx_ARR)

 这个寄存器不太常用,下面的库函数配置会讲解其库函数用法。

4. 定时器输出通道引脚

定时器输出PWM和定时器中断不同,定时器中断只需要开启这一外设即可工作,定时器输出PWM需要在单片机的引脚上输出实实在在的脉冲信号。

下面是定时器3的通道引脚,可以使用部分映射或者完全映射。其它定时器的引脚可以查看芯片手册。

5.定时器PWM库函数配置

  • 输出库函数配置

和定时器中断实验不同,在初始化时基单元之后,还需要对输出通道进行初始化:

void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

 其结构体成员如下:

typedef struct
{
  uint16_t TIM_OCMode;  //PWM模式1或者模式2
  uint16_t TIM_OutputState; //输出使能 OR失能
  uint16_t TIM_OutputNState;
  uint16_t TIM_Pulse; //比较值,写CCRx
  uint16_t TIM_OCPolarity; //比较输出极性
  uint16_t TIM_OCNPolarity; 
  uint16_t TIM_OCIdleState;  
  uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef;

 初始化实例:

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure. TIM_Pulse=100;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
  • 设置比较值函数

void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);
  •  使能输出比较预装载

void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

  • 使能自动重装载的预装载寄存器允许位
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

输出配置步骤

① 使能定时器3和相关IO口时钟。
         使能定时器3时钟:RCC_APB1PeriphClockCmd();

         使能GPIOB时钟:RCC_APB2PeriphClockCmd();

②     初始化IO口为复用功能输出。函数:GPIO_Init();

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      

③ 这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,
       所以需要开启AFIO时钟。同时设置重映射。

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE)

④    初始化定时器:ARR,PSC等:TIM_TimeBaseInit();

⑤    初始化输出比较参数:TIM_OC2Init();

⑥   使能预装载寄存器: TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

⑦   使能定时器。TIM_Cmd();

⑧   不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare2();

6.实例

我们使用STM32单片机的定时器TIM3的PWM功能,输出占空比可变的PWM波,用来驱动LED灯,从而达到LED亮度由暗变亮,又从亮变暗,如此循环。代码如下:

//timer.c源文件
 
#include "timer.h"
#include "led.h"
#include "usart.h"
 
 
//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
 
   //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
 
   //初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
 
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
 
	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
	
 
}

//timer.h头文件
 
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
 
 
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif

//main.c源文件
 
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"
 
 
 int main(void)
 {		
 	u16 led0pwmval=0;
	u8 dir=1;	
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
 	TIM3_PWM_Init(899,0);	 //不分频。PWM频率=72000000/900=80Khz
   	while(1)
	{
 		delay_ms(10);	 
		if(dir)led0pwmval++;
		else led0pwmval--;
 
 		if(led0pwmval>300)dir=0;
		if(led0pwmval==0)dir=1;										 
		TIM_SetCompare2(TIM3,led0pwmval);		   
	}	 
 }
 

总结

本章从STM32定时器的原理、寄存器介绍、定时器配置以及定时器的几个常用的功能(如定时器中断、定时器输出比较PWM波形)的使用方法来教大家掌握定时器这一外设。希望读者能够仔细学习,掌握这一重要的外设

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhuxinmingde/article/details/131784852

智能推荐

查找二叉树、完全二叉树、线索二叉树、最优二叉树_二叉树 完全二叉树 查找二叉树-程序员宅基地

文章浏览阅读3.3k次,点赞30次,收藏38次。提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、查找二叉树(二叉排序树)二、完全二叉树前言2021年上半年 软件设计师 上午试卷中有这样一道题58.当二叉树的结点数目确定时,________的高度一定是最小的。A.二叉排序树 B.完全二叉树 C.线索二叉树 D.最优二叉树我已此为契机,了解一下查找二叉树、完全二叉树、线索二叉树、最优二叉树的一些相关定义(此题结尾会给出答案详解)一、查找二叉树(二叉排序树)二叉排序树的定义:1、若根结点的左子树._二叉树 完全二叉树 查找二叉树

pyhon---之argparse_python3 argparse不输出usage和error-程序员宅基地

文章浏览阅读1.8k次。argparseargparse 是 Python 内置的一个用于命令项选项与参数解析的模块,通过在程序中定义好我们需要的参数,argparse 将会从 sys.argv 中解析出这些参数,并自动生成帮助和使用信息。当然,Python 也有第三方的库可用于命令行解析,而且功能也更加强大,比如 docopt,Click。argparse 使用简单示例我们先来看一个简单示例。主要有三个步骤:创建 Ar..._python3 argparse不输出usage和error

决策树算法和CART决策树算法详细介绍及其原理详解-程序员宅基地

文章浏览阅读2.1k次。今天给大家带来的主要内容包括:决策树算法、基尼系数和CART决策树算法。废话不多说,下面就是本文的全部内容了!_cart决策树

Retrofit请求怎样接收返回的数据格式_android retrofit 如何知道接受类型-程序员宅基地

文章浏览阅读4.5k次。因为有时候接口文档没有提前发出来,只能自己请求接口后才能知道后台返回的数据格式是怎样的,所以这里我们可以设置返回的类是ResponeBody,如果知道返回的数据类型,就设置为返回的实体类步骤一:网络请求的接口返回类型改为ResponseBody步骤二:Gson转接收的实体bean这个就不需要了步骤三:response.body().string()就是返回的数据,自己看着转..._android retrofit 如何知道接受类型

【超快超轻YOLO】YOLO-Fastest从Darknet源码编译、测试再到训练完整图文教程!-程序员宅基地

文章浏览阅读5.9k次,点赞4次,收藏54次。最轻的YOLO算法出来了!这是个模型非常小、号称目前最快的YOLO算法——大小只有1.3MB,单核每秒148帧,移动设备上也能轻易部署。而且,这个YOLO-Fastest算法满足所有平台..._yolo-fastest

oracle自治事务的写法_oracle存储过程自治事务-阿里云开发者社区-程序员宅基地

文章浏览阅读196次。pb调用存储过程的时候,使用了事务,为了存储过程的逻辑功能完整,往往在存储过程中也会使用事务。如何保证存储过程内外的事务合理使用显得尤为重要。pb调用存储过程的事务,我们称其为主事务。他与存储过程内的事务关系,无非就两种情况。两个事务是同一个事务或者两个事务是独立的两个事务。oracle提供了参数PRAGMA AUTONOMOUS_TRANSACTION用于标示存储过程内的事务为自治事务,实例如下...

随便推点

Flink Table Api 将数据写出到mysql_flink 读取s3-程序员宅基地

文章浏览阅读9.5k次。Flink Table Api 将数据写出到mysql_flink 读取s3

QClipboard类文档_qt使用qclipboard的clear方法无法清除数据-程序员宅基地

文章浏览阅读407次。QClipboard类提供了对窗口系统剪贴板的访问。#include "qclipboard.h"继承了QObject。所有成员函数的列表。公有成员void clear()bool supportsSelection () constbool ownsSelection() constbool ownsClipboard() con..._qt使用qclipboard的clear方法无法清除数据

mybatis_plus获取批量插入id_mybatisplus批量插入获取id-程序员宅基地

文章浏览阅读1.4k次。mybatis_plus获取批量插入id_mybatisplus批量插入获取id

将date命令结果转换为yyyymmdd日期格式_date转yyyy-mm-dd-程序员宅基地

文章浏览阅读3.3k次。date -d yesterday '+%Y%m%d' 以yyyymmdd格式显示昨天日期date -d today '+%Y%m%d' 以yyyymmdd格式显示当天日期date -d tomarrow '+%Y%m%d' 以yyyymmdd格式显示明天日期_date转yyyy-mm-dd

日常BUG ——乱码-程序员宅基地

文章浏览阅读1.5k次。日常问题定位分析。

【JavaEE基础与高级 第27章】基本类型包装类的使用,装箱以及拆箱与parseInt方法_java包装类parseint-程序员宅基地

文章浏览阅读1.3w次,点赞44次,收藏35次。Java 中的数据类型分为基本类型和引用类型两大类,使用基本类型可以提升效率但是java是面向对象的语言,java的设计思想是一切皆对象,而基本数据类型不是对象,于是 Java 为每种基本数据类型都设计了对应的类,称为包装类。......_java包装类parseint

推荐文章

热门文章

相关标签