利用STM32的TIM1/TIM8输出可以移相的互补PWM

发布者:Huanle最新更新时间:2019-05-27 来源: eefocus关键字:STM32  TIM1  TIM8输  互补PWM 手机看文章 扫描二维码
随时随地手机看文章

前言:TIM1、TIM8是STM32的高级定时器,在高容量的STM32芯片中含有TIM8,低容量芯片只有TIM1。这两个定时器是完全独立工作的。在实际工作中,我们希望他们有时间上的联系。比如做全桥移相的时候,需要两个PWM之间有一个相位差,并且可以调整相位宽度。这点STM32是可以做到的。

思路:TIM1作为主定时器,TIM8作为从定时器。TIM1_CH1/CH1N、TIM8_CH1/CH1N互补输出。另取通道TIM1_CH2产生的OC2REF作为触发源TRGO。设置TIM1_CH2的比较寄存器TIM1_CCR2,设定延时时间。当TIM1_CH2比较溢出,产生OC2REF上升沿,TIM8作为从模式收到TRGI上升沿,产生复位,从头产生PWM。从而实现TIM1/TIM8双路PWM产生时间差,即移相。

重点:


 MMS@TIM1_CR2设置为“101” 【主模式,OC2REF用作触发输出TRGO】


 TS@TIM8_SMCR设置为“000” 【TIM8触发输入TRGI选择内部触发0(ITR0),也就是对应TIM1】


在这里插入图片描述

 SMS@TIM8_SMCR设置为“100” 【TIM8从模式选择复位模式】


开整:


TIM1模式设置

void TIM1_Mode_Config(void)

{

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_DeInit(TIM1);

TIM_TimeBaseStructure.TIM_Period =_PWM_PeriodVal;                   /*1.设置定时时间ARR*/

TIM_TimeBaseStructure.TIM_Prescaler = 0;                          /*2.设置预分频:不预分频,即为72MHz  */

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;          /*3.设置时钟分频因子[TIMx_CR1:CKD]:不分频。采样输入时有效*/

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;          /*向上计数模式*/

TIM_TimeBaseStructure.TIM_RepetitionCounter=0; /*不使用重复计数器*/

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); /*初始化结构体*/

    TIM_InternalClockConfig(TIM1); /*关闭从模式,即预分频器使用内部时钟驱动*/

TIM_Cmd(TIM1,ENABLE); /*使能TIM1*/


}



TIM1输出设置。包括通道1和通道2,通道1产生互补PWM,通道2不输出信号,只产生触发源

/*********************************************

 *函数名:TIM1_OC_Config

 *函数描述:TIM1输出设置

 *输入参数:无

 *输出结果:无

 *返回值:无

***********************************************/

void TIM1_OC_Config(void)

{

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_BDTRInitTypeDef TIM_BDTRInitStructure;

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /*TIM1_OC1的模式为PWM1*/

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; /*允许输出*/

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; /*允许输出*/

TIM_OCInitStructure.TIM_Pulse = (_PWM_PeriodVal)/2; /*CCR1=ARR*50%*/

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; /*CC1P:输出极性高为有效*/

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; /*CC1PN*/

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

TIM_OC1Init(TIM1, &TIM_OCInitStructure);

//----------------------------------------------

/*TIM_OC2设置,作为触发信号,来复位TIM8*/

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Active; /*TIM1_OC2REF的模式为高电平有效*/

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;  /*输出关闭*/

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;/*输出关闭*/

TIM_OCInitStructure.TIM_Pulse = _PHASE_TimeVal;                /*相位差*/

TIM_OC2Init(TIM1,&TIM_OCInitStructure);

TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC2Ref);  /*TIM1_OC2REF作为主模式TRGO输出*/

//----------------------------------------------

/*预装载使能*/

TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); /*TIM_OCPreload_Enable     TIM_OCPreload_Disable */

TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); /*TIM_OCPreload_Enable  */  

//----------------------------------------------

/*使能TIM1重载寄存器ARR*/

TIM_ARRPreloadConfig(TIM1, ENABLE);

//-----------------------------------------------

TIM_BDTRStructInit(&TIM_BDTRInitStructure); /*BDTR初始化,默认初始值*/

//------------------------------------------------

/*运行模式下定时器不工作时,输出无效电平*/

TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable;  

/*空闲模式下定时器不工作时,禁止OC/OCN输出 */  

TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable; /*锁定级别LEVEL1*/

/*设置死区时间1us*/

TIM_BDTRInitStructure.TIM_DeadTime = 72; /*0~0xFF 1us*72M*/

/*刹车除能*/

TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;  

// TIM_BDTRInitStructure.TIM_TIM_BreakPolarity =TIM_BreakPolarity_High; /*TIM_BreakPolarity_High

//                                                                            TIM_BreakPolarity_Low */

/*自动输出除能 AOE只能被软件置1*/

TIM_BDTRInitStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Disable; /*TIM_AutomaticOutput_Disable

TIM_AutomaticOutput_Enable */


TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure); /*更改BDTR寄存器值*/

}



在上面代码中可以看到对TIM1_CH2通道的设置。主要是设置OC2REF极性,和相位。

TIM_OCInitStructure.TIM_Pulse = _PHASE_TimeVal; /*相位差*/

后面可以直接对TIM1_CCR2操作,来调整相位。

比如使用:


TIM_SetCompare2 (TIM1,PhaseVal);


或者直接操作:


TIM1->CCR2 = PhaseVal;


设置TIM1_CH2为TRGO触发源:


TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC2Ref);  /*TIM1_OC2REF作为主模式TRGO输出*/

1

TIM8 模式设置、输出设置与TIM1相同,不贴代码了。

TIM8输入设置

/*********************************************

 *函数名:TIM8_IC_Config

 *函数描述:TIM8输入设置

 *输入参数:无

 *输出结果:无

 *返回值:无

***********************************************/

void TIM8_IC_Config(void)

{

    TIM_SelectSlaveMode(TIM8,TIM_SlaveMode_Reset);             /*从模式 复位模式*/

TIM_SelectInputTrigger (TIM8,TIM_TS_ITR0);                 /*触发源 TIM_TS_ITR0对应TIM1*/


}


设置完毕,调用即可

TIM1_Mode_Config();

TIM1_OC_Config();

TIM_Cmd(TIM1, ENABLE);                                   /* TIM1 counter enable */

TIM_CtrlPWMOutputs(TIM1, ENABLE);                        /* TIM1 Main Output Enable */

TIM8_Mode_Config();

TIM8_IC_Config();

TIM8_OC_Config();

TIM_Cmd(TIM8, ENABLE);                                   /* TIM8 counter enable */

TIM_CtrlPWMOutputs(TIM8, ENABLE);                        /* TIM8 Main Output Enable */


其他需要注意的地方


在其他程序段修改TIM1->CCR2的值时,可能会出现寄存器值修改了,但是实际输出却没有变化的情况。

因为我们将TIM1_CH2设置成了TIM_OCMode_Active,高逻辑有效。所以在得到高逻辑之后,无法自动回到低逻辑状态,所以需要干预一下。

事实上,我认为将TIM1_CH2设置成PWM1模式比较合适。但是没有调试没有成功,不知道原因。于是选择了这种办法。如下代码。在修改TIM1->CCR2之前将模式强制拉低,然后再改为TIM_OCMode_Active,这样就可以正常工作了。


TIM_ForcedOC2Config(TIM1,TIM_ForcedAction_InActive);

TIM_SelectOCxM(TIM1,TIM_Channel_2,TIM_OCMode_Active);

TIM_SetCompare2(TIM1,50);


while(TIM_GetFlagStatus(TIM8, TIM_FLAG_Trigger) == RESET);


Delay(3000);  

TIM_ForcedOC2Config(TIM1,TIM_ForcedAction_InActive);

TIM_SelectOCxM(TIM1,TIM_Channel_2,TIM_OCMode_Active);

TIM_SetCompare2(TIM1,400);

while(TIM_GetFlagStatus(TIM8, TIM_FLAG_Trigger) == RESET);


  Delay(3000);


关键字:STM32  TIM1  TIM8输  互补PWM 引用地址:利用STM32的TIM1/TIM8输出可以移相的互补PWM

上一篇:STM32之多通道AD使用DMA采集数据
下一篇:STM32调试,无法进入main函数 LDR r0,[pc,#0]

推荐阅读最新更新时间:2024-11-08 19:21

STM32串口实现485双机通信原理
RS485通信想必大家都知道,在学习RS232时,都会拿485(RS485下文就用485代替)和其作对比。485优缺点不说,网上有。 我用的是STM32库函数学的485通信,所以接下来就讲讲STM32串口实现485双机通信的原理: 485和232都是基于串口的通讯接口,在数据的收发操作上都是一致的。但是他两的通讯模式却大不相同~!232是全双工(例:A- B的同时B- A,瞬时同步)工作模式,而485是半双工(发时不能收,收时不能发)工作模式。在232通信中,主机在发送数据的同时可以收到从机发过来的数据;但在485通信中,收发要经过模式位的切换来进行,譬如发送数据时,会把模式为置‘1’,表示为发送模式,此时不能接收;当接收
[单片机]
<font color='red'>STM32</font>串口实现485双机通信原理
STM32库函数配置
stm32 固件库V3.0以上的版本,main等源文件中不再直接包含stm32f10x_conf.h,而是stm32f10x.h,stm32f10x.h则定义了启动设置,以及所有寄存器宏定义,此文件中需要注意的有: 使用V3.0以上版本固件库的方法如下: 1.选择device(配置函数STM32F10x.h,具体配置方法如下) 在STM32F10x.h中有如下代码: #if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (S
[单片机]
<font color='red'>STM32</font>库函数配置
STM32_TEST.axf: Error: L6218E: Undefi
STM32_TEST.axf: Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_md.o). 此问题错误提示已经十分清楚的告诉你错在哪里了,Undefined symbol SystemInit ,翻译过来就是:SystemInit 这个符号没有定义,随后的小括号告诉你了,是在startup_stm32f10x_md.o这个文件里面被提及的,这个.o文件在工程里面并没有,它是一个在编译的时候根据.c/.s文件生成的。所以我们只需要找到工程里面的.s或者.c即可,这里对应这个名字的就是startup_stm32f10x_
[单片机]
STM32 PWM输入捕获
STM32定时器具有PWM的输入捕获模式。PWM输入捕获是定时器输入捕获的一个特例,它专门用于测量PWM波的频率与占空比(芯片设计得还真人性化)。在上一篇博文中,我用输入捕获实现了输入PWM波的频率测量,而这一次,我用定时器的PWM输入捕获来测量PWM波的频率与占空比。他们的基本思路差不多,唯一区别的地方就是前者采用软件实现计数值的记录,而后者硬件直接记录计数值。如下图所示PWM输入捕获的时序: 上面说过PWM的输入捕获是硬件自动记录计数值,从上图就可知道:当检测到上升沿信号,硬件会自动清除计数值,然后当检测到下降沿时,就将当前定时器的计数值保存在IC2捕获寄存器中,当再次检测到一个上升沿信号时,则保存当前的计数值到IC1捕
[单片机]
<font color='red'>STM32</font> <font color='red'>PWM</font>输入捕获
STM32 Printf函数实现方法
今天调试了stm32f407的ADC,一切顺利,然而用串口发送ADC结果时都是16进制数,看着很不爽。于是打算用用牛B的 printf 函数,按照以前的做法,在main文件中添加了 stdio.h ,写好了 printf 函数,沏杯茶,打算边品茶边坐等结果,然而这一坐竟坐了半天也没见结果 。一调试发现程序停在了printf函数处,百思不得其解,百度之,得答案,不敢独享,分享如下: STM32串口通信中使用printf发送数据配置方法(开发环境 Keil RVMDK) 标签: STM32 串口通信 printf方法 2011-06-29 23:29 在STM32串口通信程序中使用printf发送数据,非常的方便。可在刚
[单片机]
<font color='red'>STM32</font> Printf函数实现方法
STM32自打包的UART串口通讯编程方法
在对通讯时间要求比较高的时候,就需要自己对UART的通讯底层直接进行操作。我以STM32单片机为例,讲一下比较快速的UART编程方法。——其实不止是STM32这么处理,我以前使用过51的单片机,TI的MSP单片机,三菱的16位单片机,都可以采用这种方法。 基本的处理思路如下: 1. UART接收的处理方法 打开UART的接收中断,每收到一个字节就放到接收缓冲区,同时更新接收指针。当连续100ms没有收到接收字符,则认为本次帧接收完毕,置位帧接收完成标志,由主程序进行处理。 2. UART发送的处理方法 将需要发送的数据放到发送缓冲区,设置发送长度。然后发送第一个字节,并打开发送中
[单片机]
STM32高级定时器之时钟源
1、定时器时钟源框图 从图片中可以看到定时器有4个时钟源, (1)内部时钟 ;(2) 外部时钟模式1,定时器的通道1、2 ; (3) 外部时钟模式模式2 ,ETR脚 ; (4)内部触发输入 下面分别介绍这几种时钟源的详细配置 2、内部时钟 寄存器SMCR的SMS选择000 3、外部时钟模式1 中文手册已经有以通道2为例子详细说明,这里我以通道1来说明,算是对它的温故和补充 3.1 滤波器设置,我的理解这里的滤波,比如我这里配置为0001,不是说通道来了N=2个脉冲才算这个输入有效,而是脉冲到来后,延时N/Fsampling的时间,还是高电平,就认为这个脉冲有效 类似按键检测的延时去抖动,如果理解
[单片机]
<font color='red'>STM32</font>高级定时器之时钟源
正点原子STM32 USB读卡器代码分析
USB读卡器的基本原理就是向主机提供SD读写功能,并不需要加入文件系统功能。 USB设备的实现步骤: 1、 初始化系统时钟,设置USB时钟 2、 配置USB中断,选择通道,设置优先级,使能中断 3、 配置GPIO 4、 USB的初始化,对描述符、设备的端点接口等的初始化 5、 FLASH的初始化 sd_size=(long long)SD_GetSectorCount()*512; //得到SD卡容量,字节. Mass_Memory_Size =sd_size%4294967296; //当SD卡容量超过4G的时候,需要用到两个u32来表示 Mass_Memory_Size
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved