0->ARR计数
信号的周期由ARR决定,和定时器时钟有关
CCRx决定占空比
OC有两个,一个OC正一个OC负。
比较然后控制输出。
PWM模式1和模式2
1: 在向上计数时,CNT<CCR1时通道1为有效电平,否则为无效电平
在向下计数时,CNT>CCR1时通道1为无效电平,否则为有效电平
2:相反
PWM模式
脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率,由TIMx_CRRx寄存器确定占空比的信号。
在TIM1_CCMRi寄存器中的OCiM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCi输出通道产生一路PWM。必须设置TIM1_CCMRi寄存器的OCiPE位使能相应的预装载寄存器,也可以设置TIM1_CR1寄存器的ARPE位使能自动重装载的预装载寄存器(在向上计数模式或中央对称模式中)。
由于仅当发生一个更新事件的时候,预装载寄存器才能被传送到影子寄存器,因此在计数器开始计数之前,必须通过设置TIM1_EGR寄存器的UG位来初始化所有的寄存器。
OCi的极性可以通过软件在TIM1_CCERi寄存器中的CCiP位设置,它可以设置为高电平有效或低电平有效。OCi的输出使能通过(TIM1_CCERi和TIM1_BKR寄存器中)CCiE、MOE、OISi和OSSR位和OSSI位的组合来控制。详见TIM1_CCERi寄存器的描述。
在PWM模式(模式1或模式2)下,TIM1_CNT和TIM1_CCRi始终在进行比较,(依据计数器的计数方向)以确定是否符合TIM1_CCRi≤TIM1_CNT或者TIM1_CNT≤TIM1_CCRi。
根据TIM1_CR1寄存器中CMS位域的状态,定时器能够产生边沿对齐的PWM信号或中央对齐的PWM信号。
关于使能预装载
使能预装载的意义在于可以多个通道同时输出时,时序能准确地同步。网上的一段有意义的解释是:设计preload register和shadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload register和shadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。可见如果只是单通道输出,多通道输出时没时序精准的同步更新要求,不使能也可以的。
所以这个实验只使用一个通道的话,完全可以不要这个预装载。
#include <stm32f2xx.h>
#include "SYSINIT.h"
/**
PWM输出实验
使用定时器1的PWM功能,
输出占空比可变的PWM波,用来驱动LED灯
从而达到LED PE14 亮度的变化
**/
vu16 Delay_ms(vu16 count);
int main(){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/**系统初始化**/
SYS_INIT();
//使能定时器时钟和IO口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE , ENABLE);
//PE14 和 TIM1_CH4复用
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);//GPIO口复用输出,输出TIM1_CH4的PWM波形
/**************IO口初始化*************************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; //PE14
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //模式设置位交替/复用的
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
/******************初始化定时器*********************/
//不分频。PWM频率=72000/(899+1)=80khz
//80kHz的PWM波
TIM_TimeBaseStructure.TIM_Period = 899; //设置在下一个更新事件装入活动的自动重转载寄存器周期
TIM_TimeBaseStructure.TIM_Prescaler =0; //设置涌来作为TIM1实在频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
//初始化定时器
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据参数初始化TIM1
//初始化通道4
/**
PWM模式2:向上计数时,CNT>CCR时为有效电平
输出极性为高:就是有效电平是高电平
**/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //定时器模式:TIM脉冲宽度调制PWM模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值 比较值 写CCRx
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 -> 输出有效极性为高
//TIM1通道4 TIM1_CH4 有四个通道这里是4
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
//CH4预装载使能 TIM_CCMRx寄存器OCxPE位 可以不要,这个实验只有一个通道
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
//使能TIM1在ARR上的预装在寄存器
//ARPE使能 ARPE=0 ARR立即生效 ,ARPE=1 ARR下个比较周期生效
TIM_ARRPreloadConfig(TIM1, ENABLE);
//TIM1是高级定时器
/**
普通定时器在完成以上设置了之后, 就可以输出 PWM 了,
但是高级定时器,我们还需要使能刹车和死区寄存器( TIM1_BDTR)的 MOE 位,
以使能整个 OCx(即 PWM)输出。
**/
//MOE 主输出使能
TIM_CtrlPWMOutputs(TIM1,ENABLE);
//使能TIM1
TIM_Cmd(TIM1, ENABLE);
/********************************************************************************/
u16 led0pwmval=0;
u8 dir=1;
while(1)
{
Delay_ms(5);
if(dir==1){
led0pwmval++;
}else{
led0pwmval--;
}
//原本让这个大于300导致暗不去,应该是大于周期的值了,后来重新设300又行了,迷惑
if(led0pwmval>200)
dir=0;
if(led0pwmval==0)
dir=1;
//通道4的比较值
//led0pwmval是输出高电平的时间
//这个值如果大于周期的值,将会与周期保持一致
TIM_SetCompare4(TIM1,led0pwmval); // 改变占空比
}
}
vu16 Delay_ms(vu16 Count)
{
u16 i=0;
while(Count--)
{
for(i=12000;i>0;i--);
}
return Count;
}