zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    主线程——main线程
    进程和线程概念及原理
    抓取网贷之家的数据爬虫
    感知哈希算法的java实现
    最短路径—Dijkstra算法和Floyd算法
    关于图像特征提取
    hive学习之WordCount单词统计
    pig、hive以及hbase的作用
    zookeeper入门知识
    hadoop文件系统浅析
  • 原文地址:https://www.cnblogs.com/rs232/p/4546934.html
Copyright © 2011-2022 走看看