STM32 定时器TIM

定时器基础知识

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

STM32F10X系列总共最多有八个定时器

三种STM32定时器的区别:

向上是指1234逐个递增计数,向下是指逐个递减计数,向上/向下是指中央对齐模式(基本定时器只能向上,上图写错了) ,捕获指的是输入捕获,比较指的是输出比较

基本定时器

1. 时钟源 2. 控制器 3. 时基单元

时钟源

时钟源来自RCC的TIMx_CLK(属于内部的CK_INIT)

外设挂载在总线下的APB1对应的是时钟2~时钟7(所以我们的基本定时器TIM6 TIM7在APB1下的)

根据时钟树

因为AHB 72M,(AHB默认分频是2)所以APB1是 36M,(APB1默认分频是2)所以根据(如果APB1预分频系数=1则频率不变,否则频率x2.)可知定时器的频率 = 72M

时基(定时器的心脏)

定时器最重要的就是时基部分:包括预分频器、计数器、自动重装载寄存器

预分频器:1-16位预分频器PSC对内部时钟CK_PSC进行分频之后,得到计数器时钟CK_INT=CK_PSC/(PSC+1)

CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_INT

计数器、重装在寄存器:定时器使能(CEN置1)后,计数器CNT在CK_CNT驱动 下计数,当CNT值与ARR的设定值相等时就自动生成事件并CNT自动清零,然后 自动重新开始计数,如此重复以上过程。

影子寄存器

1.PSC和ARR都有影子寄存器,功能框图上有个影子

2.影子寄存器的存在起到一个缓冲的作用,用户值->寄存器->影子寄存器->起作用, 如果不使用影子寄存器则用户值在写到寄存器之后则里面起作用,ARR影子, TIMx_CR1:APRE位控制。

定时时间的计算

定时器时间=(PSC+1)*(ARR+1)/72M

因为我们的计数器是从0开始计数的,所以要加1

基本定时器的功能

1.计数器16bit,只能向上计数,只有TIM6和TIM7

2.没有外部的GPIO,是内部资源,只能用来定时

3.时钟来自PCKL1,为72M,可实现1~65536分频

通用定时器

STM32 的通用定时器功能:

位于低速的APB1总线上(APB1)

16 位/32 位(仅 TIM2 和 TIM5)向上、向下、向上/向下自动装载计数器 (TIMx_CNT),注意:TIM9~TIM14 只支持向上(递增)计数方式

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

4 个独立通道(TIMx_CH1~4,TIM9~TIM14 最多 2 个通道),这些通道可以用来作为:

输入捕获

输出比较

PWM 生成(边缘或中间对齐模式) ,注意:TIM9~TIM14 不支持中间对齐模式

单脉冲模式输出

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

如下事件发生时产生中断/DMA(TIM9~TIM14 不支持 DMA):

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

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

输入捕获

输出比较

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

触发输入作为外部时钟或者按周期的电流管理(TIM9~TIM14 不支持)

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

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

计数器模式

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

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

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

通用定时器框图

框图可以分为四个大部分,分别是:

时钟产生部分

时基单元部分

输入捕获部分

输出捕获部分

时钟产生部分

内部时钟(CKINT)

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

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

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

时机单元

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

计数器寄存器(TIMx_CNT)

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

预分频器寄存器(TIMx_PSC)

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

自动装载寄存器(TIMX ARR)

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

输入捕获通道

1.IC1、2和IC3、4可以分别通过软件设置将其映射到T11、TI2和TI3、TI4;

2.4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值,

3.当产生一次捕捉,相应的CCxIF标志位被置1;同时如果中断或DMA请求使能,则产生中断或DMA请求。

4.如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。

输出比较通道

PWM模式运行产生:

定时器2、3和4可以产生独立的信号:频率和占空比可以进行如下设定一个自动重载寄存器用于设定PWM的周期;每个PWM通道有一个

捕捉比较寄存器用于设定占空时间。

两种可设置PWM模式:

边沿对齐模式

中心对齐模式

常用库函数

定时器参数初始化函数(第一个参数定时器几,第二个参数结构体指针)

cs 复制代码
 void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

结构体内部成员

cs 复制代码
typedef struct
{
    uint16_t TIM_ClockDivision;     //外部输入时钟分频因子,基本定时器没有
    uint16_t TIM_CounterMode;       //计数模式,基本定时器只能向上计数
    uint16_t TIM_Period;           //自动重装载值 //注意重装载值和分频因子的数配置不能超过65535
    uint16_t TIM_Prescaler;    //分频因子      
    uint8_t TIM_RepetitionCounter;  //重复计数值,基本定时器没有,高级定时器专用

} TIM_TimeBaseInitTypeDef;  
65535

定时器控制LED灯软件流程设计

初始化系统

初始化定时器和LED的IO时钟、初始化LED的引脚IO

使能定时器时钟、初始化定时器、开启中断配置、使能定时器、

编写定时器中断函数

定时器时间= (ARR+1)*(PSC+1)/TCLK(72M=72 000 000)

假如定时1秒 1= 72 00*10000/72M

cs 复制代码
#include "stm32f10x.h"
#include "tim.h"

void Base_Tim_Init()
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	TIM_TimeBaseInitTypeDef TIM_TimeIinitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	TIM_TimeIinitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeIinitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeIinitStruct.TIM_Period = 7200 - 1;
	TIM_TimeIinitStruct.TIM_Prescaler = 10000 - 1;
	TIM_TimeIinitStruct.TIM_RepetitionCounter = 0;
	
	TIM_TimeBaseInit(TIM2,&TIM_TimeIinitStruct);
	
  TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
	TIM_Cmd(TIM2, ENABLE);

	NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	
	NVIC_Init(&NVIC_InitStruct);

}
	
cs 复制代码
  TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
第二个参数
输入捕获输出比较所用到的通道
如果我们只是想产生定时器的更新源中断用第一个参数
cs 复制代码
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"
#include "usart.h"
#include "stdio.h"
#include "tim.h"

void delay(uint16_t time) {
    uint16_t i = 0;
    while (time--) {
        i = 12000;
        while (i--);
    }
}

int main() 
{
		
		Led_Init();
    Base_Tim_Init();

    while (1)
		{       			
			
        }
}

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
		
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
		delay(1000);
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		delay(1000);
		
	}

		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	

}

定时器中断应用

超声波模块

1.工作原理

首先单片机给Trig引脚,给至少10us(10微秒)的高电平信号。

模块自动发送8个40KHz的方波,自动检测是否有信号返回。

有信号返回,通过Echo引脚输出高电平,高电平持续时间就是超声波从发射到返回的时间

HC-SR04超声波测距模块提供2cm-400cm的测距功能,精度达3mm。

2.硬件接线

四根杜邦线,VCC连接单片机3.3-5V(推荐5V供电),GND接到板子的GND,Trig为外部触发信号输入,输入一个10us的高电平即可触发模块测距,Echo(接收引脚)即为 回响信号输出,测距结束时此管引脚输出一个低电平,电平宽度反映超声波往返时间之和。

3.控制超声波测距步骤

初始化定时器时钟和定时器中断

初始化超声波时钟和超声波引脚模式

编写定时器中断函数测距

先发送10us的高电平信号,发送了之后我的定时器就开始捕获Echo的高电平的时间,什么时候低电平就什么时候关闭定时器,就开始算比如说我们产生了多少次定时器的中断,比如是一次定时器中断是1秒,多少个定时器中断就是多少个秒,通过一系列公式就能知道距离是多少

  1. 发送 10μs 的高电平信号(触发信号)
  • 目的 :启动一次测距操作。

    这里的 "发送高电平" 通常是通过单片机的 IO 口输出一个持续 10 微秒(μs) 的高电平脉冲(如 HC-SR04 模块需要这样的触发信号)。

  • 为什么是 10μs?

    这是目标设备(如超声波传感器)的协议规定,用于告知传感器 "开始发射信号"(例如超声波传感器会在接收到 10μs 高电平后,发射一束超声波)。

  1. 定时器开始捕获 Echo 信号的高电平时间
  • Echo 信号是什么?

    Echo 是 "回波信号",即目标设备接收到反射回来的信号后,输出的电信号。例如:

    • 发送端发射超声波后,Echo 信号保持低电平;

    • 当超声波遇到障碍物反射回来被接收端检测到,Echo 信号变为高电平;

    • 直到信号接收完毕,Echo 信号重新变为低电平。

  • 定时器的作用

    从触发信号发送完成的时刻起,定时器开始记录 Echo 信号 高电平的持续时间(即从 "收到回波" 到 "回波结束" 的时间)。

  1. 检测到低电平时关闭定时器
  • 何时关闭定时器?

    当 Echo 信号从高电平跳转为低电平时(即回波接收完毕),立即停止定时器计数。

  • 本质

    定时器记录的是 "回波信号高电平的持续时间 T" ,这个时间 T 等于信号从发射到接收的 往返时间(即信号从发射端→障碍物→接收端的总时间)。

  1. 通过定时器中断次数计算时间 T
  • 定时器中断机制

    定时器通常配置为按固定周期产生中断(例如每 1μs、1ms 产生一次中断),每次中断时计数器加 1。

    • 假设定时器中断周期为 1μs (即每 1 微秒产生一次中断),中断次数为 N 次,则总时间 T = N × 1μs

    • (原句中 "一次中断是 1 秒" 是简化举例,实际应用中中断周期远小于 1 秒,通常为微秒或毫秒级,否则精度不足。)

  • 如何计算中断次数?

    定时器启动后,每当 Echo 为高电平时,中断计数器持续累加,直到 Echo 变低时停止计数,此时计数器的值即为高电平期间的中断次数。

  1. 通过公式计算距离
  • 核心公式(以超声波测距为例)

    距离 = (信号速度 × 时间 T) / 2

    • 除以 2 的原因:信号往返一次(发射→障碍物→接收),实际距离是单程距离。

    • 信号速度:超声波在空气中约为 340m/s(即 0.034cm/μs),光速约为 3×10⁸m/s(用于激光测距)。

  • 举例计算

    若 T = 1000μs(1 毫秒),则距离 = (0.034cm/μs × 1000μs) / 2 = 17cm。

超声波代码框架

只有收到回响信号的时候,我们的trigr,在信号发出的时候我的echo引脚输入给我们的单片机,然后如果我们的单片机之前是低电平,检测高电平的瞬间才开始打开定时器(怎么打开和关闭定时器呢)之前配置定时器的时候结构体配置和中断的配置TIM_Cmd(TIM2, DISABLE);函数,先关闭

当收到信号的时候再打开,怎么计算高电平时间?首先要先判断echo引脚什么时候变成高电平

用GPIO_ReadInputDataBit函数然后这里再打开定时器这时就开始我们的中断函数,中断函数去计数定时器进入的次数,因为我们用定时器的开启的时候用定时器的中断计算进入定时器的时间,注意 这里定时器的配置TIM_Initstruct.TIM_Period = 1000 -1; TIM_Initstruct.TIM_Prescaler = 72 -1;

所以定时器的定时周期的1毫秒,计数器每计1次代表1微秒 ,中断1次是1毫秒,因为我们对应的时间是高电平的时间等于中断次数加上不足一个中断的次数(不足一个中断的次数是说不到1毫秒但有多少个微秒呢)打开定时器,就会跳到定时器中断函数void TIM2_IRQHandler()让mscount++;这里需要定义一个新变量,然后关闭定时器,计算总电平时间,定义一个变量uint16_t t=0;定义一个函数专门用来封装总的高电平时间int Get_Echon_Time()(这里返回值是int)然后将总时间换算成距离以种种方式将t换算距离然后返回值length

cs 复制代码
#include "stm32f10x.h"
#include "tim.h"

  uint16_t mscount = 0;//定义一个变量专门用来记录中断的次数

void delay_us(uint32_t us)
{
		us*= 8;
		while(us--);
	//延时微秒函数
	
}	
void delay_ms(uint32_t ms)
{
		while(ms--)
		{
			delay_us(1000);
			
		}	
	//延时毫秒函数
	
	
}


void Base_Tim_Init()
{
	TIM_TimeBaseInitTypeDef TIM_Initstruct;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitTypeDef NVIC_TIM_Initstruct;


	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	
	TIM_Initstruct.TIM_ClockDivision =TIM_CKD_DIV1;
	TIM_Initstruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_Initstruct.TIM_Period = 1000 -1;
	TIM_Initstruct.TIM_Prescaler = 72 -1;
	TIM_Initstruct.TIM_RepetitionCounter = 0;
	
	TIM_TimeBaseInit(TIM2, &TIM_Initstruct);
	TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);
	TIM_Cmd(TIM2, DISABLE);


	NVIC_TIM_Initstruct.NVIC_IRQChannel =  TIM2_IRQn;
	NVIC_TIM_Initstruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_TIM_Initstruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_TIM_Initstruct.NVIC_IRQChannelSubPriority = 0;
	
	NVIC_Init(&NVIC_TIM_Initstruct);
	
}
void HC04_Iint()
{
	

	GPIO_InitTypeDef GPIO_Initstruction;
	
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);

	
	//Tring B11
	GPIO_Initstruction.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Initstruction.GPIO_Pin = GPIO_Pin_11;
	GPIO_Initstruction.GPIO_Speed = GPIO_Speed_10MHz;
	
	GPIO_Init(GPIOB, &GPIO_Initstruction);
    //Echo B10
	GPIO_Initstruction.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Initstruction.GPIO_Pin = GPIO_Pin_10;

	
	GPIO_Init(GPIOB, &GPIO_Initstruction);
	
	
}

void Open_Tim()
{
	
	TIM_SetCounter(TIM2, 0);
	mscount = 0;
	
	TIM_Cmd(TIM2, ENABLE);
	
	
	
}
void Close_Tim()
{
	
	TIM_Cmd(TIM2, DISABLE);
	
	
}
//获取定时器中断的次数
void TIM2_IRQHandler()
{

if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	{
			mscount++;
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

	}
	
	
}

//获取总的高电平时间
int Get_Echon_Time()
{
	
	uint16_t t = 0;
	
	t = mscount * 1000;
	t = t +TIM_GetCounter(TIM2);
	delay_ms(50);
	
	TIM_SetCounter(TIM2, 0);

	return t;
				
}


float Get_Length()
{
	float sum = 0;
	uint16_t t=0;
	float length = 0;
    int i = 0;
    while(i != 5)
  {
	
	//1.hc04开始工作 Tring引脚输出高电平20us
	GPIO_SetBits(GPIOB,  GPIO_Pin_11)
	
	delay_us(20);//延时20微秒
	
	GPIO_ResetBits(GPIOB,  GPIO_Pin_11);//然后关闭

	//2.定时器计算高电平时间
	while(GPIO_ReadInputDataBit(GPIOB,  GPIO_Pin_10) == 0);//当GPIO 10引脚高电平时 会卡在这
	Open_Tim();//打开定时器
	while(GPIO_ReadInputDataBit(GPIOB,  GPIO_Pin_10) == 1);//当高电平跳成低电平时
	Close_Tim();//关闭定时器
	t = Get_Echon_Time();
    //3.将时间换算成距离
	
	length = ((float)t/58.0);
		
	sum = sum+length;
	
  }
	length = sum/5.0;
	

	return length;
	
	
	
}
cs 复制代码
int main() 
{
	
	float length = 0;
	
	
		my_usart_init();
		Ch04_Init();
		Led_Init();
		Base_Tim_Init();

    while (1)
		{
      
			
			length = Get_Length();
			printf("%f\r\n",length);
						
			
        }
}

通用定时输出PWM

第一步内部时钟的选择,第二步是预分频器,计数器,去配置输出 捕获和比较

定时器3的通道2

以TIM3为例,STM32的通用定时器氛围TIM2,TIM3,TIM4,TIM5,每个定时器都有独立的四个通道可以用来作为: 输入捕获,输出比较,PWM输出,单脉冲模式输出等。

STM32的定时器除了TIM6和TIM7(基本定时器)之外,其他的定时器都可以产生PWM波输出,高级定时器TIM1,TIM8可以同时产生7路PWM输出,而通用定时器可以同时产生4路PWM输出,这样STM32可以最多同时输出30路PWM输出。

PWM****的工作原理

以向上计数为例,讲述PWM原理:

①在PWM输出模式下除了CNT(计数器当前值),ARR(自动重装载值),CCRx(捕获/比较寄存器值)。

②当CNT小于CCRx时,TIMx_CHx通道输出低电平

③当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平

假设ARR设置是100CRRX是80,在0加到80过程中都属于低电平,在80加到100都属于高电平,这就是一个周期,所以占空比为百分之二十,

所谓脉宽调制信号(PWM波),就是一个TIMx_ARR自动重装载寄存器确定频率=周期的导数(由它决定PWM周期),TIM_CCRx寄存器确定占空比信号。

占空比=高电平占低电平的时间

PWM****的内部运作机制

CCR1:设置捕获比较寄存器,设置比较值。

CCMR1寄存区:设置PWM模式1 或者PWM模式2。

CCER: P位:输出/捕获 :设置极性: 0 高电平有效,1 低电平有效

E位:输出/捕获 : 使能端口

PWM****的模式

模式一 边沿对齐模式

向上计数时: 当TIMx_CNT<TIMx_CCRx时通道1为有效电平,否则为无效电平;(计数值小于有效值是有效电平)

向下计数时: 一旦TIMx_CNT>TIMx_CCRx,CCR1通道1为无效电平,否则为有效电平。(计数值大于比较值为无效电平)

但是这里的有效电平是高电平还是低电平有极性( 0 高电平有效,1 低电平有效)去选择

模式二 中央对齐模式

向上计数时: 当TIMx_CNT<TIMx_CCRx时通道1为无效电平,否则为无效电平;

向下计数时: 一旦TIMx_CNT>TIMx_CCRx,CCR1通道1为有效电平,否则为无效电平。

和模式一相反

但是这里的有效电平是高电平还是低电平有极性( 0 高电平有效,1 低电平有效)去选择

自动加载的预加载寄存器

简单的说:

APER =1 ,ARR立即生效

APER =0,ARR下个周期生效

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

定时器输出PWM结构体

cs 复制代码
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;

定时器输出PWM库函数

cs 复制代码
void TIM_OCxInit                      //结构体初始化
(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_SetCompare1            //设置比较值函数
(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_OC1PreloadConfig     //使能输入比较预装载
(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_Cmd                            //开启定时器
 (TIM_TypeDef* TIMx, FunctionalState NewState)
void TIM_ARRPreloadConfig     //使能自动重装载的预装载寄存器允许位
(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_OC1PolarityConfig      //配置修改极性
(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

定时器输出PWM库函数

TIM3 PWM输出 驱动SG90电机 配置过程:

1.GPIO结构体

2.配置通用定时器结构体

3.配置定时去输出PWM结构体

4.打开时钟 ---> GPIO时钟,TIM定时器时钟,部分重映射时钟

5.配置PWM比较值

cs 复制代码
void motor_config(void)
{
	
	
	GPIO_InitTypeDef GPIO_MotorInitStruct;
	TIM_TimeBaseInitTypeDef TIM_MotorInit;
	TIM_OCInitTypeDef TIMPWM_MotorInit;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);//部分重映射配置

	
	GPIO_MotorInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_MotorInitStruct.GPIO_Pin = GPIO_Pin_5;
	GPIO_MotorInitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_MotorInitStruct);

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	TIM_MotorInit.TIM_ClockDivision = TIM_CKD_DIV1;       //设置时钟分割
	TIM_MotorInit.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
	TIM_MotorInit.TIM_Period = 200-1;//设置下一个更新事件装入活动的自动重装载值
	TIM_MotorInit.TIM_Prescaler = 7200 -1;	//分频周期
	TIM_TimeBaseInit(TIM3, &TIM_MotorInit);

	TIMPWM_MotorInit.TIM_OCMode = TIM_OCMode_PWM1;//选择定时器模式1
	TIMPWM_MotorInit.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
	TIMPWM_MotorInit.TIM_OCNPolarity = TIM_OCPolarity_Low;//选择有效输出极性
	
	TIM_OC2Init(TIM3, &TIMPWM_MotorInit);//因为选择的是定时器3的通道2 所以选OC2
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
	TIM_Cmd(TIM3, ENABLE);

	

}
cs 复制代码
int main() 
{
	
	uint16_t pwmval = 155;
	 motor_config();
	
	
		while(1)
		{
			for(pwmval = 195;pwmval >= 175;pwmval-=5)
			{
				TIM_SetCompare2(TIM2,  pwmval);
				delay(500);
			
			}
						
		}

			
}

垃圾桶项目

cs 复制代码
int main() 
{
	
	int  pwmval =195;
	float Length =0;
	Ch04_Init();	
	my_usart_init();
	motor_config();
	while(1)
	{
		pwmval =155;
    Length= Get_Length();
		printf("%.3f\r\n",Length);
	
		
		if(Length<5)
		{
		   for(pwmval=195;pwmval>=155;pwmval-=15)
			{
			  TIM_SetCompare2(TIM3, pwmval);
				delay(500);	
			}

		}
					else if(Length>5)
			{
			  TIM_SetCompare2(TIM3, pwmval-20);
			
			}
	}
			
}
相关推荐
ltqshs5 分钟前
STM32标准库和HAL库SPI发送数据的区别-即SPI_I2S_SendData()和HAL_SPI_Transmit()互换
stm32·单片机·嵌入式硬件
程序员JerrySUN21 分钟前
驱动开发硬核特训 · Day 22(上篇): 电源管理体系完整梳理:I2C、Regulator、PMIC与Power-Domain框架
linux·驱动开发·嵌入式硬件
xyd陈宇阳1 小时前
STM32(M4)入门:定时器延时与系统滴答(价值 3w + 的嵌入式开发指南)
stm32·单片机·嵌入式硬件
即安莉2 小时前
STM32 CAN通信 HAL库实战教程:从零到测试成功
stm32·单片机·嵌入式硬件
优信电子2 小时前
STM32 驱动 INA226 测量电流电压功率
stm32·单片机·嵌入式硬件
BW.SU2 小时前
单片机 + 图像处理芯片 + TFT彩屏 复选框控件
单片机·嵌入式硬件·gpu·ra8889·ra6809·液晶控制芯片·图形处理芯片
小智学长 | 嵌入式2 小时前
单片机-89C51部分:5、点亮LED
单片机·嵌入式硬件
嵌入式学习之旅3 小时前
单片机之间的双向通信
单片机·嵌入式硬件
零零刷3 小时前
德州仪器(TI)—TDA4VM芯片详解(1)—产品特性
人工智能·嵌入式硬件·深度学习·神经网络·自动驾驶·硬件架构·硬件工程