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
}
Previous article:STM32 MCU - encoder speed measurement
Next article:stm32F4 encoder measures speed and prints through serial port --- program source code
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- CATL releases October battle report
- Battery industry in October 2024: growth momentum remains unabated!
- Mercedes-Benz will launch the eCitaro equipped with NMC4 batteries to provide high energy density and long life
- Many companies have announced progress on solid-state batteries. When will solid-state batteries go into mass production?
- Xsens Sirius Series Inertial Sensors Enable 3D Inertial Navigation in Harsh Environments
- Infineon's Automotive Landscape: From Hardware to Systems
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- Live Review: Basic Knowledge, Application and Calibration of Fluke Data Loggers on December 7
- Live Review: December 8th MPS new generation magnetic angle sensor MA600 introduction and application
- [BoLiu BL606P audio and video development board] 1. Environment construction and HelloWord Demo operation
- Looking back at 2022 and looking forward to 2023+A busy year
- 【Sipeed BL808 all-round board】- Development environment 2 burning software
- [ ST NUCLEO-U575ZI-Q Review] STM32Cube MCU Package Example
- Is there any problem driving the DC motor like this?
- GaN Technology in-depth article
- PADS9.5 Application Tutorial
- GD32E230F8P8 IAR simulation configuration