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

hazy1k

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

2024-09-13 15:41阅读: 22评论: 0推荐: 0

第30章 通用定时器-同步

第三十章 通用定时器-同步

1. 硬件设计

无需硬件设计

2. 软件设计

2.1 编程大纲

  1. 定时器参数宏定义

  2. 定时器GPIO初始化

  3. 定时器输出PWM及主从模式配置

2.2 代码分析

2.2.1 定时器相关参数宏定义

/* 主从定时器参数 */
#define TIM_MASTER TIM2 // 主定时器--TIM2
#define TIM_MASTER_CLK RCC_APB1Periph_TIM2
#define TIM_SLAVE1 TIM3 // 从定时器1--TIM3
#define TIM_SLAVE1_CLK RCC_APB1Periph_TIM3
#define TIM_SLAVE2 TIM4 // 从定时器2--TIM4
#define TIM_SLAVE2_CLK RCC_APB1Periph_TIM4

/* 主从定时器通道参数 */
#define TIM_MASTER_PIN GPIO_Pin_10 // TIM2-PB10
#define TIM_MASTER_PORT GPIOB
#define GTIM_MASTER_GPIO_CLK RCC_APB2Periph_GPIOB

/* 从定时器输出通道参数 */
#define TIM_SLAVE1_PIN GPIO_Pin_6 // TIM3-PC6
#define TIM_SLAVE1_PORT GPIOC
#define GTIM_SLAVE1_GPIO_CLK RCC_APB2Periph_GPIOC
#define TIM_SLAVE2_PIN GPIO_Pin_6 // TIM4-PB6
#define TIM_SLAVE2_PORT GPIOB
#define GTIM_SLAVE2_GPIO_CLK RCC_APB2Periph_GPIOB

2.2.2 定时器GPIO初始化

// 初始化GPIO,配置与定时器相关的引脚
static void TIM_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  // 使能与定时器相关的GPIO时钟
  RCC_APB2PeriphClockCmd(GTIM_MASTER_GPIO_CLK | GTIM_SLAVE1_GPIO_CLK | GTIM_SLAVE2_GPIO_CLK, ENABLE);
  // 使能AFIO时钟,用于处理引脚复用
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
  // 配置TIM2的引脚重映射,将TIM2_CH3映射到PB10引脚
  GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 重映射TIM2引脚 TIM2_CH3 -> PB10
  // 配置TIM3的引脚重映射,将TIM3_CH1映射到PC6引脚
  GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); // 重映射TIM3引脚 TIM3_CH1 -> PC6
  // 配置从定时器1(TIM3)的GPIO引脚,PC6
  GPIO_InitStructure.GPIO_Pin = TIM_SLAVE1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速度
  GPIO_Init(TIM_SLAVE1_PORT, &GPIO_InitStructure); // 初始化TIM3_CH1(PC6)
  // 配置从定时器2(TIM4)的GPIO引脚,PB6
  GPIO_InitStructure.GPIO_Pin = TIM_SLAVE2_PIN;
  GPIO_Init(TIM_SLAVE2_PORT, &GPIO_InitStructure); // 初始化TIM4_CH2(PB6)
  // 配置主定时器(TIM2)的GPIO引脚,PB10
  GPIO_InitStructure.GPIO_Pin = TIM_MASTER_PIN;
  GPIO_Init(TIM_MASTER_PORT, &GPIO_InitStructure); // 初始化TIM2_CH3(PB10)
}
  1. 使能GPIO时钟
  • RCC_APB2PeriphClockCmd 使能了与主定时器和从定时器相关的GPIO时钟,并使能了AFIO时钟。
  • GPIO_PinRemapConfig 配置了定时器通道的引脚重映射,例如将 TIM2_CH3 重映射到 PB10
  1. 配置GPIO引脚
  • 使用 GPIO_InitTypeDef 结构体配置引脚。
  • GPIO_InitStructure.GPIO_Mode 设置为推挽复用输出 (GPIO_Mode_AF_PP),以支持定时器的PWM输出。
  • GPIO_InitStructure.GPIO_Speed 设置为 50MHz。
  1. 具体GPIO引脚配置
  • PC6: 配置为 TIM3_CH1 的推挽复用输出。
  • PB6: 配置为 TIM4_CH1 的推挽复用输出。
  • PB10: 配置为 TIM2_CH3 的推挽复用输出。

这里出现了一个新的库函数,我们需要分析一下:

GPIO_PinRemapConfig 是一个用于配置GPIO引脚重映射的库函数,通常用于定时器或其他外设的引脚重映射,以便将外设功能映射到不同的引脚上。它的主要功能是在微控制器中重新定义某些功能引脚的位置。

函数原型

void GPIO_PinRemapConfig(GPIO_TypeDef* GPIOx, FunctionalState NewState);

参数说明

  • GPIOx: 需要重映射的GPIO配置。例如,GPIO_FullRemap_TIM2 代表定时器2的完全重映射。
  • NewState: 指定是否启用重映射。ENABLE 启用重映射,DISABLE 禁用重映射。

功能描述

  • 重映射引脚: 该函数将定时器或其他外设的特定功能引脚映射到其他可用引脚上。例如,将 TIM2_CH3 的功能映射到 PB10
  • 灵活性: 提供了更大的灵活性以适应不同的硬件布局和需求。

使用场景

  • 当你需要将外设的功能引脚分配到不同的物理引脚时,例如在开发过程中调整硬件布局或在应用程序中使用不同的引脚。

示例

GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE); // 启用 TIM2 的完全重映射

2.2.3 TIM模式配置

// 初始化定时器的工作模式(主从定时器模式)
static void TIM_Mode_Init(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  // 使能主定时器和从定时器的时钟
  RCC_APB1PeriphClockCmd(TIM_MASTER_CLK | TIM_SLAVE1_CLK | TIM_SLAVE2_CLK, ENABLE);
  // 配置主定时器时基参数
  TIM_TimeBaseStructure.TIM_Period = 72; // 设置定时器的自动重载值(周期为72)
  TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不使用预分频器
  TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分频系数为0
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数向上计数
  TIM_TimeBaseInit(TIM_MASTER, &TIM_TimeBaseStructure); // 初始化主定时器
  // 配置从定时器1时基参数(周期设置为4)
  TIM_TimeBaseStructure.TIM_Period = 4; // 设置周期为4
  TIM_TimeBaseInit(TIM_SLAVE1, &TIM_TimeBaseStructure); // 初始化从定时器1
  // 配置从定时器2时基参数(周期设置为4)
  TIM_TimeBaseStructure.TIM_Period = 4; // 设置周期为4
  TIM_TimeBaseInit(TIM_SLAVE2, &TIM_TimeBaseStructure); // 初始化从定时器2
  // 配置主定时器为PWM模式
  TIM_OCInitTypeDef TIM_OCInitStructure;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置为PWM模式1
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
  TIM_OCInitStructure.TIM_Pulse = 5; // 设置PWM占空比为5
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性为高
  TIM_OC3Init(TIM_MASTER, &TIM_OCInitStructure); // 配置主定时器的PWM输出通道3
  // 配置主定时器为主从模式
  TIM_SelectMasterSlaveMode(TIM_MASTER, TIM_MasterSlaveMode_Enable); // 使能主从模式
  TIM_SelectInputTrigger(TIM_MASTER, TIM_TRGOSource_Update); // 设置输出触发源为更新事件
  // 配置从定时器1为PWM模式
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置为PWM模式1
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
  TIM_OCInitStructure.TIM_Pulse = 4; // 设置PWM占空比为4
  TIM_OC1Init(TIM_SLAVE1, &TIM_OCInitStructure); // 配置从定时器1的PWM输出通道1
  // 配置从定时器1为主从模式
  TIM_SelectMasterSlaveMode(TIM_SLAVE1, TIM_MasterSlaveMode_Enable);
  // 配置从定时器1为门控同步模式
  TIM_SelectSlaveMode(TIM_SLAVE1, TIM_SlaveMode_Gated); // 设置为门控同步模式
  TIM_SelectInputTrigger(TIM_SLAVE1, TIM_TS_ITR1); // 设置触发源为主定时器的更新事件
  // 配置从定时器2为门控同步模式
  TIM_SelectSlaveMode(TIM_SLAVE2, TIM_SlaveMode_Gated); // 设置为门控同步模式
  TIM_SelectInputTrigger(TIM_SLAVE2, TIM_TS_ITR2); // 设置触发源为另一个输入触发源
  // 启动主定时器和从定时器
  TIM_Cmd(TIM_MASTER, ENABLE); // 启动主定时器
  TIM_Cmd(TIM_SLAVE1, ENABLE); // 启动从定时器1
  TIM_Cmd(TIM_SLAVE2, ENABLE); // 启动从定时器2
}

2.2.4 主函数

#include "stm32f10x.h"
#include "general_tim.h"

int main(void)
{
  TIMx_Init();
  while(1)
  {
  }
}

3. 小结

其他步骤我们已经很熟悉了,下面重点来分析一下配置TIM模式:

3.1 启用定时器时钟

RCC_APB1PeriphClockCmd(GENERAL_TIM_MASTER_CLK | GENERAL_TIM_SLAVE1_CLK | GENERAL_TIM_SLAVE11_CLK, ENABLE);

这行代码启用了主定时器(GENERAL_TIM_MASTER)和两个从定时器(GENERAL_TIM_SLAVE1GENERAL_TIM_SLAVE11)的时钟,使能它们的计数功能。

3.2 配置时基

TIM_TimeBaseStructure.TIM_Period = 72;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(GENERAL_TIM_MASTER, &TIM_TimeBaseStructure);
  • TIM_Period:定时器计数周期。当计数器的值从0增加到此值时,会产生一个溢出事件。
  • TIM_Prescaler:预分频器的值。它控制定时器计数频率。此处设置为0,意味着时钟频率没有被分频。
  • TIM_ClockDivision:时钟分频系数。设置为0时,定时器时钟没有额外分频。
  • TIM_CounterMode:计数模式,这里设置为TIM_CounterMode_Up,意味着计数器将从0向上计数。

3.3 配置 PWM 模式

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 36; // 占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(GENERAL_TIM_MASTER, &TIM_OCInitStructure);
  • TIM_OCMode:输出比较模式,这里设置为TIM_OCMode_PWM1,配置为PWM1模式。
  • TIM_OutputState:设置为TIM_OutputState_Enable,启用输出。
  • TIM_Pulse:设置PWM信号的脉宽,决定占空比。脉宽为36。
  • TIM_OCPolarity:输出极性设置为高,即PWM信号的高电平在计数器计数期间持续时间。

3.4 配置从定时器

TIM_TimeBaseStructure.TIM_Period = 4;
TIM_TimeBaseInit(GENERAL_TIM_SLAVE1, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(GENERAL_TIM_SLAVE11, &TIM_TimeBaseStructure);

为两个从定时器设置周期为4的计数器。

TIM_OCInitStructure.TIM_Pulse = 1; // 占空比
TIM_OC1Init(GENERAL_TIM_SLAVE1, &TIM_OCInitStructure);
TIM_OC1Init(GENERAL_TIM_SLAVE11, &TIM_OCInitStructure);

3.5 配置主从模式

使能主从模式

TIM_SelectMasterSlaveMode(GENERAL_TIM_MASTER, TIM_MasterSlaveMode_Enable);

启用主定时器的主从模式,这使得主定时器可以作为触发源来驱动从定时器。

选择输出触发源

TIM_SelectOutputTrigger(GENERAL_TIM_MASTER, TIM_TRGOSource_Update);

设置主定时器的触发源为更新事件(计数器溢出时),主定时器的更新事件将触发从定时器。

配置从定时器为从模式

TIM_SelectSlaveMode(GENERAL_TIM_SLAVE1, TIM_SlaveMode_Gated);
TIM_SelectInputTrigger(GENERAL_TIM_SLAVE1, TIM_TS_ITR1);

GENERAL_TIM_SLAVE1配置为“门控模式”(Gated Mode),这意味着从定时器的计数会被主定时器的触发事件控制。触发源设置为输入触发1(ITR1),这是主定时器的触发信号。

TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Gated);
TIM_SelectInputTrigger(GENERAL_TIM_SLAVE11, TIM_TS_ITR2);

同样地,将GENERAL_TIM_SLAVE11配置为“门控模式”,并设置触发源为输入触发2(ITR2),另一个主定时器的触发信号。

3.6 启用定时器

TIM_Cmd(GENERAL_TIM_SLAVE1, ENABLE);
TIM_Cmd(GENERAL_TIM_MASTER, ENABLE);
TIM_Cmd(GENERAL_TIM_SLAVE11, ENABLE);

最后,启用所有定时器,使它们开始计数和生成PWM信号。


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

2025.1.26 优化代码

本文作者:hazy1k

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

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

posted @   hazy1k  阅读(22)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起