STM32学习笔记(12)——定时器初步应用

Posted Mount256

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32学习笔记(12)——定时器初步应用相关的知识,希望对你有一定的参考价值。

前续:STM32学习笔记(11)——定时器初步应用(1)

三、高级定时器——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初步应用

STM32学习及应用笔记一:SysTick定时器学习及应用

STM32学习笔记

stm32学习笔记-第一天

stm32学习笔记-第一天

stm32学习笔记-第一天