Writing /var/lib/dokuwiki/data/meta/teaching/ie0624/proyectos/control_motores_sincronicos/codigo.meta failed
teaching:ie0624:proyectos:control_motores_sincronicos:codigo
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| teaching:ie0624:proyectos:control_motores_sincronicos:codigo [2018/12/17 03:07] – created micros | teaching:ie0624:proyectos:control_motores_sincronicos:codigo [2022/09/20 00:08] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Código Fuente Utilizado para la Implementación del Control ===== | + | ====== Código Fuente Utilizado para la Implementación del Sistema de Control ====== |
| + | |||
| + | ==== Diagrama de Flujo==== | ||
| + | * A continuación se muestra el código fuente utilizado para la implementación de Sistema de Control, incluyendo la comunicación a través de USART, y las señales enviadas al puente H para el control de potencia. | ||
| + | Para una mejor comprensión de la lógica general, ver el [[teaching: | ||
| + | |||
| + | <code C> | ||
| + | |||
| + | /* | ||
| + | * Copyright (C) 2018 ARCOS-Lab Universidad de Costa Rica | ||
| + | * | ||
| + | * This program is free software: you can redistribute it and/or modify | ||
| + | * it under the terms of the GNU General Public License as published by | ||
| + | * the Free Software Foundation, either version 3 of the License, or | ||
| + | * (at your option) any later version. | ||
| + | * | ||
| + | * This program is distributed in the hope that it will be useful, | ||
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| + | * GNU General Public License for more details. | ||
| + | * | ||
| + | * You should have received a copy of the GNU General Public License | ||
| + | * along with this program. | ||
| + | */ | ||
| + | |||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include " | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | #define SYSFREQ | ||
| + | #define PWMFREQ | ||
| + | #define PWMFREQ_F | ||
| + | #define PRESCALE | ||
| + | #define PWM_PERIOD_ARR | ||
| + | |||
| + | #define LBLUE GPIOE, GPIO8 | ||
| + | #define LRED GPIOE, GPIO9 | ||
| + | #define LORANGE GPIOE, GPIO10 | ||
| + | #define LGREEN GPIOE, GPIO11 | ||
| + | #define LBLUE2 GPIOE, GPIO12 | ||
| + | #define LRED2 GPIOE, GPIO13 | ||
| + | #define LORANGE2 GPIOE, GPIO14 | ||
| + | #define LGREEN2 GPIOE, GPIO15 | ||
| + | |||
| + | #define LD4 GPIOE, GPIO8 | ||
| + | #define LD3 GPIOE, GPIO9 | ||
| + | #define LD5 GPIOE, GPIO10 | ||
| + | #define LD7 GPIOE, GPIO11 | ||
| + | #define LD9 GPIOE, GPIO12 | ||
| + | #define LD10 GPIOE, GPIO13 | ||
| + | #define LD8 GPIOE, GPIO14 | ||
| + | #define LD6 GPIOE, GPIO15 | ||
| + | |||
| + | |||
| + | void leds_init(void) { | ||
| + | rcc_peripheral_enable_clock(& | ||
| + | gpio_mode_setup(GPIOE, | ||
| + | } | ||
| + | |||
| + | void system_init(void) { | ||
| + | rcc_clock_setup_hsi(& | ||
| + | |||
| + | leds_init(); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | // | ||
| + | |||
| + | |||
| + | void tim_init(void) | ||
| + | { | ||
| + | /* Enable TIM1 clock. and Port E clock (for outputs) */ | ||
| + | rcc_periph_clock_enable(RCC_TIM1); | ||
| + | rcc_periph_clock_enable(RCC_GPIOE); | ||
| + | |||
| + | //Set TIM1 channel (and complementary) output to alternate function push-pull' | ||
| + | //f4 TIM1=> GIO9: CH1, GPIO11: CH2, GPIO13: CH3 | ||
| + | //f4 TIM1=> GIO8: CH1N, GPIO10: CH2N, GPIO12: CH3N | ||
| + | gpio_mode_setup(GPIOE, | ||
| + | gpio_set_af(GPIOE, | ||
| + | |||
| + | /* Reset TIM1 pepheral. */ | ||
| + | rcc_periph_reset_pulse(RST_TIM1); | ||
| + | |||
| + | /* Timer global mode: | ||
| + | * - No divider | ||
| + | * - Alignment edge | ||
| + | * - Direction up | ||
| + | */ | ||
| + | timer_set_mode(TIM1, | ||
| + | | ||
| + | // | ||
| + | // | ||
| + | // | ||
| + | | ||
| + | |||
| + | timer_set_prescaler(TIM1, | ||
| + | timer_set_repetition_counter(TIM1, | ||
| + | timer_enable_preload(TIM1); | ||
| + | timer_continuous_mode(TIM1); | ||
| + | |||
| + | /* Period (32kHz). */ | ||
| + | timer_set_period(TIM1, | ||
| + | |||
| + | /* Configure break and deadtime. */ | ||
| + | timer_set_enabled_off_state_in_idle_mode(TIM1); | ||
| + | timer_set_enabled_off_state_in_run_mode(TIM1); | ||
| + | timer_disable_break(TIM1); | ||
| + | timer_set_break_polarity_high(TIM1); | ||
| + | timer_disable_break_automatic_output(TIM1); | ||
| + | timer_set_break_lock(TIM1, | ||
| + | |||
| + | /* Disable outputs. */ | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | timer_disable_oc_output(TIM1, | ||
| + | |||
| + | /* -- OC1 and OC1N configuration -- */ | ||
| + | /* Configure global mode of line 1. */ | ||
| + | timer_enable_oc_preload(TIM1, | ||
| + | timer_set_oc_mode(TIM1, | ||
| + | /* Configure OC1. */ | ||
| + | timer_set_oc_polarity_high(TIM1, | ||
| + | timer_set_oc_idle_state_unset(TIM1, | ||
| + | /* Configure OC1N. */ | ||
| + | timer_set_oc_polarity_high(TIM1, | ||
| + | timer_set_oc_idle_state_unset(TIM1, | ||
| + | |||
| + | |||
| + | //####### | ||
| + | /* Set the capture compare value for OC1. */ | ||
| + | //######### | ||
| + | |||
| + | |||
| + | |||
| + | /* ARR reload enable. */ | ||
| + | timer_enable_preload(TIM1); | ||
| + | |||
| + | /* | ||
| + | * Enable preload of complementary channel configurations and | ||
| + | * update on COM event. | ||
| + | */ | ||
| + | timer_disable_preload_complementry_enable_bits(TIM1); | ||
| + | |||
| + | /* Enable outputs in the break subsystem. */ | ||
| + | timer_enable_break_main_output(TIM1); | ||
| + | |||
| + | /* Generate update event to reload all registers before starting*/ | ||
| + | timer_generate_event(TIM1, | ||
| + | |||
| + | timer_set_oc_mode(TIM1, | ||
| + | timer_enable_oc_output(TIM1, | ||
| + | timer_disable_oc_output (TIM1, TIM_OC1N); | ||
| + | |||
| + | /* Counter enable. */ | ||
| + | timer_enable_counter(TIM1); | ||
| + | |||
| + | //enable capture compare interrupt | ||
| + | timer_enable_update_event(TIM1); | ||
| + | |||
| + | timer_enable_irq(TIM1, | ||
| + | nvic_enable_irq(NVIC_TIM1_UP_TIM16_IRQ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | //ADC ######################################################################################## | ||
| + | |||
| + | static void adc_setup(void) | ||
| + | { | ||
| + | //ADC | ||
| + | rcc_periph_clock_enable(RCC_ADC12); | ||
| + | rcc_periph_clock_enable(RCC_GPIOA); | ||
| + | //ADC | ||
| + | gpio_mode_setup(GPIOA, | ||
| + | gpio_mode_setup(GPIOA, | ||
| + | adc_power_off(ADC1); | ||
| + | adc_set_clk_prescale(ADC1, | ||
| + | adc_set_single_conversion_mode(ADC1); | ||
| + | adc_disable_external_trigger_regular(ADC1); | ||
| + | adc_set_right_aligned(ADC1); | ||
| + | /* We want to read the temperature sensor, so we have to enable it. */ | ||
| + | adc_enable_temperature_sensor(); | ||
| + | adc_set_sample_time_on_all_channels(ADC1, | ||
| + | uint8_t channel_array[] = { 2 }; /* ADC1_IN2 (PA1) */ | ||
| + | adc_set_regular_sequence(ADC1, | ||
| + | adc_set_resolution(ADC1, | ||
| + | adc_power_on(ADC1); | ||
| + | |||
| + | /* Wait for ADC starting up. */ | ||
| + | int i; | ||
| + | for (i = 0; i < 800000; i++) | ||
| + | __asm__(" | ||
| + | } | ||
| + | |||
| + | void tim1_up_tim16_isr(void) { //Timer overflow interrupt, PWM frecuency | ||
| + | // Clear the update interrupt flag | ||
| + | timer_clear_flag(TIM1, | ||
| + | gpio_toggle(GPIOE, | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | // | ||
| + | |||
| + | |||
| + | static void usart_setup(void) | ||
| + | { | ||
| + | /* Enable clocks for GPIO port A (for GPIO_USART2_TX) and USART2. */ | ||
| + | rcc_periph_clock_enable(RCC_USART2); | ||
| + | rcc_periph_clock_enable(RCC_GPIOA); | ||
| + | |||
| + | /* Setup GPIO pin GPIO_USART2_TX/ | ||
| + | gpio_mode_setup(GPIOA, | ||
| + | gpio_set_af(GPIOA, | ||
| + | |||
| + | /* Setup UART parameters. */ | ||
| + | usart_set_baudrate(USART2, | ||
| + | usart_set_databits(USART2, | ||
| + | usart_set_stopbits(USART2, | ||
| + | usart_set_mode(USART2, | ||
| + | usart_set_parity(USART2, | ||
| + | usart_set_flow_control(USART2, | ||
| + | |||
| + | /* Finally enable the USART. */ | ||
| + | usart_enable(USART2); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | //print numbers func. with USART | ||
| + | |||
| + | static void my_usart_print_int(uint32_t usart, int16_t value)// | ||
| + | { | ||
| + | int8_t i; | ||
| + | int8_t nr_digits = 0; | ||
| + | char buffer[25]; | ||
| + | |||
| + | if (value < 0){ | ||
| + | value = value*(-1); | ||
| + | } | ||
| + | if (value == 0) { | ||
| + | usart_send_blocking(usart, | ||
| + | } | ||
| + | |||
| + | while (value > 0) { | ||
| + | buffer[nr_digits++] = " | ||
| + | value /= 10; | ||
| + | } | ||
| + | |||
| + | for (i = nr_digits-1; | ||
| + | usart_send_blocking(usart, | ||
| + | } | ||
| + | |||
| + | usart_send_blocking(usart, | ||
| + | usart_send_blocking(usart, | ||
| + | } | ||
| + | |||
| + | //funcion para esperar tiempos | ||
| + | static void delay(int t){ | ||
| + | for(int i= 0; i< | ||
| + | __asm__(" | ||
| + | } | ||
| + | |||
| + | //funcion que recibe un valor entre -99% y 99% para el valor de referencia | ||
| + | static valor_de_referencia(){ | ||
| + | uint16_t ret=0; | ||
| + | int16_t in_data[4]={0}; | ||
| + | uint8_t i=0; | ||
| + | int new_data=0; | ||
| + | |||
| + | while(i< | ||
| + | |||
| + | switch (new_data){ | ||
| + | case 0: //Si la primera tecla no es - o +, no avanza | ||
| + | in_data[0]=usart_recv_blocking(USART2); | ||
| + | if(in_data[0]== 0x2B || in_data[0]== 0x2D){ | ||
| + | usart_send_blocking(USART2, | ||
| + | i++; | ||
| + | new_data=1; | ||
| + | } | ||
| + | break; | ||
| + | case 1: //Si la segunda tecla no es un numero no avanza | ||
| + | in_data[1]=usart_recv_blocking(USART2); | ||
| + | if(in_data[1]> | ||
| + | usart_send_blocking(USART2, | ||
| + | i++; | ||
| + | new_data=2; | ||
| + | } | ||
| + | break; | ||
| + | case 2://Si la tercer tecla no es un numero no avanza | ||
| + | |||
| + | in_data[2]=usart_recv_blocking(USART2); | ||
| + | if(in_data[2]> | ||
| + | usart_send_blocking(USART2, | ||
| + | i++; | ||
| + | new_data=3; | ||
| + | } | ||
| + | break; | ||
| + | case 3: //Si la cuarta tecla no es un enter no finaliza | ||
| + | in_data[3]=usart_recv_blocking(USART2); | ||
| + | if(in_data[3]==0x0D){ | ||
| + | i++; | ||
| + | } | ||
| + | break; | ||
| + | } | ||
| + | |||
| + | } | ||
| + | if(in_data[0]==0x2B){ret=100; | ||
| + | ret=ret+(in_data[1]-48)*10+(in_data[2]-48); | ||
| + | |||
| + | //regresa el valor convertido a un int, si es mayor a 100 es positivo, y si es menor a 100 es negativo. +50 = 150; -50 = 050 | ||
| + | return ret; | ||
| + | |||
| + | |||
| + | } | ||
| + | |||
| + | |||
| + | // | ||
| + | |||
| + | int main(void) | ||
| + | { | ||
| + | double duty; | ||
| + | double kp=0.3; | ||
| + | double Ti=40; | ||
| + | double rango=4096; | ||
| + | double e; | ||
| + | double I=0.0; | ||
| + | double Inew=0.0; | ||
| + | double Iant=0.0; | ||
| + | double control; | ||
| + | double vel; | ||
| + | double P; | ||
| + | int16_t temp; | ||
| + | bool sentido; | ||
| + | int16_t ref;//% del valor deseado, | ||
| + | int cambio_sentido; | ||
| + | |||
| + | system_init(); | ||
| + | tim_init(); | ||
| + | adc_setup(); | ||
| + | usart_setup(); | ||
| + | |||
| + | |||
| + | ref=valor_de_referencia(); | ||
| + | if(ref> | ||
| + | sentido=true;// | ||
| + | ref=ref-100;// | ||
| + | } else { | ||
| + | sentido=false;// | ||
| + | ref=ref*(-1); | ||
| + | } | ||
| + | cambio_sentido=ref; | ||
| + | |||
| + | while (1){ | ||
| + | |||
| + | // | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | if(sentido==true){ | ||
| + | usart_send_blocking(USART2, | ||
| + | } else { | ||
| + | usart_send_blocking(USART2, | ||
| + | } | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | |||
| + | // | ||
| + | // | ||
| + | adc_start_conversion_regular(ADC1); | ||
| + | while (!(adc_eoc(ADC1))); | ||
| + | temp=adc_read_regular(ADC1); | ||
| + | |||
| + | if (gpio_get(GPIOA, | ||
| + | ref=valor_de_referencia(); | ||
| + | if(ref> | ||
| + | sentido=true;// | ||
| + | ref=ref-100; | ||
| + | } else { | ||
| + | sentido=false;// | ||
| + | ref=ref*(-1); | ||
| + | } | ||
| + | |||
| + | if (cambio_sentido*ref< | ||
| + | gpio_clear(GPIOE, | ||
| + | gpio_clear(GPIOE, | ||
| + | delay(5000); | ||
| + | } | ||
| + | cambio_sentido=ref; | ||
| + | } | ||
| + | |||
| + | // | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | //Control PI | ||
| + | //Calculo de error normalizado | ||
| + | e=((double)ref/ | ||
| + | |||
| + | usart_send_blocking(USART2, | ||
| + | if (e>0){ | ||
| + | usart_send_blocking(USART2, | ||
| + | } else { | ||
| + | usart_send_blocking(USART2, | ||
| + | } | ||
| + | my_usart_print_int(USART2, | ||
| + | //Control proporcional | ||
| + | P = e*kp; | ||
| + | usart_send_blocking(USART2, | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | //Anti windup | ||
| + | if (control > 1.0){ | ||
| + | control=1.0; | ||
| + | I=Iant; | ||
| + | } | ||
| + | if (control < -1.0){ | ||
| + | control=-1.0; | ||
| + | I=Iant; | ||
| + | } | ||
| + | |||
| + | | ||
| + | | ||
| + | } else { | ||
| + | duty=control*(-1); | ||
| + | } | ||
| + | |||
| + | // Control Integral | ||
| + | usart_send_blocking(USART2, | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | //Senal de control PI | ||
| + | control = P + I; | ||
| + | usart_send_blocking(USART2, | ||
| + | if (control> | ||
| + | usart_send_blocking(USART2, | ||
| + | } else { | ||
| + | usart_send_blocking(USART2, | ||
| + | } | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | |||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | |||
| + | // | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | if ((control)< | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | |||
| + | // | ||
| + | Iant = I; | ||
| + | Inew = I + (kp/ | ||
| + | | ||
| + | |||
| + | | ||
| + | // | ||
| + | |||
| + | |||
| + | //Se imprime el valor de la velocidad | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | usart_send_blocking(USART2, | ||
| + | my_usart_print_int(USART2, | ||
| + | |||
| + | |||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | * **NOTA:** El código fuente utilizado para la implementación del sistema de control, está diseñado para una alimentación de '' | ||
| + | |||
| + | <code C> | ||
| + | // | ||
| + | e=((double)ref/ | ||
| + | </ | ||
| + | |||
| + | y cambiar el valor '' | ||
| + | |||
| + | |||
| + | [[teaching: | ||
teaching/ie0624/proyectos/control_motores_sincronicos/codigo.1545016053.txt.gz · Last modified: 2022/09/20 00:08 (external edit)