STM32用一个定时器输出多路不同频率及占空比的PWM(输出比较

发布者:温暖梦想最新更新时间:2019-05-27 来源: eefocus关键字:STM32  定时器输出  频率  占空比  PWM 手机看文章 扫描二维码
随时随地手机看文章

我们使用STM32输出PWM时会使用定时器的PWM输出模式来进行生成,但是这样子生成PWM是有局限的,它只能生成四路频率相同的PWM,当你设定了TIMx_PSC(预分频寄存器)和TIMx_ARR(自动重装载寄存器),这时PWM的频率就被定下来了,为系统的时钟/TIMx_PSC+1/TIMx_ARR+1,你可以通过改变各个通道的CCR寄存器来改变占空比。但是如果我们想生成多路不同频率的PWM的话,使用这个方法只能使用多个定时器了,这样对于定时器资源较少的板子无疑是不可取的,在前几周准备蓝桥杯比赛的时候我发现了32定时器有一个输出比较的模式,可以生成多路不同频率及占空比的PWM。


    配置代码如下:


__IO u16 CCR1_Val=40;//72000000/36/40=50KHZ

__IO u16 CCR2_Val=20000;//72000000/36/20000=100HZ

float zhankong1=0.5;

float zhankong2=0.5;

u16 capture=0;

u8 pa6_state=0,pa7_state;

 

//比较输出PWM配置

void TIM3_PWM_Init2(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);//IO口配置

 

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);//TIM3中断配置

TIM_TimeBaseStructure.TIM_Period = 39999;

TIM_TimeBaseStructure.TIM_Prescaler = 35;

TIM_TimeBaseStructure.TIM_ClockDivision = 0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//定时器基本配置

/* Output Compare Toggle Mode configuration: Channel1 */

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;

TIM_OC1Init(TIM3, &TIM_OCInitStructure);//通道1设置为输出比较模式

 

TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);

 

/* Output Compare Toggle Mode configuration: Channel2 */

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

 

TIM_OC2Init(TIM3, &TIM_OCInitStructure);//通道2也设置为输出比较模式

 

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);//使能预装载

/* TIM enable counter */

TIM_Cmd(TIM3, ENABLE);//定时器3使能

/* TIM IT enable */

TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);//通道1、通道2中断使能

}

    定时器的中断服务函数:


void TIM3_IRQHandler(void)

{

  /* TIM3_CH1 toggling with frequency = 50KHz */

  if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );

    capture = TIM_GetCapture1(TIM3);

  if(pa6_state==0)

  {

  TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val *zhankong1 );

  pa6_state=1;

  }

  else

  {

  TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val *(1-zhankong1) );

  pa6_state=0;

  }

  }

 

  /* TIM3_CH2 toggling with frequency = 100 Hz */

  if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)

  {

    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);

    capture = TIM_GetCapture2(TIM3);

   if(pa7_state==0)

  {

  TIM_SetCompare2(TIM3, capture + (u16)CCR2_Val *zhankong2 );

  pa7_state=1;

  }

  else

  {

  TIM_SetCompare2(TIM3, capture + (u16)CCR2_Val *(1-zhankong2) );

  pa7_state=0;

  }

  }

}

    原理讲解:

        输出比较个人感觉原理还是有那么一点复杂的,可能我会讲的不太清楚,如果你看完以后有一点迷糊或者没有看懂,还是希望你可以仔细的阅读官方手册与代码,然后如果有问题或者有不同的看法欢迎留言


        首先关于我们配置了IO口,这个就是TIM3的通道1、通道2对应的IO口,分别是PA6和PA7


        接下来我们设置了定时器3的中断以及定时器的一些基本配置,比如预分频值、重加载值等,我们这里设置预分频值为35(实际会+1为36),重装载值为39999(实际会+1为40000)


        然后我们来配置通道1和通道2,配置为输出比较模式,使能输出,设置比较值为CCR1_Val,设置有效电平为低电平,同样通道2也是如此的配置


        最后我们使能预装载,使能定时器,使能中断


        接下来就到了输出比较模式的核心----中断服务函数了,中断服务函数中的处理是十分关键的,当有中断触发(CNT寄存器的值累加到了某个通道的比较值时),就会触发中断,根据中断的标志来判断是哪个通道触发了中断,紧接着它会查看当前CNT寄存器的值(使用TIM_GetCapturex函数),然后它判断现在是高电平还是低电平(这个是由有效电平控制,并有state标志位来判断),由此来设置新的比较值(使用TIM_SetComparex函数),这样就可以连续的生成固定频率固定占空比的PWM。


        有几个需要注意的点:因为CNT的值是从0计数到ARR寄存器值的,而我们每次会设置CCRx_Val这个值,所以说ARR寄存器的值最好是你每个通道CCRx_Val的公倍数,否则在每次重加载的时候波形会发生混乱。我们可以通过改变CCRx_Val来改变PWM的频率,通过改变zhankongx来改变PWM的占空比,这两个值是随时都可以修改的。


    总结:

       使用输出比较的方法可以在使用1个定时器的情况下有效的生成两路不同频率及占空比的PWM,它对比PWM输出模式的缺点肯定就是它会有中断的处理,如果生成的PWM频率较高时它会频繁的进入比较中断,这可能会给单片机带来较大的负担,但是在输出较低频率的PWM时,这种方法还是很好用的。



关键字:STM32  定时器输出  频率  占空比  PWM 引用地址:STM32用一个定时器输出多路不同频率及占空比的PWM(输出比较

上一篇:STM32输出可控数量与频率的脉冲
下一篇:STM32 ISP下载模式和JLINK下载模式

推荐阅读最新更新时间:2024-11-11 18:10

STM32时钟讲解(内部构架说明)
在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。 其实是四个时钟源,如下图所示(灰蓝色),PLL是由锁相环电路倍频得到PLL时钟。  ①、HSI是高速内部时钟,RC振荡器,频率为8MHz。  ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。  ③、LSI是低速内部时钟,RC振荡器,频率为40kHz。  ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。  ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 其中40kHz的LSI供独立看门狗IW
[单片机]
<font color='red'>STM32</font>时钟讲解(内部构架说明)
STM32—USART
前言: 最近在调试STM32L152芯片的USART配置程序,实现STM32串口打印功能,本文总结下STM32L152芯片USART的使用方法。 硬件平台:STM32L152 软件平台:keil v5+cubeMX 函数库:HAL库 1:usart初始化 UART_HandleTypeDef huart3; uint8_t rxbuf; void MX_USART3_UART_Init(void) { huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_8B;
[单片机]
实现输出两路频率1x、2x的方波
简介:本文是用STM32的一个定时器实现输出两路频率1x、2x的方波,本文详细介绍了程序并配有仿真图形。 /****************************************************************************************** * 函数名称 : TIM3_Configuration * 功能描述 : TIM3初始化函数 * 参数 : 无 * 返回值 : 无 * 全局变量 : 无 * 全局静态变量: 无 * 局部静态变量: 无 ***********************************************************************
[单片机]
实现<font color='red'>输出</font>两路<font color='red'>频率</font>1x、2x的方波
STM32 FSMC 外部使用SRAM
SRAM是什么: SRAM是英文Static RAM的缩写,中文名叫静态存储器,它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据。 目前SRAM的品牌主要有ISSI芯成、cypress赛普拉斯、来杨Lyontek、瑞萨renesas、VTI、JSC韩国济州半导体、NETSOL等多种品牌,分为同步SRA、异步SRAM、高速SRAM等各类存储器。 SRAM用来做什么: SRAM相当于单片机的“内存:,而内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。 内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的
[单片机]
<font color='red'>STM32</font> FSMC 外部使用SRAM
STM32 在 KEIL 下使用 SWV 输出调试信息
—— 使用STM32,个人认为 keil 还是首选 SWV 需要占用一个引脚 PB3/JTDO/TRACES WO 与 JTDO 复用,使用 SW 时,这一脚将被占用,作为 TRACES WO,一般常见仿真器直接支持 首先重写 fputc #include stdio.h int fputc(int c, FILE *f) { ITM_SendChar(c); return(c); } 就可以使用 printf 输出调试信息,但实际上我这么做失败了,初始化的时候不知道卡在了哪里,也不弄了,反正 ITM_SendChar 一样可以输出。 打开工程选项: - project - options for target - Debug 标
[单片机]
STM32 Systick定时器在实现1us延时时的问题与解决
问题: 使用systick_config()函数来实现计数,这个函数在下面代码中的 SysTick_CTRL_TICKINT_Msk 开启了中断。不论系统时钟为72Mhz或36Mhz若设置STM32每10us进入一次中断,计时是可以的;而每1us进入中断,由于中断指令较多,那么程序就会困在中断里出不来。 static __INLINE uint32_t SysTick_Config(uint32_t ticks) { if (ticks SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
[单片机]
AVR单片机ATmega16之初识PWM模式
书本上开篇关于这部分的描述是这样讲的:相对于一般的8位单片机而言,AVR不仅配备了更多的定时/计数器接口,而且还是增强型的例如通过定时/计数器与比较匹配寄存器相互配合,生成占空比可调的方波信号,即脉冲宽度调制输出的PWM信号,用于D/A转换,电机无极调速控制、变频控制等(这样一段书上的导语其实已经很好地概括了PWM的产生原理,和用途),下面说说具体的实现方式吧(都是以T/C0定时器为例来实现的)。按照我自己的粗略总结大致分为三大类(下面会逐条详细解释):1.CTC模式产生(50%占空比的方波信号) 2.快速PWM模式 3.相位可调PWM模式 (因为是初学如有不对,还望朋友们指正!!!) 先来看看这东西对应的输出引脚吧: (根据
[单片机]
AVR单片机ATmega16之初识<font color='red'>PWM</font>模式
STM32数据类型的定义
/* exact-width signed integer types */ typedef signed char int8_t; typedef signed short int int16_t; typedef signed int int32_t; typedef signed __int64 int64_t; /* exact-width unsigned integer types */ typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned in
[单片机]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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