STM32高级定时器输出指定数量PWM(STM32CubeMx配置)

本文详细介绍了如何利用STM32的高级定时器和重复计数器特性来输出指定数量的PWM波。通过STM32CubeMx配置定时器、通道和GPIO口,设置PWM周期和占空比,并开启更新中断。在中断服务函数中,通过调整重复计数器的值来控制PWM的个数。同时,文章还涉及到中断回调函数的编写和按键功能的集成,用于动态改变PWM输出次数。

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

原理了解

高级定时器中有一个重复计数器,本实验输出指定个数PWM就是利用了重复计数器的特性,先来看看重复计数器的特性是什么:

计数器每次上溢或下溢都能使重复计数器减1,减到0时,再发生一次溢出就会产生更新事件

这是什么意思呢,这里举个例子比如说我设定重复计数器的值为3,则计数器上溢一次则重复计数器的值变为2,再继续上溢知道重复计数器的值变为0,此时在溢出一次,则产生更新中断,即如果重复计数器的值为3,则计数器需要溢出4次才会产生更新事件,那么结合本实验输出指定数量的PWM波,通过将N-1写入重复计数器中,则可以产生N个PWM波。在这里插入图片描述
从上图来看,当RCR为0时,计数器每溢出一次就会产生更新事件;当RCR为1时,计数器每溢出两次就会产生更新事件,以此类推;那么这里着重看一下最后一个是怎么产生更新事件,当由软件产生一次更新事件后,计数器的值会回到初始状态即0或最大值,然后再溢出4次再次产生更新事件,即软件产生了更新事件后,将会把RCR的值装载进影子寄存器中,重新开始计数。

STM32CubeMx配置

定时器及通道配置

这里使用定时器8通道一作为我们的PWM输出,配置如下:
在这里插入图片描述
选择内部时钟源,通道一配置为PWM输出,然后设置PWM周期的频率,这里以2KHz设置,根据公式:

Tout= ((arr+1)*(psc+1))/Tclk

先代入PSC为7200-1,Tclk为72M(系统时钟源),则可算出arr为5000-1。
在这里插入图片描述
配置PWM为模式一,pulse为设置占空比,设置为arr一半则占空比为50%,输出极性为高。
在这里插入图片描述
打开定时器8更新中断,设置抢占优先级及相应优先级(根据用户自身需求)

GPIO口选择

查看数据手册
在这里插入图片描述
PC6为定时器八通道一的复用口,同时查看硬件原理图:
在这里插入图片描述
选择PE5作为输入验证程序输出指定数量PWM,通过生成N个PWM使LED亮N次;选择PB5作为输出,控制LED亮灭证明程序烧写成功。
在这里插入图片描述
添加PE4按键,通过按键更改生成的PWM数量。
STM32CubeMx配置如下:
在这里插入图片描述
配置完成后就可生成工程了。

工程生成及代码编写

工程文件

生成工程后,可以看到左边已经有了相关代码:
在这里插入图片描述
在输出指定数量PWM波中有如下几个比较重要的函数:

void MX_TIM8_Init(void);		//定时器八初始化函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle);		//相关时钟使能、中断开启函数
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel);	//使能PWM输出
HAL_TIM_GenerateEvent(TIM_HandleTypeDef *htim, uint32_t EventSource);	//产生指定事件
void TIM8_UP_IRQHandler(void);						//定时器8中断处理服务函数
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim);	//定时器中断公共处理函数
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);		//更新中断回调函数,需要用户重写该函数
__HAL_TIM_ENABLE_IT(__HANDLE__, __INTERRUPT__);		//这是一个宏定义,使能中断
__HAL_TIM_ENABLE(__HANDLE__);		//这是一个宏定义,使能计数器

代码编写

tim.c编写

首先打开tim.c文件:
在这里插入图片描述
可以看到里面已经帮我们完成了STM32CubeMx配置的初始化,需要完成输出指定数量PWM波功能我们需要开启PWM输出及使能更新中断,即在用户代码区中添加如下函数:

__HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE);
HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1);

中断相关函数

打开stm32f1xx_it.c文件可以看到中断的处理函数已经写好了:
在这里插入图片描述
需要做的则是编写中断回调函数,即:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

实现功能函数

首先为了实现输出指定PWM波实验,这里新添一个atimp.c文件方便管理:

atim.c及atim.h编写

#include "atimp.h"

static uint8_t g_npwm_set = 0;		//pwm设置输出数量

//输出pwm个数配置函数
void atim_timx_npwm_chy_set(uint8_t npwm)
{
    if(0 == npwm)
        return;
    
    g_npwm_set = npwm;
    HAL_TIM_GenerateEvent(&htim8, TIM_EVENTSOURCE_UPDATE);          //通过软件启动更新中断
    __HAL_TIM_ENABLE(&htim8);                                       //使能计数器
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM8)
    {
        if(g_npwm_set)                                                      //判断设置的pwm数量
        {
            TIM8->RCR = g_npwm_set-1;                                       //要想产生N个pwm将N-1放入RCR寄存器中
            HAL_TIM_GenerateEvent(&htim8, TIM_EVENTSOURCE_UPDATE);          //通过软件启动更新中断将设定值放入影子寄存器中
            __HAL_TIM_ENABLE(&htim8);                                       //使能计数器产生进行PWM输出
            g_npwm_set = 0;
        }
        else
        {
            TIM8->CR1 &= ~(1 << 0);                                         //关闭计数器
        }
    }
}
#ifndef __ATIMP_H__
#define __ATIMP_H__

#include "main.h"
#include "tim.h"

void atim_timx_npwm_chy_set(uint8_t npwm);

#endif

用到按键,再添加一个key.c文件

key.c及key.h编写

#include "key.h"

uint8_t key_scan()
{
    static uint8_t key_sta = 1;
    uint8_t key_value = 0;
    
    if(key_sta && (KEY0 == 0))
    {
        HAL_Delay(10);
        key_sta = 0;
        
        if(KEY0 == 0)
            key_value = KEY0_PRESS;

    }
    else if(KEY0)
    {
        key_sta = 1;
    }
    
    return key_value;
}
#ifndef __KEY_H
#define __KEY_H

#include "main.h"

#define KEY0_PRESS 1        //PE4按下状态

#define KEY0 HAL_GPIO_ReadPin(GPIOE, KEY0_Pin)      //读取当前PE4状态

uint8_t key_scan(void);

#endif

main.c编写

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM8_Init();
  /* USER CODE BEGIN 2 */
    uint8_t key = 0;            //记录键值
    uint8_t t =0;
    atim_timx_npwm_chy_set(5);	//设置PWM输出5次
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    key = key_scan();
    if(key == KEY0_PRESS)
    {
        atim_timx_npwm_chy_set(3);	//设置PWM输出3次
    }
    
    /*LED翻转证明程序正常工作*/
    t++;
    if(t > 20)
    {
        t = 0;
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
    }
    HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

至此,代码就编写完成啦。

### STM32CubeMX 战舰项目配置与使用教程 #### 1. 创建新工程并选择芯片型号 打开STM32CubeMX软件,通过点击"New Project"创建一个新的工程项目。在弹出的窗口中,选择具体的STM32微控制器型号,例如常用的STM32F103ZET6,这是战舰V3开发板的核心处理器[^3]。 #### 2. 配置时钟树与时钟源 进入Clock Configuration界面,设置系统的主时钟频率。对于大多数应用,默认的8MHz外部晶振配合PLL倍频至72MHz是一个常见的选择。确保HSE(High Speed External Clock)被启用,并调整PLL参数以达到所需的系统时钟速度。 #### 3. GPIO端口初始化 根据实际需求,在Pinout & Configuration页面定义GPIO的功能。如果计划利用PWM控制LED亮度来模拟呼吸灯效果,则需指定相应的定时器通道作为PWM输出引脚[^5]。例如,TIM3 Channel 2可以连接到某个LED驱动电路。 #### 4. 定时器外设设定 继续在外设配置阶段完成定时器的相关参数调节。针对上述提到的呼吸灯案例,需要开启高级控制定时器Advanced Control Timer或者通用定时器General Purpose Timer之一,并为其分配合适的预分频值Prescaler以及自动重装载寄存器Auto Reload Register数值以便生成期望周期长度的脉冲信号。 ```c // 初始化定时器实例结构体 htim3 的部分代码片段展示如下: htim3.Instance = TIM3; htim3.Init.Prescaler = 7199; // 设置预分频系数为7200-1=7199对应约1KHz频率 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 999; // 自动重载值设为1000-1=999即计数范围上限 ``` #### 5. 中断管理与RTOS集成可选操作 如果有更复杂的应用场景比如多任务调度等考虑引入FreeRTOS操作系统支持的话,可以在中间件Middleware选项卡下勾选FreeRTOS组件加载进来之后再进一步做详细的线程优先级规划等工作[^2]。当然也可以单纯依靠硬件中断机制处理一些实时性强的任务响应情况而不必依赖额外的操作系统框架层面上的支持。 #### 6. 能量优化考量 考虑到便携式设备续航能力的重要性,在适当时候应该探索如何降低整个系统的能耗水平。借助于STM32内部丰富的电源管理模式Power Modes组合运用起来能够有效减少不必要的电能消耗。值得注意的是当采用由STM32CubeMX自动生成HAL库形式构建应用程序的时候往往已经包含了必要的PWR模块初始化语句(__HAL_RCC_PWR_CLK_ENABLE();)无需重复声明除非特殊定制化需求存在例外情形之外一般情况下都适用既定模板方案即可满足基本要求[^4]。 #### 结论总结 综上所述,基于STM32CubeMX工具链搭建面向特定应用场景如战舰主题类项目的软硬件联合设计方案流程清晰明了易于理解和实践操作。从最基础的新建空白工程起步直至深入探讨各个层面的技术细节均有所涉猎涵盖了广泛的知识范畴有助于初学者快速入门同时也给有一定经验积累者提供了更多创新改进空间值得推荐尝试体验一番!
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

葛叶灬

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

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

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

打赏作者

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

抵扣说明:

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

余额充值