STM32定时器输出多路可调频率方波实现细节记录

最近有个项目要用到多达16路的可调频率的方波,于是想到用stm32的定时器输出比较翻转模式(TIM_OCMode_Toggle),一个定时器可以产生4路的信号输出。仔细阅读手册,并且参考了官方的例程,大体过程实现过程是:打开一个TIMx计数器,再打开TIMx的一路或几路输出比较器(共4路),都配置好以后,计数器开始计数,当计数器里的值和比较寄存器里的值相等时,产生输出比较中断,在中断中将计数器中的值读出,与翻转周期相加再写道比较寄存器中。

先以timer3为例,上代码:

TIM3配置部分:

  1 /******************** (C) COPYRIGHT 2015**************************
  2  * ÎļþÃû  £ºhal_TIM.c
  3  * ÃèÊö    £º         
  4  * ʵÑéƽ̨£ºTHE ONE 103 
  5  * Ó²¼þÁ¬½Ó£º---------------------
  6  *          |  PA.06: (TIM3_CH1)  |
  7  *          |  PA.07: (TIM3_CH2)  |
  8  *          |  PB.00: (TIM3_CH3)  | 
  9  *            |  PB.01: (TIM3_CH4)  |
 10  *           ---------------------                
 11  * ¿â°æ±¾  £ºST3.5.0
 12  * ×÷Õß    £º´ú¾°¾©
 13 **********************************************************************************/
 14 #include "hal_TIM.h"
 15 
 16 /* ƵÂʱ仯ȫ¾Ö±äÁ¿ */
 17 uint16_t CCR1_Val = 0x8000;        
 18 uint16_t CCR2_Val = 0x4000;
 19 uint16_t CCR3_Val = 0x2000;
 20 uint16_t CCR4_Val = 0x1000;
 21 
 22 
 23 /*
 24  * º¯ÊýÃû£ºTIM3_GPIO_Config
 25  * ÃèÊö  £ºÅäÖÃTIM3¸´ÓÃÊä³öPWMʱÓõ½µÄI/O
 26  * ÊäÈë  £ºÎÞ
 27  * Êä³ö  £ºÎÞ
 28  * µ÷Óà  £ºÄÚ²¿µ÷ÓÃ
 29  */
 30 static void TIM3_GPIO_Config(void) 
 31 {
 32   GPIO_InitTypeDef GPIO_InitStructure;
 33 
 34     /* TIM3 clock enable */
 35     //PCLK1¾­¹ý2±¶Æµºó×÷ΪTIM3µÄʱÖÓÔ´µÈÓÚ72MHz
 36   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 
 37 
 38   /* GPIOA and GPIOB clock enable */
 39   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); 
 40 
 41   /*GPIOA Configuration: TIM3 channel 1 and 2 as alternate function push-pull */
 42   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
 43   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;            // ¸´ÓÃÍÆÍìÊä³ö
 44   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 45 
 46   GPIO_Init(GPIOA, &GPIO_InitStructure);
 47 
 48   /*GPIOB Configuration: TIM3 channel 3 and 4 as alternate function push-pull */
 49   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 | GPIO_Pin_1;
 50 
 51   GPIO_Init(GPIOB, &GPIO_InitStructure);
 52 }
 53 
 54 /*
 55  * º¯ÊýÃû£ºTIM3_Mode_Config
 56  * ÃèÊö  £ºÅäÖÃTIM3Êä³öµÄÐźŵÄģʽ
 57  * ÊäÈë  £ºÎÞ
 58  * Êä³ö  £ºÎÞ
 59  * µ÷Óà  £ºÄÚ²¿µ÷ÓÃ
 60  */
 61 static void TIM3_Mode_Config(void)
 62 {
 63     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
 64     TIM_OCInitTypeDef  TIM_OCInitStructure;
 65 
 66   /* Time base configuration */         
 67   TIM_TimeBaseStructure.TIM_Period = 65535;      
 68   TIM_TimeBaseStructure.TIM_Prescaler = 2;        //ÉèÖÃÔ¤·ÖƵ£º²»Ô¤·ÖƵ£¬¼´Îª72MHz
 69   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;    //ÉèÖÃʱÖÓ·ÖƵϵÊý£º²»·ÖƵ
 70   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //ÏòÉϼÆÊýģʽ
 71   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
 72 
 73   /* PWM1 Mode configuration: Channel1 */
 74   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;        //ÅäÖÃΪ±È½ÏÊä³öģʽ·­×ªÄ£Ê½
 75     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //µ±¶¨Ê±Æ÷¼ÆÊýֵСÓÚCCR1_ValʱΪµÍµçƽ
 76     
 77     //ʹÄܱȽÏÊä³ö·­×ªÄ£Ê½Í¨µÀ1
 78   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    
 79   TIM_OCInitStructure.TIM_Pulse = CCR1_Val;       //ÉèÖÃÌø±äÖµ£¬µ±¼ÆÊýÆ÷¼ÆÊýµ½Õâ¸öֵʱ£¬µçƽ·¢ÉúÌø±ä
 80   TIM_OC1Init(TIM3, &TIM_OCInitStructure);     //ʹÄÜͨµÀ1
 81   TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
 82 
 83     //ʹÄܱȽÏÊä³ö·­×ªÄ£Ê½Í¨µÀ2
 84   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
 85   TIM_OCInitStructure.TIM_Pulse = CCR2_Val;      //ÉèÖÃͨµÀ2µÄµçƽÌø±äÖµ£¬Êä³öÁíÍâÒ»¸öÕ¼¿Õ±ÈµÄPWM
 86   TIM_OC2Init(TIM3, &TIM_OCInitStructure);      //ʹÄÜͨµÀ2
 87   TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);
 88     
 89     //ʹÄܱȽÏÊä³ö·­×ªÄ£Ê½Í¨µÀ3
 90     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
 91   TIM_OCInitStructure.TIM_Pulse = CCR3_Val;    //ÉèÖÃͨµÀ3µÄµçƽÌø±äÖµ£¬Êä³öÁíÍâÒ»¸öÕ¼¿Õ±ÈµÄPWM
 92   TIM_OC3Init(TIM3, &TIM_OCInitStructure);     //ʹÄÜͨµÀ3
 93     TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);
 94 
 95     //ʹÄܱȽÏÊä³ö·­×ªÄ£Ê½Í¨µÀ4
 96   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
 97   TIM_OCInitStructure.TIM_Pulse = CCR4_Val;    //ÉèÖÃͨµÀ4µÄµçƽÌø±äÖµ£¬Êä³öÁíÍâÒ»¸öÕ¼¿Õ±ÈµÄPWM
 98   TIM_OC4Init(TIM3, &TIM_OCInitStructure);    //ʹÄÜͨµÀ4
 99   TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);
100 
101   TIM_ARRPreloadConfig(TIM3, ENABLE);             // ʹÄÜTIM3ÖØÔؼĴæÆ÷ARR
102 
103   /* TIM3 enable counter */
104   TIM_Cmd(TIM3, ENABLE);                   //ʹÄܶ¨Ê±Æ÷3
105     TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
106 }
107 
108 /*********************************************************************
109   * @brief  Initialize the NCIC
110     * @param  None
111   * @retval None   
112     * @date   20141205
113 ***********************************************************************/
114 void TIM_NVIC_Configuration(void)
115 {
116     NVIC_InitTypeDef NVIC_InitStructure;
117     
118     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
119 
120   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
121   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
122   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
123   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
124   NVIC_Init(&NVIC_InitStructure);        
125 }
126 
127 
128 /*
129  * º¯ÊýÃû£ºTIM3_PWM_Init
130  * ÃèÊö  £ºTIM3 Êä³öPWMÐźųõʼ»¯£¬Ö»Òªµ÷ÓÃÕâ¸öº¯Êý
131  *         TIM3µÄËĸöͨµÀ¾Í»áÓÐPWMÐźÅÊä³ö
132  * ÊäÈë  £ºÎÞ
133  * Êä³ö  £ºÎÞ
134  * µ÷Óà  £ºÍⲿµ÷ÓÃ
135  */
136 void TIM3_PWM_Init(void)
137 {
138     TIM3_GPIO_Config();
139     TIM3_Mode_Config();
140     TIM_NVIC_Configuration();    
141 }
142 
143 /******************* (C) COPYRIGHT 2015 *****END OF FILE************/

 

TIM3中断里面更新CCRx的值:

 1 extern uint16_t CCR1_Val;
 2 extern uint16_t CCR2_Val;
 3 extern uint16_t CCR3_Val;
 4 extern uint16_t CCR4_Val;
 5 /******************************************************************************/
 6 /*                                                                            */
 7 /*             ¶¨Ê±Æ÷3ÖжϷþÎñ³ÌÐò                                            */
 8 /******************************************************************************/
 9 void TIM3_IRQHandler(void)                   
10 {
11     u16 capture;
12     
13     if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)  //¼ì²éTIM3¸üÐÂÖжϷ¢ÉúÓë·ñ
14     {
15         TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );
16         capture = TIM_GetCapture1(TIM3);
17 //        capture = TIM_GetCounter(TIM3);
18         TIM_SetCompare1(TIM3, capture + CCR1_Val );
19     }
20     
21     if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)  //¼ì²éTIM3¸üÐÂÖжϷ¢ÉúÓë·ñ
22     {
23         TIM_ClearITPendingBit(TIM3, TIM_IT_CC2 );
24         capture = TIM_GetCapture2(TIM3);
25 //        capture = TIM_GetCounter(TIM3);
26         TIM_SetCompare2(TIM3, capture+CCR2_Val );
27     }
28     
29     if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)  //¼ì²éTIM3¸üÐÂÖжϷ¢ÉúÓë·ñ
30     {
31         TIM_ClearITPendingBit(TIM3, TIM_IT_CC3 );
32         capture = TIM_GetCapture3(TIM3);
33 //        capture = TIM_GetCounter(TIM3);
34         TIM_SetCompare3(TIM3, capture + CCR3_Val );
35     }
36     
37     if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET)  //¼ì²éTIM3¸üÐÂÖжϷ¢ÉúÓë·ñ
38     {
39         TIM_ClearITPendingBit(TIM3, TIM_IT_CC4 );
40         capture = TIM_GetCapture4(TIM3);
41 //        capture = TIM_GetCounter(TIM3);
42         TIM_SetCompare4(TIM3, capture + CCR4_Val );
43     }
44     
45 }  

 

设置每个通道在输出比较匹配时产生中断,在中断中将比较寄存器的数值读出并加上新设置的数值,如果计算出的数值超过16位则舍弃超出的部分,再把这个新的数值写回相应的比较寄存器;这样下次比较成功将刚好发生在一个半波周期之后,对应的管脚将被翻转。

为什么还要加上上次的比较寄存器的值,这样岂不是每次的比较寄存器的值都不一样啊?直接设置最新的比较寄存器的值不行吗?当然不行,因为输出比较器比较的是当前的值与CNT的值,而不是比较的是CNT计数的个数。是绝对值,而不是相对值!计数器(CNT)的值一直是累加的,上面程序中设置的自动装载的值是65535,这样的目的是让计数器循环的进行累加,从而CCRx的值永远小于等于CNT,使输出比较寄存器匹配时,CNT的值不会是中间从0开始计数的,这样保证了方波占空比是固定的50%。当输出比较匹配时,进入中断,产生信号翻转,同时给CCRx赋新值,但是CNT此时有可能不是从0开始计数,所以必须把之前的CCRx中的值读出来。加上新设置的值然后再赋给CCRx。

posted on 2015-06-02 16:43  代景京  阅读(909)  评论(0编辑  收藏  举报

导航