void exti0_isr(void)//EXTI, or external interruption function, this one would be called if the interruption was generated by external means, in our case, the User Button
{
exti_reset_request(EXTI0);//resets the EXTI interruption so it can be called again
gpio_toggle(GPIOD, GPIO13);//this toggles the orange led on or off upon entering the EXTI interruption
if (direction==UP) //this checks if the interruption should increment or decrement the the frequency, i.e the speed of the motor.
{
if (current_freq < max_sine_freq) //this checks if the speed has reached the upper limit
{
current_freq+=sine_freq_increment;//then increments the frequency
}
else{
direction=DOWN; //if top have been reached, changes direction
current_freq-=sine_freq_increment;//and then starts decrementing the frequency
}
}
else
{
if (current_freq > min_sine_freq)//this checks if the speed has reached the lower limit
{
current_freq-=sine_freq_increment;//then decrement the frequency
}
else
{
direction=UP; //if bottom have been reached, then changes direction
current_freq+=sine_freq_increment;//and starts incrementing the frequency
}
}
}
void tim1_cc_isr (void)//TIM1 CC interruption, (Timer 1, capture and compare interruption) this will be called if the CCR has been reached by the timer
{
/* Clear the update interrupt flag. */
timer_clear_flag(TIM1, TIM_SR_CC1IF);
static float ticks=0.0f; //cicle counter
static float //this command lets you declare and initialize a value for a variable that will only be taken in consideration the first time you run your program.
//this does not change upon calling this funtion again, this means that the last value for this variable will be the one kept the next time you use this function.
duty_a=0.0f, //this inits the duty cicle for the first PWM
duty_b=0.0f, //this inits the duty cicle for the second PWM
duty_c=0.0f; //this inits the duty cicle for the third PWM
float attenuation=attenuation_value; //an attenuation value that let's you have better control over the CCR value, meaning you can change the sinusoidal frecuency faster or slower with the same frecuency change
float angle;//angle variable declaration
float max_ticks=pwmfreq_f/current_freq; //defines how many PWM cicles we require to generate a sinusoidal wave of certain frecuency
angle=2.0f*PI*ticks/max_ticks;//current angle calculation
duty_a=sinf(angle);//new duty cycle for the first PWM, that will generate the first Sinusoidal Wave
duty_b=sinf(angle+2.0f*PI/3.0f);//new duty cycle for the second PWM, that will generate the second Sinusoidal Wave
duty_c=sinf(angle+4.0f*PI/3.0f);//new duty cycle for the third PWM, that will generate the third Sinusoidal Wave
if (duty_a < 0.0f)//if my duty is negative,
{
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1); //set's my timer mode in comparison mode
timer_disable_oc_output(TIM1,TIM_OC1); // then disables the forward channel
timer_enable_oc_output (TIM1, TIM_OC1N);// and enables the reverse channel, this will send the current on the reverse direction, then generating oposite voltage, so my lower part of the sinusoidal wave.
duty_a=-duty_a;//re-sets the value of mu duty to positive, so my CCR is calculated to a positive value, this prevents errors on the comparison.
}
else //else if it's positive
{
timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1); //set's my timer mode in comparison mode
timer_enable_oc_output(TIM1, TIM_OC1 ); // then enables the forward channel, to generate positive tension and so my upper side of the sinusoidal wave
timer_disable_oc_output (TIM1, TIM_OC1N);// and disables the reverse channel, so there is only one channel enabled at a time
}
if (duty_b < 0.0f)//same logic as for the duty_a
{
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
timer_disable_oc_output(TIM1, TIM_OC2 );
timer_enable_oc_output (TIM1, TIM_OC2N);
duty_b=-duty_b;
}
else
{
timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
timer_enable_oc_output(TIM1, TIM_OC2 );
timer_disable_oc_output (TIM1, TIM_OC2N);
}
if (duty_c < 0.0f)//same logic as for the duty_a and b
{
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
timer_disable_oc_output(TIM1, TIM_OC3 );
timer_enable_oc_output (TIM1, TIM_OC3N);
duty_c=-duty_c;
}
else
{
timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
timer_enable_oc_output(TIM1, TIM_OC3 );
timer_disable_oc_output (TIM1, TIM_OC3N);
}
/* Set the capture compare value for OC1. */
timer_set_oc_value(TIM1, TIM_OC1, duty_a*attenuation*pwm_period_ARR);
/* Set the capture compare value for OC2. */
timer_set_oc_value(TIM1, TIM_OC2, duty_b*attenuation*pwm_period_ARR);
/* Set the capture compare value for OC3. */
timer_set_oc_value(TIM1, TIM_OC3, duty_c*attenuation*pwm_period_ARR);
if (ticks<max_ticks)//if we haven't finished a period of the sinusoidal wave
{
ticks+=1.0f;//then we continue counting
}
else //if we have reached the max value of cicles, then we have succesffully generated one full period of the sinusoidal wave
{
ticks=0.0f; //then we need to reset the value to start over a new period
gpio_toggle(GPIOD, GPIO15);// this will toggle the blue led ON/OFF each time a full sinusoidal period has passed
}
}
Motor Control
INDEX