STM32---------- PWM(Pulse Width Modulation,利用TIM定时器)
来源:互联网 发布:自学电吉他难吗 知乎 编辑:程序博客网 时间:2024/06/05 20:28
/* 配置系统时钟为72M */ SystemInit();
GPIO端口初始化:
/**************************************************************** * 函数名:void GPIO_Config(void) * 描述 :配置复用输出PWM时用到的I/O ***************************************************************/ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* GPIOA and GPIOB clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); /*GPIOA Configuration: TIM3 channel 1 and 2 as alternate function push-pull */ 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); }Timer初始化:
/**************************************************************** * 函数名:void TIM3_Config(void) * 描述 :配置TIM3输出的PWM信号的模式 * CH1:输出 T=2.5ms(f=1/2.5ms=400Hz) D=0.6的PWM波(高电平在前,低电平在后) * CH2:输出 T=2.5ms(f=1/2.5ms=400Hz) D=0.4的PWM波(高电平在后,低电平在前) * 步骤一:通过T和TIMxCLK的时钟源确定TIM_Period和TIM_Prescaler * T=(TIM_Period+1)*(TIM_Prescaler+1)/TIMxCLK=2.5ms * 因为 TIM_Period<65535,所以 TIM_Prescaler>1,即 TIM_Prescaler=2 * 所以 TIM_Period=59999=0xEA5F * 步骤二:根据TIM_Period的值,高低电平的先后D,确定CCR和TIM_OCPolarity * CH1:因为D=0.6,先高后低; * 所以CCR1=(TIM_Period+1)* D=36000;TIM_OCPolarity=TIM_OCPolarity_High * CH2:因为D=0.4,先高后低; * 所以CCR1=(TIM_Period+1)* (1-D)=36000;TIM_OCPolarity=TIM_OCPolarity_Low * 步骤三:基础寄存器初始化 * 步骤四:通道寄存器初始化 * 步骤五:使能TIM3重载寄存器ARR * 步骤六:使能TIM3 ***************************************************************/ void TIM3_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* PWM信号电平跳变值 */ u16 CCR1= 36000; u16 CCR2= 36000; /*PCLK1经过2倍频后作为TIM3的时钟源等于72MHz*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period =0xEA5F; TIM_TimeBaseStructure.TIM_Prescaler = 2; //设置预分频:预分频=2,即为72/3=24MHz TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分频系数:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数溢出模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* PWM1 Mode configuration: Channel1 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR1; //设置跳变值,当计数器计数到这个值时,电平发生跳变 TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High; //当定时器计数值小于CCR1时为高电平 TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能通道1 TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); /* PWM1 Mode configuration: Channel2 */ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR2; //设置通道2的电平跳变值,输出另外一个占空比的PWM TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //当定时器计数值小于CCR2时为低电平 TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能通道2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIM3重载寄存器ARR /* TIM3 enable counter */ TIM_Cmd(TIM3, ENABLE); //使能TIM3 }
主函数代码:
/*************************************************************** * 函数名:main * 描述 :主函数 ***************************************************************/ int main(void) { SystemInit(); GPIO_Config(); TIM3_Config(); while (1) { } }
1)TIM_TimeBaseInitTypeDef
时基初始化结构体,它包括了四个成员函数:TIM_ClockDivision、TIM_CounterMode、TIM_Period、TIM_Prescaler。比较重要的是TIM_Period成员,它控制的是定时周期。比如说将TIM_Period设置成999,则计数器会数1000个(TIM_Period+1)节拍为一个定时器的周期。这个和后面需要配置的TIM_Pulse共同控制着定时器输出波形的占空比。TIM_ClockDivision在参考手册中的定义是“Specifies the clock division”——指定时钟的分频。可见其是用来对时钟分频的,而TIM_Prescaler的定义是“Specifies the prescaler value used to divide the TIM clock”,用来指定TIM时钟的分频值。也就是说它是进一步来分频TIM clock的。TIM_CounterMode是计数器模式,分为向上、向下、中间计数三种。
2)TIM_OCInitTypeDef
输出通道(output channel)初始化结构体。该结构体主要配置TIM的工作模式。需要注意的是每一个定时器的4个通道分别对应一个初始化函数,也就是TIM_OCXInit(X=1,2,3,4)。总结其中几个重要的成员函数。
i)TIM_OCPolarity
定时器极性。它的参数为TIM_OCPolarity_High、TIM_OCPolarity_Low,用来设置定时器在未达到跳变 值时的电平(高低)。之所以重要是因为它也可以决定占空比,因为占空比的定义是高电平占周期的比例,如果顶一顶的有效电平不是高电平,那么实际占空比为(1-所观测的占空比)。
ii)TIM_Pulse
之前提到的定时器暂停。我更喜欢称他为定时器跳变,当计数器CNT中的值小于它的值时,输出为有效电平,即为之前配置的高电平,当达到跳变值时输出跳变(下跳)。它与TIM_Period共同决定了PWM波的占空比。占空比=( TIM_Pulse / ( TIM_Period + 1 ) ) * 100% 。比如我要产生一个50%的=PWM,只需要将TIM_Period设置成999,TIM_Pulse设置成500即可。在前半个周期计数器值达不到TIM_Pulse ,故一直输出高电平,当达到TIM_Pulse 时刻输出值下跳为低电平,然后再次计数半个周期。当这个周期走完时,ARR恰好溢出(其内装入的值为TIM_Period ),然后计数器清零,再次计数,重复上述过程,即产生了PWM波。
iii)TIM_OutputState
输出状态。它的参数是ENABLE和DISABLE,它之所以重要不是因为它配置占空比或者周期,而是每次初始化一个通道时这个成员函数都要重新填写。我们知道在填写结构体时,当我填好了第一个结构体并且将其应用了,下次再填写时只需要修改与上一次配置不同的成员函数,其他保持不变即可,因为结构体若不修改会一直保存。也就是说当我们配置4个通道时。很多成员都不需要重复填写,但是这个成员函数确实每次必须填写的,暂时不知道为什么。
3)TIM_OC1PreloadConfig
在我们初始化完了OCX之后,别忘了配置OCX的预装载寄存器,将其使能即可。
4)TIM_ARRPreloadConfig
配置完了所有通道后使能自动重装载寄存器。
最后不要忘了Cmd该外设,这是所有外设操作的最后一步,也是很重要的步骤,容易遗漏。
另外,在仿真调试时遇到的一个问题是在setup一个波形发生器时对于信号的选择出了问题。归纳一下选择的步骤。以GPIOA_Pin6为例,首先选择PORTA,代表的是A组的GPIO,而不是别的组。然后选择Mask为0x00000040,代表了GPIO_Pin_6,查stm32f10x_gpio.h可知"#define GPIO_Pin_6 ((uint16_t)0x0040)
",这一步是找到Pin6,然后关键的一步是Shift Right 设置为6,这个项目的设置就是Pin_x中的x。设置错误的话还是找不到PA6引脚,这一点要注意。
0 0
- STM32---------- PWM(Pulse Width Modulation,利用TIM定时器)
- Pulse Width Modulation (PWM)
- PWM(Pulse Width Modulation)调试原理
- 脉冲宽度调制(Pulse Width Modulation) PWM简介
- Introduction to Pulse Width Modulation (PWM)
- Pulse Width Modulation
- STM32自学系列——2.定时器TIM和PWM的输出
- STM32定时器(TIM)概论
- stm32 PWM & 定时器总结
- STM32定时器PWM输出
- TIM通用定时器:PWM输入捕获模式
- 定时器TIM和PWM的输出
- 利用STM32的定时器输出PWM(1)
- STM32定时器(TIM)之通用定时器
- stm32篇--定时器和PWM
- STM32通用定时器的PWM
- stm32的定时器和PWM
- stm32 定时器pwm输入捕获
- Web基础系列三、JavaScript(页面行为)
- 如何查看mac系统是32位还是64位的操作系统
- ubuntu中apache的配置
- 为什么long和int都是四个字节?
- R语言包在linux上的安装、卸载
- STM32---------- PWM(Pulse Width Modulation,利用TIM定时器)
- pn532中遇到的坑-----Mifare1 Card(一)
- NS2.35下编写协议trace文件出错原因分析
- dede站点空间转移搬家后,数据库要怎么连接?
- highcharts 阶梯图表并填充颜色(自己认为:直角折线图表)
- Facebook Hacker Cup 2016 Round 1 Boomerang Tournament
- iOS Provisioning Profile(Certificate)与Code Signing详解
- jquery 方法收集(slideToggle,toggleClass,wrap)
- Nginx