Discuz! REAL TIME TECHNOLOGY

 找回密码
 立即注册
查看: 16991|回复: 7
打印 上一主题 下一主题

STM32通用定时器PWM输出

[复制链接]

405

主题

0

好友

6581

积分

内部组员

Rank: 8Rank: 8

活跃会员 论坛元老

跳转到指定楼层
楼主
发表于 2013-5-23 10:33:34 |只看该作者 |倒序浏览
STM32通用定时器(TIM2-5)PWM输出
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。一般用来控制步进电机的速度等等。STM32的定时器除了TIM6和TIM7之外,其他的定时器都可以用来产生PWM输出,其中高级定时器TIM1和TIM8可以同时产生7路的PWM输出,而通用定时器也能同时产生4路的PWM输出。
PWM输出模式
STM32的PWM输出有两种模式,模式1和模式2,由TIMx_CCMRx寄存器中的OCxM位确定的(“110”为模式1,“111”为模式2)。模式1和模式2的区别如下:
110:PWM模式1-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
111:PWM模式2-在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
由此看来,模式1和模式2正好互补,互为相反,所以在运用起来差别也并不太大。
而从计数模式上来看,PWM也和TIMx在作定时器时一样,也有向上计数模式、向下计数模式和中心对齐模式,关于3种模式的具体资料,可以查看《STM32参考手册》的“14.3.9 PWM模式”一节,在此就不详细赘述了。
PWM输出管脚
PWM的输出管脚是确定好的,具体的引脚功能可以查看《STM32参考手册》的“8.3.7 定时器复用功能重映射”一节。在此需要强调的是,不同的TIMx有分配不同的引脚,但是考虑到管脚复用功能,STM32提出了一个重映像的概念,就是说通过设置某一些相关的寄存器,来使得在其他非原始指定的管脚上也能输出PWM。但是这些重映像的管脚也是由参考手册给出的。比如说TIM3的第2个通道,在没有重映像的时候,指定的管脚是PA.7,如果设置部分重映像之后,TIM3_CH2的输出就被映射到PB.5上了,如果设置了完全重映像的话,TIM3_CH2的输出就被映射到PC.7上了。
PWM输出信号
PWM输出的是一个方波信号,信号的频率是由TIMx的时钟频率和TIMx_ARR预分频器所决定的,具体设置方法在前面一个学习笔记中有详细的交代。而输出信号的占空比则是由TIMx_CRRx寄存器确定的。其公式为“占空比=(TIMx_CRRx/TIMx_ARR)*100%”,因此,可以通过向CRR中填入适当的数来输出自己所需的频率和占空比的方波信号。
按以下步骤配置:
1. 设置RCC时钟;
2. 设置GPIO时钟;
3. 设置TIMx定时器的相关寄存器;
4. 设置TIMx定时器的PWM相关寄存器;
    第1步设置RCC时钟已经在前文中给出了详细的代码,在此就不再多说了。需要注意的是通用定时器TIMx是由APB1提供时钟,而GPIO则是由APB2提供时钟。注意,如果需要对PWM的输出进行重映像的话,还需要开启引脚复用时钟AFIO。
   第2步设置GPIO时钟时,GPIO模式应该设置为复用推挽输出GPIO_Mode_AF_PP,如果需要引脚重映像的话,则需要用GPIO_PinRemapConfig()函数进行设置。
   第3步设置TIMx定时器的相关寄存器时,和前一篇学习笔记一样,设置好相关的TIMx的时钟和技术模式等等。
   第4步设置PWM相关寄存器,首先要设置PWM模式(默认情况下PWM是冻结的),然后设置占空比(根据前面所述公式进行计算),再设置输出比较极性:当设置为High时,输出信号不反相,当设置为Low时,输出信号反相之后再输出。最重要是是要使能TIMx的输出状态和使能TIMx的PWM输出使能。相关设置完成之后,就可以通过TIM_Cmd()来打开TIMx定时器,从而得到PWM输出了。
以下是我写的参考程序:
void GPIO_PA_Init()
{//PA13管脚配置
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_DeInit(GPIOA);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP ;//复用推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);//使能端口时钟A
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void TIMER3_Init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_DeInit(TIM3);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseStructure.TIM_Period=10000-1;//ARR的值周期10K
TIM_TimeBaseStructure.TIM_Prescaler=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
}
void TIMER3_PWM_Init()
{  
TIM_OCInitTypeDef TIMOCInitStructure;
TIMOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM模式1输出
TIMOCInitStructure.TIM_Pulse =0;//占空比=(CCRx/ARR)*100%
TIMOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM输出比较极性高
TIMOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出状态
TIM_OC2Init(TIM3, &TIMOCInitStructure);//TIM3的CH2输出
TIM_CtrlPWMOutputs(TIM3,ENABLE);//设置TIM3的PWM输出为使能
TIM_Cmd(TIM3, ENABLE); //开启时钟
}
http://blog.sina.com.cn/s/blog_4a3946360100wh5w.html
回复

使用道具 举报

405

主题

0

好友

6581

积分

内部组员

Rank: 8Rank: 8

活跃会员 论坛元老

沙发
发表于 2013-5-23 10:42:55 |只看该作者
STM32 定时器产生PWM彻底应用

这次学习STM32花了很长时间,一个礼拜多,也有颇多收获,学习过程也有颇多曲折。这次的任务是:用STM32的一个定时器在四个通道上产生四路频率可调占空比可调的PWM波。
看到这个题,我先看STM32的数据手册,把STM32的定时器手册看完就花了一天,但是看了一遍任然不知道所云,就看库函数,略有点理解,就想一哈把这个程序调出来,于是就花了一天多时间仿照网上别人的程序来写,花了一天多写出来调试,结果行不通,做了无用功,于是静下心来想想,还是一步一步的来。
我先用STM32的通用定时器用PWM模式产生四路相同占空比,不同频率的PWM波,配置如下:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使能TIM2时钟
       TIM_InternalClockConfig(TIM2);//使用内部时钟
       TIM_BaseInitStructure.TIM_Prescaler=3; //设置TIM时钟频率除数的预分频值
      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数器模式
      TIM_BaseInitStructure.TIM_Period=1799;//设置下一个更新事件装入活动的自动重装载寄存器周期的值
      TIM_BaseInitStructure.TIM_ClockDivision=0;//设置时钟分割
       TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);
      
       //通道1
       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//选择定时器模式
      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//选择输出比较状态
      TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//选择互补输出比较状态
      TIM_OCInitStructure.TIM_Pulse=CCR1_Val;//设置了待装入捕获比较器的脉冲值
      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出极性
      TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//设置互补输出极性
      TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//选择空闲状态下得非工作状态
      TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//选择互补空闲状态下得非工作状态
       TIM_OC1Init(TIM2,&TIM_OCInitStructure);
       TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
       //通道2  
      TIM_OCInitStructure.TIM_Pulse=CCR2_Val;//设置了待装入捕获比较器的脉冲值
       TIM_OC2Init(TIM2,&TIM_OCInitStructure);
       TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);
       //通道3
       TIM_OCInitStructure.TIM_Pulse=CCR3_Val;//设置了待装入捕获比较器的脉冲值
       TIM_OC3Init(TIM2,&TIM_OCInitStructure);
       TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);
       //通道4
       TIM_OCInitStructure.TIM_Pulse=CCR4_Val;//设置了待装入捕获比较器的脉冲值
       TIM_OC4Init(TIM2,&TIM_OCInitStructure);
       TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);
       TIM_Cmd(TIM2, ENABLE);
       TIM_CtrlPWMOutputs(TIM2,ENABLE);
pwm模式输出的频率和占空比是固定的,不可调,要想输出频率可调,占空比可调,必须得使用比较输出模式。这点资料是在STM32全国巡回研讨会上看到的,如图:
所以,接下来我就写了一个程序通过输出比较模式产生一路PWM波,这个波的频率和占空比都由自己确定,函数配置如下:
       TIM_BaseInitStructure.TIM_Prescaler=3; //设置TIM时钟频率除数的预分频值(18M)
      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//选择计数器模式
      TIM_BaseInitStructure.TIM_Period=1800;//设置下一个更新事件装入活动的自动重装载寄存器周期的值
      TIM_BaseInitStructure.TIM_ClockDivision=0;//设置时钟分割
       TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);
       //通道1
       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;//选择定时器模式
      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//选择输出比较状态
      TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//选择互补输出比较状态
      TIM_OCInitStructure.TIM_Pulse=CCR1_Val1;//设置了待装入捕获比较器的脉冲值
      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出极性
      TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//设置互补输出极性
      TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//选择空闲状态下得非工作状态
      TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//选择互补空闲状态下得非工作状态
       TIM_OC1Init(TIM2,&TIM_OCInitStructure);
       TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
       TIM_ARRPreloadConfig(TIM2,ENABLE);
       TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE);
       TIM_Cmd(TIM2,ENABLE);
            
}
void TIM2_IRQHandler(void)
{
       TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
       if(n==1)
       {
              n=0;
              TIM_SetCompare1(TIM2,CCR1_Val2);
       }
       else
       {
              n=1;
             TIM_SetCompare1(TIM2,CCR1_Val1);
       }                                    
}
通过改变比较寄存器(CCR1)中的值,改变PWM的占空比,在每次匹配中断中改变CCR1的值。上面程序实现的是产生一路频率为10K占空比为40%PWM波。
有了上面的思想我就想产生四路不同频率不同占空比的PWM波,经过反复思考光配函数似乎不能实现,在网上去查了的,很多网友也说不能实现,有一个网友给了一个提示:软件模拟。刚开始没明白什么意思,于是还是自己继续配置库函数,在这个过程中一直有两个疑问:
每次中断中,CCR寄存器的值都在循环的增加,CCR的寄存器不可能是无限大吧?就算是无限大,计数器也不是无限大呀,他只能记到65535。初步确定使用匹配中断不行,我有想过同时使用溢出中断和匹配中断,但这样四路PWM波只能是固定的,频率和占空比不能调。大概说一下怎样用溢出中断和匹配中断实现四路固定的PWM波,把计数器寄存器(CNT)的值装最大周期的那个PWM波,当一次计数完成算一下三路小点周期数,在匹配中断中对应的设个变量,CCR就改变几次,溢出中断来了就再次给计数器装初值,同时四个比较寄存器从装初值,这样很麻烦,理论上可以实现,但我考虑到最终不能实现我的要求,就没有去验证。所以产生四路频率可调占空比可调,用一个定时器似乎不能实现,就一直卡到这里,我又在想飞哥说能实现,就肯定能实现,我又在网上找资料,还是没找到,只是有人题四路,软模拟,于是我就思考用软模拟实现,最后在一个师兄的指点下,确实用软件模拟一个中间比较寄存器能实现,思路大概是这样子的,首先让比较寄存器装满,也就是最大值(65535),然后通过改变模拟比较寄存器的值,每次匹配中断只需把模拟比较寄存器的值去比较就行,具体方案看程序。
unsigned char  Cnt[4]; //一个数组,这个数组的每个元素对应一个通道,用来判断装PWM得高电平还是低电平数
unsigned int  T[4];//周期数组
unsigned int  R[4];//模拟的比较寄存器数组,一样的每个通道对应一个数组元素
unsigned int  Rh[4];[url=]//[/url]模拟的PWM高电平比较寄存器
unsigned int  Rl[4]; //模拟的PWM低电平比较寄存器
unsigned char F[4];//占空比数组
unsigned int CCR1,CCR2,CCR3,CCR4;
void Init(void)
{
       unsigned char i = 0;      
       for(i = 0; i < 4; i++)
       {
              Cnt= 0;
              T  = 0;
              R  = 0;
              Rh = 0;
              Rl = 0;
              F  = 0;
       }   
       //t的范围为(0~65536   
       T[0] = 450;        //F=40K
       T[1] = 600;        //F=30K
       T[2] = 900;        //F=20K
       T[3] = 1800;   //F=10K
       //F(占空比)的范围为(0~100
       F[0] = 40;
       F[1] = 30;
       F[2] = 20;
       F[3] = 10;     
       for(i = 0; i < 4; i++)
       {
              Rh = (T * F) / 100;
              Rl = T - Rh;
       }   
       R[0] = Rl[0];
       R[1] = Rl[1];
       R[2] = Rl[2];
       R[3] = Rl[3];
      
       CCR1 = R[0];
       CCR2 = R[1];
       CCR3 = R[2];
       CCR4 = R[3];
}
对应的数组初始化
void RCC_Configuration(void)
{
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
}
时钟配置
void GPIO_Configuration(void)
{
       GPIO_InitTypeDef GPIO_InitStructure;
   //Key1 PA0 Key3 PA8
       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
       GPIO_Init(GPIOA,&GPIO_InitStructure);
       //Key2 PC13
       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
       GPIO_Init(GPIOC,&GPIO_InitStructure);
       //Key PD3
       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
       GPIO_Init(GPIOD,&GPIO_InitStructure);
       //TIM3 CH1 CH2
       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
       GPIO_Init(GPIOA,&GPIO_InitStructure);
       //TIM3 CH3 CH4
       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
       GPIO_Init(GPIOB,&GPIO_InitStructure);
}
管脚配置
void NVIC_Configuration(void)
{
       NVIC_InitTypeDef NVIC_InitStructure;
       #ifdef VECT_TAB_RAM
       NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
       #else
       NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
       #endif
       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
       NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQChannel;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
      NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
       NVIC_Init(&NVIC_InitStructure);     
}
中断配置
void TIM_Configuration(void)
{
       TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
       TIM_OCInitTypeDef TIM_OCInitStructure;
       TIM_InternalClockConfig(TIM3);
       TIM_BaseInitStructure.TIM_Prescaler=3;//4分频,18M
      TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
      TIM_BaseInitStructure.TIM_Period=65535;
      TIM_BaseInitStructure.TIM_ClockDivision=0;
      TIM_BaseInitStructure.TIM_RepetitionCounter=0;
       TIM_TimeBaseInit(TIM3,&TIM_BaseInitStructure);
       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
      TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse=CCR1;
      TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
       TIM_OC1Init(TIM3,&TIM_OCInitStructure);
       TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable);
       TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
       TIM_OCInitStructure.TIM_Pulse=CCR2;
       TIM_OC2Init(TIM3,&TIM_OCInitStructure);
       TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Disable);
       TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
     TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
       TIM_OCInitStructure.TIM_Pulse=CCR3;
       TIM_OC3Init(TIM3,&TIM_OCInitStructure);
       TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Disable);
       TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);
       TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;
       TIM_OCInitStructure.TIM_Pulse=CCR4;
       TIM_OC4Init(TIM3,&TIM_OCInitStructure);
       TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Disable);
       TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);
       TIM_Cmd(TIM3,ENABLE);
       TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
       TIM_ITConfig(TIM3,TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);
}
void TIM3_IRQHandler(void)
{
       if(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)
       {
              TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
              Cnt[0]=(~Cnt[0])&0x01;
              if(Cnt[0]==0x01)  
                     R[0]+=Rl[0];
              else
                     R[0] += Rh[0];
              if(R[0]>65535)
                     R[0]=R[0]-65535;
              CCR1=R[0];
              TIM_SetCompare1(TIM3,CCR1);
       }
       if(TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)
       {
              TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);
              Cnt[1]=(~Cnt[1])&0x01;
              if(Cnt[1]==0x01)  
                     R[1]+=Rl[1];
              else
                     R[1] += Rh[1];
              if(R[1]>65535)
                     R[1]=R[1]-65535;
              CCR2=R[1];
              TIM_SetCompare2(TIM3,CCR2);
       }   
       if(TIM_GetITStatus(TIM3,TIM_IT_CC3)!=RESET)
       {
              TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);
              Cnt[2]=(~Cnt[2])&0x01;
              if(Cnt[2]==0x01)  
                     R[2]+=Rl[2];
              else
                     R[2] += Rh[2];
              if(R[2]>65535)
                     R[2]=R[2]-65535;
              CCR3=R[2];
              TIM_SetCompare3(TIM3,CCR3);
       }   
       if(TIM_GetITStatus(TIM3,TIM_IT_CC4)!=RESET)
       {
              TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);
              Cnt[3] = (~Cnt[3])&0x01;
            
              if(Cnt[3]==0x01)  
                     R[3]+=Rl[3];
              else
                     R[3] += Rh[3];
              if(R[3]>65535)
                     R[3]=R[3]-65535;
              CCR4=R[3];
              TIM_SetCompare4(TIM3,CCR4);                     
       }
}
中断函数
其余就是按键扫描函数,通过改变周期数组中的值和占空比寄存器中的值就能改变PWM波的频率和占空比,当然按键可以设置为4个(一个按键对应一个通道),如果IO够用也可以设置8个,没两个按键对应一个通道分别改变频率和占空比。

http://home.eeworld.com.cn/my/space-uid-320111-blogid-55195.html
回复

使用道具 举报

405

主题

0

好友

6581

积分

内部组员

Rank: 8Rank: 8

活跃会员 论坛元老

板凳
发表于 2013-5-23 10:43:58 |只看该作者
Wjianw 发表于 2013-5-23 10:42
STM32 定时器产生PWM彻底应用

这次学习STM32花了很长时间,一个礼拜多,也有颇多收获,学习过程也有颇多曲 ...

STM32 PWM输出总结

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

44

主题

0

好友

4124

积分

内部组员

Rank: 8Rank: 8

地板
发表于 2013-6-5 15:34:06 |只看该作者
(1),附件中的工程是V1.5版的 TEC驱动程序。其中包含了PWM程序、呼吸灯程序,DS18B20程序、USART程序。具体功能可参照main.c文件中的“说明”。
(2),程序中,我自己编写的代码大部分都有注释。
(3),如果要在任意一台电脑上运行,必须装有 Keil uVision 4.0以上版本,同时参考附件中《本模板需要手动配置的.txt》进行配置,否则编译出错!
(4),如果想直接运行在STM32F107,那么直接在 V1.5 >>> PROJ >>> Object >>> TEC_Driver.hex 文件,烧录到Flash中,按下复位键即可运行。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

44

主题

0

好友

4124

积分

内部组员

Rank: 8Rank: 8

5#
发表于 2014-6-8 17:14:12 |只看该作者
现在使用TIM3来产生PWM波形,并通过软件打开/关闭PWM以实现调制波形。做法是:
打开:TIM_Cmd(TIM3, ENABLE);
关闭:TIM_Cmd(TIM3, DISABLE);
跟踪到TIM_Cmd之后,发现直接操作寄存器就可以了:TIMx->CR1 |= CR1_CEN_Set;
这个问题算解决了。
但是PWM关闭后,管脚电平是高电平,这不是我需要的……需要的是低电平。尝试关闭PWM后,加一行GPIO_ResetBits(GPIOC, GPIO_Pin_6);以把管脚设置为低电平。测试代码:
while(1)
{
       ENABLE_PWM();
        Delay_ms(10);//延时若干ms
        DISABLE_PWM();
        GPIO_ResetBits(GPIOC, GPIO_Pin_6);
        Delay_ms(10);//延时若干ms
}
用示波器观测了一下,发现PWM关闭期间管脚电平有时是高电平,有时是低电平……查找手册也没找到相关说法。用TIM_OC1Init()把TIM3重新配置一下倒是可以解决,但是速度太慢了。不知香水城有什么好办法没有?
回复

使用道具 举报

44

主题

0

好友

4124

积分

内部组员

Rank: 8Rank: 8

6#
发表于 2014-6-8 17:14:44 |只看该作者

“PWM关闭期间管脚电平有时是高电平,有时是低电平”,这是因为你关闭输出的时机不对。如果希望关闭PWM时,引脚为低,则应在PWM输出低时关闭;反之则在PWM输出高时关闭。

如果你使用的是PWM输出模式,每个周期都会有一个更新中断,可以在更新中断关闭PWM输出。

另一个办法是在关闭PWM输出时,设置寄存器转换至强制输出模式。
回复

使用道具 举报

44

主题

0

好友

4124

积分

内部组员

Rank: 8Rank: 8

7#
发表于 2014-6-8 17:15:10 |只看该作者

不错,通过TIM_ForcedOC1Config(TIM3, TIM_ForcedAction_InActive);强制输出低电平解决了,呵呵。
回复

使用道具 举报

44

主题

0

好友

4124

积分

内部组员

Rank: 8Rank: 8

8#
发表于 2014-6-8 17:15:41 |只看该作者
本帖最后由 DXiaoFei 于 2014-6-8 21:13 编辑

这是这个帖子:

http://bbs.21ic.com/icview-141333-1-1.html
和这个帖子:
http://hi.baidu.com/andyzhou502/item/19581657f7fcc63a33e0a92f
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

Archiver|手机版|Real Time Group

GMT+8, 2025-3-16 03:35 , Processed in 0.038043 second(s), 27 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部