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

一、定时器介绍
1、概念:
        能够对内部时钟信号或外部输入信号进行计数,数值达到设定要求时,向CPU发起中断请求,完成外部程序的运行。
  本质就是进行计数,选择内部时钟脉冲,作为计数器时,技术信号的来源选择非周期脉冲信号。
      STM32中定时器可分为高级定时器、通用定时器、基本定时器三类,他们都是由一个可编程的16位预分频器(TIMX_PSC)驱动的16位。

2、定时器的分类:
 定时器一般来说可分为3类:

1、基本定时器:功能最少,只能充当基本的时基,甚至都没有外部引脚
2、通用定时器:拥有基本定时器的全部功能,同时有输入捕获模式,用以接收外部的PWM,脉冲之类的信息
3、高级定时器:又有通用定时器的全部功能,又有互补输出模式,功能最为强大

通常我们使用的都是通用定时器,通用定时器特点:

1.位于ABP1低速总线上
2.16位向下,向上/向下(中心对齐模式)计数模式,自动重装载计数器(TIMx_CNT)
3.16位可编程(可以实现修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65535任意数值
4.四个独立通道(TIMx_CH1~4),通道用来支持:
①输入捕获
②输出比较
③PWM生成
④单脉冲模式输出
5.可使用外部信号(TIM_ETR)控制定时器和定时器互连的同步电路

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


4.定时时钟计算方法
Tout = ((arr+1)(psc+1))/Tclk
其中:
Tclk:定时器的输入时钟频率(单位MHZ)
Tout:定时器溢出时间(单位为us)
arr: 计数装载值
psc: 时钟分频系数

5.工作过程
  在选定的时钟源(可以是内部的也可以是外部的)和预分频器TIMX_PSC的驱动下,根据设置的计数模式(向上、向下、中央对齐)自动。

  装载计数器TIMX_CNT开始计数;如果使能了相应的事件(更新事件、触发事件、输入捕获、输出比较)则会产生相应的中断。

如果没有开启输入和输出,只使能了计数器计数溢出后自动装载,可以做为一个简单定时器使用,计数器自己开始周期计数
如果开启了通道输入捕获,当检测到ICx信号上相应的边沿后,计数器(CNT)的当前值被锁存到捕获/比较寄存器(TIMx_CCRx)中,通过中断的方式可以读取出来假设为
n1,然后更改输入捕获的信号级性(上升沿或下降沿),当再次检测到ICx信号上相应的边沿后,计数器(CNT)的当前值再次被锁存到捕获/比较寄存器(TIMx_CCRx)中假设为
n2;n2 -n1节可算出电平的持续时间
如果开启了输出控制,可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的PWM信号。
如果选择外部的同步时钟信号(TI1F_ED、TI1FP1、TI2FP2)作为计数器的时钟源,可以用来统计脉冲,实现脉冲频率采集功能
二、PWM介绍
1.定义
  PWM(Pulse Width Modulation)即脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术;它是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。
基本原理

2.基本原理
  PWM就是对逆变电路开关器件的通断进行控制,使输出端得到一系列幅值相等的脉冲,用这些脉冲来代替正弦波或所需要的波形。也可以这样理解,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。只要带宽足够,任何模拟值都可以使用 PWM 进行编码。
  该信号在预定义的时间和速度中设置为高(5v或3.3v)和低(0v)。通常,我们将PWM的高电平称为1,低电平为0。

3.优点及应用范围
  由于其控制简单、灵活和动态响应好等优点而成为电力电子技术应用最广泛的控制方式,其应用领域包括测量,通信, 功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习PWM具有十分重要的现实意义。

4.主要参数
PWM占空比:
PWM信号保持高电平的时间百分比称为占空比。如果信号始终为高电平,则它处于100%占空比,如果它始终处于低电平,则占空比为0%。如图1所示,T1为占空比,T为一个PWM周期。

PWM的频率:
PWM信号的频率决定PWM完成一个周期的速度。STM32的MDK编译器可以选择5MHZ,10MHZ,20MHZ和50MHZ。

5.PWM的产生
  STM32的定时器除了TIM6和7,其他的定时器都可以用来产生PWM输出。其中高级定时器TIM1和TIM8可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出。
  通过STM32控制板,有两种方式能产生PWM,第一是利用普通IO口输出PWM,第二种是利用定时器的PWM的IO口或复用IO口。一般能够输出PWM的端口都会在主要功能那一栏出现CHx的标志,而普通定时器没有出现这种标志。如图所示,上面的红框就是普通的定时器,不是专用的PWM端口

注意:一般而言,尽量选用PWM口进行PWM输出,因为普通IO口模拟PWM的输出频率越高,进入定时器中断的次数就越快,中断间隔的时间越短,如果再有其他类型的中断也要处理时,会因为中断的优先级嵌套等待响应,影响控制精度,PWM输出误差增大,也会影响其他如ADC等中断处理,甚至会较出现单片机逻辑出错,死机或者跑飞的情况。

6.PWM工作原理
  在下图的通用定时器框图中,主要涉及到最顶上的一部分(计数时钟的选择)、中间部分(时基单元)、右下部分(PWM输出)这三个部分。 

     在PWM输出模式下,除了CNT(计数器当前值)、ARR(自动重装载值)之外,还多了一个值CCRx(捕获/比较寄存器值);
     当CNT小于CCRx时,TIMx_CHx通道输出低电平;
     当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平;
      这个时候就可以对其下一个准确的定义了:所谓脉冲宽度调制模式(PWM模式),就是可以产生一个由TIMx_ARR寄存器确定频率,由TIMx_CCRx寄存器确定占空比的信号。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术

7.PWM输出的模式区别
PWM模式1:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)

PWM模式2:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平
注意:PWM的模式只是区别什么时候是有效电平,但并没有确定是高电平有效还是低电平有效。这需要结合CCER寄存器的CCxP位的值来确定。

例如:若PWM模式1,且CCER寄存器的CCxP位为0,则当TIMx_CNT<TIMx_CCR1时,输出高电平;同样的,若PWM模式1,且CCER寄存器的CCxP位为2,则当TIMx_CNT<TIMx_CCR1时,输出低电平。

8、PWM相关配置寄存器 
         包含三个寄存器:捕获/比较模式寄存器(TIMx_CCMR1/2)、捕获/比较使能寄存器(TIMx_CCER)、捕获/比较寄存器(TIMx_CCR1~4)。设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。在TIMx_CCMRx寄存器中的OCxM位写入110(PWM模式1)或111(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。

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

作用:在PWM输出模式下,确定PWM的模式、使能相应的预装载寄存器等操作

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

作用:在PWM输出模式下,确定PWM的输出极性和输出使能

(3)捕获/比较寄存器(TIMx_CCR1) 

作用:在PWM输出模式下,确定比较的值


 三、定时器捕获介绍
输入捕获简介

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

测量频率

当捕获通道 TIx(如TIM2_CH1) 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并把捕获寄存器中的值读取到 value1中。当出现第二次上升沿时,发生第二次捕获,计数器 CNT 的值会再次被锁存到捕获寄存器 CCR 中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到 value3 中,并清除捕获记录标志。利用 value3和value1 的差值我们就可以算出信号的周期(频率)。

测量脉宽

当捕获通道 TIx(如TIM2_CH1) 上出现上升沿时,发生第一次捕获,计数器 CNT 的值会被锁存到捕获寄存器 CCR 中,而且还会进入捕获中断,在中断服务程序中记录一次捕获(可以用一个标志变量来记录),并把捕获寄存器中的值读取到 value1中。然后把捕获边沿改变为下降沿捕获,目的是捕获后面的下降沿。当下降沿到来的时候,发生第二次捕获,计数器 CNT的值会再次被锁存到捕获寄存器 CCR中,并再次进入捕获中断,在捕获中断中,把捕获寄存器的值读取到 value3中,并清除捕获记录标志。然后把捕获边沿设置为上升沿捕获。 在测量脉宽过程中需要来回的切换捕获边沿的极性,如果测量的脉宽时间比较长,定时器就会发生溢出,溢出的时候会产生更新中断,我们可以在中断里面对溢出进行记录处理。

四、解决的问题
深入了解STM32定时器原理,掌握脉宽调制pwm生成方法。

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

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

3. 再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。

五、定时器串口定时点亮LED灯
1、搭建STM32HAL库环境:
请参考我的这篇博客:STM32使用HAL库点亮流水灯-CSDN博客

 2、使用HAL库建立工程:
(1)打开STM32CubeMX,在主界面点击:ACCESS TO MCU SELECTOR:

  (2)选择的单片机型号以及点击开始工程项目: 

(3)配置RCC

点System Cor,选择RCC,在右侧弹出的菜单栏中选Crystal/Ceramic Resonator

(4)配置SYS

选择调试接口,点System Cor,选择SYS。,在右侧弹出的菜单栏中选Serial Wire。

(5)配置IO口输出

这里选择PA0作为LED灯的输出,将其选为GPIO-OUT,这里我们只使用一个灯,做演示用。

(6)配置定时器2和定时器3

这里我们使用定时器2和定时器3来实现定时的功能。如图所示,定时器2配置:依次点击位置2,选中定时器2;位置3,配置定时器2的时钟源为内部时钟;位置4,分频系数为71;位置5,向上计数模式,计数周期为5000,使能自动重载模式。

 定时器3配置:依次按照下图所示进行配置即可:

 注:分频系数那里虽然写的是71,但系统处

<think>我们使用STM32F103C8T6的TIM3和TIM4来驱动两个舵机(每个定时器一个通道即可,因为舵机控制只需要一个通道)。 舵机控制信号是周期为20ms(50Hz),高电平宽度在0.5ms到2.5ms之间的PWM信号。 我们使用标准库配置两个定时器分别产生两个PWM信号,通过改变占空比来控制舵机角度。 步骤: 1. 使能时钟(TIM3, TIM4, GPIO) 2. 配置GPIO为复用推挽输出(PA6和PA7,或者根据实际硬件连接) 注意:STM32F103C8T6的TIM3_CH1在PA6,TIM3_CH2在PA7;TIM4_CH1在PB6,TIM4_CH2在PB7。这里我们假设使用PA6和PB6。 3. 配置定时器时基:周期为20ms,预分频和重装载值根据系统时钟计算(系统时钟72MHz)。 4. 配置PWM模式(TIM_OCMode_PWM1) 5. 设置占空比初始值(对应0度或中间位置) 6. 使能定时器通道输出 7. 使能定时器 计算: 定时器时钟为72MHz,要产生20ms周期,则计数周期为20ms / (1/72MHz) = 1.44e6个计数。但定时器16位最大65535,所以需要分频。 预分频值 = 7200 - 1,则分频后时钟为72MHz / 7200 = 10KHz,即每个计数0.1ms。 重装载值 = 20000 - 1(因为20ms / 0.1ms = 200个计数,但这样精度不够?实际上0.1ms*200=20ms,但舵机控制要求精度较高,我们提高分辨率) 重新计算:为了得到更高的分辨率,我们可以使用更小的分频,但注意最大计数65535。 目标:20ms周期,计数次数为20000个(每个计数1us)?但1us对应72分频(72MHz/72=1MHz,即1us)。但是这样重装载值需要20000(20ms/1us=20000),在16位定时器范围内(65535>20000)。 因此: 预分频值 = 72 - 1 (72分频) 重装载值 = 20000 - 1 (计数20000次,即20ms) 那么占空比设置:0.5ms对应500个计数(0.5ms/1us=500),2.5ms对应2500个计数。所以角度0度对应500,180度对应2500。 注意:舵机可能角度范围不同,请根据实际舵机调整。 我们将使用: 舵机1:TIM3_CH1 -> PA6 舵机2TIM4_CH1 -> PB6 代码结构: 初始化函数:void Servo_Init(void) 设置舵机1角度:void Servo1_SetAngle(float angle) // angle范围0~180 设置舵机2角度:void Servo2_SetAngle(float angle) 在初始化函数中配置两个定时器的PWM输出。 注意:由于两个定时器独立,所以分别配置。 下面给出代码:</think>以下是基于STM32F103C8T6的Keil C语言标准库双舵机驱动代码实现: ### 舵机驱动原理 舵机通过PWM信号控制,典型参数: - 周期:20ms(频率50Hz) - 脉宽范围:0.5ms(0°)~ 2.5ms(180°) - 控制精度:1° ≈ 11.11μs脉宽变化 ```c #include "stm32f10x.h" #include "stm32f10x_tim.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" // 定义舵机PWM参数 #define SERVO_PERIOD 20000 // 20ms周期(72MHz时钟下) #define SERVO_MIN_PULSE 500 // 0.5ms脉冲 #define SERVO_MAX_PULSE 2500 // 2.5ms脉冲 // 舵机1配置 (TIM3通道1) #define SERVO1_TIM TIM3 #define SERVO1_TIM_RCC RCC_APB1Periph_TIM3 #define SERVO1_GPIO GPIOA #define SERVO1_PIN GPIO_Pin_6 #define SERVO1_GPIO_RCC RCC_APB2Periph_GPIOA #define SERVO1_CHANNEL TIM_Channel_1 // 舵机2配置 (TIM4通道1) #define SERVO2_TIM TIM4 #define SERVO2_TIM_RCC RCC_APB1Periph_TIM4 #define SERVO2_GPIO GPIOB #define SERVO2_PIN GPIO_Pin_6 #define SERVO2_GPIO_RCC RCC_APB2Periph_GPIOB #define SERVO2_CHANNEL TIM_Channel_1 // 初始化PWM输出 void Servo_PWM_Init(TIM_TypeDef* TIMx, uint32_t TIM_RCC, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, uint32_t GPIO_RCC, uint16_t TIM_Channel) { // 1. 时钟使能 RCC_APB2PeriphClockCmd(GPIO_RCC, ENABLE); if (TIMx == TIM2 || TIMx == TIM3 || TIMx == TIM4) { RCC_APB1PeriphClockCmd(TIM_RCC, ENABLE); } // 2. GPIO配置 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = GPIO_Pin; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOx, &GPIO_InitStruct); // 3. 定时器基本配置 TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_TimeBaseStruct.TIM_Period = SERVO_PERIOD - 1; // 自动重装载值 TIM_TimeBaseStruct.TIM_Prescaler = 72 - 1; // 72分频(1MHz计数) TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStruct); // 4. PWM通道配置 TIM_OCInitTypeDef TIM_OCInitStruct; TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse = SERVO_MIN_PULSE; // 初始脉宽 TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效 switch(TIM_Channel) { case TIM_Channel_1: TIM_OC1Init(TIMx, &TIM_OCInitStruct); TIM_OC1PreloadConfig(TIMx, TIM_OCPreload_Enable); break; case TIM_Channel_2: TIM_OC2Init(TIMx, &TIM_OCInitStruct); TIM_OC2PreloadConfig(TIMx, TIM_OCPreload_Enable); break; // 可扩展其他通道 } // 5. 启动定时器 TIM_Cmd(TIMx, ENABLE); TIM_CtrlPWMOutputs(TIMx, ENABLE); } // 设置舵机角度 void Servo_SetAngle(TIM_TypeDef* TIMx, uint16_t TIM_Channel, float angle) { // 角度限幅 0~180° if(angle < 0) angle = 0; if(angle > 180) angle = 180; // 计算脉宽(单位:μs) uint16_t pulse = SERVO_MIN_PULSE + (uint16_t)((SERVO_MAX_PULSE - SERVO_MIN_PULSE) * angle / 180.0f); // 更新比较寄存器 switch(TIM_Channel) { case TIM_Channel_1: TIMx->CCR1 = pulse; break; case TIM_Channel_2: TIMx->CCR2 = pulse; break; // 可扩展其他通道 } } // 双舵机初始化 void DualServo_Init(void) { Servo_PWM_Init(SERVO1_TIM, SERVO1_TIM_RCC, SERVO1_GPIO, SERVO1_PIN, SERVO1_GPIO_RCC, SERVO1_CHANNEL); Servo_PWM_Init(SERVO2_TIM, SERVO2_TIM_RCC, SERVO2_GPIO, SERVO2_PIN, SERVO2_GPIO_RCC, SERVO2_CHANNEL); } // 示例使用 int main(void) { DualServo_Init(); while(1) { // 舵机1从0°到180°扫描 for(uint8_t i = 0; i <= 180; i += 10) { Servo_SetAngle(SERVO1_TIM, SERVO1_CHANNEL, i); Servo_SetAngle(SERVO2_TIM, SERVO2_CHANNEL, 180 - i); // 舵机2反向运动 Delay_ms(200); // 简单延时 } } } ``` ### 关键配置说明 1. **时钟配置**: - 系统时钟72MHz,PWM计数频率1MHz(72分频) - 计时分辨率:1μs/计数 2. **引脚分配**: - 舵机1:PA6(TIM3_CH1) - 舵机2:PB6(TIM4_CH1) - 可根据需求修改宏定义 3. **角度计算**: ```c pulse = 500 + (2000 * angle / 180) // 脉宽(μs) = 500 + (2000 * angle/180) ``` ### 使用示例 ```c // 设置舵机1到90°位置 Servo_SetAngle(SERVO1_TIM, SERVO1_CHANNEL, 90); // 设置舵机2到45°位置 Servo_SetAngle(SERVO2_TIM, SERVO2_CHANNEL, 45); ``` ### 硬件连接 | 舵机引脚 | STM32F103C8T6 | 说明 | |----------|---------------|------| | 信号线(黄) | PA6/PB6 | PWM信号输入 | | 电源线(红) | 5V电源 | 建议外部供电 | | 地线(棕) | GND | 共地 | > ⚠️ **注意**:舵机工作电流较大(峰值可达1A),建议使用外部5V电源供电,避免MCU稳压器过载[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值