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
[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