STM32 定时器输出比较时间模式

发布者:春林初盛最新更新时间:2016-10-11 来源: eefocus关键字:STM32  定时器输出  时间模式 手机看文章 扫描二维码
随时随地手机看文章
之前在《SM32定时器要点》中曾经讲过,定时器可以配置成六种模式,如下:
  TIM_OCMode  函数库描述  解释 
 TIM_OCMode_Timing  TIM输出比较时间模式  冻结,输出比较不起作用
 TIM_OOCMode_Active  TIM输出比较主动模式  当比较发生时,强制输出高电平
 TIM_OCMode_Inactiive  TIM输出比较非主动模式  当比较发生时,强制输出低电平
 TIM_OCMode_Toggle  TIM输出比较触发模式  当比较发生时,输出翻转
 TIM_OCMode_PWM1  TIM脉冲宽度调制模式1  PWM1
 TIM_OCMode_PWM2  TIM脉冲宽度调制模式2  PWM2
这里先讲讲定时器输出比较时间模式。输出比较时间模式的话,上面解释了它其实是冻结了输出功能,也就是说,当定时器发生计数值比较的时候,它什么也不做。既然如此,要它何用?其实虽然它对与输出没有任何作用,但是它也是可以产生一个比较事件,也就是说定时器的计数值等于设定的比较值时可以出发一个定时器中断,然后我们可以在定时器中断中做文章。它每次从0到计数值这些时间就进入中断一次,就相当于是在定时一样,所以它被叫做输出比较时间模式!
这里,我用定时器的输出比较时间模式在任意引脚上生成PWM波作为例子讲述。还是基于我自己的规范工程。
1、工程的修改
1)这里用到了定时器,所以需要将库文件stm32f10x_tim.c文件添加到STM32F10x_StdPeriod_Driver工程组中。
2)还要打开stm32f10_conf.h文件,将里面的#include "stm32f10x_tim.h"原先屏蔽去掉。
· 3)新建OCTiming.c与OCTiming.h两个文件,分别保存在BSP文件夹里下的src与inc中,然后在将OCTiming.c添加到BSP工程组。
 
2、OCTimingc与OCTiming.h文件的程序编写
首先要初始化一些引脚作为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_InitStructure;

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: 设置定时器2的4路输出比较
Input : none
return : none
*************************************************************/
static void OCTiming_TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

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_Timing;//输出比较时间模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;//设置比较值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//当定时器计数值小于CCR1_Val时为高电平
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道11
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;//设置比较值
TIM_OC2Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道2
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;//设置比较值
TIM_OC3Init(TIM2, &TIM_OCInitStructure);//初始化TIM2的输出比较通道3
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);//不自动重转计数值

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;//设置比较值
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_InitStructure;

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);

#endif

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/49152/2=732Hz,占空比为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");
while(1)
{
LED1_Toggle();
Delay_ms(1000);
}
}

5、测试
将示波器的探头分别连接引脚PC6、PC7、PC8、PC9,可以看到个引脚输出的波形与频率。
PC6输出频率为732Hz,占空比都是50%的PWM波,如下图所示:
STM32 定时器输出比较翻转模式 - ziye334 - ziye334的博客
PC7输出频率为099Hz,占空比都是50%的PWM波,如下图所示:
STM32 定时器输出比较翻转模式 - ziye334 - ziye334的博客
PC8输出频率为2197Hz,占空比都是50%的PWM波,如下图所示:
STM32 定时器输出比较翻转模式 - ziye334 - ziye334的博客
PC9输出频率为4395Hz,占空比都是50%的PWM波,如下图所示:
STM32 定时器输出比较翻转模式 - ziye334 - ziye334的博客

关键字:STM32  定时器输出  时间模式 引用地址:STM32 定时器输出比较时间模式

上一篇:STM32 定时器输出比较主动模式
下一篇:STM32 生成7路PWM波

推荐阅读最新更新时间:2024-03-16 15:14

STM32延时函数的四种方法
单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ms( )。 1.普通延时法 (1)普通延时法1 这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,不过要做的比较精准还是要下一番功夫。下面的代码是在网上搜到的,经测试延时比较精准。 //粗延时函数,微秒 void delay_us(u16 time) { u16 i=0; while(time--) { i=10; //自己定义 while(i--) ; } } //毫秒级的延时 void delay_ms(u16 time) { u16 i=0;
[单片机]
关于STM32的140个问题汇总
1、AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2 1,意思是APB2接高速设备 2、Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为stm32f10x_conf.h专门控制外围器件的配置,也就是开关头文件的作用 3、HSE Osc(High Speed External Oscillator)高速外部晶振,一般为8MHz,HSI RC(High Speed InternalRC)高速内部RC,8MHz 4、LSE Osc(Low Speed External Oscillator)低速外部晶振,一般为32.768KHz,LSI RC(Low Speed InternalR
[单片机]
关于<font color='red'>STM32</font>的140个问题汇总
STM32学习—systick系统定时器
SysTick定时器配置步骤 SysTick定时器的操作可以分为 4 步: (1)设置SysTick定时器的时钟源。 (2)设置SysTick定时器的重装初始值(如果要使用中断的话,就将中 断使能打开)。 (3)清零SysTick定时器当前计数器的值。 (4)打开SysTick定时器。 SysTick_Init()函数: void SysTick_Init(u8 SYSCLK) //SYSCLK默认系统时钟是72M { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //对系统是进行8分频 fac_us=SYSCLK/8; //1 us所需要的次数 fac
[单片机]
STM32 SD卡_没有加文件系统
下图是万利板子的SD卡部分 其中SD_PWR连接到了 PD10 通过一个控制 P-Channel 2.5-V (G-S) MOSFET 控制SD卡的电源 ===================================================================== SPI模式 读写SD卡 SD卡初始化过程: 1. 初始化STM32的SPI接口 使用低速模式 2. 延时至少74clock 3. 发送CMD0,需要返回0x01,进入Idle状态 4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态 5. 设置读写block大小为512byte 5.
[单片机]
<font color='red'>STM32</font> SD卡_没有加文件系统
STM32中DMA模块的使用
DMA(Direct Memory Access)常译为“存储器直接存取”。早在Intel的8086平台上就有了DMA应用了。 一个完整的微控制器通常由CPU、存储器和外设等组件构成。这些组件一般在结构和功能上都是独立的,而各个组件的协调和交互就由CPU完成。如此一来,CPU作为整个芯片的核心,其处理的工作量是很大的。如果CPU先从A外设拿到一个数据送给B外设使用,同时C外设又需要D外设提供一个数据。。。这样的数据搬运工作将使CPU的负荷显得相当繁重。 严格的说,搬运数据只是CPU的比较不重要的一种工作。CPU最重要的工作室进行数据运算,从加减乘除到一些高级的运算,包括浮点、积分、微分、FFT等。CPU还需要负责复杂的中断
[单片机]
<font color='red'>STM32</font>中DMA模块的使用
独立看门狗IWDG详细解析
独立看门狗IWDG详细解析 为什么要有看门狗? 看门狗的定时原理 寄存器功能简介 看门狗定时器计数原理 看门狗相关寄存器 KR寄存器 PR寄存器 RLR寄存器 SR寄存器 看门狗相关基础知识 什么是“溢出时间”? 溢出时间指的是“从重装载值递减至0的时间”,当距离上次使能键寄存器的时间超过溢出时间,那么看门狗会自动复位,重投开始执行程序。例如:当我们设定溢出时间为1s,但是我们操作键寄存器距离上次使能键寄存器的时间已经是1.2s了,这说明程序已经Reset复位,从头开始执行(从main函数的头部开始执行)。 预分频系数有什么用? “溢出时间”如何计算? 不同预分频系数
[单片机]
独立看门狗IWDG详细解析
stm32使用中,printf函数不执行的问题
一、程序中已经添加了printf的库函数 #include“stdio.h” 二、stm32串口通讯测试没问题,此处可以通过调用 USART_SendData(USART1, 0xAA)函数来进行验证; 三、现象。printf函数无法工作 四、解决办法,使用自带的迷你库,就可以正常运行。
[单片机]
<font color='red'>stm32</font>使用中,printf函数不执行的问题
大神教你如何快速使用DMA处理ADC
ADC: 1.STM32内部的ADC模块有三个ADC1,ADC2,ADC3,他们彼此独立,所以可以进行同步采样。 2ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生,要在RCC_CFGR配置,再ADC自己的寄存器中在没有时钟分频的配置位。 3.ADC转换时间: STM32F103xx增强型产,时钟为56MHz时为1μ s( 时钟为72MHz为1.17 μ s) 4.ADC的转换精度默认设置为12位,输入范围:ADC输入范围:V REF-≤ VIN≤ VREF+ 5.共有18个通道,其中外部16个通道,内部两个通道,内部温度传感器连接在ADC1_IN16,内部参考电压V REFINT连接在ADC1_IN17 6
[单片机]
大神教你如何快速使用DMA处理ADC
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved