人若无名 便可潜心练剑.|

hazy1k

园龄:7个月粉丝:14关注:0

2024-09-12 16:38阅读: 25评论: 0推荐: 0

第28章 通用定时器-4路PWM输出

第二十八章 通用定时器-4路PWM输出

1. 硬件设计

无硬件设计

2. 软件设计

2.1 编程大纲

  1. TIM GPIO和CHx相关参数宏定义

  2. 输出通道GPIO配置

  3. TIM四路输出PWM模式配置

  4. 主函数测试

2.2 代码分析

2.2.1 TIM3相关参数和四个通道宏定义

#ifndef __GENERAL_TIM_H
#define __GENERAL_TIM_H

#include "stm32f10x.h"
/* TIM相关参数宏定义 */
#define TIMx TIM3
#define TIM_APBxClock RCC_APB1PeriphClockCmd
#define TIMx_CLK RCC_APB1Periph_TIM3
#define TIMx_Period 9
#define TIMx_Prescaler 71

/* 四路输出通道宏定义 */
#define TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA // TIM3_CH1 PA6
#define TIM_CH1_GPIO_PORT GPIOA
#define TIM_CH1_GPIO_PIN GPIO_Pin_6
#define TIM_CH2_GPIO_CLK RCC_APB2Periph_GPIOA // TIM3_CH2 PA7
#define TIM_CH2_GPIO_PORT GPIOA
#define TIM_CH2_GPIO_PIN GPIO_Pin_7
#define TIM_CH3_GPIO_CLK RCC_APB2Periph_GPIOB // TIM3_CH3 PB0
#define TIM_CH3_GPIO_PORT GPIOB
#define TIM_CH3_GPIO_PIN GPIO_Pin_0
#define TIM_CH4_GPIO_CLK RCC_APB2Periph_GPIOB // TIM3_CH4 PB1
#define TIM_CH4_GPIO_PORT GPIOB
#define TIM_CH4_GPIO_PIN GPIO_Pin_1

void GeneralTim_Init(void);

#endif /* __GENERAL_TIM_H */

2.2.2 GPIO配置

// 输出比较通道GPIO配置
static void TIM_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(TIM_CH1_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = TIM_CH1_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TIM_CH1_GPIO_PORT, &GPIO_InitStructure); // TIM_CH1 GPIO初始化
    RCC_APB2PeriphClockCmd(TIM_CH2_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = TIM_CH2_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TIM_CH2_GPIO_PORT, &GPIO_InitStructure); // TIM_CH2 GPIO初始化
    RCC_APB2PeriphClockCmd(TIM_CH3_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = TIM_CH3_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TIM_CH3_GPIO_PORT, &GPIO_InitStructure); // TIM_CH3 GPIO初始化
    RCC_APB2PeriphClockCmd(TIM_CH4_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = TIM_CH4_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(TIM_CH4_GPIO_PORT, &GPIO_InitStructure); // TIM_CH4 GPIO初始化
}

2.2.3 TIM配置四路PWM输出

// TIM Mode配置
static void TIM_Mode_Init(void)
{
    TIM_APBxClock(TIMx_CLK, ENABLE);
/*-------------------------时基配置-------------------------*/
    // 计数器时钟 = 系统时钟 / (分频系数 + 1) = 72M / (71 + 1) = 1MHz
    // PWM信号周期 = (ARR+1)*(PSC+1)/CNTxCLK = (ARR+1)*1
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = TIMx_Period; // 时钟周期9
    TIM_TimeBaseStructure.TIM_Prescaler = TIMx_Prescaler; // 分频系数71
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频系数1
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
    TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); // TIMx时基初始化
/*----------------------输出比较通道配置----------------------*/
    uint16_t CCR1_Val = 5; // 通道1的占空比50%
    uint16_t CCR2_Val = 4; // 通道2的占空比40%
    uint16_t CCR3_Val = 3; // 通道3的占空比30%
    uint16_t CCR4_Val = 2; // 通道4的占空比20%
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 极性高
    // 配置TIM3_CH1
    TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
    TIM_OC1Init(TIMx, &TIM_OCInitStructure);
    TIM_OC1PolarityConfig(TIMx, TIM_OCPreload_Enable); // 使能预装载
    // 配置TIM3_CH2
    TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
    TIM_OC2Init(TIMx, &TIM_OCInitStructure);
    TIM_OC2PolarityConfig(TIMx, TIM_OCPreload_Enable);
    // 配置TIM3_CH3
    TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
    TIM_OC3Init(TIMx, &TIM_OCInitStructure);
    TIM_OC3PolarityConfig(TIMx, TIM_OCPreload_Enable);
    // 配置TIM3_CH4
    TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
    TIM_OC4Init(TIMx, &TIM_OCInitStructure);
    TIM_OC4PolarityConfig(TIMx, TIM_OCPreload_Enable);
    TIM_Cmd(TIMx, ENABLE);
}

其中一个新的库函数我们需要解释一下:

TIM_OC1PreloadConfig 是 STM32 微控制器中用于配置定时器输出比较通道的函数。其原型如下:

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
  • TIMx: 指定定时器实例,如 TIM1TIM2 等。
  • TIM_OCPreload: 预装载使能状态,取值为 TIM_OCPreload_Enable 或 TIM_OCPreload_Disable

功能: 启用或禁用通道1的预装载寄存器。启用预装载使得在更新事件发生时,比较寄存器的值可以被预装载寄存器的值替代,从而避免在运行中改变比较值。

示例:

// 启用通道1的预装载
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
// 这将确保在定时器更新事件时,新的比较值会被加载。

2.2.4 主函数

// TIM—通用定时器-4路PWM输出应用
#include "stm32f10x.h"
#include "led.h"
#include "GeneralTim.h"  

int main(void)
{
	LED_Init();
	LED_BLUE();
	GeneralTim_Init();
	while(1)
	{      
	}
}

3. 小结

如何利用通用定时器进行4路PWM输出,我们简化一下流程:

  1. 初始化 GPIO:配置对应的 GPIO 引脚为定时器输出模式。
  2. 初始化定时器:设置定时器的计数周期、预分频器等。
  3. 配置输出比较通道:设置每个通道的 PWM 参数。
  4. 启动定时器:启动定时器并开始输出 PWM 信号。

下面是一个简单的示例代码,使用 TIM2 定时器产生 4 路 PWM 输出信号。假设你使用的是 STM32F103 系列的微控制器,通道配置如下:

  • 通道 1: GPIOA Pin 0
  • 通道 2: GPIOA Pin 1
  • 通道 3: GPIOA Pin 2
  • 通道 4: GPIOA Pin 3
#include "stm32f10x.h"

// 初始化 GPIO
void GPIO_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    // 启用 GPIOA 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 配置 GPIOA 的四个引脚为定时器输出模式
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

// 初始化定时器
void TIM_Config(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    // 启用 TIM2 时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    // 配置定时器基准时间
    TIM_TimeBaseStructure.TIM_Period = 999;          // 自动重装载寄存器值
    TIM_TimeBaseStructure.TIM_Prescaler = 71;        // 预分频器,APB1 时钟 / (71 + 1)
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    // 配置通道 1 PWM 输出
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM 模式 1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 499;             // PWM 占空比的脉冲宽度 (50% 的占空比)
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 极性高
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 1 的预装载

    // 配置通道 2 PWM 输出
    TIM_OCInitStructure.TIM_Pulse = 249;             // 不同的占空比
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 2 的预装载

    // 配置通道 3 PWM 输出
    TIM_OCInitStructure.TIM_Pulse = 749;             // 不同的占空比
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 3 的预装载

    // 配置通道 4 PWM 输出
    TIM_OCInitStructure.TIM_Pulse = 999;             // 不同的占空比
    TIM_OC4Init(TIM2, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能通道 4 的预装载

    // 启动定时器
    TIM_Cmd(TIM2, ENABLE);
}

// 主函数
int main(void) {
    // 配置 GPIO
    GPIO_Config();

    // 配置定时器
    TIM_Config();

    while (1) {
        // 主循环中可以进行其他操作
    }
}

代码解释

  1. GPIO_Config:
  • 启用 GPIOA 的时钟。
  • 配置 GPIOA 的四个引脚为推挽输出模式,用于输出 PWM 信号。
  1. TIM_Config:
  • 启用 TIM2 的时钟。
  • 配置定时器 TIM2 的基准时间,包括周期(TIM_Period)、预分频器(TIM_Prescaler)、计数模式等。
  • 配置 TIM2 的四个通道为 PWM 输出模式,并设置各通道的占空比。
  • 启动 TIM2 定时器。
  1. 主函数:
  • 调用配置函数初始化 GPIO 和定时器。
  • 进入无限循环,持续运行主程序。

该示例代码中,PWM 信号的占空比是通过调整 TIM_OCInitStructure.TIM_Pulse 来设置的。


2024.9.12 第一次修订,后期不再维护

2025.1.26 优化代码

本文作者:hazy1k

本文链接:https://www.cnblogs.com/hazy1k/p/18410541

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hazy1k  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起