STM32的定时器可以设置成单脉冲模式(OPM)。所谓的单脉冲就是通过程序在一定可控延时后,产生一个脉宽可控的脉冲。这里的延时时间与脉冲宽度都可以设置,主要通过比较:定时器的计数值TIM_CNT、定时器的比较值TIM_CCRx与定时器的周期值TIM_ARR 这三个值来得出。具体如下:
增计数模式:延时时间 = TIM_CCRx - 0 脉冲宽度 = TIM_ARR - TIM_CCRx
减计数模式:延时时间 = TIM_ARR - TIM_CCRx 脉冲宽度 = TIM_CCRx - 0
一个简单的单脉冲模式例子的如下图所示:
当定时器的通道2(即图中的TI2)检测一个上升沿后,经过tDelay延时后,通道1原先的低电平就变成了高电平,再经过tPULSE时间后,有倍拉低了,这里高电平的时间就是脉冲宽度。
接下去就讲讲怎么实现上面这个简单的例程:定时器的通道2检测到上升沿,后延时一定时间后输出一定时间的脉冲。还是基于我自己的规范工程。
1、工程的修改
1)这里用到了定时器,所以需要将stm32f10x_tim.h添加到STM32F10x_StdPeriod_Driver工程组中。
2)打开stm32f0x_conf.h文件,将其中原先被屏蔽的语句:#include "stm32f10x_tim.h"的注释去掉。
3)新建OnePulse.c与OnePulse.h两个文件,分别保存在BSP文件夹里下的src与inc中,然后在将OnePulse.c添加到BSP工程组。
2、OnePulse.c与OnePulse.h文件程序的编写
首先是引脚的初始化。在这里我选择定时器4,定时器4的通道1作为输出单脉冲的通道,定时器的通道2设置成输入捕获,用来捕获上升沿。所以TIM4通道1对应的引脚PB6设置成复用推挽输出,TIM4的通道2对应的引脚PB7设置成悬空输入。代码如下:
/*************************************************************
Function : OnePulse_GPIO_Init
Description: 定时器器的引脚初始化
Input : none
return : none
*************************************************************/
static void OnePulse_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//TIM4 CH1对应的引脚配置成复用输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//TIM4 CH2对应的引脚配置成悬空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
接下去是定时器的配置。代码如下:
/*************************************************************
Function : OnePulse_TIM4_Init
Description: 定时器4配置
Input : none
return : none
*************************************************************/
static void OnePulse_TIM4_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//初始化TIM4的时钟
/*---------------------------------------------------------
TIM4的定时时基为1/(72M/72)=1us
TIM4的CH1配置成PWM2输出模式,TIM4的CH2配置成输入捕获模式,
PWM2模式增计数下,计数值小于比较值为无效电平即低电平,
TIM2 CH2检测到一个上升沿后,经过一定的延时时间,输出一个脉冲,
延时时间 = 10000 * 1us = 10ms
脉冲宽度 = (65535 - 10000) * 1us = 65.535ms。
---------------------------------------------------------*/
TIM_TimeBaseStructure.TIM_Period = 65535;//定时器周期值
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;//预分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0;//时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//增计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);//初始化定时器时基
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//TIM4 CH1配置成PWM2输出模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = 10000;//设置跳变值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_ICStructInit(&TIM_ICInitStructure);//初始化输入捕获结构体
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//TIM4 CH2 配置为输入捕获模式
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//管教与寄存器直接对应
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//不与分频
TIM_ICInitStructure.TIM_ICFilter = 0;//不滤波
TIM_ICInit(TIM4, &TIM_ICInitStructure);//初始化TIM4 CH2
TIM_SelectOnePulseMode(TIM4, TIM_OPMode_Single);//选择定时器为单脉冲模式
TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);//选择触发源为IC2
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Trigger);//选择定时器从模式为上升沿触发
}
先是设置定时器增计数,72预分频,然后设置周期值,这里设置为65535,也就是我们上面说过的TIM_ARR。接着设置定时器的通道1。上面讲过通道1是用来输出波形用的,所以采用PWM2模式,设定有效电平为高电平,然后设定它的比较值,也就是我们上面的TIM_CCRx,通道1就是TIM_CCR1了。在来设置通道2,通道2用于检查是否有上升沿,配置成输入捕获模式,不会上升沿。然后再设定定时器为单脉冲模式,触发源为IC2(也就是通道2),且上升沿触发。这样就配置好了定时器。由上面配置就可以计算出单脉冲的延长时间和脉冲宽度:
延长时间 = 1 / (72M/72/10000) = 10ms
脉冲宽度 = 1 / (72M/72/(65535 - 10000)) = 65.535ms
还要编写一个总函数:OnePulse_Init()来初始化下相关的代码:
/*************************************************************
Function : OnePulse_Init
Description: 单脉冲模式初始化
Input : none
return : none
*************************************************************/
void OnePulse_Init(void)
{
OnePulse_GPIO_Init();
OnePulse_TIM4_Init();
}
下面是OnePulse.h的代码,只是声明了OnePulse_Init()函数:
#ifndef __ONEPULSE_H__
#define __ONEPULSE_H__
#include "stm32f10x.h"
void OnePulse_Init(void);
#endif
3、main函数的编写
main函数很简单,只是调用下相关的初始化函数,代码如下:
/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
BSP_Init();
OnePulse_Init();
PRINTF("\nmain() is running!\r\n");
while(1)
{
LED1_Toggle();
Delay_ms(1000);
}
}
4、测试
将示波器的探头连接到TIM4通道1对应的引脚PB6,然后用杜邦线将TIM4通道2对应的引脚PB7连接到GND接地引脚,然后马上在将杜邦线拔掉,这样来模拟一个上升沿。在示波器上就检测到了一个脉冲,如下图所示:
通过测量可以等到示波器上得到的单脉冲波形,脉冲的长度为65ms左右。类似下图: