STM32 定时器输出比较时间模式
10:20:03来源: eefocus
之前在《SM32定时器要点》中曾经讲过,定时器可以配置成六种模式,如下:
&&TIM_OCMode
&函数库描述
&TIM_OCMode_Timing
&TIM输出比较
&冻结,输出比较不起作用
&TIM_OOCMode_Active
&TIM输出比较主动模式
&当比较发生时,强制输出高电平
&TIM_OCMode_Inactiive
&TIM输出比较非主动模式
&当比较发生时,强制输出低电平
&TIM_OCMode_Toggle
&TIM输出比较触发模式
&当比较发生时,输出翻转
&TIM_OCMode_PWM1
&TIM脉冲宽度调制模式1
&TIM_OCMode_PWM2
&TIM脉冲宽度调制模式2
这里先讲讲比较时间模式。输出比较时间模式的话,上面解释了它其实是冻结了输出功能,也就是说,当定时器发生计数值比较的时候,它什么也不做。既然如此,要它何用?其实虽然它对与输出没有任何作用,但是它也是可以产生一个比较事件,也就是说定时器的计数值等于设定的比较值时可以出发一个,然后我们可以在定时器中断中做文章。它每次从0到计数值这些时间就进入中断一次,就相当于是在定时一样,所以它被叫做输出比较时间模式!
这里,我用定时器的输出比较时间模式在任意引脚上生成PWM波作为例子讲述。还是基于我自己的规范工程。
1、工程的修改
1)这里用到了定时器,所以需要将库文件stm32f10x_tim.c文件添加到F10x_StdPeriod_Driver工程组中。
2)还要打开stm32f10_conf.***件,将里面的#include "stm32f10x_tim.h"原先屏蔽去掉。
& 3)新建OCTiming.c与OCTiming.h两个文件,分别保存在BSP文件夹里下的src与inc中,然后在将OCTiming.c添加到BSP工程组。
2、OCTimingc与OCTiming.***件的程序编写
首先要初始化一些引脚作为PWM的输出引脚,这里需要注意的是,最好不要初始化定时器通道对应的引脚(如果定时器引脚配置成GPIO_Mode_AP_PP模式的话,不会有任何现象),选择其他引脚作为输出引脚,这里我选择PC6、PC7、PC8、PC9这4个引脚,并且要配置成GPIO_Mode_Out_PP模式,代码如下:
/*************************************************************
Function : OC_GPIO_Init
Description: 定时器输出比较的引脚初始化
Input : none
return : none
*************************************************************/
static void OCTiming_GPIO_Init(void)
GPIO_InitTypeDef GPIO_InitS
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //打开GPIOA的时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
接下去再来配置定时器。代码如下,
/*************************************************************
Function : OC_TIM2_Init
Description: 设置的4路输出比较
Input : none
return : none
*************************************************************/
static void OCTiming_TIM2_Init(void)
TIM_TimeBaseInitTypeDef TIM_TimeBaseS
TIM_OCInitTypeDef TIM_OCInitS
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = 65535;//定时周期值
TIM_TimeBaseStructure.TIM_Prescaler = 0;//不预分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0;//时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//增计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//初始化定时器
/* -------------------------------------------------------
定时器配置陈输出比较时间模式:
定时器的时钟频率为72M
PC6输出的频率为72M/CCR1_Val/2=732Hz,占空比为50%的PWM波
PC7输出的频率为72M/CCR2_Val/2=1099Hz,占空比为50%的PWM波
PC8输出的频率为72M/CCR3_Val/2=2197Hz,占空比为50%的PWM波
PC9输出的频率为72M/CCR4_Val/2=4395Hz,占空比为50%的PWM波
---------------------------------------------------------*/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_T//输出比较时间模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_E//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR1_V//设置比较值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_H//当定时器计数值小于CCR1_Val时为高电平
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道11
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_E//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR2_V//设置比较值
TIM_OC2Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道2
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_E//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR3_V//设置比较值
TIM_OC3Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道3
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_E//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR4_V//设置比较值
TIM_OC4Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道3
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值
TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);//清除中断标志为
TIM_Cmd(TIM2, ENABLE);//打开定时器
定时器的首先配置它的时基,这里设置定时周期数为65535,然后在设置定时器各通道的定时值,并打开个通道的输出比较中断。这样的话,每次定时比较值想匹配的就会进入中断,然后在中断中翻转引脚的电平,再重新设置比较值,这样的话就可以生成PWM波了。
既然打开了中断,那就要配置下中断,代码如下:
/*************************************************************
Function : OC_Int_Config
Description: 定时器输出比较中断配置
Input : none
return : none
*************************************************************/
static void OCTiming_Int_Config(void)
NVIC_InitTypeDef NVIC_InitS
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//TIM2中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
这里设置TIM2的的中断优先级为1.
还要编写一个总函数:OCTiming_Init()将上面的初始化代码全部调用一遍,代码如下:
/*************************************************************
Function : OC_Init
Description: 定时器输出比较初始化
Input : none
return : none
*************************************************************/
void OCTiming_Init(void)
OCTiming_GPIO_Init(); //输出比较引脚配置
OCTiming_TIM2_Init(); //定时器2的输出比较初始化
OCTiming_Int_Config(); //输出比较中断配置
接下去将OCTiming.h的内容如下:
#ifndef __TIMEBASE_H__
#define __TIMEBASE_H__
#include "stm32f10x.h"
#define CCR1_Val 49152
#define CCR2_Val 32768
#define CCR3_Val 16384
#define CCR4_Val 8192
void OCTiming_Init(void);
3、stm32f10x_it.c文件的修改
在这个文件中,需要编写中断服务函数,在这个函数中,通过引脚的翻转来实现PWM波,代码如下:
/*************************************************************
Function : TIM2_IRQHandler
Description: 定时器2中断服务程序
Input : none
return : none
*************************************************************/
void TIM2_IRQHandler(void)
static u16 capture = 0;
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//输出比较通道1
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_WriteBit(GPIOC, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_6)));//翻转电平值,生成频率为72M/CCR1_Val/2,占空比为50%的PWM波
capture = TIM_GetCapture1(TIM2);//获取比较值
TIM_SetCompare1(TIM2, capture + CCR1_Val);//重新设置比较值
if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//输出比较通道1
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
GPIO_WriteBit(GPIOC, GPIO_Pin_7, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_7)));//翻转电平值,生成频率为72M/CCR2_Val/2,占空比为50%的PWM波
capture = TIM_GetCapture2(TIM2);//获取比较值
TIM_SetCompare2(TIM2, capture + CCR2_Val);//重新设置比较值
if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)//输出比较通道1
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
GPIO_WriteBit(GPIOC, GPIO_Pin_8, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_8)));//翻转电平值,生成频率为72M/CCR3_Val/2,占空比为50%的PWM波
capture = TIM_GetCapture3(TIM2);//获取比较值
TIM_SetCompare3(TIM2, capture + CCR3_Val);//重新设置比较值
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)//输出比较通道1
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_9)));//翻转电平值,生成频率为72M/CCR4_Val/2,占空比为50%的PWM波
capture = TIM_GetCapture4(TIM2);//获取比较值
TIM_SetCompare4(TIM2, capture + CCR4_Val);//重新设置比较值
在中断函数中,如果检测到比较中断标志,就会调用GPIO_WriteBit(GPIOC, GPIO_Pin_7, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_7)));这个语句翻转引脚的电平。翻转电平后,然后获取当前的捕获值,再在这个基础上重新设置我们的捕获值。在这里,我重新设置比较值为与原先比较时间相同(让然也可以不这么设置),这样的话,引脚输出一半时间是高电平,一半是低电平,这样输出占空比为50%的占空比。如CCR1_Val值为49152,每次计数值到达这个时,就翻转引脚电平,然后重新设置比较值为 49152 + 49152,考虑到定时器是16为定时器会溢出,所以重新设置的计数值为32768。这样的话,就有49152计数值时间输出高电平,有49152计数值时间输出低电平,所以最后输出的PWM波的频率为72M/Hz,占空比为50%。
4、main函数的编写
mian函数其实没做什么,只是条用各个模块的初始化函数,代码如下:
/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
BSP_Init();
OCTiming_Init(); //输出比较初始化
PRINTF("\nmain() is running!\r\n");
1_Toggle();
Delay_ms(1000);
将的探头分别连接引脚PC6、PC7、PC8、PC9,可以看到个引脚输出的波形与频率。
PC6输出频率为732Hz,占空比都是50%的PWM波,如下图所示:
PC7输出频率为099Hz,占空比都是50%的PWM波,如下图所示:
PC8输出频率为2197Hz,占空比都是50%的PWM波,如下图所示:
PC9输出频率为4395Hz,占空比都是50%的PWM波,如下图所示:
关键字:&&&&
编辑:什么鱼
引用地址:
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或***通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。
微信扫一扫加关注 论坛活动 E手掌握
微信扫一扫加关注
芯片资讯 锐利解读
大学堂最新课程
TTI携TE传感器样片与你相见,一起传感未来
馆内包含了 纵览FRAM、独立FRAM存储器专区、FRAM内置LSI专区三大部分内容。
热门资源推荐
频道白皮书
何立民专栏
北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。今日: 0|主题: 7|排名: 12&
- [回帖奖励
- [阅读权限 255]&...
带交易单号申请
带交易单号提问
点击联系售后
Powered by