1. 程式人生 > >STM32定時器輸出帶有死區時間的PWM波形

STM32定時器輸出帶有死區時間的PWM波形

要求得到下列波形,死區時間為1us,CH1,CH2,CH3之間的相位差為3us,頻率為50KHz


main.c

/*********************************************
    標題:定時器輸出帶有死區時間的PWM波形
    軟體平臺:MDK-ARM Standard Version4.70
    硬體平臺:stm32f4-discovery	
    主頻:168M
	Periph_Driver_version: V1.0.0
    
    描述:用一個定時器(TIM1),輸出帶有死區時間的PWM波形,要求:死區時間為1us,CH1,CH2,CH3之間的相位差為3us,頻率為50KHz
		  程式碼參考自STM32F4-Discovery_FW_V1.1.0\Project\Peripheral_Examples\TIM_ComplementarySignals

    author:大舟
    data:2013-04-15
**********************************************/


#include "stm32f4_discovery.h"


TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
uint16_t TimerPeriod = 0;
uint16_t Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0;

/* Private function prototypes */
void TIM_Config(void);


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

	/* TIM1 Configuration */
	TIM_Config();

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

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

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

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

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

	The Three Duty cycles are computed as the following description:

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

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

	2/ Insert a dead time equal to (11/SystemCoreClock) ns	//這句不對,示波器裡觀測也不對,不是這樣算的。
	
	正確的deadtime的計算方法(經理論與示波器測試成功)
	TIM_BDTRInitStructure.TIM_DeadTime=255 //這句設定的就是暫存器TIMx_BDTR的後8位,即DTG[7:0],所以最大值為255
	從下面的程式碼中的“第五步”中,實際上就相當於TIM1->BDTR=0x71FF;
	
	檢視"STM32中文參考手冊2009.pdf"的TIMx_BDTR(第248頁),列暫存器TIMx_BDTR的後8位如下:
	位7:0	UTG[7:0]: 死區發生器設定 (Dead-time generator setup) 
			這些位定義了插入互補輸出之間的死區持續時間。假設DT表示其持續時間: 
			DTG[7:5]=0xx => DT=DTG[7:0] × Tdtg,		Tdtg = Tdts; 
			DTG[7:5]=10x => DT=(64+DTG[5:0]) × Tdtg,	Tdtg = 2 × Tdts;
			DTG[7:5]=110 => DT=(32+DTG[4:0]) × Tdtg,	Tdtg = 8 × Tdts;
			DTG[7:5]=111 => DT=(32+DTG[4:0]) × Tdtg,	Tdtg = 16× Tdts;
			
			例:若Tdts = 1/168us(頻率為168M),可能的死區時間DT為:
			0到756ns,		若步長時間Tdtg為1/168us;
			762ns到1512ns,	若步長時間Tdtg為2/168us;
			1524ns到3us,	若步長時間Tdtg為8/168us;
			3048ns到6us,	若步長時間Tdtg為16/168us;
	
	計算
	這裡要求設定deadtime為1us,落在區間"762ns到1512ns",所以選擇公式“DTG[7:5]=10x => DT=(64+DTG[5:0])×Tdtg,Tdtg=2×Tdts;”
	列方程:(64+x)×2/168us = 1us;得x=20。所以DTG[5:0]=010100;推出DTG[7:0]=10010100=0x94。所以TIM_DeadTime=0x94。
	
	
	3/ Configure the break feature, active at High level, and using the automatic
	output enable feature

	4/ Use the Locking parameters level1.

	5/ 	這裡要求3個通道的波形不是對齊的,所以必須設定為TIM_OCMode_Toggle模式,這樣,ARR得走兩趟才是一個週期,
		CCR1(TIM_Pulse)、CCR2、CCR3不同,則觸發的點也不同,即錯開了相位。
		注意,不管TIM_Pulse為什麼值,佔空比都是50%。因為ARR走一趟才取反一次。
	
	6/	要求pwm輸出頻率為50KHz。所以ARR=(SystemCoreClock/100000)-1 = 1679。即對時鐘進行1680分頻。
	
	7/	PWM1和PWM2的相位差為3us。計算如下
		因為ARR自加1的時間為(1/168M)s,即可列方程:(1/168M)x=3us,得x=504。
		即,CCR1、CCR2、CCR3之間相隔504時,PWM的相位差就為3us
		
	Note:
	SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file.
	Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate()
	function to update SystemCoreClock variable value. Otherwise, any configuration
	based on this variable will be incorrect.
	----------------------------------------------------------------------- */

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

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

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

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

	/**@step第一步配置時鐘*/
	/**@step第二步配置goio口*/
	/**@step第三步定時器基本配置*/
	/* Time Base configuration */
	TIM_TimeBaseStructure.TIM_Prescaler = 0;//時鐘預分頻數,對168M進行1(0+1)分頻
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上計數 
	TIM_TimeBaseStructure.TIM_Period = TimerPeriod;//自動重灌載暫存器的值,ARR=9561
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;	//取樣分頻 
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//重複暫存器,用於自動更新pwm佔空比

	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/**@step第四步 PWM輸出配置*/
	/* Channel 1, 2 and 3 Configuration in PWM mode */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;				//PWM1為正常佔空比模式,PWM2為反極性模式
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//High為佔空比高極性,此時佔空比為20%;Low則為反極性,佔空比為80%
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能該通道輸出
	TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;	//設定佔空比時間,CCR1_Val=4780,佔空比為4780/(9561+1)=0.5
	
	//-------下面幾個引數是高階定時器才會用到通用定時器不用配置
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;	//使能互補端輸出
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;		//設定互補端輸出極性
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;	//剎車之後輸出狀態Specifies the TIM Output Compare pin state during Idle state
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;	//剎車之後互補端輸出狀態
	//-------
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);//對channel1進行配置
	
	TIM_OCInitStructure.TIM_Pulse = Channel2Pulse;//CCR2_Val=2390,比較值
	TIM_OC2Init(TIM1, &TIM_OCInitStructure);//對channel2進行配置
	TIM_OCInitStructure.TIM_Pulse = Channel3Pulse;//CCR3_Val=1195,比較值
	TIM_OC3Init(TIM1, &TIM_OCInitStructure);//對channel3進行配置

	/**@step第五步死區和剎車功能配置,高階定時器才有的,通用定時器不用配置*/
	/* Automatic Output enable, Break, dead time and lock configuration*/
	TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;				//執行模式下輸出
	TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;				//空閒模式下輸出選擇 
	TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;					//鎖定設定,鎖定級別1
	TIM_BDTRInitStructure.TIM_DeadTime = 0x94;//死區時間1us
	TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;					//剎車功能使能
	TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;		//剎車輸入極性,即剎車控制引腳接GND時,PWM停止
	TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;	//自動輸出使能
	TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
	/*	剎車控制引腳為TIM1_BKIN pin(PB.12),將PB12接GND,channel和其互補通道,都變為剎車後的電平,具體為0還是1,要看如下兩個設定:
		.TIM_OCIdleState = TIM_OCIdleState_Reset;	//剎車之後,PWM通道變為0
		.TIM_OCNIdleState = TIM_OCNIdleState_Reset;	//剎車之後,PWM互補通道變為0
		
		注意:如果沒必要,還是不要開啟剎車功能,因為會對PWM產生影響,特別是當PB12懸空時,波形將會有很大的波動。
			  這裡不開啟剎車功能,即.TIM_Break = TIM_Break_Disable;
	*/
	
	/**@step第六步使能端的開啟*/
	/* TIM1 counter enable */
	TIM_Cmd(TIM1, ENABLE);//開啟TIM1

	/* Main Output Enable */
	TIM_CtrlPWMOutputs(TIM1, ENABLE);//PWM輸出使能,一定要記得打

	while (1);
}

/**
* @brief  Configure the TIM1 Pins.
* @param  None
* @retval None
*/
void TIM_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

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

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

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

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

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

	/* Connect TIM pins to AF1 */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);	//引腳功能,檢視readme.txt
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_TIM1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_TIM1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_TIM1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);
	GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_TIM1);
}
/**@end*/










#ifdef  USE_FULL_ASSERT
/**
* @brief  Reports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @param  file: pointer to the source file name
* @param  line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
	/* User can add his own implementation to report the file name and line number,
	ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

	while (1)
	{}
}
#endif
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

readme.txt
/**
  @page TIM_ComplementarySignals TIM Complementary Signals example
  
  @verbatim
  ******************** (C) COPYRIGHT 2011 STMicroelectronics *******************
  * @file    TIM_ComplementarySignals/readme.txt 
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    19-September-2011
  * @brief   Description of the TIM Complementary Signals example.
  ******************************************************************************
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  ******************************************************************************
   @endverbatim

@par Example Description 

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

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

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

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

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

The TIM1 waveform can be displayed using an oscilloscope.


@par Directory contents 

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

  
@par Hardware and Software environment 

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

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


@par How to use it ? 

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

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

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

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

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