STM32学习笔记(12)——定时器初步应用
Posted Mount256
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32学习笔记(12)——定时器初步应用相关的知识,希望对你有一定的参考价值。
三、高级定时器——PWM互补输出
【实现功能】通过使用高级定时器 TIM1 的输出通道 CH1,输出一对互补信号 PWM。要求占空比为 50%。
【基本思路】查看原理图,在 STM32F103ZE 中,高级定时器 TIM1 的输出通道 1 对应的引脚是 PA8,互补输出通道 1 对应的引脚是 PB13,刹车通道对应的引脚是 PB12。只需初始化这三个引脚即可。
还是跟以前一样,我们设置分频因子为 72,则得到了一次计数周期为 1us,再设置重装载值为 1000,则计数器数到 1000 会重新清零,此时过去了 1000 * 1us = 1000us = 1ms。于是我们得到了 1ms 为周期的方波信号,不过此时还未设置占空比。
现在我们已经设置重装载值为 1000(对应的寄存器是ARR),为了使占空比为 50%,则我们要将脉冲宽度设置为 500(对应的寄存器是CCR1),因为 500/1000 = 50%。如果我们需要将占空比调整至 30%,则寄存器 CCR1 的值应该设置为 300。
在配置互补输出信号的时候,将两者电平极性设置为高电平,这样我们之前设置的占空比才是对应高电平的;如果设置的是低电平的话,那么占空比对应的就是低电平了。
解释一下空闲电平:如果中途关闭了输出使能,那么此时输出通道输出的就是空闲电平。空闲电平极性为高,则一直输出高电平;空闲电平极性为低,则一直输出低电平。
最后提一句,用通用定时器一样也能实现PWM互补输出。
【编程要点】
- 输出通道、互补输出通道、刹车通道 GPIO 引脚初始化;
- TIM1 时基单元初始化配置;
- TIM1 输出比较通道、互补输出比较通道、刹车通道初始化配置;
- main 函数调用 TIM 的初始化函数;
- 通过 keil5 仿真逻辑仪查看实验结果。
完整代码如下:
1. advance_tim.h
#ifndef __ADVANCE_TIM_H
#define __ADVANCE_TIM_H
#include "stm32f10x.h"
#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
#define ADVANCE_TIM_PERIOD (1000 - 1) // 重装载值:1000us = 1ms
#define ADVANCE_TIM_PSC (72 - 1) // 分频:72,得到周期:1us
#define ADVANCE_TIM_CCR1 500 // 脉冲宽度:500us
#define ADVANCE_TIM_RECNT 0
#define ADVANCE_TIM_CH1_PORT_CLK RCC_APB2Periph_GPIOA
#define ADVANCE_TIM_CH1_PORT GPIOA
#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8
#define ADVANCE_TIM_CH1N_PORT_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_CH1N_PORT GPIOB
#define ADVANCE_TIM_CH1N_PIN GPIO_Pin_13
#define ADVANCE_TIM_BKIN_PORT_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_BKIN_PORT GPIOB
#define ADVANCE_TIM_BKIN_PIN GPIO_Pin_12
#define ADVANCE_TIM_DEAD_TIME 11 // 配置死区时间为152ns,计算方法参见STM32中文手册
void ADVANCE_TIM_Init(void);
#endif /* __ADVANCE_TIM_H */
2. advance_tim.c
#include "advance_tim.h"
static void ADVANCE_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStrutcure;
/* 输出比较通道初始化(PA8) */
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_PORT_CLK, ENABLE);
GPIO_InitStrutcure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
GPIO_InitStrutcure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStrutcure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_CH1_PORT ,&GPIO_InitStrutcure);
/* 输出比较互补通道初始化(PB13) */
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_PORT_CLK, ENABLE);
GPIO_InitStrutcure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;
GPIO_InitStrutcure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStrutcure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_CH1N_PORT ,&GPIO_InitStrutcure);
/* 输出比较刹车通道初始化(PB12) */
RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_PORT_CLK, ENABLE);
GPIO_InitStrutcure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;
GPIO_InitStrutcure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStrutcure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_BKIN_PORT ,&GPIO_InitStrutcure);
/* BKIN引脚默认输出低电平 */
GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT, ADVANCE_TIM_BKIN_PIN);
}
static void ADVANCE_TIM_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CLK, ENABLE);
/* 时基单元初始化 */
TIM_TimeBaseStructure.TIM_Prescaler = ADVANCE_TIM_PSC; // 计数器时钟分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数模式
TIM_TimeBaseStructure.TIM_Period = ADVANCE_TIM_PERIOD; // 自动重装载寄存器
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频因子(再次分频)
TIM_TimeBaseStructure.TIM_RepetitionCounter = ADVANCE_TIM_RECNT; // 重复计数器
TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure); // 使能时基单元
/* 输出比较初始化 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出使能
TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_CCR1; // 设置脉冲宽度
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // 互补输出通道电平极性配置
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // 输出通道空闲电平极性配置
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; // 互补输出通道空闲电平极性配置
TIM_OC1Init(TIM1, &TIM_OCInitStructure); // 开启TIM1定时器输出比较功能
TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable); // 使用影子寄存器
/* 刹车死区初始化 */
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; // 运行模式下“关闭状态”选择
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; // 空闲模式下“关闭状态”选择
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; // 锁定设置
TIM_BDTRInitStructure.TIM_DeadTime = ADVANCE_TIM_DEAD_TIME; // 配置死区时间为152ns
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable; // 刹车通道使能
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; // 刹车通道电平极性为高电平
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // 自动输出使能
TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure); // 使能刹车功能
/* 使能定时器 */
TIM_Cmd(ADVANCE_TIM, ENABLE);
/* 定时器主输出使能,通用定时器不需要这一句 */
TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
}
void ADVANCE_TIM_Init(void)
{
ADVANCE_TIM_GPIO_Config();
ADVANCE_TIM_Mode_Config();
}
3. main.c
#include "stm32f10x.h"
#include "advance_tim.h"
int main(void)
{
ADVANCE_TIM_Init(); // 只需调用这个函数,STM32就会输出一对互补信号PWM
while(1)
{
}
}
4. Keil5 逻辑分析仪仿真
因为手头没有示波器,因此用软件自带逻辑分析仪进行仿真。这里只是大概说一下怎么设置,详细步骤请查看其它相关博文。
首先在魔法棒(options for target)的 debug 选项卡按照下图设置好(DARMSTM.DLL)(-pSTM32F103ZE):
如下图所示,菜单栏点击 Debug/Start Debug Session,然后点击图中1处的示波器,选择 Logic Analyzer。菜单栏点击 View/Symbols Window,然后右边会出现窗口,点击其中的 Virtual Registers,便可以查看哪些寄存器可以加入观察对象。
点击上图2处的setup,加入 PORTA 和 PORTB,并设置好显示类型、掩码和右移位数。比如我要查看 PA13,那么 Display Type 设置为 Bit,掩码为 0x100(二进制 0000 0001 0000 0000 = 十六进制 0x100),右移8位。如图所示:
点击 Run,等一会时间再点 Stop,即可查看仿真结果(基本符合预期):
注意,仿真结果并不代表实际结果也是这样。因为仿真的是理想状态。
附:呼吸灯的实现
现在我们来讲讲呼吸灯是如何实现的。如果不用定时器,用延时函数写呼吸灯的部分程序如下:
#include "stm32f10x.h"
#include "systick.h"
#include "led.h"
int main(void)
{
uint16_t i = 0;
uint16_t num = 1500;
LED_Init();
while(1)
{
for(i = 0; i < num; i++)
{
LED0_ON;
Systick_Delay_us(i); // 我自己用systick写的延时函数,可参考我以前的systick文章
LED0_OFF;
Systick_Delay_us(num - i);
}
for(i = num; i > 0; i--)
{
LED0_ON;
Systick_Delay_us(i);
LED0_OFF;
Systick_Delay_us(num - i);
}
}
}
由以上程序可知呼吸灯的实现原理。其实现原理非常简单,就是利用人眼的延缓视觉效果,逐渐加快 LED 亮灭的频率,然后逐渐减慢 LED 亮灭的频率,其实质是一个高电平占空比不断变少、而后不断变多的方波信号,即可调制信号 PWM,这样就实现呼吸灯的效果了,如下图所示(借用了他人图片,若有侵权请联系本人进行删除):
类似的,如果使用定时器去实现,那么只需每次循环都修改占空比即可,这样就达到了不断修改占空比的功能,进而实现呼吸灯的目的。修改后的 main 函数:
#include "stm32f10x.h"
#include "systick.h"
#include "advance_tim.h"
int main(void)
{
uint16_t i;
ADVANCE_TIM_Init();
while(1)
{
for(i = 0; i < 1000; i++)
{
TIM_SetCompare1(TIM1, i); // 每次循环都重新设置CH1脉冲宽度(亮变暗)
Systick_Delay_us(1500);
}
for(i = 999; i > 0; i--)
{
TIM_SetCompare1(TIM1, i); // 每次循环都重新设置CH1脉冲宽度(暗变亮)
Systick_Delay_us(1500);
}
Systick_Delay_ms(500);
}
}
需要注意的是,STM32的高级定时器 TIM1 的输出引脚与 LED 引脚并不连在一起,那我们怎么去实现呼吸灯呢?这里提供两个办法:
方法1:使用杜邦线和面包板外接 LED 灯
需要自行准备LED灯(注意区分正负极),自己连接电路,记得连上拉电阻,大概 100 - 200 欧姆即可。如果忘记连电阻,LED 会烧掉,几分钱也没了,不仅如此,还会伴随一股焦味,如果手没及时拿开还可能会肉疼一会儿。
这里只实现了一个呼吸灯。本来打算写个四路输出PWM(实现起来很简单,就是输出通道初始化4次即可,下面第四部分将展示4路输出是如何编写的),实现4个流水呼吸灯的小玩意,但是我的面包板似乎总是间歇性接触不良,导致进一步的调试极为麻烦,而且板载 LED 只有两个,因此不得不放弃。
方法2:使用杜邦线将输出引脚和 LED 引脚连起来,即飞线
这种办法比较便捷:一般的系统版上都会有排针,可以用两端都是母头的杜邦线将输出引脚(PA8)和 LED0(PB5)连起来,将互补输出引脚(PB13)和 LED1(PE5)连起来,你会看到两盏呼吸灯相互亮灭,这与仿真结果符合。
四、高级定时器——PWM输入捕获
这部分内容挺重要的,因为是最后压轴出场!!!
【实现功能】使用通用定时器输出4路不同占空比的PWM信号,然后使用高级定时器的输入捕获功能测量PWM输出信号的周期和占空比,并将结果通过USART输出到上位机上。
【基本思路】通用定时器的4路输出就不用讲了,思路与呼吸灯是一样的。下面我们来详细分析输入捕获是如何工作的,如图所示:
我们使用高级定时器 TIM1 的输入捕获功能来测量信号的周期和占空比,使用的是 TI1 通道,通过输入滤波器和边沿检测器后产生2路滤波信号 TI1FP1 和 TI1FP2,其中 TI1FP1 映射到了捕获通道 IC1,捕获到的值送入寄存器 CCR1;TI1FP2 映射到了捕获通道 IC2,捕获到的值送入到寄存器 CCR2。因此实际上 TIM1 使用了两路通道 CH1 和 CH2。
我们需要理解信号 TI1FP1 和 TI1FP2 的实质:二者均来自于同一个通道 TI1,然后映射到不同的捕获通道,其实还是同一路信号,但是由于经过了边沿检测器,这两路信号的极性相反。当我们将 TI1FP1 配置为上升沿触发的时候,TI1FP2 就是下降沿触发;反之亦然。
既然有两路信号 TI1FP1 和 TI1FP2,那么用哪个通道判断 PWM 上升沿的到来?STM32提供的办法是:可以将其中一路信号设置为触发信号,告诉定时器,如果这路信号检测到上升沿,那么就可以开始捕获工作了。我们选择 TI1FP1 作为触发信号。
那么另外一路信号 TI1FP2 怎么办呢?STM32提供的办法是:将另一路信号 TI1FP2 设置为从机模式,这样另一路信号就会在主信号 TI1FP1 触发时也会被触发。这时的 TI1FP1 称之为从模式触发源。 从模式在 STM32 一共有四种:复位模式、门控模式、触发模式、外部时钟模式2 + 其他三种触发模式(说白了就是可以与其他模式搭配使用)。我们将 TI1FP2 配置为从模式的复位模式。现在我们只需要记住复位模式的功能:在发生一个触发输入事件时,计数器和它的预分频器能够重新被初始化。
读到这里的同学可能不明白上面这一通操作是干嘛的,我们举个例子就明白了:PWM 上升沿到来,TI1FP1 检测到上升沿(被触发了),由于 TI1FP2 是从机,因此也会被触发;由于是复位模式,计数器的值清零,此时不会产生捕获中断。下降沿到来时,TI1FP2 是下降沿触发,因此会 发生捕获事件,将此时计数器的值存到寄存器 CCR2。新一轮上升沿到来时,TI1FP1 是上升沿触发,因此发生捕获事件,将此时计数器的值存到寄存器 CCR1,此时产生捕获中断,同时计数器清零。因此我们测得的周期是 72MHz / CCR1,测得的占空比是 CCR2 / CCR1。但实际上,计数器是从0开始计数的,所以正确的结果是:周期 = 72MHz / (CCR1+1),占空比 = (CCR2+1) / (CCR1+1)。 整个过程如下图所示:
看到这里大家也许明白为什么要弄个从机模式了。因为测量占空比和测量周期的工作必须要同时开始进行,所以需要一个主通道和一个从通道,主通道说开始要做事了,从通道也会跟着同时做事!
到这里其实已经讲解的很清楚了,不过需要注意三点:
(1)因为只有 TI1FP1 和 TI2FP2 连到了从模式控制器,所以PWM输入模式只能使用 TIMx_CH1 和 TIMx_CH2 信号,用 CH3 和 CH4 是不行的哦,可以对照功能框图进行查看。
(2)注意直连(TIM_ICSelection_DirectTI)和非直连(TIM_ICSelection_IndirectTI)的区别:直连指的是输入通道 IC1 连接 CH1,输入通道 IC2 连接到 CH2;非直连指的是输入通道 IC1 连接 CH2,输入通道 IC2 连接到 CH1。对于我们这个实验来说,选择直连,IC1 测得就是周期,IC2 测的是占空比;选择非直连,IC1 测得就是占空比,IC2 测的是周期。
(3)不用配置 IC2(或者说TI1FP2),因为你给一个通道配置了时钟和极性后,另一个通道会通过硬件给你配置好。如果你多配置了 IC2,反而测量结果会不正确。
最后我们附上STM32中文参考手册里的 PWM 输入模式的配置步骤:
- 两个ICx信号被映射至同一个TIx输入。
- 这2个ICx信号为边沿有效,但是极性相反。
- 其中一个TIxFP信号被作为触发输入信号,而从模式控制器被配置成复位模式。
例如,你需要测量输入到TI1上的PWM信号的长度(TIMx_CCR1寄存器)和占空比(TIMx_CCR2
寄存器),具体步骤如下(取决于CK_INT的频率和预分频器的值):
- 选择TIMx_CCR1的有效输入:置TIMx_CCMR1寄存器的CC1S=01(选中TI1)。
- 选择TI1FP1的有效极性(用来捕获数据到TIMx_CCR1中和清除计数器):置CC1P=0(上升沿
有效)。- 选择TIMx_CCR2的有效输入:置TIMx_CCMR1寄存器的CC2S=10(选中TI1)。
- 选择TI1FP2的有效极性(捕获数据到TIMx_CCR2):置CC2P=1(下降沿有效)。
- 选择有效的触发输入信号:置TIMx_SMCR寄存器中的TS=101(选择TI1FP1)。
- 配置从模式控制器为复位模式:置TIMx_SMCR中的SMS=100。
- 使能捕获:置TIMx_CCER寄存器中CC1E=1且CC2E=1。
【编程要点】
- 通用定时器时基单元初始化;
- 通用定时器4个GPIO引脚初始化;
- 通用定时器4路PWM输出CH1-CH4初始化;
- 高级定时器时基单元初始化;
- 高级定时器GPIO引脚初始化;
- 高级定时器输入捕获IC1初始化(不用初始化IC2);
- 开启高级定时器捕获中断,并配置NVIC;
- 编写高级定时器中断服务函数,并计算测量结果,然后输出。
完整代码如下:
1. general_tim.h
#ifndef __GENERAL_TIM_H
#define __GENERAL_TIM_H
#include "stm32f10x.h"
/*******通用定时器TIMx输出比较******/
#define GENERAL_TIM TIM3
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM3
#define GENERAL_TIM_PERIOD (100 - 1) // 100 * 1us = 100us, f = 1 / 10^(-4) = 10^4Hz = 10000Hz
#define GENERAL_TIM_PSC (72 - 1) // 1us
#define GENERAL_TIM_RECNT 0
#define GENERAL_TIM_CH1_PORT_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_6
#define GENERAL_TIM_CCR1 10 // 占空比:10%
#define GENERAL_TIM_CH2_PORT_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH2_PORT GPIOA
#define GENERAL_TIM_CH2_PIN GPIO_Pin_7
#define GENERAL_TIM_CCR2 25 // 占空比:25%
#define GENERAL_TIM_CH3_PORT_CLK RCC_APB2Periph_GPIOB
#define GENERAL_TIM_CH3_PORT GPIOB
#define GENERAL_TIM_CH3_PIN GPIO_Pin_0
#define GENERAL_TIM_CCR3 50 // 占空比:50%
#define GENERAL_TIM_CH4_PORT_CLK RCC_APB2Periph_GPIOB
#define GENERAL_TIM_CH4_PORT GPIOB
#define GENERAL_TIM_CH4_PIN GPIO_Pin_1
#define GENERAL_TIM_CCR4 75 // 占空比:75%
void GENERAL_TIM_Init(void);
#endif /* __GENERAL_TIM_H */
2. general_tim.c
#include "general_tim.h"
/* 输出通道 GPIO初始化 */
static void GENERAL_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 输出通道CH1 GPIO初始化(PA6) */
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_PORT_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;
GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);
/* 输出通道CH2 GPIO初始化(PA7) */
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_PORT_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;
GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);
/* 输出通道CH3 GPIO初始化(PB0) */
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_PORT_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;
GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure);
/* 输出通道CH4 GPIO初始化(PB1) */
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_PORT_CLK, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH4_PIN;
GPIO_Init(GENERAL_TIM_CH4_PORT, &GPIO_InitStructure);
}
/* 时基单元和输入捕获通道初始化 */
static void GENERAL_TIM_MODE_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(GENERAL_TIM_CLK, ENABLE);
/* 时基单元结构体初始化 */
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM_PERIOD;
TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM_PSC;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
/* 输出比较通道结构体初始化 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
//TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; // 不使用互补输出,不用理会
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; // 不使用互补输出,不用理会
//TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; // 不使用空闲电平,不用理会
//TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; // 不使用互补输出,不用理会
/* 输出通道CH1初始化 */
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR1;
TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
/* 输出通道CH2初始化 */
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR2;
TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
/* 输出通道CH3初始化 */
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR3;
TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
/* 输出通道CH4初始化 */
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR4;
TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
/* 使能计数器 */
TIM_Cmd(GENERAL_TIM, ENABLE);
}
void GENERAL_TIM_Init(void)
{
GENERAL_TIM_GPIO_Config();
GENERAL_TIM_MODE_Config();
}
3. advance_tim.h
#ifndef __ADVANCE_TIM_H
#define __ADVANCE_TIM_H
#include "stm32f10x.h"
#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
#define ADVANCE_TIM_PERIOD (1000 - 1) // 重装载值:1000us
#define ADVANCE_TIM_PSC (72 - STM32学习笔记(14)——ADC初步应用