【STM32】定时器之PWM输出与舵机控制(CUBEMX+HAL库)

本文介绍了脉宽调制(PWM)基本概念,重点讲述了如何在CUBEMX中配置STM32定时器以生成PWM信号,控制舵机转动,并提供了舵机PWM参数设置和HAL库函数的使用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里总结一下初次认识PWM的时候遇到的一些问题,也希望能帮大家解决一些在使用CUBEMX配置PWM输出的时候遇到的一些问题

PWM认识

PWM(Pulse Width Modulation)简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在测量、通信、工控等方面。

占空比:可以简单理解为一个周期内脉宽时间与周期时间之比*100%,如20ms周期中,若脉宽为5ms,则占空比为25%。

通过PWM可以输出低于最大输出电压的电压值

对PWM有以上基础的认识我觉得就足够了

CUBEMX配置定时器输出PWM

PWM的输出主要用定时器完成,通过定时器的配置可以调控PWM的频率以及占空比,通过PWM占空比的设置就可以实现电机调速以及舵机转动等,当然PWM也可以用于控制LED灯的亮度等,下面以一个新手的视角讲解如何使用CUBEMX+HAL库控制舵机的转动

工程前期配置

一些基础的工程创建以及debug和时钟配置在这篇博文中有介绍,纯新手可以参考这篇博文完成一些前期的配置

【STM32】CUBEMX之串口:串口三种模式(轮询模式、中断模式、DMA模式)的配置与使用示例 + 串口重定向 + 使用HAL扩展函数实现不定长数据接收_cubemx stm32f1 dma 中断-CSDN博客

定时器的配置

打开PWM通道

找到timers->TIM1->channel1->PWM generation CH1

这里的只要目的是打开定时器1的PWM输出通道,而CH1N表示PWM互补波形输出,这里我们不需要

如果需要同时控制多个舵机,也可以打开channel2,3,4,可以看见,tim1可以同时输出四路PWM波(不算互补波形)

注意事项

以下有几点注意事项:

1、TIM1挂在APB2总线上,也就是说TIM1的基础频率与APB2相同,通过查看时钟树可以知道APB2频率为72MHz

2、一般舵机的PWM周期为20ms,且脉宽范围在500μs-2500μs之间,其中500μs时舵机旋转到最小角度,2500μs是转到最大角度

3、对于一些参数的介绍

Prescaler/PSC(预分频):大部分时候定时器不需要总线那么高的频率,预分频可以将APB总线上的频率降低,具体降低后频率大小为 总线频率/(PSC+1),如若PSC值为71,APB2总线频率为72MHz,则输入tim1的频率为72/(71+1) = 1MHz

counter mode(计数方式):字面意思,就是决定定时器的计数方式,有向上,向下,中心对齐计数,这里不必深究

Counter Period(计数周期):指定时器中的数值累积到多少后算完成一次计数,大小为该数值+1,如若配置为19999,则表示定时器接收到20000个脉冲后结束一次计数,并开始下一次的计数,可以理解为计数的上限

auto reload preload(自动重装载预加载):这个可了解可不了解,具体的可以看看其他博主更详细的讲解

Pulse:表示PWM脉宽长度,Pulse/Counter Period *100%就表示占空比的大小

了解如上注意事项和知识点,我们就可以开始配置用于舵机输出的PWM了

PWM频率、占空比的计算与配置

预分频值设置为71,则定时器频率为72/(71+1)=1MHz,1*10^-6s计数值+1

计数周期设置为19999,周期为(19999+1)*10^-6=20ms

将auto-reload preload配置为Enable

占空比暂时不需要设置,注:此时占空比为500-2500时对应的PWM脉宽为500-2500μs.

HAL库函数与Keil工程代码编写

HAL库函数

启动PWM函数

HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);
//参数分别是时钟句柄、通道,示例
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);

设置占空比函数

#define __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__) \
  (((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCR1 = (__COMPARE__)) :\
   ((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCR2 = (__COMPARE__)) :\
   ((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCR3 = (__COMPARE__)) :\
   ((__HANDLE__)->Instance->CCR4 = (__COMPARE__)))
//参数分别为时钟句柄,通道,脉宽长度,示例
	__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,500);

关闭PWM函数

HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel);
//参数分别是时钟句柄、通道,示例
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);

需要的基本HAL库函数如上就足够了,还有一些函数,想了解的可以去了解一下

//获取定时器计数值函数
	__HAL_TIM_GET_COUNTER(_HANDLE_);
//设置定时器计数值函数
	__HAL_TIM_SET_COUNTER(_HANDLE_);
//获取重装载寄存器的值函数
	__HAL_TIM_GET_AUTORELOAD(_HANDLE_);
//设置重装载寄存器的值函数
	__HAL_TIM_SET_AUTORELOAD(_HANDLE_);
//设置预分频器的值函数
	__HAL_TIM_SET_PRESCALER(_HANDLE_);
//定时器更新中断启动函数
	HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);

代码编写

打开keil

在main.c函数中添加如下代码块

HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);		//打开定时器通道
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,500);		//最低脉宽500,让舵机复位到0度

接好对应的线,我们可以看到舵机复位到了0度

接下来更改脉宽为1500,便会观察到舵机转动90度

这里角度与脉宽值的对应关系就是脉宽的500-2500对应映射到舵机转动角度的0-最大角度

比如我用的最大角度为180,则500-2500分别对应0-180度

### 使用 STM32 HAL 控制舵机 #### 一、硬件配置 为了使用 STM32 单片机通过 HAL 控制舵机,首先需要完成硬件连接。通常情况下,舵机有三个引脚:电源正极 (VCC),接地 (GND) 和信号输入 (PWM)。这些引脚应分别连接到 STM32 开发板上的对应管脚。 对于总线舵机或其他类型的伺服电机,推荐采用专用驱动电路供电以避免电流过大损坏 MCU[^1]。此外,确保所选定时器通道能够提供足够的分辨率支持 PWM 波形生成。 #### 二、软件初始化 在 STM32CubeMX 中配置项目时,需启用 TIM 定时器功能并设置其模式为 PWM 输出。以下是具体步骤概述: - 打开 STM32CubeMX 工具创建新工程; - 配置系统时钟至目标频率(如72MHz); - 添加TIMx外设资源,并将其工作模式设定成PWM输出型态; - 调整预分频系数(PSC)以及自动重装载寄存器(ARR)数值以便得到合适的载波频率占空比范围适合于一般标准RC伺服马达操作需求约50Hz刷新率下每周期持续时间为20ms左右即可满足大部分场合下的精度要求[^3]。 #### 三、示例代码展示 下面给出一段基于上述理论编写而成的实际应用源码片段供参考学习之用: ```c #include "main.h" TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); while (1){ __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,50); // 设置初始角度 HAL_Delay(1000); __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,250); // 改变角度 HAL_Delay(1000); } } // 初始化GPIO函数定义省略... // 初始化TIM2函数定义如下: static void MX_TIM2_Init(void){ TIM_OC_InitTypeDef sConfigOC; htim2.Instance = TIM2; htim2.Init.Prescaler = 8399; /* Prescaler value to achieve desired frequency */ htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 19999; /* ARR value corresponding to ~50 Hz */ htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim2); sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim2,&sConfigOC,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); } ``` 此程序实现了让连接在 TIM2_CH1 上的 SG90 小型舵机每隔一秒转动一次不同方向的功能[^4]。 #### 四、注意事项 当实际动手实践过程中可能会遇到一些常见问题需要注意解决办法包括但不限于以下几点建议考虑进去以免影响最终成果质量评估结果不佳等问题发生前做好充分预防措施非常重要! - 确认使用的定时器是否其他外设有冲突。 - 测试不同的 PSC 和 ARR 值组合找到最适合自己应用场景的最佳参数配对方案。 - 如果发现动作不平稳或者抖动严重,则可能是由于负载过重引起动力不足造成的现象可以通过增加电容滤波等方式改善情况尝试优化性能表现达到预期效果为止[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不出寝室爱睡觉.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值