- /*********************************************
- 标题:定时器输出带有死区时间的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);
- }
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 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*/