stm32f103c8t6 PWM output

preface

First, let's understand the concept of PWM. PWM (Pulse Width Modulation) is Pulse Width Modulation. Put it here, simply put, is to use the single chip microcomputer to generate the square wave with specified duty cycle and specified frequency. For example, the MCU outputs a square wave with high level of 0.5s and low level of 0.5s. Then, the duty cycle of this square wave is 0.5 / (0.5 + 0.5) = 50%, the high and low levels account for half respectively, and the frequency is the reciprocal of the cycle (0.5s+0.5s), that is, 1Hz. If the high level is 0.2s and the low level is 0.8s, the duty cycle is 0.2 / (0.2 + 0.8) = 20%, and so on.
Taking the single chip microcomputer STM32F103C8T6 as an example, this paper explains the generation of PWM. Through the internal timer of the single chip microcomputer, the corresponding PWM signal can be output at the IO port. The MCU has 8 timers, namely TIM1-TIM8. Among them, TIM1 and TIM8 are advanced timers, each of which can generate up to 7 PWM signals and output them from 7 IO ports at the same time. TIM2-TIM5 are general timers, each generating 4 PWM signals at the same time. TIM6 and TIM7 are basic timers and cannot generate PWM signals.
Implementation functions:
Configure 4 PWM channels of TIM4 to output signals with frequency of 1Hz at the same time, where:

  • The duty cycle of the first way (TIM4_CH1) is 10%
  • The duty cycle of the second circuit (TIM4_CH2) is 20%
  • Third way (TIM4_CH3) duty cycle 50%
  • Fourth way (TIM4_CH4) duty cycle 80%

Step 1: determine the IO port corresponding to the four PWM outputs of TIM4

See the official data manual STM32F103x8_B enhanced series medium capacity product data manual, page P20, and the screenshot is as follows:

PWM channel of TIM4_ CH1-TIM4_ The GPIO corresponding to CH4 is PB6~PB9.

int main(void)
{
      TIM4_PWM_Init(7999,8999);//Square wave frequency 1Hz

      TIM_SetCompare1(TIM4, 800);//Duty cycle 10%
      TIM_SetCompare2(TIM4,1600);//Duty cycle 20%  
      TIM_SetCompare3(TIM4,4000);//Duty cycle 50%
      TIM_SetCompare4(TIM4,6400);//Duty cycle 80%
    
      while(1);//Main cycle     
}

Step 2: square wave frequency calculation -- void TIM4_PWM_Init(u16 arr,u16 psc)

  • 1. The input clock CLK of timer TIM4 is 72MHz, which determines that the maximum frequency of output PWM is lower than 72MHz;
  • 2.CLK performs psc+1 frequency division through pre frequency division counter, and the input clock is reduced to 72MHz / (psc+1);
  • 3. After frequency division, the PWM output of one cycle is completed after counting (arr+1) times, so the frequency is reduced by (arr+1) times;
  • 4.PWM frequency = 72MHz / (psc+1) / (arr+1)
  • 5. According to the parameter 72MHz/(7999+1)/(8999+1) = 1Hz

Step 3: duty cycle setting -- void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);

  • 1. The count register of timer TIM4 is accumulated from 0 to arr cycle, and the value N of the count register is compared with Compare1;
  • 2. In one cycle, when N is less than Compare1, the output is high, and when N is greater than Compare1, the output is low; (or set opposite)
  • 3. Therefore, duty cycle: Compare1/(arr+1);
  • 4. According to the parameters, 10% duty cycle Compare1=800, that is, 10% = 800 / (7999 + 1), and so on.
void TIM4_PWM_Init(u16 arr,u16 psc)
{ 
      GPIO_InitTypeDef GPIO_InitStructure;
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      TIM_OCInitTypeDef TIM_OCInitStructure;

      //Enable timer TIM4 clock. Note that TIM4 clock is APB1 instead of APB2
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
      //Enable PWM output GPIO port clock
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); 
                                                                          
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PWM output channel 1 of timer TIM4, TIM4_CH1
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//Multiplexed push-pull output
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PWM output channel 1 of timer TIM4, TIM4_CH2
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//Multiplexed push-pull output
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//PWM output channel 3 of timer TIM4, TIM4_CH3
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//Multiplexed push-pull output
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//PWM output channel 2 of timer TIM4, TIM4_CH4
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//Multiplexed push-pull output
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIO

      TIM_TimeBaseStructure.TIM_Period = arr;//Auto reload value
      TIM_TimeBaseStructure.TIM_Prescaler =psc; //Clock prescaled frequency
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM up count mode
      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //Initialize TIM4
     
      //Initialize TIM4_ PWM mode of ch1
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//Set PWM mode 1
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//Compare output enable
      TIM_OCInitStructure.TIM_Pulse = 0; //
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//Output polarity is high
      TIM_OC1Init(TIM4, &TIM_OCInitStructure);//Initialize TIM4_CH1

      //Initialize TIM4_ PWM mode of CH2
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
       //TIM4_CH2 initialization. Note that OC2 is used instead of OC1. The following two channels are analogized in turn.
      TIM_OC2Init(TIM4, &TIM_OCInitStructure);

       //Initialize TIM4_ PWM mode of CH3
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC3Init(TIM4, &TIM_OCInitStructure);

      //Initialize TIM4_ PWM mode of CH4
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC4Init(TIM4, &TIM_OCInitStructure);

      //Enable preload registers for 4 channels
      TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC1
      TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC2
      TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC3
      TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC4
      TIM_ARRPreloadConfig(TIM4, ENABLE); //Enable reload register

      TIM_Cmd(TIM4, ENABLE);//Enable timer TIM4, preparation 
}

 

Tags: stm32

Posted on Sun, 19 Sep 2021 05:56:39 -0400 by Jeller