[STM32F0] STM32定时器输出带有死区时间的PWM波形

[复制链接]
4491|7
 楼主| neeringstu 发表于 2016-11-17 20:11 | 显示全部楼层 |阅读模式
本帖最后由 neeringstu 于 2016-11-17 20:14 编辑

要求得到下列波形,死区时间为1us,CH1,CH2,CH3之间的相位差为3us,频率为50KHz



main.c
  1. /*********************************************
  2.     标题:定时器输出带有死区时间的PWM波形
  3.     软件平台:MDK-ARM Standard Version4.70
  4.     硬件平台:stm32f4-discovery   
  5.     主频:168M
  6.     Periph_Driver_version: V1.0.0
  7.    
  8.     描述:用一个定时器(TIM1),输出带有死区时间的PWM波形,要求:死区时间为1us,CH1,CH2,CH3之间的相位差为3us,频率为50KHz
  9.           代码参考自STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples\TIM_ComplementarySignals

  10.     author:大舟
  11.     data:2013-04-15
  12. **********************************************/


  13. #include "stm32f4_discovery.h"


  14. TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  15. TIM_OCInitTypeDef  TIM_OCInitStructure;
  16. TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
  17. uint16_t TimerPeriod = 0;
  18. uint16_t Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0;

  19. /* Private function prototypes */
  20. void TIM_Config(void);


  21. int main(void)
  22. {
  23.     /*!< At this stage the microcontroller clock setting is already configured,
  24.     this is done through SystemInit() function which is called from startup
  25.     file (startup_stm32f4xx.s) before to branch to application main.
  26.     To reconfigure the default setting of SystemInit() function, refer to
  27.     system_stm32f4xx.c file
  28.     */

  29.     /* TIM1 Configuration */
  30.     TIM_Config();

  31.     /* -----------------------------------------------------------------------
  32.     1/ Generate 3 complementary PWM signals with 3 different duty cycles:

  33.     In this example TIM1 input clock (TIM1CLK) is set to 2 * APB2 clock (PCLK2),
  34.     since APB2 prescaler is different from 1 (APB2 Prescaler = 2, see system_stm32f4xx.c file).
  35.     TIM1CLK = 2 * PCLK2
  36.     PCLK2 = HCLK / 2
  37.     => TIM1CLK = 2*(HCLK / 2) = HCLK = SystemCoreClock

  38.     To get TIM1 counter clock at 168 MHz, the prescaler is computed as follows:
  39.     Prescaler = (TIM1CLK / TIM1 counter clock) - 1
  40.     Prescaler = (SystemCoreClock / 168 MHz) - 1 = 0

  41.     The objective is to generate PWM signal at 17.57 KHz:
  42.     - TIM1_Period = (SystemCoreClock / 17570) - 1

  43.     To get TIM1 output clock at 17.57 KHz, the period (ARR) is computed as follows:
  44.     ARR = (TIM1 counter clock / TIM1 output clock) - 1 = 9561
  45.    

  46.     The Three Duty cycles are computed as the following description:

  47.     TIM1 Channel1 duty cycle = (TIM1_CCR1/ TIM1_ARR)* 100 = 50%
  48.     TIM1 Channel2 duty cycle = (TIM1_CCR2/ TIM1_ARR)* 100 = 25%
  49.     TIM1 Channel3 duty cycle = (TIM1_CCR3/ TIM1_ARR)* 100 = 12.5%

  50.     The Timer pulse is calculated as follows:
  51.     - TIM1_CCRx = (DutyCycle * TIM1_ARR)/ 100

  52.     2/ Insert a dead time equal to (11/SystemCoreClock) ns    //这句不对,示波器里观测也不对,不是这样算的。
  53.    
  54.     正确的deadtime的计算方法(经理论与示波器测试成功)
  55.     TIM_BDTRInitStructure.TIM_DeadTime=255 //这句设定的就是寄存器TIMx_BDTR的后8位,即DTG[7:0],所以最大值为255
  56.     从下面的代码中的“第五步”中,实际上就相当于TIM1->BDTR=0x71FF;
  57.    
  58.     查看"STM32中文参考手册2009.pdf"的TIMx_BDTR(第248页),列寄存器TIMx_BDTR的后8位如下:
  59.     位7:0    UTG[7:0]: 死区发生器设置 (Dead-time generator setup)
  60.             这些位定义了插入互补输出之间的死区持续时间。假设DT表示其持续时间:
  61.             DTG[7:5]=0xx => DT=DTG[7:0] × Tdtg,        Tdtg = Tdts;
  62.             DTG[7:5]=10x => DT=(64+DTG[5:0]) × Tdtg,    Tdtg = 2 × Tdts;
  63.             DTG[7:5]=110 => DT=(32+DTG[4:0]) × Tdtg,    Tdtg = 8 × Tdts;
  64.             DTG[7:5]=111 => DT=(32+DTG[4:0]) × Tdtg,    Tdtg = 16× Tdts;
  65.             
  66.             例:若Tdts = 1/168us(频率为168M),可能的死区时间DT为:
  67.             0到756ns,        若步长时间Tdtg为1/168us;
  68.             762ns到1512ns,    若步长时间Tdtg为2/168us;
  69.             1524ns到3us,    若步长时间Tdtg为8/168us;
  70.             3048ns到6us,    若步长时间Tdtg为16/168us;
  71.    
  72.     计算
  73.     这里要求设置deadtime为1us,落在区间"762ns到1512ns",所以选择公式“DTG[7:5]=10x => DT=(64+DTG[5:0])×Tdtg,Tdtg=2×Tdts;”
  74.     列方程:(64+x)×2/168us = 1us;得x=20。所以DTG[5:0]=010100;推出DTG[7:0]=10010100=0x94。所以TIM_DeadTime=0x94。
  75.    
  76.    
  77.     3/ Configure the break feature, active at High level, and using the automatic
  78.     output enable feature

  79.     4/ Use the Locking parameters level1.

  80.     5/     这里要求3个通道的波形不是对齐的,所以必须设定为TIM_OCMode_Toggle模式,这样,ARR得走两趟才是一个周期,
  81.         CCR1(TIM_Pulse)、CCR2、CCR3不同,则触发的点也不同,即错开了相位。
  82.         注意,不管TIM_Pulse为什么值,占空比都是50%。因为ARR走一趟才取反一次。
  83.    
  84.     6/    要求pwm输出频率为50KHz。所以ARR=(SystemCoreClock/100000)-1 = 1679。即对时钟进行1680分频。
  85.    
  86.     7/    PWM1和PWM2的相位差为3us。计算如下
  87.         因为ARR自加1的时间为(1/168M)s,即可列方程:(1/168M)x=3us,得x=504。
  88.         即,CCR1、CCR2、CCR3之间相隔504时,PWM的相位差就为3us
  89.         
  90.     Note:
  91.     SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file.
  92.     Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate()
  93.     function to update SystemCoreClock variable value. Otherwise, any configuration
  94.     based on this variable will be incorrect.
  95.     ----------------------------------------------------------------------- */

  96.     /* Compute the value to be set in ARR register to generate signal frequency at 17.57 Khz */
  97.     TimerPeriod = (SystemCoreClock / 100000) - 1;    //1679;17570 ARR=9561

  98.     /* Compute CCR1 value to generate a duty cycle at 50% for channel 1 */
  99.     Channel1Pulse = 100;//= (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);//CCR1_Val=4780,比较值

  100.     /* Compute CCR2 value to generate a duty cycle at 25%  for channel 2 */
  101.     Channel2Pulse = 604;// = (uint16_t) (((uint32_t) 25 * (TimerPeriod - 1)) / 100);//CCR2_Val=2390,比较值

  102.     /* Compute CCR3 value to generate a duty cycle at 12.5%  for channel 3 */
  103.     Channel3Pulse = 1108;// = (uint16_t) (((uint32_t) 125 * (TimerPeriod - 1)) / 1000);//CCR3_Val=1195,比较值

  104.     /**@step第一步配置时钟*/
  105.     /**@step第二步配置goio口*/
  106.     /**@step第三步定时器基本配置*/
  107.     /* Time Base configuration */
  108.     TIM_TimeBaseStructure.TIM_Prescaler = 0;//时钟预分频数,对168M进行1(0+1)分频
  109.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
  110.     TIM_TimeBaseStructure.TIM_Period = TimerPeriod;//自动重装载寄存器的值,ARR=9561
  111.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;    //采样分频
  112.     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//重复寄存器,用于自动更新pwm占空比

  113.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  114.     /**@step第四步 PWM输出配置*/
  115.     /* Channel 1, 2 and 3 Configuration in PWM mode */
  116.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;                //PWM1为正常占空比模式,PWM2为反极性模式
  117.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;        //High为占空比高极性,此时占空比为20%;Low则为反极性,占空比为80%
  118.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //使能该通道输出
  119.     TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;    //设置占空比时间,CCR1_Val=4780,占空比为4780/(9561+1)=0.5
  120.    
  121.     //-------下面几个参数是高级定时器才会用到通用定时器不用配置
  122.     TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;    //使能互补端输出
  123.     TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;        //设置互补端输出极性
  124.     TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;    //刹车之后输出状态Specifies the TIM Output Compare pin state during Idle state
  125.     TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;    //刹车之后互补端输出状态
  126.     //-------
  127.     TIM_OC1Init(TIM1, &TIM_OCInitStructure);//对channel1进行配置
  128.    
  129.     TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;//CCR2_Val=2390,比较值
  130.     TIM_OC2Init(TIM1, &TIM_OCInitStructure);//对channel2进行配置
  131.     TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;//CCR3_Val=1195,比较值
  132.     TIM_OC3Init(TIM1, &TIM_OCInitStructure);//对channel3进行配置

  133.     /**@step第五步死区和刹车功能配置,高级定时器才有的,通用定时器不用配置*/
  134.     /* Automatic Output enable, Break, dead time and lock configuration*/
  135.     TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;                //运行模式下输出
  136.     TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;                //空闲模式下输出选择
  137.     TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;                    //锁定设置,锁定级别1
  138.     TIM_BDTRInitStructure.TIM_DeadTime = 0x94;//死区时间1us
  139.     TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;                    //刹车功能使能
  140.     TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;        //刹车输入极性,即刹车控制引脚接GND时,PWM停止
  141.     TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;    //自动输出使能
  142.     TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
  143.     /*    刹车控制引脚为TIM1_BKIN pin(PB.12),将PB12接GND,channel和其互补通道,都变为刹车后的电平,具体为0还是1,要看如下两个设置:
  144.         .TIM_OCIdleState = TIM_OCIdleState_Reset;    //刹车之后,PWM通道变为0
  145.         .TIM_OCNIdleState = TIM_OCNIdleState_Reset;    //刹车之后,PWM互补通道变为0
  146.         
  147.         注意:如果没必要,还是不要开启刹车功能,因为会对PWM产生影响,特别是当PB12悬空时,波形将会有很大的波动。
  148.               这里不打开刹车功能,即.TIM_Break = TIM_Break_Disable;
  149.     */
  150.    
  151.     /**@step第六步使能端的打开*/
  152.     /* TIM1 counter enable */
  153.     TIM_Cmd(TIM1, ENABLE);//打开TIM1

  154.     /* Main Output Enable */
  155.     TIM_CtrlPWMOutputs(TIM1, ENABLE);//PWM输出使能,一定要记得打

  156.     while (1);
  157. }

  158. /**
  159. * [url=home.php?mod=space&uid=247401]@brief[/url]  Configure the TIM1 Pins.
  160. * @param  None
  161. * @retval None
  162. */
  163. void TIM_Config(void)
  164. {
  165.     GPIO_InitTypeDef GPIO_InitStructure;

  166.     /* GPIOA and GPIOB clocks enable */
  167.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOE, ENABLE);

  168.     /* TIM1 clock enable */
  169.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

  170.     /* GPIOA Configuration: Channel 1 and 3 as alternate function push-pull */
  171.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_10;
  172.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  173.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  174.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  175.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  176.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  177.     /* GPIOA Configuration: Channel 2 as alternate function push-pull */
  178.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  179.     GPIO_Init(GPIOE, &GPIO_InitStructure);

  180.     /* GPIOB Configuration: BKIN, Channel 1N, 2N and 3N as alternate function push-pull */
  181.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  182.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  183.     /* Connect TIM pins to AF1 */
  184.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);    //引脚功能,查看readme.txt
  185.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1);
  186.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_TIM1);
  187.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_TIM1);
  188.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_TIM1);
  189.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);
  190.     GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_TIM1);
  191. }
  192. /**@end*/



 楼主| neeringstu 发表于 2016-11-17 20:14 | 显示全部楼层
  1. #ifdef  USE_FULL_ASSERT
  2. /**
  3. * @brief  Reports the name of the source file and the source line number
  4. *         where the assert_param error has occurred.
  5. * @param  file: pointer to the source file name
  6. * @param  line: assert_param error line source number
  7. * @retval None
  8. */
  9. void assert_failed(uint8_t* file, uint32_t line)
  10. {
  11.         /* User can add his own implementation to report the file name and line number,
  12.         ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  13.         while (1)
  14.         {}
  15. }
  16. #endif
  17. /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/


 楼主| neeringstu 发表于 2016-11-17 20:15 | 显示全部楼层
readme.txt
  1. /**
  2.   [url=home.php?mod=space&uid=204422]@page[/url] TIM_ComplementarySignals TIM Complementary Signals example
  3.   
  4.   @verbatim
  5.   ******************** (C) COPYRIGHT 2011 STMicroelectronics *******************
  6.   * [url=home.php?mod=space&uid=288409]@file[/url]    TIM_ComplementarySignals/readme.txt
  7.   * [url=home.php?mod=space&uid=187600]@author[/url]  MCD Application Team
  8.   * [url=home.php?mod=space&uid=895143]@version[/url] V1.0.0
  9.   * [url=home.php?mod=space&uid=212281]@date[/url]    19-September-2011
  10.   * @brief   Description of the TIM Complementary Signals example.
  11.   ******************************************************************************
  12.   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  13.   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  14.   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  15.   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  16.   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  17.   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  18.   ******************************************************************************
  19.    @endverbatim

  20. @par Example Description

  21. This example shows how to configure the TIM1 peripheral to generate three
  22. complementary TIM1 signals, to insert a defined dead time value, to use the break
  23. feature and to lock the desired parameters.

  24. TIM1CLK is fixed to SystemCoreClock, the TIM1 Prescaler is equal to 0 so the
  25. TIM1 counter clock used is SystemCoreClock (168 MHz).

  26. The objective is to generate PWM signal at 17.57 KHz:
  27.   - TIM1_Period = (SystemCoreClock / 17570) - 1

  28. The Three Duty cycles are computed as the following description:
  29. The channel 1 duty cycle is set to 50% so channel 1N is set to 50%.
  30. The channel 2 duty cycle is set to 25% so channel 2N is set to 75%.
  31. The channel 3 duty cycle is set to 12.5% so channel 3N is set to 87.5%.
  32. The Timer pulse is calculated as follows:
  33.   - ChannelxPulse = DutyCycle * (TIM1_Period - 1) / 100

  34. A dead time equal to 11/SystemCoreClock is inserted between the different
  35. complementary signals, and the Lock level 1 is selected.
  36. The break Polarity is used at High level.

  37. The TIM1 waveform can be displayed using an oscilloscope.


  38. @par Directory contents

  39.   - TIM_ComplementarySignals/stm32f4xx_conf.h    Library Configuration file
  40.   - TIM_ComplementarySignals/stm32f4xx_it.c      Interrupt handlers
  41.   - TIM_ComplementarySignals/stm32f4xx_it.h      Interrupt handlers header file
  42.   - TIM_ComplementarySignals/main.c              Main program
  43.   - TIM_ComplementarySignals/system_stm32f4xx.c  STM32F4xx system source file

  44.   
  45. @par Hardware and Software environment

  46.   - This example runs on STM32F4xx Devices Revision A.
  47.   
  48.   - This example has been tested with STM32F4-Discovery (MB997) RevA and can be
  49.     easily tailored to any other development board.
  50.    
  51.   - STM32F4-Discovery
  52.     - Connect the TIM1 pins to an oscilloscope to monitor the different waveforms:
  53.       - TIM1_CH1  pin (PA.08)  
  54.       - TIM1_CH1N pin (PB.13)  
  55.       - TIM1_CH2  pin (PE.11)  
  56.       - TIM1_CH2N pin (PB.14)  
  57.       - TIM1_CH3  pin (PA.10)  
  58.       - TIM1_CH3N pin (PB.15)

  59.     - Connect the TIM1 break pin TIM1_BKIN pin (PB.12) to the GND. To generate a
  60.       break event, switch this pin level from 0V to 3.3V.  


  61. @par How to use it ?

  62. In order to make the program work, you must do the following :

  63. + EWARM
  64.     - Open the TIM_ComplementarySignals.eww workspace
  65.     - Rebuild all files: Project->Rebuild all
  66.     - Load project image: Project->Debug
  67.     - Run program: Debug->Go(F5)

  68. + MDK-ARM
  69.     - Open the TIM_ComplementarySignals.uvproj project
  70.     - Rebuild all files: Project->Rebuild all target files
  71.     - Load project image: Debug->Start/Stop Debug Session
  72.     - Run program: Debug->Run (F5)   

  73. + TASKING
  74.     - Open TASKING toolchain.
  75.     - Click on File->Import, select General->'Existing Projects into Workspace'
  76.       and then click "Next".
  77.     - Browse to  TASKING workspace directory and select the project "TIM_ComplementarySignals"   
  78.     - Rebuild all project files: Select the project in the "Project explorer"
  79.       window then click on Project->build project menu.
  80.     - Run program: Select the project in the "Project explorer" window then click
  81.       Run->Debug (F11)

  82. + TrueSTUDIO
  83.     - Open the TrueSTUDIO toolchain.
  84.     - Click on File->Switch Workspace->Other and browse to TrueSTUDIO workspace
  85.       directory.
  86.     - Click on File->Import, select General->'Existing Projects into Workspace'
  87.       and then click "Next".
  88.     - Browse to the TrueSTUDIO workspace directory and select the project "TIM_ComplementarySignals"
  89.     - Rebuild all project files: Select the project in the "Project explorer"
  90.       window then click on Project->build project menu.
  91.     - Run program: Select the project in the "Project explorer" window then click
  92.       Run->Debug (F11)
  93.    
  94. * <h3><center>© COPYRIGHT 2011 STMicroelectronics</center></h3>
  95. */


戈卫东 发表于 2016-11-17 21:25 | 显示全部楼层
有死区的波形不是你画的那样的。。。。。。
戈卫东 发表于 2016-11-17 21:26 | 显示全部楼层
用你的波形去驱动半桥要炸的。
734774645 发表于 2016-11-17 23:01 | 显示全部楼层
原来两个互补的通道,在一段时间内同时出现了低电平信号,就是死区啊。懂了。
734774645 发表于 2016-11-17 23:01 | 显示全部楼层
就是两个互补信号出现了同样电平的时间段是死区,比如同时低电平,同时高电平。
戈卫东 发表于 2016-11-18 01:10 | 显示全部楼层
734774645 发表于 2016-11-17 23:01
就是两个互补信号出现了同样电平的时间段是死区,比如同时低电平,同时高电平。 ...

死区就是绝不允许出现都“ON”的状态。
为了保证这个原则不被违背,在ON/OFF转变的时候,插入一段都OFF的时间
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

235

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部