STM32F10X PWM configuration routine detailed explanation, test correct

Publisher:落霞与孤鹜Latest update time:2018-07-06 Source: eefocusKeywords:STM32F10X Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Hardware platform: STM32F10X PWM module + JLink + oscilloscope

Software platform: Keil 4 

1. Basic knowledge

First, according to the chip model, STM32 small-capacity, medium-capacity products and STM32F105xx/STM32F107xx interconnected products include one advanced control timer (TIM1). The large-capacity STM32F103xx product includes two advanced control timers (TIM1 and TIM8).

An advanced timer can output seven PWM waves, while a general timer can only output four complementary PWM waves at most.

The general timer and advanced timer are independent of each other and do not affect each other, and can operate at the same time.

If you need more PWM, such as controlling six axes, you can choose different timers yourself. If one is not enough, you can choose two.

Secondly, each general timer generally has only 4 channels, each channel has a comparison register. After setting different values ​​during initialization, 4 PWM signals can be generated. However, the PWM frequencies of these 4 channels are the same, but the duty cycles can be different. 

Finally, if you have any specific questions about pin multiplexing and related registers, please refer to the corresponding data sheet.

The essence of PWM is the use of the timer module.

2. Corresponding modules

The modules involved in the program are:

RCC: reset and clock control module, used to initialize the STM32 USART peripheral clock and IO port multiplexing clock;

GPIO: general input and output port multiplexing configuration module;

Delay: Delay module written using the system clock SysTick, also known as "tick";

Led: system operation prompt module;

Timer: Timer module configuration, PWM configuration is also included.

Three: Code

RCC

  #include "Rcc.h"

  

  void RCC_Init(void)

  {  

   ErrorStatus HSEStartUpStatus;

   //Define enumeration type error status variable

    

   RCC_DeInit(); //Reset system clock settings

  

   RCC_HSEConfig(RCC_HSE_ON);

   //Turn on the external high-speed clock crystal and enable HSE

   /*RCC_HSE_ON on

   _off _bypass hse crystal oscillator is bypassed by external clock*/

    

   HSEStartUpStatus = RCC_WaitForHSEStartUp();

   /*RCC_WaitForHSEStartUp() returns an ErrorStatus enumeration value,

   Success is good, error is not good*/

  

   if(HSEStartUpStatus == SUCCESS) //HES is ready

   {  

   RCC_HCLKConfig(RCC_SYSCLK_Div1);

   //AHB clock (HCLK) = system clock

  

   RCC_PCLK1Config(RCC_HCLK_Div2);

   //Set the low-speed AHB clock (APB1) to 2 times the frequency of HCLK  

    

   RCC_PCLK2Config(RCC_HCLK_Div1);

   //Set high-speed AHB clock (APB2) = HCLK clock

    

   FLASH_SetLatency(FLASH_Latency_2);

   //Set the FLASH delay cycle number to 2

    

   // Enable receiving finger cache

   FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    

   RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

   //Set the PLL clock source and frequency multiplication factor to 9 times the HSE frequency 8MHz * 9 = 72MHz

   /*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)

   RCC_PLLSource_HSI_Div2 pll input clock = hsi/2;

   RCC_PLLSource_HSE_Div1 PLL Input Clock = HSE

   RCC_PLLSource_HSE_Div2 PLL input clock = hse/2

    

   RCC_PLLMul_2 ------_16 pll input clock*2---16

   PLL output clock must not exceed 72MHZ*/  

    

   RCC_PLLCmd(ENABLE);

   //ENABLE / DISABLE

    

   while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait for PLL output to stabilize

   /*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG) Check the specified RCC flag

   Return SET OR RESET

   RCC_FLAG_HSIRDY HSI crystal oscillator ready

   RCC_FLAG_HSERDY

   RCC_FLAG_PLLRDY

   RCC_FLAG_LSERDY 

   RCC_FLAG_LSIRDY.......*/  

    

   RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

   //Set PLL as system clock source

   /*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource) Set the system clock

   RCC_SYSCLKSource_HSI 

   RCC_SYSCLKSource_HSE 

   RCC_SYSCLKSource_PLLCLK selects HSI HSE PLL as system clock*/  

    

   while(RCC_GetSYSCLKSource() != 0x08);

   //Judge whether PLL is the system clock

   /*u8 RCC_GetSYSCLKSource(void) Returns the clock source used as the system clock

   0x00:HSI 0x04:HSE 0x08:PLL */

   }  

    

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | 

   RCC_APB2Periph_AFIO |

   RCC_APB2Periph_GPIOB , ENABLE);

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

   //U2 U3 clock is in APB1

   //Turn on the GPIO clock, multiplexing function, the clock of serial port 1              

  

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //Enable CAN1 clock

   //How strange, is it because the official library function is updated?

   //Doesn't it mean that the F10X series only has one CAN, while the F4 has CAN1 CAN2?

   //Why is can1 in his system configuration file? ? ? ? ?

    

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Clock enable

    

   /*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState) 

   Enable or disable apb2 peripheral clock

   RCC_APB2Periph_AFIO function multiplexing IO clock

   RCC_APB2Periph_GPIOA/B/C/D/E GPIOA/B/C/D/E Clock

   RCC_APB2Periph_ADC1/ADC2 ADC1/2 clock

   RCC_APB2Periph_TIM1 

   RCC_APB2Periph_SPI1

   RCC_APB2Periph_USART1 

   RCC_APB2Periph_ALL All APB2 peripheral clocks*/

  }

GPIO


  #include "GPIO.h"

  

  void MYGPIO_Init(void)

  {

   GPIO_InitTypeDef GPIO_InitStructure;

   //GPIO_InitStructure initialization structure is GPIO_InitTypeDef structure

   GPIO_DeInit(GPIOA);

   GPIO_StructInit(&GPIO_InitStructure);

   //Function: Pointer to structure GPIO_InitTypeDef, to be initialized

  

   //CAN TX: A12

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

   GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplex push-pull

   GPIO_Init(GPIOA, &GPIO_InitStructure); //Initialize IO

   //CAN TX: A111

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //Pull-up input

   GPIO_Init(GPIOA, &GPIO_InitStructure); //Initialize IO

  

   // USART TX :A9

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

   //2. GPIO_SPEED: GPIO_SPEED_10MHz/_2MHz/_50MHz maximum output rate

   GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   /*Mode, working status: GPIO_MODE_AIN ----- analog input

   _IN_FLOATING ----- floating input

   _IPD ----- Pull-up output

   _IPU ----- Pull-up input

   _OUT_OD ----- Open drain output

   _OUT_PP ----- Push-pull output

   _AF_OD ----- Multiplexed open drain output

   _AF_PP ----- Multiplexed push-pull output*/

   GPIO_Init(GPIOA, &GPIO_InitStructure);

  

   // USART RX :A10

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

   //IO floating input

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   //initialization

    

   /************pwm2 pa1************************/

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplex push-pull output

   GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

   GPIO_Init(GPIOA, &GPIO_InitStructure); //Initialize GPIO

    

  }


Delay


  #include "delay.h"

  

  static u8 fac_us=0; //us delay multiplier   

  static u16 fac_ms=0; //ms delay multiplier, under ucos, represents the number of ms per beat

  

     

  // Initialize delay function

  //SYSTICK clock is fixed to 1/8 of HCLK clock

  //SYSCLK: system clock

  void delay_init()

  {

   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //Select external clock HCLK/8

   fac_us=SystemCoreClock/8000000; //1/8 of the system clock 

  

   fac_ms=(u16)fac_us*1000; //Non-OS, represents the number of systick clocks required for each ms 

  }    

  

  //Delay nus

  //nus is the number of us to be delayed.       

  void delay_us(u32 nus)

  {

   u32 temp;      

   SysTick->LOAD=nus*fac_us; //Time loading    

   SysTick->VAL=0x00; //Clear the counter

   SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Start countdown  

   do

   {

   temp=SysTick->CTRL;

   }while((temp&0x01)&&!(temp&(1<<16))); //Wait for time to arrive   

   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //Turn off the counter

   SysTick->VAL =0X00; //Clear the counter  

  }

  //Delay nms

  //Note the range of nms

  //SysTick->LOAD is a 24-bit register, so the maximum delay is:

  //nms<=0xffffff*8*1000/SYSCLK

  //SYSCLK is in Hz, nms is in ms

  //Under 72M conditions, nms<=1864 

  void delay_ms(u16 nms)

  {    

   u32 temp;   

   SysTick->LOAD=(u32)nms*fac_ms; //Time loading (SysTick->LOAD is 24bit)

   SysTick->VAL =0x00; //Clear the counter

   SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //Start countdown  

   do

   {

   temp=SysTick->CTRL;

   }while((temp&0x01)&&!(temp&(1<<16))); //Wait for time to arrive   

   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //Turn off the counter

   SysTick->VAL =0X00; //Clear the counter      

  } 


Led


  #include "led.h"

  

  //Initialize PB12 and 13 as output ports and enable the clocks of these two ports    

  

  void LED_Init(void)

  { 

   GPIO_InitTypeDef GPIO_InitStructure;

  

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //Enable PB, PE port clock

  

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;  

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //Push-pull output

   GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz; //IO port speed is 50MHz

   GPIO_Init(GPIOB, &GPIO_InitStructure); //Initialize GPIOB according to the set parameters

   GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);

  }


Timer


#include "timer.h"

#include "led.h"

 

//Timer 3 interrupt service routine

void TIM2_IRQHandler(void) //TIM2 interrupt

{

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) 

// Check whether the specified TIM interrupt occurs: TIM interrupt source 

//Not equal to RESET, that is, SET, which means something happened

//(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) 

{

TIM_ClearITPendingBit(TIM2, TIM_IT_Update );  

// Clear the interrupt pending bit of TIMx: TIM interrupt source 

LED0=!LED0;

}

}

//General timer 3 interrupt initialization

//The clock here is selected to be twice that of APB1, and APB1 is 36M

//arr: automatically reload value.

//psc: clock pre-division number

 

//TIMX X:1----4

//TIM2 PWM initialization 

//PWM output initialization

//arr: automatically reload value

//psc: clock pre-division number

void TIM2_PWM_Init(u16 arr,u16 psc)

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

/*typedef struct 

u16 TIM_Period; 

The value of the auto-reload register cycle, 0x00000-----0xFFFF

u16 TIM_Prescaler; 

TIMX clock frequency divisor prescaler value 0x0000----0xFFFF

u8 TIM_ClockDivision; 

Clock division TIM_CKD_DIV1 T DTS = Tck_tim  

TIM_CKD_DIV2 T DTS = 2Tck_tim 

TIM_CKD_DIV4 T DTS = 4Tck_tim 

u16 TIM_CounterMode; 

Counter mode TIM_CounterMode_Up TIM up counting mode

TIM_CounterMode_Down Down counting mode

TIM_CounterMode_CenterAligned1 -----3 Center alignment mode 1--3 counting mode

} TIM_TimeBaseInitTypeDef;*/

TIM_OCInitTypeDef TIM_OCInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

 

//Initialize TIM2

TIM_TimeBaseStructure.TIM_Period = arr; 

//Set the value of the auto-reload register cycle to load the activity at the next update event, which is 500ms when the cycle counts to 5000

TIM_TimeBaseStructure.TIM_Prescaler =psc; 

//Set the pre-division value used as the TIMx clock frequency divisor 10Khz counting frequency  

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 

//Set clock division: T DTS = Tck_tim  

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  

//TIM up counting mode

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 

//Initialize the time base unit of TIMx according to the parameters specified in TIM_TimeBaseInitStruct

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //Enable the specified TIM2 interrupt and allow update interrupt

 

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2 interrupt

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //Preempt priority level 0

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //From priority level 3

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel is enabled

NVIC_Init(&NVIC_InitStructure); //Initialize peripheral NVIC registers according to the parameters specified in NVIC_InitStruct

 

TIM_Cmd(TIM2, ENABLE); //Enable TIMx peripherals

//GPIO_PinRemapConfig(GPIO_PartialRemap2_TIM2, ENABLE); How to use it???

//Change the mapping of the specified pin Timer3 partially remaps TIM2_CH2->PB5

//Initialize TIM2 Channel2 PWM mode  

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 

//Select timer mode: TIM pulse width modulation mode 1

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 

//Compare output enable

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 

//Output polarity: TIM output comparison polarity high

//TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

//TIM_Pulse pulse value to be loaded into the comparison register 0x0000----0xFFFF

TIM_OC2Init(TIM2, &TIM_OCInitStructure);  

//Initialize peripheral TIM2 OC2 according to the parameters specified by T

 

TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  

// Enable TIM2 preload register on CCR2

//TIM_ARRPreloadConfig(TIM2, ENABLE);

// Enable TIM2 preload register on ARR

 

TIM_Cmd(TIM2, ENABLE); //Enable TIM2

}


Keywords:STM32F10X Reference address:STM32F10X PWM configuration routine detailed explanation, test correct

Previous article:STM32 MCU - encoder speed measurement
Next article:stm32F4 encoder measures speed and prints through serial port --- program source code

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号