STM32 timer generates PWM application

It took a long time to study STM32, a lot of worship, and a lot of gains, and the learning process has many twists and turns. The task of this time is to generate four PWM pulses with adjustable frequency-duty duty cycle on four channels using a timer of STM32.

Seeing this question, I first looked at the STM32 data sheet. It took a day to read the STM32 timer manual, but after reading it all the time, I didn’t know what it was, just look at the library function, I understand it a bit, I want to I transferred this program out, so I spent more than a day copying it on the other people's programs on the Internet. I spent more than a day writing and debugging. The result didn't work and I didn't work. So I calmed down and thought about it step by step.

I first use the STM32 general-purpose timer to generate four channels of the same duty cycle and PWM waves of different frequencies using the PWM mode. The configuration is as follows:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//Enable TIM2 clock

TIM_InternalClockConfig(TIM2);//Use internal clock

TIM_BaseInitStructure.TIM_Prescaler=3; //Set the prescaler value of the TIM clock frequency divisor

TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//Select counter mode

TIM_BaseInitStructure.TIM_Period=1799; / / set the value of the automatic update register cycle of the next update event load activity

TIM_BaseInitStructure.TIM_ClockDivision=0;//Set the clock split

TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);

//channel 1

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//Select timer mode

TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//Select output comparison status

TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//Select complementary output comparison status

TIM_OCInitStructure.TIM_Pulse=CCR1_Val;//Set the pulse value to be loaded into the capture comparator

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//Set the output polarity

TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//Set the complementary output polarity

TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//Select non-working state in idle state

TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//Select non-working state in complementary idle state

TIM_OC1Init(TIM2,&TIM_OCInitStructure);

TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

//channel 2

TIM_OCInitStructure.TIM_Pulse=CCR2_Val;//Set the pulse value to be loaded into the capture comparator

TIM_OC2Init(TIM2,&TIM_OCInitStructure);

TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

//channel 3

TIM_OCInitStructure.TIM_Pulse=CCR3_Val;//Set the pulse value to be loaded into the capture comparator

TIM_OC3Init(TIM2,&TIM_OCInitStructure);

TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);

//channel 4

TIM_OCInitStructure.TIM_Pulse=CCR4_Val;//Set the pulse value to be loaded into the capture comparator

TIM_OC4Init(TIM2,&TIM_OCInitStructure);

TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);

TIM_Cmd(TIM2, ENABLE);

TIM_CtrlPWMOutputs(TIM2,ENABLE);

The frequency and duty cycle of the output in pwm mode are fixed and not adjustable. In order to adjust the output frequency and adjust the duty cycle, the comparison output mode must be used. This information was seen at the STM32 National Tour Symposium, as shown in the figure:

So, I wrote a program to generate a PWM wave through the output comparison mode. The frequency and duty cycle of this wave are determined by ourselves. The function configuration is as follows:

TIM_BaseInitStructure.TIM_Prescaler=3; //Set the prescaler value of the TIM clock frequency divisor (18M)

TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//Select counter mode

TIM_BaseInitStructure.TIM_Period=1800; / / set the value of the automatic update register cycle of the next update event load activity

TIM_BaseInitStructure.TIM_ClockDivision=0;//Set the clock split

TIM_TimeBaseInit(TIM2,&TIM_BaseInitStructure);

//channel 1

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;//Select timer mode

TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//Select output comparison status

TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//Select complementary output comparison status

TIM_OCInitStructure.TIM_Pulse=CCR1_Val1;//Set the pulse value to be loaded into the capture comparator

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//Set the output polarity

TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;//Set the complementary output polarity

TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Set;//Select non-working state in idle state

TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCNIdleState_Reset;//Select non-working state in complementary idle state

TIM_OC1Init(TIM2,&TIM_OCInitStructure);

TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);

TIM_ARRPreloadConfig(TIM2, ENABLE);

TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);

TIM_Cmd(TIM2, ENABLE);

}

Void TIM2_IRQHandler(void)

{

TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);

If(n==1)

{

n=0;

TIM_SetCompare1(TIM2,CCR1_Val2);

}

Else

{

n=1;

TIM_SetCompare1(TIM2,CCR1_Val1);

}

}

The value of CCR1 is changed in each match interrupt by changing the value in the compare register (CCR1), changing the duty cycle of the PWM. The above program realizes generating a PWM wave with a frequency of 10K and a duty cycle of 40%.

With the above thoughts, I want to generate four PWM waves with different duty cycles and different duty cycles. After repeated thinking about the optical distribution function, it seems that it cannot be realized. I checked it on the Internet. Many netizens said that they could not be realized. A hint: software simulation. I didn't understand what it was at first, so I continued to configure the library functions myself. There have been two questions in this process:

In each interrupt, the value of the CCR register is increased in the loop. Can the CCR register be infinitely large? Even if it is infinite, the counter is not infinite, he can only remember 65535. Initially determined that the use of matching interrupts does not work, I have thought of using both overflow and match interrupts, but the four PWM waves can only be fixed, the frequency and duty cycle can not be adjusted. Probably talk about how to use the overflow interrupt and match interrupt to achieve four fixed PWM waves, the value of the counter register (CNT) is loaded with the maximum period of the PWM wave, when the count is completed, calculate the number of three small dot cycles, in the match interrupt In the corresponding variable, the CCR changes several times. When the overflow interrupt comes, the counter is loaded with the initial value again. At the same time, the four comparison registers are loaded with the initial value. This is very troublesome and theoretically achievable, but I can't think of it at the end. To achieve my requirements, I did not verify. Therefore, the four-channel frequency adjustable duty cycle can be adjusted. It seems that it cannot be realized with a timer. It has been stuck here. I am thinking that Fei Ge said that it can be realized. I can definitely achieve it. I am looking for information on the Internet. Didn't find it, just someone asked the four way, soft simulation, so I thought about using soft simulation to achieve, and finally under the guidance of a brother, really use software to simulate an intermediate comparison register can be achieved, the idea is probably like this, first let the comparison The register is full, that is, the maximum value (65535), and then by changing the value of the analog compare register, each match interrupt only needs to compare the value of the analog compare register, the specific program to see the program.

Unsigned charCnt[4]; //An array, each element of this array corresponds to a channel, used to determine whether the PWM is high or low.

Unsigned intT[4];//cycle array

Unsigned intR[4]; / ​​/ analog comparison register array, the same for each channel corresponds to an array element

Unsigned intRh[4];//analog PWM high level compare register

Unsigned intRl[4]; //analog PWM low level compare register

Unsigned char F[4];//duty cycle array

Unsigned int CCR1, CCR2, CCR3, CCR4;

Void Init(void)

{

Unsigned char i = 0;

For(i = 0; i " 4; i++)

{

Cnt[i]= 0;

T[i]= 0;

R[i]= 0;

Rh[i] = 0;

Rl[i] = 0;

F[i]= 0;

}

The range of //t is (0~65536)

T[0] = 450;//F=40K

T[1] = 600;//F=30K

T[2] = 900;//F=20K

T[3] = 1800;//F=10K

//F (duty cycle) range is (0~100)

F[0] = 40;

F[1] = 30;

F[2] = 20;

F[3] = 10;

For(i = 0; i " 4; i++)

{

Rh[i] = (T[i] * F[i]) / 100;

Rl[i] = T[i] - Rh[i];

}

R[0] = Rl[0];

R[1] = Rl[1];

R[2] = Rl[2];

R[3] = Rl[3];

CCR1 = R[0];

CCR2 = R[1];

CCR3 = R[2];

CCR4 = R[3];

}

Corresponding array initialization

Void RCC_Configuration(void)

{

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);

}

Clock configuration

Void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

//Key1 PA0 Key3 PA8

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_Init(GPIOA,&GPIO_InitStructure);

//Key2 PC13

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_Init(GPIOC,&GPIO_InitStructure);

//Key PD3

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;

GPIO_Init(GPIOD, &GPIO_InitStructure);

//TIM3 CH1 CH2

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIO_InitStructure);

//TIM3 CH3 CH4

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_Init(GPIOB,&GPIO_InitStructure);

}

Pin configuration

Void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

#ifdef VECT_TAB_RAM

NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

#endif

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

Interrupt configuration

Void TIM_Configuration(void)

{

TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_InternalClockConfig(TIM3);

TIM_BaseInitStructure.TIM_Prescaler=3;//4 divided, 18M

TIM_BaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;

TIM_BaseInitStructure.TIM_Period=65535;

TIM_BaseInitStructure.TIM_ClockDivision=0;

TIM_BaseInitStructure.TIM_RepetitionCounter=0;

TIM_TimeBaseInit(TIM3,&TIM_BaseInitStructure);

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_Pulse=CCR1;

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

TIM_OC1Init(TIM3,&TIM_OCInitStructure);

TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);

TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

TIM_OCInitStructure.TIM_Pulse=CCR2;

TIM_OC2Init(TIM3,&TIM_OCInitStructure);

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

TIM_OCInitStructure.TIM_Pulse=CCR3;

TIM_OC3Init(TIM3,&TIM_OCInitStructure);

TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);

TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_Toggle;

TIM_OCInitStructure.TIM_Pulse=CCR4;

TIM_OC4Init(TIM3,&TIM_OCInitStructure);

TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);

TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);

TIM_Cmd(TIM3, ENABLE);

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

TIM_ITConfig(TIM3, TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4, ENABLE);

}

Void TIM3_IRQHandler(void)

{

If(TIM_GetITStatus(TIM3,TIM_IT_CC1)!=RESET)

{

TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);

Cnt[0]=(~Cnt[0])&0x01;

If(Cnt[0]==0x01)

R[0]+=Rl[0];

Else

R[0] += Rh[0];

If(R[0]》65535)

R[0]=R[0]-65535;

CCR1=R[0];

TIM_SetCompare1(TIM3, CCR1);

}

If(TIM_GetITStatus(TIM3,TIM_IT_CC2)!=RESET)

{

TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);

Cnt[1]=(~Cnt[1])&0x01;

If(Cnt[1]==0x01)

R[1]+=Rl[1];

Else

R[1] += Rh[1];

If(R[1]"65535)

R[1]=R[1]-65535;

CCR2=R[1];

TIM_SetCompare2(TIM3, CCR2);

}

If(TIM_GetITStatus(TIM3,TIM_IT_CC3)!=RESET)

{

TIM_ClearITPendingBit(TIM3,TIM_IT_CC3);

Cnt[2]=(~Cnt[2])&0x01;

If(Cnt[2]==0x01)

R[2]+=Rl[2];

Else

R[2] += Rh[2];

If(R[2]》65535)

R[2]=R[2]-65535;

CCR3=R[2];

TIM_SetCompare3(TIM3, CCR3);

}

If(TIM_GetITStatus(TIM3,TIM_IT_CC4)!=RESET)

{

TIM_ClearITPendingBit(TIM3,TIM_IT_CC4);

Cnt[3] = (~Cnt[3])&0x01;

If(Cnt[3]==0x01)

R[3]+=Rl[3];

Else

R[3] += Rh[3];

If(R[3]》65535)

R[3]=R[3]-65535;

CCR4=R[3];

TIM_SetCompare4(TIM3, CCR4);

}

}

Interrupt function

The rest is the key scan function. The frequency and duty cycle of the PWM wave can be changed by changing the value in the period array and the value in the duty cycle register. Of course, the button can be set to 4 (one button corresponds to one channel), if IO Eight can also be set, and no two buttons correspond to one channel to change the frequency and duty cycle respectively.

Copper Cooling Tube

Copper Cooling Tube

[HIGH REFRIGERATION EFFICIENCY]Good heat dissipation and refrigeration capability,high strength at low temperature.Copper tubes are hollow,so has strong heat transfer capability.If you need refrigeration for refrigerators, freezers, air conditioners, this is a good choice

[COPPER MATERIAL]Copper refrigerator tube has the features of high temperature resistance, corrosion resistance, oxidation resistance, durability, long service life
[SOFT & SHAPE CHANGEABLE]Because refrigeration copper pipe can bend and deform, they can often be made into elbows and joints. Smooth bending allows copper tubes to bend at any angle
[WIDELY APPLICATION]Refrigerator Tubing is not only used for refrigerator, freezer and air conditioner as refrigeration tubing coil, but also used as a HVAC system pipe.

Condenser Copper Tube,Copper Cooling Tube,Copper Tube Air Cooling,Copper Cooling Fin Tube

FOSHAN SHUNDE JUNSHENG ELECTRICAL APPLIANCES CO.,LTD. , https://www.junshengcondenser.com