Software para la simulación del comportamiento del conjunto Motor DC - Encoder TITULACIÓ: Enginyeria en Automàtica i Electrònica Industrial. AUTOR: Jacob Pié Vallvé. DIRECTOR: Esteban del Castillo Pérez. DATA: Juny / 2012 Índice 1 Memoria Descriptiva ........................................................................................... 4 1.1 Introducción ................................................................................................. 5 1.2 Objetivo ....................................................................................................... 5 1.3 Descripción de la Planta .............................................................................. 6 1.4 Modelado de la Planta................................................................................ 16 1.4.1 Modelo del Motor de corriente continua ................................................ 16 1.4.2 Análisis del modelo obtenido del Motor de corriente continua ............. 20 1.4.3 Excitación PWM y sus efectos ............................................................... 23 1.4.4 Conjunto Excitación PWM + motor DC ................................................ 29 1.4.5 El control PID......................................................................................... 32 1.4.6 Lazo de Control ...................................................................................... 35 1.4.7 Sintonización Controlador PID .............................................................. 36 1.4.8 Errores del sistema ................................................................................. 39 1.5 Emulador de la Planta ................................................................................ 42 1.6 Software de simulación de la Planta .......................................................... 47 1.6.1 Descripción del Software ....................................................................... 48 1.6.2 Librería Q5.h .......................................................................................... 49 1.6.3 Librería k1.h ........................................................................................... 54 1.7 2 Anexo A ............................................................................................................ 65 2.1 3 Modo de Uso .............................................................................................. 60 El motor de corriente continua................................................................... 66 Anexo B............................................................................................................. 72 3.1 Código Librería Q5.h ................................................................................. 73 3.2 Código Librería K1.h ................................................................................. 74 Proyecto final de carrera Página 2 4 5 Anexo C............................................................................................................. 78 4.1 Librería 8259.h ........................................................................................... 79 4.2 Librería Ini_IRQ.h ..................................................................................... 80 4.3 Librería PID.h ............................................................................................ 81 4.4 Librería Printer.h ........................................................................................ 82 4.5 Librería PWM.h ......................................................................................... 84 4.6 Librería Timer.h ......................................................................................... 84 4.7 Librería Main.c .......................................................................................... 86 4.8 Librería Ini_IRQ.c ..................................................................................... 90 4.9 Librería PID.c ............................................................................................ 94 4.10 Librería PWM.c ......................................................................................... 96 4.11 Librería Timer.c ......................................................................................... 98 Anexo D: Referencias ..................................................................................... 103 Proyecto final de carrera Página 3 1 Memoria Descriptiva Proyecto final de carrera Página 4 Memoria descriptiva 1 Memoria Descriptiva 1.1 Introducción Dentro del marco de asignaturas que se imparten en el plan de estudios de primer ciclo de la Ingeniería Técnica Industrial en Electrónica Industrial se encuentra la asignatura Informática Industrial II. En esta asignatura se forma al alumnado para que obtenga los conocimientos de hardware y software necesarios para la elaboración de software de control en un PC. Dentro de los créditos de la asignatura, se realizan unas prácticas en los laboratorios habilitados, donde se ejercitan los conocimientos adquiridos. Estas prácticas consisten en implementar un control de velocidad y de posición del eje de un motor de corriente continua, a través del interfaz del puerto paralelo de un PC bajo el sistema operativo MSDOS, utilizando como lenguaje de programación el lenguaje C. Para el desarrollo de las prácticas se dispone de una “planta”, la cual está formada por un motor de corriente continua, un encoder relativo y un circuito electrónico que realiza la función de interface entre el puerto paralelo del PC y el conjunto motor-encoder. Desafortunadamente, esta planta sólo está disponible en los laboratorios habilitados para la asignatura. Para facilitar el desarrollo de las prácticas, el profesor titular de la asignatura realizo un circuito electrónico que emulaba la planta en cuestión, de esta manera el alumnado podía avanzar en el desarrollo de las practicas fuera de la universidad. Desgraciadamente, a causa de la tendencia en los últimos años en la utilización de ordenadores portátiles para el desarrollo individual de las prácticas por parte del alumnado, surge el problema de que estos nuevos equipos raramente tengan accesible externamente el puerto paralelo, aunque este esté implementado la placa base como PC compatible, con lo que comporte que el emulador pierda su funcionalidad. Para desarrollar la parte teórica de este proyecto se ha utilizado como referencia bibliográfica el libro escrito por el sr Esteban del Castillo – Control de Procesos, donde describe la implementación de una plataforma hardware/software aplicada al conjunto motor dc-encoder. 1.2 Objetivo El objetivo del presente proyecto es implementar un simulador software a base de librerías basadas en lenguaje de programación C que simule el comportamiento de la “planta” disponible en los laboratorios de la asignatura. Proyecto final de carrera Página 5 Memoria descriptiva 1.3 Descripción de la Planta La “planta” utilizada en los laboratorios de la asignatura está formada por 3 piezas bien diferenciadas: - Motor de corriente continua Encoder relativo Placa electrónica interface puerto paralelo – PC Figura 1. “Planta” utilizada en los Laboratorios 1.3.1.1 Motor de corriente continua La máquina motriz utilizada es un motor de corriente continua de imanes permanentes del fabricante Maxon, de la serie F2140, concretamente el modelo 2140.93758.236-050. Obtener el modelo concreto del motor es interesante para poder realizar un estudio de la planta, obteniendo dados particulares de su comportamiento de su hoja de características. Cabe destacar el tipo de motor utilizado es un motor de corriente continua de imanes permanentes. Este tipo de motores están clasificados como máquinas especiales Proyecto final de carrera Página 6 Memoria descriptiva dentro del campo de las máquinas eléctricas, este hecho nos dificultara su estudio, ya que gran parte de simuladores de circuitos eléctricos no contempla este tipo de motores, sólo los motores de excitación independiente. En la figura nº 2 mostramos las principales especificaciones del motor, donde podremos observar los datos necesarios para su posterior modelado, pudiendo de esta manera comprobar que el modelo realizado se aproxima a la realidad. Figura 2. Características principales motor dc De la hoja de características podemos obtener los datos para el modelado del motor los cuales son los siguientes: Resistencia óhmica en bornes armadura (Ra) Inductancia en bornes armadura (La) Constante de tiempo mecánica (τm) Inercia del rotor (J) Constante de velocidad Constante mecánica (km) Velocidad en vacío A modo de información para el alumnado, hemos descrito las principales características de los motores de corriente continua en el anexo A, para así comprender el significado de estos. Más adelante realizaremos un estudio para obtener un modelo aproximado del motor para poder realizar una simulación de la “planta”. Proyecto final de carrera Página 7 Memoria descriptiva 1.3.1.2 Encoder relativo Para un control de velocidad o posición del motor se necesita posicionar el eje de este a través de algún elemento que nos proporcione la información necesaria para determinarlo. Una forma sencilla de obtener esta posición o velocidad es conectando el eje del motor a un encoder. En el mercado existen muchos tipos de encoders con características factibles para realizar esta operación. En este caso, la planta disponible en el laboratorio está equipada con un encoder relativo bidireccional de dos canales de salida A y B, el cual permite detectar el sentido de rotación del eje. Este es de la marca Hohner, de la serie 21, modelo 21-122-200 de 200 pulsos por vuelta. En la figura 3 mostramos el interior de un encoder relativo para podernos hacer una idea de cómo están construidos. Figura 3. Interior teórico Encoder incremental Es de gran importancia comprender el funcionamiento del encoder y las señales que nos proporcionará, para poder realizar las prácticas del laboratorio de la asignatura Informática Industrial II, tanto las rutinas que tendremos que implementar nosotros en el presente proyecto para simular el comportamiento de este. En la figura nº 4 mostramos las señales A y B con el paso del tiempo. Como podemos observar, éstas están desfasadas entre ellas 90 º. A través de esta característica podremos observar el sentido de giro del motor. Por ejemplo, si la lectura actual de las señales A y B es 01 y la anterior era 11, el sentido de giro será hacia la derecha, en cambio, si la lectura anterior era 00, el sentido de giro será hacia la izquierda. Proyecto final de carrera Página 8 Memoria descriptiva Figura 4. Señales A y B del encoder 1.3.1.3 Placa electrónica interface puerto paralelo – PC Para poder utilizar el motor y el encoder a través de nuestro PC tenemos que tener un interface que comunique ambas partes. La placa electrónica montada en el conjunto motor-encoder está formada por dos partes bien diferenciadas. La primera tiene la función de atender las salidas de nuestro PC a través del puerto paralelo y adecuar estas señales con la suficiente potencia para atacar al motor de corriente continua. La segunda, adapta las señales generadas por el encoder para que esa información pueda ser utilizada y leída por puerto paralelo. Cabe puntualizar que el motor de corriente continua es un actuador que modifica la velocidad de salida según el valor medio de la tensión de excitación. A razón de esto, nuestra etapa de potencia tiene que ser capaz de realizar pequeñas variaciones del valor medio de la tensión de salida. Generalmente cuando se debe realizar esta operación en las aplicaciones de control se utiliza la técnica de la modulación de anchura de pulsos, o más bien conocido por PWM. En la figura nº 11 mostramos el esquema de este interface. Si analizamos el esquema de potencia, podemos observar que el circuito de excitación de motor está formado por un puente en H de transistores. Estos transistores se han escogido con especial cuidado, ya que deben que tener unas características especiales. Si recordamos como está formado constructivamente el interior de un motor de corriente continua, veremos que está compuesto por unas bobinas. Éstas, durante el se cargan de energía, el problema surge en el período de . Cuando llega el período período el transistor no conduce, pero por la inductancia sigue circulando una IL, encontrándose la necesidad de dar continuidad a la corriente magnetizante. Para evitar la rotura del transistor, estos tienen que llevar incorporado un diodo volante para poder realizar la descarga de la corriente de la bobina en los periodos de desconexión. Otro punto a tener en cuenta es el aislamiento galvánico de la placa electrónica. Las corrientes inducidas por las bobinas del motor provocan ruidos en las tensiones de alimentación, al igual que la conmutación de los devanados del inducido sobre su colector Proyecto final de carrera Página 9 Memoria descriptiva de delgas, que se podrían propagar a las señales del puerto paralelo del PC, pudiendo dar a errores de lectura o escritura en la salida del puerto. [1] Sin dejar de analizar la parte de potencia, podemos ver que se ha implementado una protección eléctrica en el circuito de control del puente de transistores para evitar la conexión simultánea de los dos ramales de alimentación. Pin DB2 Pin DB3 Señal Derecha Señal Izquierda 0 0 1 1 0 1 1 0 1 0 0 1 1 1 1 1 Figura 5. Tabla Verdad Pins DB2 y DB3 Para poder activar cada ramal individualmente, el diodo del optoacoplador debe entrar en modo de conducción. Este sólo entrará en este modo si la señal proporcionada por el bloque lógico es cero, tal y como mostramos en la tabla de la verdad descrita anteriormente, de lo contrario restará abierto. Por otra parte, como hemos dicho con anterioridad, el encoder que tenernos instalado en nuestra planta entrega dos señales en cuadratura, a partir de la cuales podremos detectar el sentido de giro del motor. Para poder detectar un cambio de sentido se deberá realizar un seguimiento de la secuencia proporcionada por el encoder de las señales A y B, tal y como mostramos en la figura nº 6. Figura 6. Señales de salida circuito acondicionador encoder Proyecto final de carrera Página 10 Memoria descriptiva Como podemos ver, cada vez que alguna de las señales A y B cambia de estado, a través de un flanco de subida o bajada, el bloque lógico del interface del conjunto motormotor encoder detecta el cambio y genera la correspondiente interrupción en el puerto paralelo. par Los valores que se observan justo en el flanco en que se provoca la interrupción son los valores de las señales A y B, de esta manera podremos observar el sentido de giro del eje del motor. Donde la secuencia a seguir seria: Figura 7. Sentido de giro Para poder seguir la secuencia generada por el encoder, el interface motor – PC lleva incorporado un bloque lógico que genera una señal adecuada para interrumpir la CPU del PC justo cuando acontecen los flancos de subida y bajada de las señales A y B del encoder. Para poder detectar los flancos originados por el encoder se ha utilizado un circuito lógico basado en un diferenciador. Figura 7. Circuito diferenciador Como se observa en la figura 7 el circuito diferenciador detecta los flancos ascendentes endentes y descendentes. Esta será la base para crear el bloque lógico. Para poder calcular la red RC tenemos que tener en cuenta la frecuencia máxima en que el encoder nos entregara las señales. A razón de una velocidad máxima de nuestro motor de 3980 rpm y que el encoder utilizado provoca 800 flancos por revolución, tendremos: Proyecto final de carrera Página 11 Memoria descriptiva Por lo cual tendremos un flanco cada . Si suponemos que las ventanas del encoder no están todas alineadas, nos podría llegar un flanco en un intervalo menor. Para solventar deficiencias mecánicas podemos reducir este tiempo a como coeficiente de seguridad. Por otra parte, cabe puntualizar que para preservar los estados de la señal en su tránsito por los cables, debemos acotar la anchura del pulso de bajada. Un valor del orden de es adecuado. En la siguiente figura mostramos el bloque lógico detector de flancos, el cual responde a la siguiente ecuación: Figura 8. Bloque lógico donde caída igual a 1.8 V, entonces para viable es una y siendo implicara una . [1] el umbral del inversor en , donde una solución Figura 9. Detector de flancos ascendentes y descendentes Proyecto final de carrera Página 12 Memoria descriptiva En la figura nº 9 mostramos el bloque lógico correspondiente a la señal A del encoder para poder detectar tanto los flancos ascendentes y descendentes de la señal en cuadratura. La resistencia y limitan la corriente derivada por el diodo interno de la puerta inversora a valores inferiores a 1 mA si el valor de la resistencia es de 5,6 kΩ. [1] En la siguiente figura podemos observar las señales generadas por el bloque detector de flancos, donde la señal azul corresponde a la señal en cuadratura del encoder llamada A, y en cada flanco la correspondiente detección por parte de cada bloque detector, detectando tanto el flanco ascendente como el descendente. Nótese la amplitud del pulso generado por para suplir las deficiencias de los conductores de transporte de la el bloque, siendo de 4 señal. Figura 10. Señales resultantes del bloque de detención de flancos. El bloque lógico implementado tiene que ser lo suficientemente rápido para poder generar la solicitud a las interrupciones adecuadamente. Es importante que el tiempo en nivel cero de la señal generada sea el menor posible, de esta manera el tiempo de esta en nivel 1 será el más grande posible. De esta manera si tenemos una velocidad elevada del motor el bloque lógico tendrá tiempo de generar los dos pulsos de interrupción entre las ventanas de cuadratura del encoder, ya que la señal de solicitud tendrá un pulso por paso por cero muy pequeño. En la figura nº 11 mostramos todo el montaje del interface para utilizar el conjunto motor-encoder, compuesto por las partes de potencia que alimenta al motor y lógica de control, que adapta las señales del encoder al puerto paralelo del PC. Proyecto final de carrera Página 13 Memoria descriptiva Figura 11. Esquema placa Interface con el PC En la tabla nº 1 mostramos la asociación de señales y pins del puerto paralelo. Podemos observar la dirección de la información de cada pin. En la Tabla nº 2 mostramos los registros propios del puerto paralelo y la asociación con el conector de la Tabla nº 1. Ell registro base de un puerto paralelo está ubicado en una de las direcciones 0x378, 0x278 o 0x3BC. Los pines utilizados por el interface motor – PC son los siguientes: siguientes Pins 2 y 3 del Registro Base + 0 (ataque puente transistores) Pins 12 y 13 del Registro Base + 1 (información del encoder) Pin 10 del Registro Base + 2 (activación de la IRQ del Puerto) Proyecto final de carrera Página 14 Memoria descriptiva Señal Pin Dirección /Strobe 1 OUT Data 0 2 OUT Data 1 3 OUT Data 2 4 OUT Data 3 5 OUT Data 4 6 OUT Data 5 7 OUT Data 6 8 OUT Data 7 9 OUT /Acknowledge 10 IN Busy 11 IN Paper End 12 IN Select 13 IN /Auto Feed 14 OUT /Error 15 IN /Inicialize Printer 16 OUT /Select Input 17 OUT 18-25 - Ground Tabla 1. Puerto DB25 PC Base + 0: Registro de lectura/escritura Bit 7 Pin 9 Bit 6 Pin 8 Bit 5 Pin 7 Bit 4 Pin 6 Bit 3 Pin 5 Bit 2 Pin 4 Bit 1 Pin 3 Bit 0 Pin 2 Bit 3 Pin 15 Bit 2 - Bit 1 - Bit 0 - Bit 2 Pin 16 Bit 1 /Pin 14 Bit 0 /Pin 1 Base + 1: Registro de solo lectura Bit 7 /Pin 11 Bit 6 Pin 10 Bit 5 Pin 12 Bit 4 Pin 13 Base + 2: Registro de lectura/escritura Bit 7 - Bit 6 - Bit 5 - Bit 4 IRQ Bit 3 /Pin 17 Tabla 2. Registros del puerto paralelo Proyecto final de carrera Página 15 Memoria descriptiva 1.4 Modelado de la Planta Durante el transcurso de la carrera se han realizado asignaturas donde se imparte teoría para modelar plantas en el espacio del control continuo y la implementación de controladores ontroladores para su control. control Encontramos interesante realizar un estudio del modelado de una planta real donde podremos simular elementos concretos, estudiar sus respuestas y comprobar las aproximaciones realizadas durante el modelado respecto al elemento real. real De esta manera encontrándonos ndonos con problemas reales del modelado y la correcta identificación de los parámetros suministrados por los fabricantes de los elementos (motor dc, encoder …). …) En la referencia bibliográfica nº 2 podemos encontrar en un pequeño resumen de la identificación ción de los parámetros y modelado de un pequeño motor de corriente continua. 1.4.1 Modelo delo del Motor de corriente continua conti En la figura nº 12 mostramos el esquema del cual partiremos para modelar el motor de corriente continua de imanes permanentes, permanentes obteniendo su modelo matemático y representándolo en el programa de simulación Matlab. Figura 12. Motor DC imanes permanentes Partimos de las siguientes expresiones en el dominio de Laplace, las cuales representan el comportamiento eléctrico del motor: Combinando las ecuaciones 1 y 2 obtendremos la corriente de armadura Proyecto final de carrera Página 16 Memoria descriptiva 4 Por otra parte, el par generado por el motor es el siguiente: 5 El par mecánico neto en el eje del motor será el resultante de: 6 Combinando las ecuaciones 4 y 6 obtenemos la relación entre el torque neto con la corriente de armadura. 7 En la siguiente figura, mostramos el esquema de bloques el modelo matemático del motor de corriente continua con excitación permanente a través de los imanes de su estator. Figura 13. Modelo matemático Motor DC Proyecto final de carrera Página 17 Memoria descriptiva Por otro lado, utilizando la segunda ley de Newton, obtenemos que el par neto del motor es: ! " 8 donde ! corresponde al momento de inercia del eje del motor y su carga y " la fricción de estos. Si consideramos que el par perturbador 8 obtendremos: ! es nulo e igualamos las ecuaciones 7 y 9 " operando la ecuación 9: ! 10 " ' ! ( " 11 obteniendo la función de transferencia del motor a partir de la ecuación nº 11 ' ! ( " 12 identificando los términos: ! * ' ! " ( " 13 donde tendríamos que tener una función normalizada de la forma: , Proyecto final de carrera * - * 2 . - - * Página 18 Memoria descriptiva Esta función de transferencia es la que describe la figura de bloques nº 8, siendo un sistema de segundo orden. Generalmente llegados a este punto, se suele simplificar la ecuación de transferencia despreciando frente de y la / frente la / obteniendo así una función de transferencia de primer orden. Quedando la función de transferencia descrita en la ecuación nº 13 de la siguiente manera: ! 14 " Al igual que en el sistema de segundo orden, deberíamos buscar la función de transferencia equivalente normalizada. , ,0 / 1 entonces: ! " " " ! 1 15 de forma que: ,0 / Proyecto final de carrera 16 " " ! 17 Página 19 Memoria descriptiva 1.4.2 Análisis del modelo obtenido del Motor de corriente continua Una vez realizado el modelado del comportamiento físico del motor podemos pasar a simular los resultados obtenidos en los sistemas de primer y segundo y contrastarlos con las características proporcionadas por el fabricante. De esta manera podremos comprobar la diferencia entre modelos, si la hubiera, y los diferentes resultados según la inclusión u omisión de ciertos parámetros. 1.4.2.1 Simulación sistema segundo orden El sistema a simular en este apartado está representado en la figura nº 13. Este es un modelo de segundo orden sin realizar ninguna apreciación o simplificación, excepto la de considerar el torque perturbador nulo. La simulación de este se realizará en lazo abierto para observar la respuesta de este a un escalón unitario. Los parámetros subministrados por el fabricante los podemos encontrar en la figura nº 2 de la memoria descriptiva de este proyecto. Estos parámetros son los siguientes: 41,5 2 - 5,02 34 - 55,2 353/7 - ! ; == 22,1 893² ? 24 Podemos observar que el fabricante, en los datos proporcionados, no habla en ningún momento del coeficiente de fricción que tiene el rotor. Considerando que es un motor muy pequeño, podemos estimar que este coeficiente debe ser nulo. Entonces realizaremos una primera aproximación de este modelo y efectuaremos la simulación del sistema sin este parámetro. En la figura nº 14 podemos observar el resultado obtenido de la simulación del sistema. Podemos apreciar que este no se ajusta del todo a la realidad según los parámetros entregados por el fabricante. Proyecto final de carrera Página 20 Memoria descriptiva Figura 14. Simulación modelo 2º orden sin coeficiente de fricción. Según los datos de la figura nº 2 la velocidad del motor en vacío es de 3980 rpm, en la simulación del modelo obtenemos una velocidad en vacío de 4151,5 rpm, lo que supone una diferencia entre el modelo y los datos reales del 4,3 %. Esta diferencia entre los datos del fabricante y los obtenidos en la simulación puede venir causada por la aproximación realizada en la omisión del coeficiente de fricción del modelo. Para obtener el valor del coeficiente de fricción del rotor tenemos una aproximación matemática: ;> ! / 18 que nos relaciona la inercia del rotor y la constante mecánica del sistema para obtener el coeficiente de fricción. Aplicando la formula, obtenemos: ; ! / 22.1 10@A 30 10@B 7.36 10@C Con este término, deberían coincidir los resultados de una nueva simulación con el modelo completo del motor, pero debemos ajustar este valor hasta 3,17 10@D para que los resultados obtenidos sean iguales al del fabricante. Proyecto final de carrera Página 21 Memoria descriptiva 1.4.2.2 Simulación sistema primer orden La ecuación nº 15 de la memoria descriptiva representa la simplificación del modelo del motor a un sistema de primer orden. La ecuación de transferencia normalizada de un sistema de primer orden, como hemos descrito anteriormente, es: , / ,0 1 Si paramos atención a la ecuación, podremos identificar los términos que la definen en los datos proporcionados por el fabricante. Siendo más sencillo realizar la simulación del sistema con estos datos que no a través de la ecuación encontrada mediante el modelado. Donde ,0 es la ganancia del sistema en E F ∞ que podemos identificar con el parámetro denominado como constante de velocidad (definido en el Anexo A) con un valor de 173 rpm/V. Por otra parte, la / del sistema la podemos identificar con la / del motor, con un valor de 30 10@B segundos. Con estos datos podemos proceder a realizar la simulación del sistema de primer orden, obteniendo estos resultados mostrados en la figura nº 15. Estos resultados son muy semejantes a los resultados obtenidos en la primera simulación del modelo de segundo orden, mostrados en la figura nº 14, donde no se tenía en cuenta el coeficiente de fricción del rotor. Si leemos con detenimiento la definición del parámetro de la constante de velocidad podremos ver que el valor suministrado por el fabricante no tiene en cuenta las pérdidas por fricción, de ahí la semejanza de resultados. Figura 15. Simulación modelo 1º orden. Proyecto final de carrera Página 22 Memoria descriptiva Teniendo en cuenta la definición de esta constante y realizando un pequeño ajuste de esta en el modelo, obtendremos los siguientes resultados: Figura 16. Simulación modelo 1º orden con parámetros ajustados. Con la constante de velocidad ajustada a 165,83 rpm/V, obtenemos un modelo aceptable del motor de corriente continua de imanes permanentes. A partir de este punto utilizaremos este modelo para la realización del resto de simulaciones. 1.4.3 Excitación PWM y sus efectos Como ya hemos descrito con anterioridad, el motor de corriente continua está alimentado a través de un puente en H de transistores con diodo volante y controlados por una excitación PWM. Este tipo de excitación provoca unos efectos sobre el motor dependiendo del tiempo de HI y HJJ en que nos encontremos, los cuales se traducen en una alimentación pulsante con periodos de KK y 0V respectivamente. Durante el periodo de HI el transistor está en modo de conducción y por las bobinas del motor circula , pero en HJJ el transistor corta la alimentación del motor y anula la corriente a su través. En consecuencia, se abre camino a través del diodo volante del transistor. Proyecto final de carrera Página 23 Memoria descriptiva Estee tipo de excitación modifica el comportamiento del modelo del motor estudiado hasta ahora [1].. Para comprobar este efecto, efecto hemos simulado el motor en el programa de simulación PSIM y Pspice para observado su comportamiento. Inicialmete hemos simulado la midad del puente en H con el programa Pspice con transitores sin diodo volante, para verificar la hipotesis inicial. Como carga hemos conectado una red RL de caracteristicas similares al modelo de primer orden. Figura 17. Ramal derecho puente H. En la siguiente figura se pueden observar la evolución ev temporal de la tensión y de la intensidad en la carga en la simulación del ramal derecho del puente en H (sin diodos volantes). Figura 18. Resultado simulación Ramal derecho puente H. Proyecto final de carrera Página 24 Memoria descriptiva Podemos observar que justo en el flanco de bajada donde se produce la desconexión por parte del transistor darlingthon se genera un pico negativo de tensión, que corresponde a la corriente magnetizante de la carga intentando abrise camino por las uniones de los transistores. En el caso de no incorporar diodo volante, estos transistores podrían dañarse. La simulación realizada es a titulo informativo y no es comparable en magnitud al estudio realizado del modelo del motor y su excitación, y a que la carga simulada no se ajusta totalmente al modelo anterior. Siguiendo con el estudio, realizaremos una comparación para encontrar la diferencia entre ambas excitaciones, Pero cabe nombrar que el programa de simulación PSIM no incluye la librería para simular el motor de DC de imanes permanentes, soló el motor DC de excitación independiente, el cual hemos tenido que adaptar para conseguir las mismas características que el motor de nuestro modelo. Seguidamente especificamos los parámetros empleados. Figura 19. Parámetros modelo motor DC para PSIM . En la figura nº 20.1 mostramos el esquema de la excitación PWM sin diodo volante y en la figura nº 20.2 el esquema con el diodo incorporado. Proyecto final de carrera Página 25 Memoria descriptiva Figura 20. Circuito simulación comportamiento PWM sobre motor dc. En la figura nº 21 podemos observar el resultado de la simulación sin diodo volante en los transistores de alimentación al motor. Se puede ver el pico de tensión negativa justo en la desconexión por parte de los transistores. Figura 21. Tensión transistor de la excitación PWM sin diodo volante. En la figura nº 22 se muestra la tensión del transistor con diodo volante incorporado. Se observa que el pico negativo justo en la desconexión del transistor se ha reducido considerablemente, concretamente a 1.4V que corresponde a la suma de la tensión en cada diodo en modo de conducción. Cabe puntualizar que las magnitudes de los valores mostrados en las graficas 21 y 22 son magnitudes aproximadas ya que ha utilizado una carga de 1º orden similar al modelo del motor. Proyecto final de carrera Página 26 Memoria descriptiva Figura 22. Comparación entre modelos de la corriente armadura motor dc. Visto que la alimentación del motor es de tipo pulsante y no de forma continua a causa del tipo de excitación, modificaremos el modelo para incluir esta variación del comportamiento. Si reemprendemos el estudio del modelo de primer orden encontrado en la ecuación nº 15 e incluimos este efecto, tendremos el siguiente modelo [1]: Figura 23. Esquema modelo + excitación. Donde la función de transferencia es: , Proyecto final de carrera " " ! 1 18 Página 27 Memoria descriptiva Despreciando los términos resultantes del producto de tendremos la ecuación: " , ! " " frente al producto de 19 1 Donde sustituiremos las variables A y B para poder trabajar con más claridad en el modelo, quedando: 7 L " M ! " 20 Si resolvemos el lazo de control del circuito anterior, obtendremos: 1 M M 7 7 1 7 1 7 M 1 7 7 M 7 1 1 1 21 Substituyendo con los datos obtenidos en los análisis anteriores tendremos como resultado final: ! 22,1 10@A 3² , " 4 10@D , 1959,73 0.35 1 41,5 2 , 55,2 353/7 22 Volviendo al tema que nos ocupaba al inicio del capítulo, la excitación PWM debe convertir una señal analógica con valor de == a una señal digital de periodo y amplitud constantes, obteniendo como resultado una señal con valor medio proporcional a la señal de entrada. Esta proporción se alcanza variando el tiempo de E y ajustando el tiempo de E conservando de esta manera el tiempo T constante sin variar el periodo de la señal. La función de transferencia del sistema será: 3 Proyecto final de carrera == E 23 Página 28 Memoria descriptiva y su modelo en Simulink: Figura 24. Esquema modelo PWM. 1.4.4 Conjunto Excitación PWM + motor DC Como ya habremos podido intuir con los resultados vistos en el apartado anterior, la velocidad instantánea de nuestro motor se ve influida directamente por la frecuencia de la excitación PWM. Si observamos la figura nº 25 vemos unas fluctuaciones de velocidad que del PWM. vienen causadas por los periodos de E y E Si alimentamos la entrada (m) del modulador PWM con una rampa unitaria observaremos en la respuesta del conjunto una amplia zona con fluctuaciones de velocidad [1]. En la figura nº 25 se muestra la gráfica de la velocidad de salida del sistema frente al ciclo de trabajo del la excitación PWM en forma de rampa con pendiente unitaria (multiplicando el eje X por un factor de 100 para observar mejor el efecto) donde se hacen presentes estas fluctuaciones. Figura 25. Respuesta del sistema. Proyecto final de carrera Página 29 Memoria descriptiva Las fluctuaciones de velocidad que se observan son a consecuencia de una frecuencia relativamente baja de la excitación PWM. Conociendo que la constante mecánica del motor es de 30 ms y que el periodo del PWM es de 20 ms, surge este efecto a causa de la proximidad de ambos tiempos. Este efecto puede ser reducido aumentando la frecuencia de conmutación de la excitación.[1] En la figura nº 24 se expone la evolución de la velocidad del motor y la señal del PWM de forma idealizada. Figura 26. Evolución de la velocidad del motor La evolución de la velocidad entre ambos tramos viene dada por la siguiente ecuación: O N N NP N Q @RU ST 24 donde N es la velocidad final a que llegaría el motor para t WX T y V[[ 10 , siendo N 1640 \]3 y zero en t W^^ T y V[[ 0 , N N es la velocidad inicial de partida y / es la constante de tiempo mecánica del motor. Si consideramos que la constante de tiempo mecánica del motor es la misma para cuando el motor aumenta su velocidad que cuando disminuye, se deducen las siguientes ecuaciones: _ N O * Considerando que para E P Q N Q @RU ST t WX , ]`\` 0 a E a t WX 25 ]`\` t WX a E a T _ * N Proyecto final de carrera @RU ST 1 y que para E 1 7 7 M 26 T, nos queda: 27 Página 30 Memoria descriptiva M * 28 donde: 7 M Q Q = b ST @ = b ST 29 30 En la figura nº 27 mostramos el resultado de la simulación de las anteriores ecuaciones, obteniendo la relación existente del rizado de la velocidad * frente al ciclo de trabajo (dc). Se puede observar claramente que cuanto mayor es la frecuencia de la excitación del PWM, menor es el rizado del motor, con lo que comporta que la frecuencia de conmutación no puede ser escogida a la ligera. A priori podríamos pensar que cuanto más elevada sea esta mejor, ya que tendríamos un rizado muy pequeño, pero se tienen que tener en cuenta otros factores, como por ejemplo, la resolución temporal de nuestro sistema… En este caso, debemos tener en cuenta que el tic del sistema se utiliza para generar la onda de la excitación PWM, siempre que la frecuencia del PWM sea del orden de magnitud de 10 veces mayor que la resolución del sistema no se intuyen problemas en la generación de la onda de excitación del PWM. Por ejemplo un tic de 50μ y una frecuencia PWM de 0.53 . Figura 27. Rizado de velocidad en función del ciclo de trabajo Proyecto final de carrera Página 31 Memoria descriptiva 1.4.5 El control PID Las siglas del controlador responden a la identificación de las partes activas de este, definido por las letras PID (Proporcional – Integral – Derivativo). [2] Donde: - P es la acción de control proporcional y da una salida del controlador que es proporcional al error actual, respondiendo a la siguiente función de transferencia: L E donde - d d Q E 31 es la constante proporcional ajustable. I es la acción de control integral y da una salida del controlador que es proporcional al error acumulado, respondiendo a la siguiente función de transferencia: L E 1 N R eQ E 0 f E 32 El bloque integral tiene como propósito disminuir y eliminar el error en estado estacionario provocado por el modo proporcional. El control integral actúa cuando hay una desviación entre la variable y el punto de consigna, integrando esta desviación en el tiempo y sumándola a la acción proporcional. - D es la acción de control derivativo, la cual tiene un carácter de previsión al error con lo que hace más rápida la acción del controlador, aunque tiene la desventaja de amplificar las señales de ruido y provocar la saturación en el actuador. Esta responde a la siguiente función de transferencia: L E Proyecto final de carrera fQ E f E 33 Página 32 Memoria descriptiva La suma de estas tres acciones responde a la función de transferencia: L E d 1 gQ E N R eQ E 0 fQ E h f E f E 34 Este algoritmo será implementado por el alumnado dentro de las practicas de la asignatura, y formará parte del software que se elabore, no siendo una parte física de nuestra planta. El algoritmo del controlador PID se tendrá que discretizar ya que será ejecutado en un sistema de procesado digital. De esta manera, la ecuación del controlador quedará de la siguiente manera: ∆L ∆L d L LO Q j1 N *Q k, * 1 1 d j1 P 35 BQ 2 k 2 L 36 B d 37 La ecuación nº 36 proporcionará al alumno el incremento que debe aplicar a la salida actual para corregir la respuesta del sistema. Si observamos la ecuación podremos ver que el controlador utiliza muestras anteriores del error para determinar el nuevo incremento en la salida, de esta forma sigue su evolución. Para poder utilizar la función discretizada en Simulink debemos emplear la transformada zeta. Simulink ya dispone de bloques preestablecidos para la discretización de ecuaciones, veamos el esquema de bloques. Figura 28. Unidad de retardo transformada zeta A través de este bloque podremos realizar el retardo de una muestra, consiguiendo por ejemplo Q 1 . Proyecto final de carrera Página 33 Memoria descriptiva En la siguiente figura mostramos la suma de todos los bloques del controlador, ya discretizados y en formato Simulink. Hemos enmarcado los bloques por funcionalidad para una mejor identificación. Figura 29. Controlador PID discretizado De la ecuación nº 36 podemos desgranar directamente este esquema, donde el bloque integrador multiplica el error actual por la constante / N , el bloque proporcional resta al valor actual del error el error anterior, resultando el incremento de error desde 1 a , 1 y 2 y la parte diferencial tiene en cuenta la evolución de los incrementos en y lo multiplica por la constante / . Para un sistema de control con un amplio rango de condiciones de operación, puede suceder que la variable de control alcance los límites prefijados del actuador. Cuando esto pasa, el bucle realimentado permanece en su límite independientemente de la salida del proceso. Si se usa un controlador con acción integral, el error continuará siendo integrado, incrementando aún más su valor. Esto significa que el término integral puede volverse muy grande. Para evitar esta situación se inserta el bloque de saturación, el cual implementa el concepto de la saturación integral del controlador. Éste está ubicado al final del controlador para evitar entregar a la etapa siguiente cualquier valor superior al máximo de operación, pero por otro lado, este bloque también permite una operatividad permanente del controlador, al evitar la saturación de la variable controlada. Por otra parte, el bloque de retardo colocado en el bloque integrador tiene la función de implementar la integral, ya que tenemos que recordar que este algoritmo entrega a su salida en incrementos. Las constantes ld , N , L juegan un papel importante en el comportamiento del controlador, pudiendo llevar el sistema a un error próximo a zero o por lo contrario llevarlo a la inestabilidad. La sintonización de estas variables no es una tarea fácil, por suerte hay herramientas para averiguar sus valores. Por ejemplo la técnica Ziegler-Nichols. Proyecto final de carrera Página 34 Memoria descriptiva 1.4.6 Lazo de Control La suma de todos los bloques anteriores forman el modelo completo de la planta y su realimentación para el lazo de control. Figura 30. Modelo simulink lazo de control Si procedemos a la simulación del conjunto global a una consigna concreta de 500 rpm observamos los siguientes resultados: Figura 31. Salida modelo completo con control PI con PWM 50 Hz Proyecto final de carrera Página 35 Memoria descriptiva Este resultado se ha obtenido mediante un control proporcional e integral. Se puede observar que el resultado obtenido es muy próximo a la consigna al sistema. Existe un pequeño rizado que puede venir provocado por la frecuencia de la excitación PWM como ya se explico en su momento en el apartado nº 1.4.4, que en este caso es de 50 Hz Si en cambio aumentamos la frecuencia de conmutación de la excitación a 100 Hz veremos que el rizado se reduce sensiblemente, y sin haber cambiado las constantes del controlador. Figura 32. Salida modelo completo con control PI con PWM 100 Hz 1.4.7 Sintonización Controlador PID Para sintonizar el controlador de la planta podemos utilizar el método diferentes métodos. [2] Método basado en la respuesta temporal a un escalón en lazo abierto (ZieglerNichols). Es un método grafico. Consiste en encontrar la respuesta del sistema en lazo abierto a un escalón. Seguidamente tendremos que observar el resultado y extraer los siguientes parámetros Proyecto final de carrera Página 36 Memoria descriptiva A través de la siguiente tabla podremos encontrar las diferentes constantes del controlador. Controlador P PI PID Kp Ti Td 1/a 0.9/a 3·L 1.2/a 2·L L/2 Método de la respuesta en lazo cerrado Este método consiste en conocer la ubicación de los polos del sistema utilizando el criterio de Nyquist, e ubicar estos justo encima del eje imaginario, encontrando entonces los parámetros lm (ultima ganancia) y m (útimo periodo) Para encontrar estos parámetros podemos proceder de la siguiente manera: 1. Eliminar las acciones integral y derivativa. 2. Aumentar k lentamente hasta que la planta empiece a oscilar. En el momento que se produzca la oscilación obtendremos los parámetros lm L m A través de la siguiente tabla podremos encontrar los parámetros del controlador: Controlador P PI PID Proyecto final de carrera Kp 0,5·lm 0,4·lm 0,6·lm Ti 0,8· 0,5· Td m m 0,125· m Página 37 Memoria descriptiva Método Empírico Procederemos de la siguiente manera: 1. Eliminar del controlador las acciones integral y derivativa (Td=0, Ti=inf) 2. Aumentar K hasta que encontremos una respuesta de la planta satisfactoria, sin tener en cuenta el error estacionario. 3. Aumentar K y con la acción derivativa intentar recuperar la respuesta obtenida en el apartado anterior.. 4. Repetir el anterior apartado hasta que k sea lo más grande posible. 5. Agregar la acción integral para eliminar el error en estado estacionario. Proyecto final de carrera Página 38 Memoria descriptiva 1.4.8 Errores del sistema 1.4.8.1 PWM Para poder obtener el menor rizado de velocidad en el eje del motor deberemos tener una excitación PWM con una regulación muy precisa. Este tipo de regulación implicará tener unos incrementos de E y E muy pequeños, en consecuencia necesitaremos un tic del sistema adecuado para poder generar estos tiempos [1]. Figura 33. Onda PWM En la figura anterior se puede observar el efecto que provocaría el incremento de un tic en la velocidad del motor. Claramente, si el tiempo E es más grande el motor alcanzara una mayor velocidad, y su media se verá modificada. Para examinar mejor este efecto, volveremos al estudio realizado en el apartado 1.4.4. donde extrajimos las siguientes formulas: N 1 1 7 7 M M * 27 28 donde: 7 M Proyecto final de carrera Q Q = b ST @ = b ST 29 30 Página 39 Memoria descriptiva Las cuales nos ayudaran a través de una simulación de Matlab a ver la influencia de un tic en el tiempo de E . dc=[0:0.01:1]; Taus=30e-3; Taub=500e-3; T=10e-3; A=exp(dc*(T/Taus)); B=exp((1-dc)*(T/Taub)); Wfin=1640; for n=1:101, W1(n)=Wfin*((1-A(n))/(1-A(n)*B(n))); W2(n)=B(n)*W1(n); end T=10e-3; tic=0.5e-3; x=(dc+(tic/T)); for m=1:101, if x(m)>1 x(m)=1; end end A=exp(x*(T/Taus)); B=exp((1-x)*(T/Taub)); Wfin=1640; for n=1:101, W3(n)=Wfin*((1-A(n))/(1-A(n)*B(n))); W4(n)=B(n)*W3(n); end figure(1) hold on; plot(dc,(W4-W2)); xlabel('Ciclo de Trabajo') ylabel('incremento (rpm)') hold off; Código 1. Simulación incremento velocidad respecto dc En la siguiente figura podemos observar la influencia que tiene un incremento del ciclo de trabajo de dc de un solo tic frente a la velocidad del motor, pasando a ser un ciclo de trabajo de dc a n9 o Ep9/ . Proyecto final de carrera Página 40 Memoria descriptiva Figura 34. Incremento de velocidad respecto el punto de trabajo y el tic Dependiendo de la base de tiempo del sistema un solo incremento de E en una magnitud de tic, para un ciclo de trabajo pequeño causa un incremento de velocidad muy grande. Este efecto provoca una mala regulación de la velocidad y la posición del eje del motor. El objetivo deseado es la mayor resolución de la excitación PWM posible, para poder evitar estos saltos de velocidad en un solo incremento. Cuanto más pequeño sea el tic más resolución obtenemos y en consecuencia tenemos una mejor regulación. Figura 34.1. Incremento de velocidad a causa del incremento de un tic La frecuencia de la excitación PWM viene dada por: 1 1 q Ep9 la cual es la inversa de n veces la base de tiempos tic de nuestro sistema. Si disminuimos el valor de tic, aumentaremos el valor de n, consiguiendo una mejor resolución al tener un tiempo base tic más pequeño. Proyecto final de carrera Página 41 Memoria descriptiva En cuanto al error producido por un incremento de tic en el tiempo de E , cuanto más pequeño sea éste, menor desviación tendremos en el punto de trabajo dc de la excitación PWM. Por ejemplo, con una frecuencia de excitación del PWM de 50 Hz y un ciclo de trabajo de 0,05 el error causado por un tic de 50μ es de: n9 ∆Ep9 0,05 50μ 203 0,0525 F rs |0,05 0,0525| 0,05 5% En cambio, para un tic de 10μ , el error causado por el incremento del tic es de: n9 1.5 ∆Ep9 0,05 10μ 203 0,0505 F rs |0,05 0,0505| 0,05 1% Emulador de la Planta A causa del coste de los equipos del conjunto Motor-Encoder se dispone de unas unidades limitadas. Con el fin de facilitar al alumno la realización de las prácticas en los laboratorios o bien en horas no lectivas se decidió crear un emulador para substituir el equipo principal. Este emulador es una placa electrónica de medidas reducidas que puede conectarse al puerto paralelo del PC, de forma que es substituible un equipo por otro sin realizar ningún cambio. Este nuevo equipo debe generar las señales Ay B del encoder según la tensión media que aplique la excitación PWM, y la señal de petición de interrupción al puerto paralelo. Para facilitar el diseño se utilizó el modelo de primer orden de respuesta lineal, sin contemplar el efecto del PWM y el diodo volante del puente de alimentación [1]. En la siguiente figura mostramos la base del diseño para la creación de este emulador. En la fase inicial se decidió que el emulador no diferenciaría entre el giro de derechas e izquierdas. De aquí que los pines 2 y 3 de salida del PWM desde el PC se les aplica la función OR. Proyecto final de carrera Página 42 Memoria descriptiva Figura 35. Conversión señal PWM a frecuencia a través C.I 555 La siguiente etapa se instalo para realizar una separación entre el integrador y las señales de entrada. Para dotar al emulador de unas características similares a las del motor se ha insertado un integrador con la misma constante de tiempo que tenía el sistema original, dotando de esta manera una dinámica parecida al conjunto del motor-encoder. La tensión media del integrador responderá a la siguiente ecuación: N 1 e N nE N v E 31 y su evolución temporal seguiría a una forma de onda parecida a la siguiente figura. (Orden y magnitud no comparables, sólo como ejemplo) Figura 36. Señal de salida integrador Proyecto final de carrera Página 43 Memoria descriptiva Si fijamos que la función de transferencia del sistema de primer orden del motor es: 115 0.03 1 , 32 y la función de transferencia del integrador: ,N w 1 1 / 1 1 0.033 1 1 33 Donde las dos funciones de transferencia anteriores deberían de ser parecidas para poder tener una dinámica comparable. La etapa de la fuente de corriente proporcionara la ganancia necesaria para equiparar las dos funciones de transferencia, donde esta suministrara una corriente de colector con valor: = x y z yz x 0.7 3300 N 34 El espejo de corriente se encargara de cargar el condensador de 33 nF con la misma intensidad que el colector de la fuente de corriente. Entonces la corriente de este dependerá de la tensión de salida del integrador, siendo: = 1 e p= nE w 1 w = E 35 Si consideramos que la corriente del condensador sigue una evolución con pendiente constante, tendremos que la tensión entre bornes será: Figura 37. Tensión en bornes del condensador Proyecto final de carrera Página 44 Memoria descriptiva Donde nombraremos la amplitud de la señal entre 1/3 y 2/3 de Vcc con el nombre de A, que corresponderá a: 7 = 36 w donde despejaremos: w 7 37 = y en consecuencia la frecuencia de la señal: = " 38 7 w donde substituiremos el valor de = : " 1 7 w N z yz 1 7 w N v E z yz 39 En este punto, si configuramos el oscilador C.I. 555 en formato de multivibrador estable obtendremos una señal de salida de este con una frecuencia de " 23.7 4{, siendo w 33 q|, z 3,3 2, yz 0.7 y == > N v 5 Realizando este circuito hemos creado un oscilador controlado por tensión, que en consecuencia relaciona el ciclo de trabajo del PWM con la frecuencia de salida del oscilador. El motor real considerado para la realización del emulador tiene una velocidad máxima de 1725 rpm, el cual tiene unido el encoder relativo con una resolución de 200 pulsos/revolución. Esta unión de elementos, a su máxima velocidad de funcionamiento según una tensión de alimentación de 15 V, nos supondría una frecuencia de " 200 AC0 5750 4{. D0 Esta frecuencia es del orden de 4 veces menor que la frecuencia del oscilador C.I.555, por lo que tendremos que dividir esa frecuencia para conseguir una frecuencia parecida al conjunto del motor-encoder. Proyecto final de carrera Página 45 Memoria descriptiva Para dividir esta frecuencia se han instalado unos biestables tipo D en cascada, los cuales dividirán la señal por 4 y generaran la señal en cuadratura parecida a la del encoder. También se tiene que incluir la detención de flancos para provocar la señal de la solicitud de interrupción IRQ-7, donde utilizaremos los circuitos estudiados en la figura nº 9. Figura 38. Circuito Emulador En la siguiente figura podemos observar la evolución de las señales que genera el emulador. Vemos la señal producida por el oscilador C.I.555 y cómo el biestable A1 reduce su frecuencia a la mitad, luego los biestable A2 y A3 generan la señal en cuadratura, y los detectores de flanco generan la señal para la petición de la interrupción IRQ-7. Proyecto final de carrera Página 46 Memoria descriptiva Figura 39. Relación de la evolución de las señales Emulador 1.6 Software de simulación de la Planta La premisa del software realizado en el presente proyecto es la de simular el “comportamiento” de la planta descrita en el anterior apartado, facilitando la tarea de desarrollo de las practicas de la asignatura en horas no lectivas. Figura 40. Concepto Simulador Proyecto final de carrera Página 47 Memoria descriptiva No es objeto del proyecto realizar una simulación del modelo matemático del conjunto motor dc + encoder, sino el crear unas librerías que simulen el comportamiento de la velocidad del motor respecto la alimentación recibida por la etapa de la excitación PWM, obteniendo como resultado las correspondientes señales del encoder. El camino fijado para la realización del presente simulador ha sido el componer un código que interactúe el mínimo posible con el alumno que realiza las prácticas de la asignatura, de modo que éste no desvíe su atención en la utilización/comprensión del código del simulador. De esta manera, el éxito del simulador será proporcional a su sencillez de utilización, pretendiendo confundir lo mínimo posible al alumno. Desafortunadamente, para el flujo de información entre el código creado del emulador y el código del alumno habrá una serie de restricciones, las cuales serán descritas más adelante. 1.6.1 Descripción del Software Siguiendo por el camino de la sencillez, el código del simulador se ha implementado en ficheros de cabecera *.h para facilitar su uso. Estas librerías están formadas por un código fuente en forma de macros, siguiendo al estilo de las librerías facilitadas en la asignatura para la realización de las prácticas. Este hecho ha condicionado el desarrollo del simulador. También se ha tenido en cuenta los diferentes modos de programación que se pueden utilizar en el entorno de Turbo C. Si el alumno ha realizado todo el código fuente directamente en el archivo main ( ), o por lo contrario, si el alumno ha escogido realizar un proyecto, separando en archivos el código fuente. Para facilitar la realización del código del simulador se han atacado los diferentes problemas en dos librerías diferentes, desglosando en cada archivo las macros pertinentes. Formando 2 librerías nombradas Q5.h y k1.h donde en ellas reside tanto el código del simulador, como las funciones que debe utilizar el alumno para emplearlo. Figura 41. Concepto Simulador Proyecto final de carrera Página 48 Memoria descriptiva El archivo nombrado Q5.h aborda el problema del modo de programación utilizado por el alumno (archivo main ( ) o proyecto) y el modo de funcionamiento del simulador (ON – OFF) Por otra parte el archivo k1.h aborta al completo el código fuente para la simulación del comportamiento de la planta, incluyendo las macros de comunicación con el puerto paralelo “virtualizado”. Debemos recordar que la razón de este proyecto reside en el problema de la accesibilidad del puerto paralelo. Por este motivo hemos “virtualizado” los registros del puerto paralelo ubicados en Base+0, Base+1 y Base+2 a un array de las mismas dimensiones, un array de 8+8+8 bits, como mostramos en la figura nº 42. Figura 42. Virtualización del Puerto Paralelo 1.6.2 Librería Q5.h La librería Q5.h tiene principalmente dos propósitos, solucionar: - “Modo” de programación - “Modo” de operación Dependiendo de la opción escogida por el alumno en la realización del código fuente de las prácticas, tenemos que amoldar nuestro código para que él pueda compilar el código sin ningún error. En el entorno de Turbo C tenemos las siguientes opciones para realizar un archivo ejecutable: - Realizar todo el código fuente en un archivo con extensión *.c el cual contendrá la función main ( ). - Realizar un proyecto con diferentes archivos con extensión *.c y otro archivo con extensión *.c que contenga la función main ( ) Proyecto final de carrera Página 49 Memoria descriptiva Para poder escoger entre las diferentes opciones de programación sin que fuera de difícil aplicación para el alumno, se creó la definición project. Mediante la inserción de esta definición, el alumno escoge de una manera simple y fácil el modo que utilizará. La única diferencia entre las dos opciones es la declaración de las variables a utilizar por nuestro emulador. En el caso que el alumno sólo programara en un único archivo, este problema no existiría, pero si el alumno realizaba un proyecto, podría llegar el caso que durante la compilación del código surgiera un error por no tener las variables del emulador declaradas en diferentes archivos de código fuente. Inicio NO Project defined? SI Archivo Principal Archivo Secundario Definir Variable como local Definir Variable como externa Fin Figura 43. Modo de Programación #ifndef project hard_motor virtual_motor; //Declaració variable simulador void interrupt (*old_handler_prn2)(); /* mantiene el manejador original */ #else extern hard_motor virtual_motor; #endif Código 1. Parte código librería Q5.h Mediante el código descrito anteriormente solucionamos el problema de la compilación. En el caso de haber utilizado un proyecto, se inserta la declaración #define Project, de esta manera, automáticamente se declara el puntero de la estructura de datos de forma externa en los diferentes archivos del proyecto realizado. Proyecto final de carrera Página 50 Memoria descriptiva En el anexo B se detalla las operaciones a realizar en cada caso, para facilitar el uso al alumno. El otro problema abordado en esta librería es la funcionalidad del emulador. La premisa más importante de este proyecto era la de crear un simulador de la planta, donde fuese extremadamente sencillo cambiar de modo real a modo simulación. Al inicio de las prácticas de la asignatura se hace entrega del tutorial de prácticas. En este tutorial se incluye una librería llamada “printer.h”, donde residen las macros necesarias para comunicarse con el puerto paralelo del PC, y así poder leer y escribir en el puerto. El problema surge cuando estamos utilizando un ordenador portátil, ya que normalmente no tienen accesible el puerto paralelo. De esta manera, nuestro simulador tendría que tener total compatibilidad con las macros existentes, de tal forma que a la hora de compilar no se produjeran errores. Mediante la definición de una etiqueta pudimos reparar en la solución al problema. En el caso de que el alumno defina la etiqueta #define simula, nuestro código substituirá la librería “printer.h” por la nuestra llamada “k1.h”, equipada con las mismas declaraciones de macros para no provocar errores en la compilación. En caso contrario, si esta etiqueta no se ha definido, nuestro código incluirá la librería “printer.h” y sustituirá las declaraciones de las funciones utilizadas por el simulador por macros vacías, de esta forma no se tendrá que borrar la línea de dentro del código del alumno cada vez que pase de modo simulación a modo real. Inicio SI Simula defined? NO Simulador RUN Simulador OFF Adjuntamos librería simulación Adjuntamos Liberia printer.h Fin Figura 44. ON-OFF simulador Proyecto final de carrera Página 51 Memoria descriptiva #ifdef simula #include "k1.h" #else #include "printer.h" #define ini_datos_sim() { } #define sim_motor() { } #define restaura() { } #endif Código 2. Parte código librería Q5.h Por otra parte, en esta librería se define la estructura de datos hard_motor donde se declaran las variables necesarias para realizar la simulación. typedef struct { long count; //interval abans d'executar la funci¢ associada (micro seg) long recarga; //valor de recarrega double tic; //interval entre interrupcions(microseg) int direction; //direccion motor;izquierdaderecha-0 int vel_max_motor; //velocidad maxima nominal motor int puntos_encoder; //n§ ventanas del encorder por vuelta int index; //n§ de ventana en que se encuentra el encoder (0-3) unsigned int registroPRN[3]; //variable port virtualitzat }hard_motor; Código 3. Parte código librería Q5.h Donde la variable count será el valor resultante del cálculo definido por las variables de programa del ciclo de trabajo y la velocidad máxima del motor, interviniendo también la base de tiempos del sistema (tic).. La variable recarga es el valor de recarga de la variable count una vez consumida. La variable tic hará referencia al tic que seleccione el alumno durante la ejecución de su programa, siendo la base de tiempo mínima para poder realizar los correspondientes timers. La variable direction nos indicará el sentido del motor, a izquierdas o a derechas. La variable vel_max_motor tal y como indica su nombre, es el valor de velocidad máxima según la tensión de alimentación de nuestra fuente. La variable index nos indica en qué ventana del encoder se encuentra el sistema en un momento dado. Se ha definido el orden de las ventanas en la siguiente figura: Proyecto final de carrera Página 52 Memoria descriptiva Figura 45. Orden ventanas encoder La variable registroPRN es un array de 3 posiciones de 8 bits donde almacenaremos la información que dirigíamos antes a los registros del puerto paralelo. registroPRN + 0: Bit 7 Pin 9 Bit 6 Pin 8 Bit 5 Pin 7 Bit 4 Pin 6 Bit 3 Pin 5 Bit 2 Pin 4 Bit 1 Pin 3 Bit 0 Pin 2 Bit 5 Pin 12 Bit 4 Pin 13 Bit 3 Pin 15 Bit 2 - Bit 1 - Bit 0 - Bit 5 - Bit 4 IRQ Bit 3 /Pin 17 Bit 2 Pin 16 Bit 1 /Pin 14 Bit 0 /Pin 1 registroPRN + 1: Bit 7 /Pin 11 Bit 6 Pin 10 registroPRN + 2: Bit 7 - Bit 6 - Tabla 3. Registros del puerto paralelo Habiendo sustituido los tres registros del puerto paralelo mapeados en memoria por esta variable con igual tamaño. Proyecto final de carrera Página 53 Memoria descriptiva 1.6.3 Librería k1.h En esta librería residen todas las funciones necesarias para poder simular el comportamiento de la planta estudiada, emulando la velocidad respecto la tensión de alimentación versus el ciclo de trabajo del PWM y las señales ocasionadas al respecto por el encoder. En la cabecera de la librería se declaran unas etiquetas que nos ayudaran a simplificar las operaciones de escritura del código. Seguidamente tenemos la macro llamada ini_datos_sim( ), que tal y como da a entender su nombre inicializa las variables de la estructura que contiene los datos necesarios para el funcionamiento del sistema. Como puntos más importantes a destacar de la macro es la puesta a cero de la variable donde almacenaremos los datos que iban antes a los registros del puerto paralelo y la sustitución del puntero a la función asociada a la interrupción software del puerto paralelo, pudiendo provocar de esta manera interrupciones de este a nuestra voluntad. Consiguiendo de esta manera cerrar el lazo entre la información del “encoder” y el control de la velocidad del motor. #define ini_datos_sim() { *(virtual_motor.registroPRN+0)=0x00; *(virtual_motor.registroPRN+1)=0x00; *(virtual_motor.registroPRN+2)=0x00; virtual_motor.index=0; old_handler_prn2=_dos_getvect(0x17); _dos_setvect(0x17,cuadrat); virtual_motor.vel_max_motor=25; virtual_motor.puntos_encoder=800; virtual_motor.count=0; virtual_motor.recarga=0; virtual_motor.direction=d_derecha; } Código 4. Macro ini_datos_sim. Parte código librería k1.h La base de tiempos utilizada a través de un temporizador del chip 8253 la cual se ha denominado como tic, que utiliza el alumno para realizar otros timers, no es una base de tiempo fijada. Cada alumno puede escoger una base de tiempos tic de forma sensata y dentro de unos rangos. Este hecho condiciona totalmente nuestra forma de operar. A causa de no tener fijada una base de tiempo concreta, nuestro sistema tiene que ser flexible al cambio ésta. Proyecto final de carrera Página 54 Memoria descriptiva En relación a este hecho, tenemos la macro llamada cal_time_irq7( ). #define cal_time_irq7() { float x; x=virtual_motor.vel_max_motor*inf_pwm.dc; if (x<0) { x=x*(-1); virtual_motor.direction=d_izquierda; } else {virtual_motor.direction=d_derecha; } if (x==0) x=1; x=x*virtual_motor.puntos_encoder; x=(1/x)*1000000; x=x/h_timer.tic; virtual_motor.count=x+0.5; virtual_motor.recarga=virtual_motor.count; } Código 5. Macro cal_time_irq7. Parte código librería k1.h Esta macro calcula el tiempo que asociaremos al timer count de la estructura de datos del tipo hard_motor. Este tiempo se determina a través de la velocidad máxima del motor (según su alimentación), el ciclo de trabajo determinado por el controlador PID, la resolución del encoder y finalmente por el tic escogido por el usuario. 1 qº nQ pqEQ\\~]99p}qQ € 5 Ep9 9}~qE qº nQ pqEQ\\~]99p}qQ € 5 Q• áv R s 38 n9 ]~qE} _Qq9}nQ\ 39 El timer count nos determinará el tiempo entre interrupciones asociadas a la función de interrupción software del IRQ 7. Dependiendo de la velocidad que tenga el motor, este tiempo será mayor o menor. Es importante tener un tic pequeño para conseguir una buena resolución, ya que si por lo contrario tenemos un tic grande, como cabe esperar el rizado de velocidad será elevado. qº nQ pqE. € 5 9}~qE 1 53066 35 10@D 3980 0.53 Proyecto final de carrera \Q„ 1 3pq 800 ]~•. Qq9}nQ\ 3pq 60 † ‡íqp3} 1 9}~qE † 1 35 10@D 53066 p\… Q8 28571 40 p\… Q8 41 Página 55 Memoria descriptiva Como se observa en las formulas anteriores, para la máxima velocidad del motor, con un tic de 35µs obtendríamos un error muy grande en la velocidad final de éste, a causa de tener un tic inapropiado para tener la resolución necesaria para esa velocidad. Figura 46. Tiempo entre interrupciones IRQ07 La base principal del emulador es la macro llamada sim_motor( ). Esta origina las señales A y B que generaría el encoder, según el número de ventana ya especificado más arriba, provocando posteriormente la interrupción interrupción del puerto paralelo, cerrando de esta manera el lazo de control. En la figura 47 mostramos el diagrama de ejecución. ejecución La llamada a esta sta macro debe insertarse al final de la rutina de atención a la interrupción IRQ0 realizada por el alumno, un lugar sencillo y que no entorpecerá la ejecución de su código. Si observamos el diagrama de bloques de la página anterior, la variable clave es la variable count,, la cual determina en qué qu instante debe provocarse una interrupción en IRQIRQ 07. Una vez transcurrido el tiempo, la macro recalcula el tiempo por si se ha variado el ciclo de trabajo. Dependiendo de la dirección establecida y de la ventana actual (señales encoder), se generaránn las señales A y B correctamente al igual como haría el encoder, y se provocará una llamada a la interrupción software asociada a IRQ-07. IRQ De esta forma, cerramos el lazo de control sin modificar considerablemente el código c realizado por el alumno. La clave reside en cambiar el vector que apunta a la interrupción hardware del puerto paralelo por el vector que apunta a la interrupción software de este. En modo de utilización normal con el hardware activo, el alumno coloca el puntero de la función a asociada a la interrupción el puerto paralelo en el vector 0x0F de la tabla de vectores de interrupciones. El cambio el software de simulación coloca el puntero punte de la función asociada a la interrupción IRQ-7 IRQ 7 en el vector 0x17 de la tabla de vectores de interrupción, que corresponde a la interrupción software del puerto paralelo. Proyecto final de carrera Página 56 Memoria descriptiva Rutina atención IRQ0 {…} Llamada Rutina Sim_motor ( ) Count=0 ? Count -NO SI Calcula tiempo Tiner según dc PWM Dirección ? IZQUIERDA DERECHA Genera señales AyB Genera señales AyB Provoca soft interrupt puerto paralelo Provoca soft interrupt puerto paralelo Fin rutina atención IRQ-0 Figura 47. Diagrama ejecución IRQ 0 Proyecto final de carrera Página 57 Memoria descriptiva El código fuente de la macro es el siguiente: #define sim_motor() { if (!virtual_motor.count) { cal_time_irq7(); virtual_motor.count=virtual_motor.recarga; if (virtual_motor.direction==d_derecha) { switch(virtual_motor.index){ case 0: *(virtual_motor.registroPRN+1)=0x20; geninterrupt(0x17); virtual_motor.index++; break; case 1: *(virtual_motor.registroPRN+1)=0x30; geninterrupt(0x17); virtual_motor.index++; break; case 2: *(virtual_motor.registroPRN+1)=0x10; geninterrupt(0x17); virtual_motor.index++; break; case 3: *(virtual_motor.registroPRN+1)=0x00; geninterrupt(0x17); virtual_motor.index=0; break;} } if (virtual_motor.direction==d_izquierda) { switch(virtual_motor.index){ case 0: *(virtual_motor.registroPRN+1)=0x10; geninterrupt(0x17); virtual_motor.index++; break; case 1: *(virtual_motor.registroPRN+1)=0x30; geninterrupt(0x17); virtual_motor.index++; break; case 2: *(virtual_motor.registroPRN+1)=0x20; geninterrupt(0x17); virtual_motor.index++; break; case 3: *(virtual_motor.registroPRN+1)=0x00; geninterrupt(0x17); virtual_motor.index=0; break;} } } else { virtual_motor.count--;} } Código 6. Macro sim_motor. Parte código librería k1.h Proyecto final de carrera Página 58 Memoria descriptiva A partir de este punto, tenemos que cambiar las macros que trabajaban con los registros del puerto paralelo (datos de partida en las practicas de la asignatura) por macros con igual identidad, pero cambiando su interior para operar con nuestra variable llamada registroPRN de la estructura de datos virtual_motor. Por ejemplo la macro llamada pulse_on_a( ) la cual tenía por función alimentar la parte derecha del puente de transistores. La metodología de la operación a realizar es la misma que la original, pero sobre la variable registroPRN en vez del registro del puerto paralelo. #define pulse_on_a() { *(PRN_BASE)=((*(PRN_BASE)&PULSEOFF_B)|PULSEON_A); virtual_motor.direction=d_derecha; } Código 7. Macro pulse_on_a. Parte código librería k1.h Por otra parte, al contrario que la operación anterior, se anula la alimentación a la parte derecha del puente de transistores. #define pulse_off_a() { *(PRN_BASE)=(*(PRN_BASE))&PULSEOFF_A; virtual_motor.direction=d_stop; } Código 8. Macro pulse_off_a. Parte código librería k1.h Es importante transformar todas las macros existentes en el archivo printer.h suministrado al principio de las practicas, porque durante el cambio de modo entre sistema real y sistema en emulador no surjan errores de compilación por no tener declaradas las macros. El resto de macros serán comentadas en el anexo B, donde estará especificado todo el código del emulador. Proyecto final de carrera Página 59 Memoria descriptiva 1.7 Modo de Uso Para poder utilizar este simulador y sus librerías existen unas restricciones de uso. A causa del flujo necesario de información entre el código que realice el alumno y las librerías del simulador, es necesario definir las variables nombradas de la siguiente forma: - El puntero a la estructura HARD_TIMER debe llamarse h_timer - El puntero a la estructura SOFT_TIMER debe llamarse s_timer - El puntero a la estructura PWM debe llamarse inf_pwm - El puntero a la estructura PID debe llamarse inf_pid Figura 48. Restricciones de Uso De no ser así, el programa de compilación retornará diferentes errores por variables no declaradas y no se generará el fichero ejecutable. Proyecto final de carrera Página 60 Memoria descriptiva En el caso que el alumno haya decidido realizar la programación de las prácticas en un solo archivo con extensión *.c, donde residan todas sus funciones y macros, deberá realizar estos ajustes en su código de programa para poder utilizar el simulador. - Insertar definición: # define simula - Incluir librería: #include “q5.h” , NO incluir la librería “Printer.h” - Insertar llamada a función de inicialización simulador: ini_datos_sim ( ) (Esta debe ubicarse después de las pertinentes inicializaciones de todas las variables del programa realizado por el alumno) - Insertar llamada a función de restauración: Restaura_sistema ( ) (Debe ubicarse al final del programa) - Insertar llamada a función para ejecutar el simulador: sim_motor ( ) (Esta debe ubicarse al final de la rutina de atención IRQ 0 realizada por el alumno) Figura 49. Cambios en el código Estos ajustes sólo se deberán realizar la primera vez que utilice el simulador. Las macros insertadas son inertes en caso que el simulador esté en modo de no operación. Proyecto final de carrera Página 61 Memoria descriptiva En el caso que el alumno haya decidido realizar la programación con la modalidad de proyecto, teniendo un archivo base *.c con la correspondiente función main() más archivos complementarios con extensión *.c donde residan funciones varias deberá seguir esta guía de ejemplo para realizar los cambios necesarios en el código para utilizar el simulador. Ejemplo de proyecto formado por: Archivo Main.c + Archivo Timer.c + Archivo Ini_IRQ.c + Archivo PID.c + Archivo PWM.c Cambios a realizar en archivo Main.c: - Insertar definición: # define simula Incluir librería: #include “q5.h” Insertar llamada a función de inicialización simulador: ini_datos_sim ( ) (Esta debe ubicarse después de las pertinentes inicializaciones de todas las variables del programa realizado por el alumno) Insertar llamada a función de restauración: Restaura_sistema ( ) (Debe ubicarse al final del programa) - Cambios a realizar en archivo Timer.c: (Este archivo contiene la rutina de atención a la interrupción IRQ 0) - Insertar definición: # define simula Insertar definición: # define Project Incluir librería: #include “q5.h” Insertar llamada a función para ejecutar el simulador: sim_motor ( ) (Esta debe ubicarse al final de la rutina de atención IRQ 0 realizada por el alumno) Cambios a realizar en archivo Ini_IRQ.c: - Insertar definición: # define simula Insertar definición: # define Project Incluir librería: #include “q5.h” Cambios a realizar en archivo PID.c: - Insertar definición: # define simula Insertar definición: # define Project Incluir librería: #include “q5.h” Cambios a realizar en archivo PWM.c: - Insertar definición: # define simula Insertar definición: # define Project Incluir librería: #include “q5.h” Proyecto final de carrera Página 62 Memoria descriptiva Estos ajustes sólo se deberán realizar la primera vez que utilice el simulador. Las macros insertadas son inertes en caso que el simulador este en modo OFF. Una vez realizados los cambios, para poder utilizar el simulador se debe operar de la siguiente manera: - Simulador OFF -> // #define simula (Comentar definición para no ser compilada) - Simulador ON -> #define simula (La definición debe ser compilada) Figura 51. ON/OFF simulador Proyecto final de carrera Página 63 Memoria descriptiva En el anexo C del presente proyecto adjuntamos todo el código de la práctica nº 4 de la asignatura Informática Industrial II para utilizar este simulador. Proyecto final de carrera Página 64 2 Anexo A Proyecto final de carrera Página 65 Anexo B 2.1 El motor de corriente continua En el siguiente anexo describiremos brevemente el motor de corriente continua y sus principales características de manera que el alumnado pueda comprender más fácilmente los parámetros que identifican a este tipo de motores. [2] El motor de corriente continua de imanes permanentes se compone principalmente de dos partes, una parte exterior llamada estator, la cual da soporte mecánico al aparato, y un núcleo llamado rotor, el cual es la parte móvil del motor. El estator está formado por unos imanes permanentes de altas prestaciones de polos opuestos, enfrentado entre ellos, los cuales provocan unas líneas de fuerza entre N-S de los respectivos imanes. En cambio el rotor está formado por un núcleo de hierro devanado con unas espiras de conductor eléctrico, generalmente cobre, que son alimentadas a través de dos escobillas. El movimiento del rotor viene ocasionado por la acción derivada de la repulsión y atracción entre polos magnéticos. Creando campos constantes convenientemente orientados en estator y rotor, se origina un par de fuerzas que obliga a que el rotor gire buscando la posición de equilibrio. Figura 52. Motor de corriente continua. A la hora de interpretar una hoja de características de un motor de corriente continua es conveniente conocer el significado de cada parámetro, para ello, describiremos los más significativos. Potencia nominal asignada: Esta cifra representa la máxima potencia de salida cuando se opera dentro del rango de trabajo recomendado. Unidad de medida internacional expresada en watios (w) Tensión nominal: Proyecto final de carrera Página 66 Anexo B Es el voltaje al cual se han medido los datos nominales (velocidad en vacío, par de arranque, corriente de arranque, máx. potencia de salida, máx. rendimiento). Se ha escogido este dato para no exceder la máxima velocidad recomendada en vacío. Por supuesto, el uso del motor no está limitado a este voltaje. Para alcanzar la potencia nominal asignada se permiten voltajes de trabajo más elevados. La velocidad en vacío, par de arranque y corriente de arranque dependen directamente del voltaje aplicado. Unidad de medida internacional expresada en voltios (V) Velocidad en vacío: Es la velocidad a la que gira el motor cuando no tiene carga y se le aplica la tensión nominal. En la práctica, esta velocidad es proporcional al voltaje aplicado (constante de velocidad). Unidad de medida internacional expresada en rpm. Par de arranque: Es el par teórico a la tensión nominal y con el rotor bloqueado. El par de arranque aumenta proporcionalmente con el voltaje aplicado. El valor dado corresponde a una temperatura del rotor de 25°C. El par de arranque está relacionado con la corriente de arranque. Su conexión es la constante de par km Simbolizado con las siglas Mh y la unidad de medida internacional esta expresada en Nm (newton metro) Relación velocidad/par: La relación velocidad/par da información de las prestaciones del motor y se representa por la línea (o curva) velocidad-par. Cuanto más pequeño es este valor, más potente es el motor, y consecuentemente menor es la variación de la velocidad del motor con los cambios en la carga. La constante velocidad/par depende de las prestaciones del circuito magnético (ej: imán permanente), de las dimensiones del bobinado (longitud, diámetro, número de espiras) y de la resistencia del bobinado. En la práctica, la constante velocidad/par se puede obtener dividiendo la velocidad en vacío entre el par de arranque. Simbolizado con las siglas n/M y la unidad de medida internacional esta expresada en rpm/Nm Corriente en vacío: Proyecto final de carrera Página 67 Anexo B Esta es la corriente que consume el motor sin carga, alimentado a su tensión nominal. Simbolizado con las siglas Io y la unidad de medida internacional esta expresada en Amperios (A) Corriente de arranque: Es el cociente entre el voltaje nominal U y la resistencia en bornes Ra. Esta corriente es proporcional al par de arranque. Ambas magnitudes están relacionadas mediante la constante de par km. Simbolizado con las siglas IA y la unidad de medida internacional esta expresada en Amperios (A) Resistencia en bornes: Es la resistencia en los terminales a 25°C y determina la corriente de arranque a un voltaje dado. La resistencia entre bornes es un valor compuesto por la resistencia del bobinado, la resistencia de la escobilla y la resistencia de contacto entre la escobilla y el colector. Simbolizado con las siglas Ra y la unidad de medida internacional esta expresada en Ohmios (Ω) Velocidad máxima permitida: Esta velocidad representa el límite superior del rango recomendado de funcionamiento y no debería ser excedida durante el funcionamiento normal del motor. La velocidad está limitada principalmente por la conmutación. Si el motor gira a velocidades superiores pueden aparecer problemas de conmutación, que a su vez pueden llevar a reducir la vida útil del motor. Esto es debido a los siguientes factores: 1.- Aumento del desgaste mecánico debido a que la distancia recorrida por el colector es mayor. 2.-Aumento del desgaste por electro-erosión debido a la vibración de las escobillas y la formación de chispas. Simbolizado con las siglas nmax y la unidad de medida internacional esta expresada en rpm Máxima corriente en servicio continuo: Proyecto final de carrera Página 68 Anexo B Si el motor funciona continuamente con esta corriente y a 25°C de temperatura ambiente, se calentará hasta alcanzar la máxima temperatura del bobinado. Se asume que el motor no tiene refrigeración adicional, sin otras piezas que hagan de radiador de calor y aumenten este valor sustancialmente. Un aumento de la temperatura ambiente reduce la corriente máxima en continuo. Los bobinados con baja resistencia óhmica admiten corrientes más altas que los bobinados con alta resistencia. En motores con bobinados de resistencia baja, la máxima corriente en continuo puede estar limitada por las escobillas y no por el bobinado. La máxima corriente en continuo es equivalente al máx. par permanente. Están relacionados por la constante de par km. Simbolizado con las siglas Imax y la unidad de medida internacional esta expresada en Amperios (A) Máxima par en servicio continuo: Es el par que se puede entregar continuamente, o de media, alcanzando en el bobinado la máxima temperatura admisible, basado en una temperatura ambiente de 25°C. A temperatura ambiente más alta, este valor se reduce. El par máximo limita el rango recomendado de funcionamiento. Simbolizado con las siglas Mcont y la unidad de medida internacional esta expresada en Nm (newton metro) Máxima potencia de salida: Es la máxima potencia teórica a 25°C de temperatura del rotor. La máxima potencia se alcanza en la mitad del par de arranque y la mitad de la velocidad en vacío. Los límites permitidos (máx. corriente en continuo y máx. velocidad permitida) frecuentemente están por debajo de este nivel. Simbolizado con las siglas Pmax y la unidad de medida internacional esta expresada en watios (w) Constante de par: Representa la relación del par generado y la corriente aplicada. La constante de par transforma valores de par en valores de corriente y viceversa. En la práctica, km se determina por el par de arranque MH y la corriente de arranque Ia. En el cálculo teórico, han de tomarse en consideración las dimensiones del bobinado (longitud l, diámetro 2r, número de espiras w), así como la fuerza del campo magnético. La constante de par está relacionada con la constante de velocidad kn ya que ambas están determinadas por los mismos parámetros. Simbolizado con las siglas km y la unidad de medida internacional esta expresada en Nm/A (Newton metro por Amperio) Proyecto final de carrera Página 69 Anexo B Constante de velocidad: Muestra la velocidad específica por voltio del voltaje aplicado sin contar las pérdidas por fricción. En la práctica, kn se determina por el voltaje nominal U y la velocidad en vacío n0. En el cálculo teórico, deben tenerse en cuenta las dimensiones del bobinado (longitud, diámetro, número de espiras, w), así como la fuerza del campo magnético B0. La constante de velocidad está relacionada con la constante de par km porque éstas se determinan por los mismos parámetros. Simbolizado con las siglas kn y la unidad de medida internacional esta expresada en rpm/V (revoluciones por minuto por Voltio) Inercia del motor: Es el momento de inercia del rotor, basado en el eje de giro. Determina la constante de tiempo mecánica del motor. Simbolizado con las siglas JR y la unidad de medida internacional esta expresada en km² (kilos por metro cuadrado) Constante de tiempo mecánica: Es el tiempo que tarda el rotor en acelerar desde parado hasta el 63% de la velocidad en vacío. Este valor se calcula desestimando las fricciones, carga e inercia de la carga. Transcurridas 4 veces este valor (τ) el rotor habrá alcanzado más del 99% de la velocidad en vacío. La constante mecánica de tiempo se puede calcular con la inercia del rotor y el gradiente velocidad-par Simbolizado con las siglas τm y la unidad de medida internacional esta expresada en milisegundos (ms) Inductancia entre bornes: Es la inductancia del bobinado estacionario y medida con una onda senoidal de 1 kHz. Simbolizado con las siglas La y la unidad de medida internacional esta expresada en Henrios (H) Constante eléctrica: Proyecto final de carrera Página 70 Anexo B La inductancia entre bornes y la resistencia entre bornes determina la constante eléctrica de tiempo del motor. Este parámetro se refiere al tiempo requerido por la corriente para aumentar o disminuir. Típicamente, la constante eléctrica de tiempo es de 100 a 1.000 veces más pequeña que la constante mecánica de tiempo. Los cambios de corriente ocurren instantáneamente comparados con los cambios en velocidad. Un fenómeno a destacar cuando la corriente puede reaccionar de manera tan rápida, es el caso de los motores que son alimentados mediante PWM. En algunas ocasiones se puede producir un rizo de corriente no deseado que sobrecalienta al motor. En estos casos, puede que sea necesario aumentar la frecuencia del PWM o conectar una inductancia adicional. Simbolizado con las siglas ke Proyecto final de carrera Página 71 3 Anexo B Proyecto final de carrera Página 72 Anexo B 3.1 Código Librería Q5.h #ifdef simula #include "k1.h" #else #include "printer.h" #define ini_datos_sim() { } #define sim_motor() { } #endif //Mode de funcionament simulador ON//ON-OFF segons si es declara la //definicio typedef struct { long count; //Estructura de dades necesaries pel //funcionament del simular soft //Interval de Temps abans d'executar //la funci¢ associada (micro seg) long recarga; //Valor de recarrega double tic; //Interval entre //interrupcions(microseg) int direction; //Direccio motor;Izquierda-Derecha-0 int vel_max_motor; //Velocidad maxima nominal motor int puntos_encoder; //num. Finestres del encorder per //volta int index; //nº de finestra en que es troba en //un instant el encoder (0-3) unsigned int registroPRN[3]; //Variable port paral·lel //virtualitzat }hard_motor; #ifndef project hard_motor virtual_motor; void interrupt (*old_handler_prn2)(); #else extern hard_motor virtual_motor; #endif Proyecto final de carrera //En cas de projecte declara la //variable con a interna o externa //del arxiu en questió //Mante el punter original Página 73 Anexo B 3.2 Código Librería K1.h #define PRN_IRQ_MASK 0x10 #define PULSEON_A #define PULSEOFF_A 0x01 ~PULSEON_A #define PULSEON_B #define PULSEOFF_B 0x02 ~PULSEON_B #define INI_PRN 0xFF #define VCC_ON 0xFC #define VCC_OFF #define MASK 0x00 0x80 #define CUADRAT_MASK 0x30 #define d_derecha #define d_izquierda #define d_stop 1 2 0 //Mascara interrupcions pin 10 //DB-25 //ON de pin 2 DB25 //Pulsos de control en pin 2 //DB-25 //On de pin 3 DB25 //Pulsos de control en pin 3 //DB-25 //11111111 Inicializacio del //port_base+ 1 de prn //Pines 2 y 3 a zero i pins //4...9 a ú DB25 //Pines 2...9 a zero DB25 //Mascara per confirmacio de //int //Mascara bits 4 y 5 de //cuadratura (pins 12 y 13) //Direccio motor a dreta //Direcció motor Esquerra //Motor Parat #define PRN_BASE virtual_motor.registroPRN //Etiqueta //registre #define PRN_VERIFI (virtual_motor.registroPRN+1) //Etiqueta //registre #define PRN_IRQ (virtual_motor.registroPRN+2) //Etiqueta //registre a la direccio del soft virtual PRN a la direccio del soft virtual PRN+1 a direcció del soft virtual PRN+2 //---------------------------------------------------------------------// ini_datos_sim: // Inicialitza datos principals del similador //---------------------------------------------------------------------#define ini_datos_sim() { \ *(virtual_motor.registroPRN+1)=0x00; \ virtual_motor.index=0; \ old_handler_prn2=_dos_getvect(0x17); \ _dos_setvect(0x17,cuadrat); \ virtual_motor.vel_max_motor=25; \ virtual_motor.puntos_encoder=800; \ virtual_motor.count=0; \ virtual_motor.recarga=0; \ virtual_motor.direction=d_derecha; \ } Proyecto final de carrera Página 74 Anexo B //----------------------------------------------------------------------//cal_time_irq7: // Funcio que determina el temps entre les interrupcions // irq7 realitzades pel encoder virtual en funcio del // dc del pwm, tic hardware timer i vel. max. del motor cc //----------------------------------------------------------------------#define cal_time_irq7() { \ float x; \ x=virtual_motor.vel_max_motor*inf_pwm.dc; \ if (x<0) \ { \ x=x*(-1); \ virtual_motor.direction=d_izquierda; \ } \ else \ {virtual_motor.direction=d_derecha; } \ if (x==0) x=1; \ x=x*virtual_motor.puntos_encoder; \ x=(1/x)*1000000; \ x=x/h_timer.tic; \ virtual_motor.count=x+0.5; \ virtual_motor.recarga=virtual_motor.count;\ } //----------------------------------------------------------------------//sim_motor: // Funcio que simula les senyales A i B del encorder en el port // PRN virtual i genera la interrupcio irq7 //----------------------------------------------------------------------#define sim_motor() { \ \ if (!virtual_motor.count) \ { \ cal_time_irq7(); \ virtual_motor.count=virtual_motor.recarga; \ if (virtual_motor.direction==d_derecha) \ { \ kk1++; \ switch(virtual_motor.index) \ { \ case 0: \ *(virtual_motor.registroPRN+1)=0x20; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 1: \ *(virtual_motor.registroPRN+1)=0x30; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 2: \ *(virtual_motor.registroPRN+1)=0x10; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 3: \ *(virtual_motor.registroPRN+1)=0x00; \ geninterrupt(0x17); \ virtual_motor.index=0; \ break; \ } \ Proyecto final de carrera Página 75 Anexo B } \ if (virtual_motor.direction==d_izquierda) \ { \ switch(virtual_motor.index) \ { \ case 0: \ *(virtual_motor.registroPRN+1)=0x10; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 1: \ *(virtual_motor.registroPRN+1)=0x30; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 2: \ *(virtual_motor.registroPRN+1)=0x20; \ geninterrupt(0x17); \ virtual_motor.index++; \ break; \ case 3: \ *(virtual_motor.registroPRN+1)=0x00; \ geninterrupt(0x17); \ virtual_motor.index=0; \ break; \ } \ } \ } \ else \ { \ virtual_motor.count--; \ } \ } //------------------------------------------------------------------//pulse_on_a() pin 2 DB-25 a '1' i pin 3 DB-25 a 'O' //------------------------------------------------------------------#define pulse_on_a() \ { \ *(PRN_BASE)=((*(PRN_BASE)&PULSEOFF_B)|PULSEON_A); \ virtual_motor.direction=d_derecha; \ } /*-------------------------------------------------pulse_off_a() pin 2 DB-25 a 'O' ----------------------------------------------------*/ #define pulse_off_a() { *(PRN_BASE)=(*(PRN_BASE))&PULSEOFF_A; virtual_motor.direction=d_stop; } /*--------------------------------------------------pulse_on_b() pin 3 DB-25 a '1' i pin 2 DB-25 a 'O' ---------------------------------------------------*/ #define pulse_on_b() { *(PRN_BASE)=(((*(PRN_BASE))&PULSEOFF_A)|PULSEON_B); virtual_motor.direction=d_izquierda; } Proyecto final de carrera \ \ \ \ \ \ Página 76 Anexo B /*--------------------------------------------------pulse_off_b() pin 3 DB-25 a 'O' ----------------------------------------------------*/ #define pulse_off_b() { \ *(PRN_BASE)=((*(PRN_BASE))&PULSEOFF_B); \ virtual_motor.direction=d_stop; \ } /*--------------------------------------------------ini_prn() pins 2 i 3 a zero (PWM), pins 4 i 5 a ú (cuadrat), pins 6 a 9 a ú (VCC=ON) -----------------------------------------------------*/ #define ini_prn() { \ *(PRN_BASE+1)=INI_PRN; \ } /*----------------------------------------------------verifi() pin 11 -BUSY -DB-25. Utilitzat com a comfirmació de int ------------------------------------------------------*/ //#define verifi() (inportb(PRN_VERIFI)&MASK) #define verifi() {} /*----------------------------------------------------cuadrat_leer() pin 12 Data_5 i pin 13 Data_4,info de cuadratura -------------------------------------------------------*/ #define cuadrat_leer() ((((*(PRN_BASE+1))&CUADRAT_MASK)>>4)) /*-------------------------------------------------------vcc_on() pins 2 i 3 a zero i pins 4...9 a ú DB 25 ---------------------------------------------------------*/ //# #define vcc_on() { \ *(PRN_BASE)=VCC_ON; \ } /*-------------------------------------------------------vcc_off() pines 2...9 a zero DB 25 ---------------------------------------------------------*/ #define vcc_off() { \ *(PRN_BASE)=VCC_OFF; \ } /*-------------------------------------------------------en_i_prn(): Es valida la interrupcio de prn pin 10 DB-25 ---------------------------------------------------------*/ #define en_i_prn() { \ *(PRN_IRQ)=((*(PRN_BASE))|PRN_IRQ_MASK); \ } /*-------------------------------------------------------dis_i_prn(): Inibeix interrupcions des de prn ---------------------------------------------------------*/ #define dis_i_prn() { \ *(PRN_IRQ)=((*(PRN_BASE))&~PRN_IRQ_MASK); \ } Proyecto final de carrera Página 77 4 Anexo C Proyecto final de carrera Página 78 Anexo C 4.1 Librería 8259.h /*--------------------------------------------------------------------FILE: 8259.h -declaraciones y macros para el chip 8259 MACROS: mask_prn_off() - desactiva m scara IRQ7 mask_prn_on() - activa m scara IRQ7 mask_prn() - devuelve el estado de la m scara IRQ7 eoi_ns() - fin de interrupci¢n no espec¡fica eoi_prn() - fin de interrupci¢n espec¡fica IRQ7 eoi_timer() - fin de interrupci¢n espec¡ficaIRQO -----------------------------------------------------------------------*/ #define BASE_8259 0x20 /* direcci¢n base */ #define PORT_EOI (BASE_8259+0) /* puerto para EOI */ #define PORT_MASK (BASE_8295+1) /* puerto para mascaras */ #define VECT_BASE #define VECT_TIMER #define VECT_PRN 8 (VECT_BASE+O) (VECT_BASE+7) /* vector base */ /* vector del timer 8253 */ /* vector de impresora */ #define MASK_TIMER #define MASK_PRN 0x0l 0x80 /* M scara para timer */ /* M scara para impresora */ #define EOI_TIMER 0x60 /* F¡n de interrup. para timer */ #define EOI_PRN 0x67 /* F¡n de interrup. para inpresora */ #define EOI_NS 0x20 /* F¡n deinterrup. no espec¡fica /*-------------------------------------------------------mask_prn_off() desactiva la m scara permitiendo las interrupciones. ---------------------------------------------------------*/ #define mask_prn_off() (outportb(BASE_8259+1,(inportb(BASE_8259+1)&~MASK_PRN))) /*--------------------------------------------------------mask_prn_on() activa la m scara bloqueando las interrupciones. ----------------------------------------------------------*/ #define mask_prn_on() (outportb(BASE_8259+1,(inportb(BASE_8259+1)|MASK_PRN)) /*---------------------------------------------------------mask_prn() devuelve 1 si m scara activa y O en caso contrario -------------------------------------------------------------*/ #define mask_prn() (((inportb(BASE_8259+1>>7)&0x0l) /*-----------------------------------------------------------eoi_ns() fin de interrupci¢n no espec¡fica -------------------------------------------------------------*/ #define eoi_ns() (outportb(BASE_8259,EOI_NS)) /*-----------------------------------------------------------eoi_prn() fin de interrupci¢n espec¡fica para port paralelo (IRQ7) --------------------------------------------------------------*/ #define eoi_prn() (outportb(BASE_8259,EOI_PRN)) /*------------------------------------------------------------eoi_timer() fin de interrupci¢n espec¡fica el timer (IRQO) ----------------------------------------------------------------*/ #define eoi_timer() (outportb(BASE_8259,EOI_TIMER)) Proyecto final de carrera Página 79 Anexo C 4.2 Librería Ini_IRQ.h #define CR 0x0D /* c¢digo ASCII de tecla retorno de carro */ #define PULSOS_ENCODER 200 /*pulsos por revoluci¢n*/ #define #define #define #define /* estados de cuadratura*/ ESTADO_00 ESTADO_01 ESTADO_10 ESTADO_11 0x00 0x01 0x02 0x03 #define DIRECTA 1 direcci¢n */ #define INVERSA 0 /* valores de los flags de /* declaraci¢n de tipos derivados --------------------------------*/ typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned long u_long; /* prototipos de funciones ---------------------------------*/ double get_posicion(void); void inc_p(void), dec_p(void), reset_prn(void), ini_cuadrat(void); void interrupt cuadrat(_CPPARGS); Proyecto final de carrera /* retorna la posici¢n */ /* incrementa la cuenta de pulsos /* decrementa de cuenta de pulsos /* restaura condiciones iniciales /*de prn */ /* inicilizaci¢n */ Página 80 Anexo C 4.3 Librería PID.h /*----------------------------------------------------------------------FILE: pid.h -declaracions per al pid.c -----------------------------------------------------------------------*/ typedef struct { double kp, Ti, Td, consigna, error_1, error_2, t_sample; }struct_PID; //----------------------------------------------------------------------// cap‡alera //----------------------------------------------------------------------double obtenir_voltes(void); int variables_pid(void); int control(void); int funcio_velocitat(void); Proyecto final de carrera Página 81 Anexo C 4.4 Librería Printer.h /*-------------------------------------------------------FILE: printer.h NOTAS: Se definen las macros para el acceso al port paralelo Las macros de ataque al puente excluyen la posibilidad de que ambas ramas puedan activarse simultaneamente MACROS: pulse_on_a() pulse_off_a() pulse_on_b() pulse_off_b() ini_prn() verifi() cuadrat_leer() en_i_prn() dis_i_prn() vcc_on() vcc_off() activa la rama 'a' del puente desactiva la rama 'a' del puente activa la rama 'b' del puente desactiva la rama 'b' del puente inicializa el port prn verifica que la interrupci¢n no es ruido lee estado de cuadratura para posicion habilita las interrupciones (IRQ7) deshabilita las interrupciones (IRQ7) entrega tensi¢n al exterior a trav‚s del port anula tensi¢n exterior FUNCIONES: printer() devuelve la direcci¢n base asociada al port ---------------------------------------------------------------------*/ #include <dos.h> #define PRN_BASE 0X378 #define PRN_VERIFI PRN_BASE+1 #define PRN_IRQ PRN_BASE+2 #define PRN_IRQ_MASK 0x10 DB-25 */ #define PULSEON_A 0x01 #define PULSEOFF_A ~PULSEON_A 25 */ #define PULSEON_B 0x02 #define PULSEOFF_B ~PULSEON_B 25 */ #define INI_PRN 0xFF port_base+ 1 de prn */ #define VCC_ON 0xFC 4...9 a uno DB25 */ #define VCC_OFF 0x00 #define MASK 0x80 int */ #define CUADRAT_MASK 0x30 cuadratura (pines 12 y 13)*/ #define N_PRN 0x00410 impresora */ #define D_PRN 0x00408 base de PRN */ Proyecto final de carrera /* mascara interrupciones pin 10 /* puesta a uno de pin 2 DB25 */ /* pulsos de control en pin 2 DB/* puesta a uno de pin 3 DB25 */ /* pulsos de control en pin 3 DB/* 11111111 inicializaci¢n del /* pines 2 y 3 a cero y pines /* pines 2...9 a cero DB25 */ /* m scara para confirmaci¢n de /* m scara para bits 4 y 5 de /* direcci¢n de nø de ports de /* indirecci¢n para direcci¢n Página 82 Anexo C /*------------------------------------------------pulse_on_a() pin 2 DB-25 a '1' y pin 3 DB-25 a 'O' -------------------------------------------------*/ #define pulse_on_a() (outportb(PRN_BASE,((inportb(PRN_BASE)&PULSEOFF_B)|PULSEON_A))) /*-------------------------------------------------pulse_off_a() pin 2 DB-25 a 'O' ----------------------------------------------------*/ #define pulse_off_a() (outportb(PRN_BASE,(inportb(PRN_BASE)&PULSEOFF_A))) /*--------------------------------------------------pulse_on_b() pin 3 DB-25 a '1' y pin 2 DB-25 a 'O' ---------------------------------------------------*/ #define pulse_on_b() (outportb(PRN_BASE,((inportb(PRN_BASE)&PULSEOFF_A)|PULSEON_B))) /*--------------------------------------------------pulse_off_b() pin 3 DB-25 a 'O' ----------------------------------------------------*/ #define pulse_off_b() (outportb(PRN_BASE,(inportb(PRN_BASE)&PULSEOFF_B))) /*--------------------------------------------------ini_prn() pines 2 y 3 a cero (PWM), pines 4 y 5 a uno (cuadrat), pines 6 a 9 a uno (VCC=ON) -----------------------------------------------------*/ #define ini_prn() (outport(PRN_BASE+l,INI_PRN)) /*----------------------------------------------------verifi() pin 11 -BUSY -DB-25. Usado como confirmaci¢n de int NOTA: el valor le¡do es el inverso del real ------------------------------------------------------*/ #define verifi() (inportb(PRN_VERIFI)&MASK) /*----------------------------------------------------cuadrat_leer() pin 12 Data_5 y pin 13 Data_4,info de cuadratura -------------------------------------------------------*/ #define cuadrat_leer() ((inportb(PRN_BASE+1)&CUADRAT_MASK)>>4) /*-------------------------------------------------------vcc_on() pines 2 y 3 a cero y pines 4...9 a uno DB 25 ---------------------------------------------------------*/ #define vcc_on() (outportb(PRN_BASE,VCC_ON)) /*-------------------------------------------------------vcc_off() pines 2...9 a cero DB 25 ---------------------------------------------------------*/ #define vcc_off() (outportb(PRN_BASE,VCC_OFF)) /*-------------------------------------------------------en_i_prn() se valida la interrupci¢n de prn pin 10 DB-25 ---------------------------------------------------------*/ #define en_i_prn() (outport(PRN_IRQ,(inportb(PRN_IRQ)|PRN_IRQ_MASK))) /*-------------------------------------------------------dis_i_prn() inhibe interrupciones desde prn ---------------------------------------------------------*/ #define dis_i_prn() (outportb(PRN_IRQ,(inportb(PRN_IRQ)&~PRN_IRQ_MASK))) /*------------------------------------------------------printer() -devuel ve la direcci¢n base asociada al port pasado -------------------------------------------------------------*/ int printer(int); Proyecto final de carrera Página 83 Anexo C 4.5 Librería PWM.h typedef struct { double dc; long T, ton, toff, gir, abans; }struct_PWM; #define #define #define #define dreta esquerra ON OFF 0 // referida a excitacio PWM // // // // // // cicle de treball periode (us) temps de on (us) temps de off (us) dreta/esquerra ve de on o de off 1 0 1 //--------------------------------------------------------------//Cap‡aleres de pwm.c //--------------------------------------------------------------int frequency(double freq); int duty_cycle(double dc); int pwm(void); 4.6 Librería Timer.h /*--------------------------------------------------------------FILE: TIMER.h -declaracions per al TIMER.c ----------------------------------------------------------------*/ #ifdef _cplusplus */ #define _CPPARGS... #else #define _CPPARGS #endif /* consideracions sobre el tipus de compilador /* declaraci¢ de tipus derivats --------------------------------*/ typedef struct { int port, //@ del port base timer; //un de tres double clock, //frecuencia del cristall d'exitaci¢ tic; //interval entre //interrupcions(microseg) }hard_timer; Proyecto final de carrera Página 84 Anexo C typedef struct { long count, //interval abans d'executar la funci¢ //associada (micro seg) //valor de recarrega //incremental/decremental //funcio associada a count recarga; int incremental; int (*fun)(void); }soft_timer; #define base_8253 #define tmr0 #define clock_timer 0x40 0 1193180 //@ base del timer 8253 //timer 0 del 8253 //freq encia d'oscilúlacio del //cristall //posicio del vector a la taula //vectoritzada #define vector_irq_timer 0x08 #define base_8259 #define EOI_NS 0x20 0x20 //final d'irq no especifica /*-------------------------------------Cap‡aleres de les funcions de timer.c ----------------------------------------*/ int captura_valors(double *valors); //adquireix dades del teclat int captura_tecla_teclat(char taula[30]); int set_timer(int timer,double interval);//estableix el contingut d'un //soft_timer concret int ini_timers(double *valors); //inicia tots els soft_timers void ini_struct_hard_timer(int interval);//estableix el contingut de //l'estructura del hard_timer void canvi_vector_irq(void); //posa el nou vector a la taula //vectoritzada int trans_interval_tic(void); //transforma microseg a tics int ini_8253(void); //inicialitza el timer 8253 void restaura_sistema(void); //restaura tot el sistema double get_timer(int timer); //captura el contingut d'un //soft_timer void interrupt irq_timer(void); Proyecto final de carrera //rutina d'atencio a la //interrupcio Página 85 Anexo C 4.7 Librería Main.c /*---------------------------------------------------------------FILE: inf4.c ALGORISME DE CONTROL NOTES: FORMAT D'ENTRADA: Nom del programa + espai + base de temps del 8253 en microsegons -----------------------------------------------------------------*/ //PFC #define simula #include "q5.h" //PFC #include #include #include #include "timer.h" "pwm.h" "ini_irq.h" "pid.h" #include #include #include #include #include <stdio.h> <conio.h> <stdlib.h> <dos.h> <math.h> int analisi_arguments(int argc,char **argv); int inicialitzacio(int tmp,double *valors); //Comprova els arguments //d'entrada //inicialitza tot el //sistema int control_tecla(int tecla); void presentacio (void); //PFC extern extern extern //PFC extern hard_timer h_timer; double k1,k2,k3; double error_0; soft_timer s_timer[3]; //variable declarada a timer.c extern struct_PWM inf_pwm; long int irq_8253=0; //compta les irq's provocades pel 8253 extern int error_irq; extern extern extern extern long cuenta_p; long irq_prn; double velocitat; struct_PID inf_pid; Proyecto final de carrera Página 86 Anexo C //------------------------------------------------main(int argc,char **argv) { int tmp; double valors[3]; char tecla; tmp=analisi_arguments(argc,argv); //comprova els arguments d'entrada clrscr(); if (inicialitzacio(tmp,valors)) return (1); //PFC ini_datos_sim(); //PFC while(tecla!=27) { if(error_irq) return(1); presentacio(); tecla=getch(); } restaura_sistema(); return(0); //restaura l'antic apuntador de la t.vectoritzada, //el port paralel i para el motor // retorn sense error } //------------------------------------------------------------//analisi_arguments: Analitza els arguments introduits // per teclat, realitza l'arrodoniment // //------------------------------------------------------------int analisi_arguments(int argc,char **argv) { float tmp; char *missatge="\nError en la cadena d'entrada al programa. \n\nFORMAT: Nom del programa + espai + base de temps\nen micro segons"; tmp=0.0; if ((argc==1)|(argc>2)) //Si l'argument de crida al programa no es 2 { //donarem error d'entrada dades printf("%s\n",missatge); abort(); } if(argc==2) { tmp=atof(argv[1]); //tractem argument introduit tmp=tmp+0.5; //arodonim } if ((tmp<5.0)|(tmp>200.0)) //si base temps no adecuada { //abortem programa printf("\n\nBase de temps no adecuada\n\n"); abort(); } return (tmp); } Proyecto final de carrera Página 87 Anexo C int inicialitzacio(int tmp,double *valors) { ini_struct_hard_timer(tmp); if(captura_valors(valors)) //adquireix dades del teclat { printf("\n\nError al entrar les dades"); return(1); } if (ini_timers(valors)) //inicia els soft_timers, si es //retorna 1 hi ha { //error i finalitzal'execucio printf("\n\nError en les dades dels timers"); return(1); } pulse_off_b(); pulse_off_a(); if (frequency((1/valors[1])*1e3)) { printf("Error de dades en Frequencia PWM"); return(1); } inf_pid.t_sample=valors[0]; if(variables_pid()) return(1); inf_pid.error_1=0.0; inf_pid.error_2=0.0; ini_cuadrat(); canvi_vector_irq(); if (ini_8253()) //POSAR DINS LA FUNCIO variables_pid //posa el nou apuntador a la nostra //rutina de servei dins la taula //vectoritzada //programa el 8253 per a que comenci //a comptar { printf("\n\nError en la inicialitzaci¢ del hard timer"); return(1); } return (0); } void presentacio (void) { double graus; int voltes; clrscr(); while (!kbhit()) { graus=get_posicion(); //posici¢ absoluta de l'eix voltes=(int)(graus/360.0); // voltes donades gotoxy(7,2); printf("---------------------- Control de potencia -------------"); gotoxy(7,3); |"); printf("| gotoxy(7,4); Proyecto final de carrera Página 88 Anexo C printf("--------------------------------------------------------"); gotoxy(15,5); printf("DC:%3.0lf % ",(inf_pwm.dc)*100); gotoxy(15,6); printf("Ton: %ld microsegons ",inf_pwm.ton); gotoxy(15,7); printf("Toff: %ld microsegons ",inf_pwm.toff); gotoxy(15,8); if(inf_pwm.gir==1) "); printf("Sentit de gir: DRETA else printf("Sentit de gir: ESQUERRA "); gotoxy(15,9); printf("Velocitat real motor: %4.2lf rpm ",velocitat); gotoxy(15,10); printf("Pulsos del encoder: %ld polsos ",cuenta_p); gotoxy(15,11); printf("errors encoder: %d ",error); gotoxy(15,12); printf("posici¢ absoluta de l'eix: %8.2f§C ", graus); gotoxy(15,13); printf("posici¢ relativa de l'eix: %8.2f¦C ", graus-voltes*360.0); gotoxy(15,14); printf("n§ de voltes:%5d ", voltes); //PFC gotoxy(7,15); printf("------------------------- Proves -----------------------"); gotoxy(7,16); printf("| |"); gotoxy(7,17); printf("--------------------------------------------------------"); gotoxy(7,18); printf("k1 PID:%5f ", k1); gotoxy(7,19); printf("k2 PID:%5f ", k2); gotoxy(7,20); printf("N§ Tics:%5d ", virtual_motor.recarga); gotoxy(7,21); printf("Direcci¢:%5d ", virtual_motor.direction); gotoxy(7,22); printf("Index finestra:%5d ", virtual_motor.index); gotoxy(30,18); printf("Consigna velocitat:%5f ",inf_pid.consigna); gotoxy(30,19); printf("Velocitat Real:%5f ",velocitat); gotoxy(30,20); printf("PWM:%5f ",inf_pwm.dc); gotoxy(30,21); printf("Error 0:%5f ",error_0); gotoxy(30,22); printf("Error 1:%5f ",inf_pid.error_1); gotoxy(30,23); printf("increment PWM:%4f",k1*error_0+k2*inf_pid.error_1); //PFC } } Proyecto final de carrera Página 89 Anexo C 4.8 Librería Ini_IRQ.c /*------------------------------------------------------------------FILE: ini_irq.c -medida de posici¢n del eje de un motor partiendo de dos se¤ales en cuadratura propocionadas por un encoder relativo autor: Jacob Pie NOTAS: La posici¢n se determina contando el n£mero de pulsos que se detectan en una misma direcci¢n. La direcci¢n se determina a partir de la secuencia de pulsos desfasados 90 grados que proporciona el encoder relativo. --------------------------------------------------------------------*/ //PFC #define simula #define project #include "q5.h" //PFC #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <dos.h> #include "ini_irq.h" //#include "printer.h" #include "8259.h" /*------------datos privados -------------*/ long cuenta_p; static int direccion, estado_old, flag_inver, prn_base; //conta el nø de interrupcions //del encoder //sentido de giro del motor //estado previo de la entrada //de cuadratura //flag de direcci¢n inversa //direcci¢n base del puerto //paralelo int error=0; void interrupt (*old_handler_prn)(); //mantiene el manejador //original double grados; //posici¢n absoluta del eje del //motor en grados sexagesimales //vueltas dadas int vueltas; long irq_prn=0; Proyecto final de carrera Página 90 Anexo C /*-------------------------------------------------------------------cuadrat() -Rutina de servicio a la interrupcion de cuadratura NOTA: Esta funcion es llamada a cada flanco (ascendente y descendente) de cada una de las dos se¤ales en cuadratura. El sentido de giro es funcion de la secuencia de unos y ceros provinientes de las dos se¤ales desfasadas 90§ dadas por el encoder. Asi, la accion a tomar depender del estado actual y del anterior. ---------------------------------------------------------------------*/ void interrupt cuadrat(_CPPARGS) { int estado_curso; //estado actual de cuadratura estado_curso=cuadrat_leer(); if(estado_old!=estado_curso) { switch(estado_old) //lectura de info de cuadratura //analisis de secuencia de pulsos //del encoder { case ESTADO_00: if( estado_curso==ESTADO_01) dec_p(); /* retroceso */ else if(estado_curso==ESTADO_10) inc_p(); /* avance */ else error++; /* error */ break; case ESTADO_01: if(estado_curso==ESTADO_11) dec_p(); else if(estado_curso==ESTADO_00) inc_p(); else error++; break; case ESTADO_11: if(estado_curso==ESTADO_10) dec_p(); else if(estado_curso==ESTADO_01) inc_p(); else error++; break; case ESTADO_10: if(estado_curso==ESTADO_00) dec_p(); else if(estado_curso==ESTADO_11) inc_p(); else error++; break; } Proyecto final de carrera Página 91 Anexo C estado_old=estado_curso; } irq_prn++; eoi_ns(); //el estado actual pasa a ser //el anterior ahora //fin de interrupci¢n no //espec¡fica } /*--------------------------------------------------------------------inc_p() -incrementar cuenta_p incrementa el nø de inten-upciones acumuladas ----------------------------------------------------------------------*/ static void inc_p(void) { ++cuenta_p; //incrementamos la cuenta de //pulsos if(direccion==INVERSA) //si la direcci¢n anterior era //inversa==>cambio de direcci¢n { direccion=DIRECTA; //direcci¢n actual flag_inver=1; //indicaci¢n de cambio en //direcci¢n } } /*-------------------------------------------------------------------dec_p -decrementar cuenta_p decrementa el nø de interrupciones acumuladas ---------------------------------------------------------------------*/ static void dec_p(void) { //decrementamos la cuenta de --cuenta_p; //pulsos if( direccion==DIRECTA) //si la direcci¢n anterior era //directa==>cambio de direcci¢n { direccion=INVERSA; //direcci¢n actual flag_inver=1; //indicaci¢n de cambio de //direcci¢n } } /*--------------------------------------------------------------------ini_cuadrat -inicializaci¢n ----------------------------------------------------------------------*/ void ini_cuadrat(void) { cuenta_p=0; //puesta a cero error=0; flag_inver=0; direccion=DIRECTA; estado_old=cuadrat_leer(); //arbitrariamente elegida //estado actual old_handler_prn=getvect(VECT_PRN); //guadamos vector original setvect(VECT_PRN,cuadrat); //establecemos nueva rutina de //atenci¢n Proyecto final de carrera Página 92 Anexo C en_i_prn(); mask_prn_off(); } //activamos interrup. IRQ7 (prn) //permitimos int de prn en 8259 /*----------------------------------------------------------------------reset_prn() Restaura el vector original y desactiva interrup. ----------------------------------------------------------------------*/ void reset_prn(void) { dis_i_prn(); //inhibe interrupciones de pin //10 setvect(VECT_PRN,old_handler_prn); //restaura vector original pulse_off_a(); //pin 2 DB-25 a cero pulse_off_b(); //pin 3 DB-25 a cero } /*---------------------------------------------------------------------cuadrat_getp() retorna de la posici¢n en grados sexagesimales -----------------------------------------------------------------------*/ double get_posicion(void) { long cuenta; //copia de cuenta_p disable(); //comienzo regi¢n cr¡tica cuenta=cuenta_p; //info de posici¢n en pulsos enable(); //fin de regi¢n cr¡tica return(cuenta*360.0/(PULSOS_ENCODER*4.0)); //conversi¢n a grados //cent¡grados } Proyecto final de carrera Página 93 Anexo C 4.9 Librería PID.c //----------------------------------------------------------------------FILE: pid.c Implementacio de les funcions relatives al control PID //---------------------------------------------------------------------#include #include #include #include #include <stdio.h> <conio.h> <stdlib.h> <dos.h> <math.h> #include #include #include #include "timer.h" "pwm.h" "ini_irq.h" "pid.h" double velocitat=0.0; extern long cuenta_p; double k1,k2,k3; struct_PID inf_pid; extern struct_PWM inf_pwm; extern soft_timer s_timer[3]; //taula que conte els 3 soft timers double error_0; //--------------------------------------------------------------------//funcio_velocitat: //--------------------------------------------------------------------int funcio_velocitat(void) { double espai,temps; espai=obtenir_voltes(); temps=get_timer(2)/1000.0; s_timer[2].count=0; velocitat=(espai/temps)*60.0; return(0); //nºde voltes en un interval de t //temps esta en segons //velocitat es mesura en rpm } //--------------------------------------------------------------------//obtenir_voltes() // retorna de les voltes //--------------------------------------------------------------------double obtenir_voltes(void) { long cuenta; double voltes; static long cuenta_ant=0; disable(); //comienzo regi¢n cr¡tica cuenta=cuenta_p; //info de posici¢n en pulsos enable(); //fin de regi¢n cr¡tica voltes=((cuenta-cuenta_ant)/(PULSOS_ENCODER*4.0)); cuenta_ant=cuenta; Proyecto final de carrera Página 94 Anexo C return(voltes); } //---------------------------------------------------------------------//Variables_pid:demana per teclat les variables // del controlador pid //---------------------------------------------------------------------int variables_pid(void) { char temp[10]; printf("Introdueix la variable Kp pel controlador PID: "); if (captura_tecla_teclat(temp)) return(1); else inf_pid.kp=atof(temp); //valor de kp printf("Introdueix el temps Td(ms) pel controlador PID: "); if (captura_tecla_teclat(temp)) return(1); else inf_pid.Td=atof(temp); //valor de td printf("Introdueix el temps Ti(ms) pel controlador PID: "); if (captura_tecla_teclat(temp)) return(1); else inf_pid.Ti=atof(temp); //valor de ti printf("Introdueix la consigna de velocitat pel controlador PID: "); if (captura_tecla_teclat(temp)) return(1); else inf_pid.consigna=atof(temp); //valor de consigna //inf_pid.consigna=+180; //consigna posicio k1=inf_pid.kp*(1+(inf_pid.t_sample/inf_pid.Ti)+(inf_pid.Td/inf_pid. t_sample)); k2=-(1+2*(inf_pid.Td/inf_pid.t_sample))*(inf_pid.kp); k3=inf_pid.kp*(inf_pid.Td/inf_pid.t_sample); return(0); } //----------------------------------------------------------------------//control: Funcio associada al control PID //---------------------------------------------------------------------int control(void) { if (funcio_velocitat()) return(1); error_0=inf_pid.consigna-velocitat; //error_0=inf_pid.consigna-get_posicion(); //calcul de l'error de //velocitat //calcul de l'error de //posicio inf_pwm.dc+=k1*error_0+k2*inf_pid.error_1; if(inf_pwm.dc>1.0) inf_pwm.dc=1.0; //evita la saturacio integral del PID if(inf_pwm.dc<-1.0) inf_pwm.dc=-1.0; if(duty_cycle(inf_pwm.dc)) return(1); //actualitza Ton i Toff inf_pid.error_2=inf_pid.error_1; inf_pid.error_1=error_0; return(0); } Proyecto final de carrera Página 95 Anexo C 4.10 Librería PWM.c //-----------------------------------------------------------------// FILE pwm.c //-----------------------------------------------------------------//PFC #define simula #define project #include "q5.h" //PFC #include "pwm.h" //#include "printer.h" #include "timer.h" extern hard_timer h_timer; struct_PWM inf_pwm; //-----------------------------------------------------------------// frequency(): //-----------------------------------------------------------------int frequency(double freq) { //TOTS ELS VALORS ESTAN EN us if(freq>0.0) { inf_pwm.dc=0.0; inf_pwm.T=(1/freq)*1e6; inf_pwm.ton=inf_pwm.T*inf_pwm.dc; inf_pwm.toff=inf_pwm.T-inf_pwm.ton; inf_pwm.gir=dreta; inf_pwm.abans=OFF; return(0); } return(1); //retorn amb error } //----------------------------------------------------------------// duty_cycle: //----------------------------------------------------------------int duty_cycle(double dc) { double tmp; inf_pwm.gir=inf_pwm.dc>0.0?dreta:esquerra; if ((dc>=-1.0)&&(dc<=1.0)) //comprova si tmp>0, si ho es Ton=tmp { //sino Ton=-tmp tmp=inf_pwm.T*dc; //actualitza valor de Ton inf_pwm.ton=tmp>0.0?tmp:-tmp; inf_pwm.toff=inf_pwm.T-inf_pwm.ton; //actualitza valor de Toff return(0); } return(1); //retorna amb error } Proyecto final de carrera Página 96 Anexo C //---------------------------------------------------------------// pwm(): //----------------------------------------------------------------int pwm(void) { //prove de gir a dretes //if (inf_pwm.gir==dreta) //aixi pel motor casa PFC if (inf_pwm.gir==esquerra) { if (inf_pwm.abans==ON) //prove de TON { if (set_timer(1,inf_pwm.toff)) return(1); pulse_off_b(); inf_pwm.abans=OFF; } else //prove de TOFF { if (set_timer(1,inf_pwm.ton)) return(1); pulse_on_b(); inf_pwm.abans=ON; } } else //prove de gir a esquerres { if (inf_pwm.abans==ON) //prove de TON { if (set_timer(1,inf_pwm.toff)) return(1); pulse_off_a(); inf_pwm.abans=OFF; } else //prove de TOFF { if (set_timer(1,inf_pwm.ton)) return(1); pulse_on_a(); inf_pwm.abans=ON; } } return(0); } Proyecto final de carrera Página 97 Anexo C 4.11 Librería Timer.c /*-------------------------------------------------------------------FILE: timer.c Implementacio de les funcions relatives als temporitzadors ---------------------------------------------------------------------*/ //PFC #define simula #define project #include "q5.h" //PFC #include "pid.h" #include "timer.h" #include "pwm.h" #include #include #include #include #include //necessari per l'assignacio del apuntador a //ini_timers <stdio.h> <conio.h> <stdlib.h> <dos.h> <math.h> void interrupt (*old_handler_timer)(); //mante el manejador //original extern struct_PWM inf_pwm; soft_timer s_timer[3]; //taula que conte els 3 soft timers hard_timer h_timer; extern long int irq_8253; long int PID=0; int error_irq=0; //dtecta si alguna de les funcions associades h //a generat error //-------------------------------------------------------------------//captura_valors: comprova els valors de temps introduits // des de teclat //-------------------------------------------------------------------int captura_valors(double *valors) { char temps[10]; printf("\n\nEls valors de TEMPS han d'estar en ms\n\n"); printf("Periode de mostreig PID: "); if (captura_tecla_teclat(temps)) return(1); else valors[0]=atof(temps); printf("Periode de PWM: "); if (captura_tecla_teclat(temps)) return(1); else valors[1]=atof(temps); return(0); } Proyecto final de carrera Página 98 Anexo C //----------------------------------------------------------------------// captura_tecla_teclat: captura una cadena de numeros i realitza control // d'error. // retorna una cadena de caracters //----------------------------------------------------------------------int captura_tecla_teclat(char taula[30]) { char caracter; int ind=0; caracter=getchar(); while(caracter!='\n') { if ((caracter>='0')&&(caracter<='9')||(caracter=='.')) taula[ind]=caracter; ind++; caracter=getchar(); } if(caracter=='\n') { taula[ind]='\0'; return(0); } return(1); //retorn amb error } //----------------------------------------------------------------------//set_timer: Inicialitza els camps de la estructura // s_timer d'un soft timer concret //----------------------------------------------------------------------int set_timer(int timer,double interval) { //interval esta en us switch(timer) { case 0: //timer soft decremental { s_timer[0].count=(interval/h_timer.tic)+0.5; //trunca interval s_timer[0].recarga=(interval/h_timer.tic)+0.5; break; } case 1: //timer soft decremental { s_timer[1].count=(interval/h_timer.tic)+0.5; //trunca interval s_timer[1].recarga=(interval/h_timer.tic)+0.5; break; } case 2: //timer soft incremental { s_timer[2].count=0; s_timer[2].recarga=0; break; } default: //sino es cap dels 3 retorna return(1); //un error } Proyecto final de carrera Página 99 Anexo C return(0); } //retorn sense error //------------------------------------------------------------------//ini_timers: Inicialitza tots els soft timers. // Demana a l'usuari els valors de temps per als // diferents timers // //NOTA: Els valors introduits per l'usuari seran en ms //------------------------------------------------------------------int ini_timers(double *valors) { //valors es una taula on hi ha el temps de cada timer s_timer[0].incremental=0; //timer decremental s_timer[0].fun=control; //funcio associada al timer 0 if (set_timer(0,valors[0]*1000)) return(1); //inicialitza soft_timer 0 //valor en us s_timer[1].incremental=0; //timer decremental s_timer[1].fun=pwm; //funcio associada al timer 1 if (set_timer(1,valors[1]*1000)) return(1); //inicialitza soft_timer 1 s_timer[2].incremental=1; //timer incremental s_timer[2].fun=funcio_velocitat; //funcio associada al timer 2 if (set_timer(2,valors[2]*1000)) return(1); //inicialitza soft_timer 2 return(0); //retorn sense error } //------------------------------------------------------------------//ini_struct_hard_timer: Inicialitza la estructura h_timer // colúlocant informaci¢ del timer hard // que usem per realitzar la practica //------------------------------------------------------------------void ini_struct_hard_timer(int interval) { h_timer.port=base_8253; //adre‡a base del 8253 h_timer.timer=tmr0; //selecciona el comptador 0 del 8253 h_timer.clock=clock_timer; //freq encia a la que oscilúla el //timer h_timer.tic=interval; //interval entre interrupcions } //--------------------------------------------------------------------// canvi_vector_irq: guarda l'antic apuntador de la posicio 8 de la // taula vectoritzada i hi colúloca el nou // //--------------------------------------------------------------------void canvi_vector_irq(void) { old_handler_timer=getvect(vector_irq_timer); setvect(vector_irq_timer,irq_timer); } Proyecto final de carrera Página 100 Anexo C //-----------------------------------------------------------------// trans_interval_tic: Transforma els microseg al valor // per carregar el 8253, arrodoneix i trunca // el valor a carregar //-----------------------------------------------------------------int trans_interval_tic(void) { return(((h_timer.tic)*(h_timer.clock)*1e-6)+0.5); } //-----------------------------------------------------------------//ini_8253: Inicialitza el timer 0 de la placa base del Pc // en mode rate generator. Introdu‹m el valor de // la base de temps al registre count #0 //-----------------------------------------------------------------int ini_8253(void) { int valor=0; valor=trans_interval_tic(); //transforma microseg. a tics if ((valor<2)||(valor>0xFFFF)) return(1); outportb(base_8253+3,0x3C); //timer0, mode rate generator outportb(base_8253,(unsigned char)(valor&0x00FF)); //carrega byte_L del 8253 outportb(base_8253,(unsigned char)(valor>>8)); //carrega byte_H del 8253 return(0); } //---------------------------------------------------------------------// restaura_ sistema: restaura l'antic vector de la taula vectoritzada // i restaura el valor origina del timer 8253 //---------------------------------------------------------------------void restaura_sistema(void) { disable(); setvect(vector_irq_timer,old_handler_timer); //restaura vector outportb(base_8253+3,0x3C); //timer0, mode rate generator outportb(base_8253,(unsigned char)(0xFF)); //recarrega 8253 amb valor original outportb(base_8253,(unsigned char)(0xFF)); enable(); pulse_off_a(); //para el motor pulse_off_b(); reset_prn(); //restaura port paralel printf("\n\nSortida del Programa"); } //---------------------------------------------------------------// irq_timer: Rutina de servei al timer 8253 //---------------------------------------------------------------void interrupt irq_timer(void) { int ind; for(ind=0;ind<3;ind++) { if(!(s_timer[ind].incremental)) Proyecto final de carrera //Comprova els 3 soft_timers //timer decremental Página 101 Anexo C { if(s_timer[ind].count) //si no es 0 es decrementa s_timer[ind].count--; //comprova per nivell si s_timer es //0, si es 0 continua cridant la funcio if(!s_timer[ind].count) //temps exhaurit { //es crida la funcio associada error_irq=(*s_timer[ind].fun)(); s_timer[ind].count=s_timer[ind].recarga; // recarrega el s_timer } } else { //timer incremental if((s_timer[ind].count)<2e31) s_timer[ind].count++; else error_irq=1; //error } } sim_motor(); irq_8253++; outportb(base_8259,EOI_NS); // envia final irq no especific } //-----------------------------------------------------------------------// funcio get_timer: retorna el valor actual d'un soft_timer especific //-----------------------------------------------------------------------double get_timer(int timer) { //transforma el valor a ms return(((s_timer[timer].count)*h_timer.tic)/1000); } Proyecto final de carrera Página 102 5 Anexo D: Referencias [1] [2] Libro: Esteban del Castillo, Control de Procesos, Publicacions URV, Año 2008. Libro: Felipe Espinosa Zapata, Análisis Diseño y Realización de Sistemas Electrónicos de Control Contínuo, Universidad de Alcalá de Henares, Año 2006. Libro: Manuel Mazo Quintas, Control de Motores Paso-Paso, dc con escobillas y brushless, Universidad de Alcalá de Henares, Año 1997 [3] Proyecto final de carrera Página 103