Autor Tema: Compensador Optimo  (Leído 5244 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Compensador Optimo
« en: 11 de Abril de 2010, 05:53:18 »
Introducción

La desventaja de los métodos como Zieglers-Nichols al igual que root-locus es que se basan en conocimientos empíricos y más que todo en prueba y error. Peor aún, los métodos anteriores no pueden ser implementados cuando el sistema contiene ceros de no mínima fase (ceros al lado derecho o positivos), condicion presentada en sistemas inestables.

Para encontrar el compensador optimo de una planta en un sistema de control de lazo Cerrado se utilizan Métodos de "Algebra Linear". Es un método bastante simple, lo que se debe hacer es conocer la Funcion de Transferencia (FDT) de la planta G(s) y conocer la FDT del sistema total M(s), luego debemos despejar la FDT del compensador optimo C(s) para esa planta.

Un compensador es óptimo si y solo si, cumple las siguientes condiciones:

  • El tiempo de establecimiento de la planta es mínimo, recordando que es imposible que el tiempo de establecimiento sea igual a cero, eso solo ocurre si los dispositivos fuesen ideales.
  • El overshoot debe ser igual o muy cercano a cero, ya que en ingeniería se trabajan con un rango de valores, porque es imposible lograr valores exactos a la hora del diseño.
  • El consumo de energía debe ser el menor posible.
  • El diseño debe ser sencillo e implementable.

Con las condiciones anteriores observamos que al buscar un compensador con estas características hacemos que sea muy difícil de lograr si realizáramos el diseño sin ayuda de un software especializado. Pero en la actualidad esto ha dejado de ser una limitante.

Respuesta Transitoria

Especificaciones en el dominio temporal

Antes de pasar a describir el desarrollo del método es necesario saber un poco de respuesta en el tiempo.

Estas frecuentemente involucran ciertos requerimientos asociados a la respuesta temporal del sistema. Los requerimientos para una respuesta a un escalón.

  • Tiempo de crecimiento (rise time), tr: es el tiempo que toma el sistema para alcanzar la vecindad de su nuevo set-point.
  • Tiempo de establecimiento (settling time) ts es el tiempo que toma el sistema para que el transitorio decaiga.
  • Sobrepico (overshoot) Mp: es la cantidad máxima que el sistema se sobrepasa en el transitorio su valor final dividido ese valor final (frecuentemente se lo da en porcentaje).
  • Tiempo del pico (peak time) tp: es el tiempo que toma el sistema para alcanzar el máximo valor (el sobrepico).

Sistema de Primer Orden
Este sistema se caracteriza por contener un solo polo positivo, es utilizado para modelar una gran variedad de sistemas térmicos.



$$G\left( s \right) = {a \over {s + a}}

$ T_r = \frac{2.2}{a}
  y  
$ T_s = {4 \over a}

Sistema de segundo Orden





    y    

Efecto de los polos y ceros adicionales


Según las graficas anteriores podemos inferir que si el polo adicional
$$\alpha
está más lejos que 4 veces la parte real de los polos complejos conjugados, el tiempo de crecimiento no es prácticamente afectado. Lo que significa 2 cosas:

  • Si la planta tiene polos o ceros muy alejados podriamos despreciarlos.
  • Si necesitamos que la funcion de transferencia del sistema total sea de orden superior a 2, simplemente agregaremos polos o ceros 4 veces mas alejados para no afectar la respuesta del sistema.

Pueden encontrar más información de respuesta Temporal Aquí
« Última modificación: 12 de Abril de 2010, 03:18:04 por bigluis »
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Re: Compensador Optimo
« Respuesta #1 en: 12 de Abril de 2010, 03:11:04 »
Desarrollo del Método

Los sistemas de control generalmente utilizan la siguiente configuración de sistema de lazo cerrado:



Del diagrama anterior podemos deducir que la Función de Transferencia (FDT) de un sistema total M(s), con planta G(s), compensador C(s) y con retroalimentación H(s) es la siguiente:

$$M \left( s \right) ={{N\left( s \right)} \over {D\left( s \right)}}={\frac {G \left( s \right) C \left( s \right) }{1+G \left( s \right) C \left( s \right) H \left( s \right) }}

Despejamos C(s) de la ecuacion anterior.

$$C \left( s \right) =-{\frac {M \left( s \right) }{G \left( s \right) \left( M \left( s \right) H \left( s \right) -1 \right) }}

Con este ecuación podemos encontrar el controlador optimo C(s) para la planta G(s).

Los controladores PID solo poseen un proporcionador, un integrador y un derivador los cuales se ajustan para lograr una respuesta temporal deseada pero es sumamente difícil lograr que se obtengan el Tiempo de Establecimiento mínimo y Overshoot igual a cero. Mientras que este compensador posee tantos integradores y derivadores como sea necesario para que la FDT del Sistema Total tenga una respuesta temporal que cumpla con un Tiempo de Establecimiento mínimo y Overshoot igual a cero.

Función de Transferencia Implementable
IEEE Control Systems Magazine, Octuber 1987, Volume 7, Number 5.
Introduction to the Linear Algebraic Method for Control System Design.


Si una FDT Total M(s) no es implementable, no  importa que configuración se use para implementarla, el diseño siempre violará al menos uno de las cuatro limitaciones.

  • $$M(s)
    es Estable y
    $${{M\left( s \right)} \over {G\left( s \right)}}
    es estable y propio.
  • $$D(s)
    es Hurwitz.
  • El grado de
    $$D(s)
    menos el de
    $$N(s)
     es mayor o igual al grado de
    $$D_0(s)
    menos el de
    $$N_0(s)
  • Todos los ceros ubicados en el semiplano derecho (incluyendo los imaginarios) de
    $N_0(s)
    deben estar contenidos en
    $$N(s)
    (Retencion de Ceros de no mínima fase)

Ceros ubicados en el semiplano derecho (SPD) son llamados ceros de nominima-fase. Polos ubicados en el SPD son llamados polos inestables. Vemos que ceros de nomínima-fase de G(s) imponen limitaciones para implementar M(s), pero polos inestables de G(s) no. Ya que los polos de G(s) pueden ser desplazados en los polos de M(s) en la introducción de la retroalimentación.

Sin embargo, bajo la limitante de no escape de planta, la unica forma de cambiar los ceros de G(s) es por cancelación directa. Así, si cualquier cero de nominiva-fase de G(s) no esta contenido en  M(s), debemos introducir un polo inestable para cancelarlo, y como resultado el sistema total nunca podra ser totalmente estable.
« Última modificación: 19 de Abril de 2010, 17:29:23 por bigluis »
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Re: Compensador Optimo
« Respuesta #2 en: 19 de Abril de 2010, 03:44:37 »
Ejemplo

Para la siguiente Planta

$$G \left( s \right) ={\frac {20}{ \left( s+20 \right) \left( s+2 \right) }}

y retroalimentación unitaria H(s)=1, encuentre el compensador necesario para que el tiempo de establecimiento Ts=1s, el overshoot Mp=0. y el error en estado estable ante una entrada escalón debe ser cero.

Este es un sistema bastante simple de 2 polos, por lo tanto sólo utilizaremos la segunda regla de implementabilidad para este sistema. Es decir, el sistema total debe tener 2 polos y ningun cero al igual que la planta. Por ende escogeremos la siguiente FDT.

$$M \left( s \right) ={\frac {1}{{\frac {{s}^{2}}{{\omega_{{n}}}^{2}}}+2\,{\frac { \zeta \,s}{\omega_{{n}}}}+1}

Para que M(s) tenga un tiempo de establecimiento Ts = 1s y Overshoot = 0, debemos hacer que

$$\omega_{{n}}=4.6\,{\frac{1}{ Ts}}=4.6\,{\frac{1}{1}}=4.6
    y    
$$\zeta=1

Por lo tanto M(s) quedará de la siguiente manera:

$$M \left( s \right)={1 \over {\left( {\frac{s}{4.6}}\right)^2 + 2\frac{s}{4.6}+ 1}}

$$M \left( s \right) = {1 \over{0.04725897921\,{s}^{2}+ 0.4347826086\,s+1}}

Luego procedemos a obtener la FDT del compensador utilizando la siguiente ecuación.

$$C \left( s \right) =-{\frac {M \left( s \right) }{G \left( s \right) \left( M \left( s \right) H \left( s \right) -1 \right) }}

el sistema quedaría algo así (Aquí usé Maple para realizar la sustitución y simplificación).

$$C \left( s \right) = 1666666667.0\,{\frac {{s}^{2}+ 22.0\,s+ 40.0}{\left( 1575299307.0\,s+ 14492753620.0 \right) s}}

De la ecuación anterior podemos observar como este compensador o controlador elimina los polos de la planta con sus ceros e impone sus propios polos haciendo que el sistema tenga el tiempo de establecimiento y el overshoot deseado.

« Última modificación: 19 de Abril de 2010, 17:44:42 por bigluis »
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA

Desconectado Renatox_

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 541
    • máquinas cnc
Re: Compensador Optimo
« Respuesta #3 en: 19 de Abril de 2010, 13:32:51 »
Esa forma de hallar el compensador me va a servir mucho porque mi lazo de realimentación no es 1, sino un filtro entonces LGR no me ayuda pero tu método si, voy a probarlo en la realidad haber como va.

Por cierto la FT en lazo cerrado debe ser asi:
M=G*C/(1+G*C*H)

gracias
control de movimiento

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Re: Compensador Optimo
« Respuesta #4 en: 19 de Abril de 2010, 17:32:37 »
 :oops: Gracias Renatox, tenías razon, ya he corregido el error.

 :) He abierto un nuevo post para que realicen los Comentarios.
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Re: Compensador Optimo
« Respuesta #5 en: 01 de Mayo de 2010, 13:46:43 »
Discretización

Antes de implementar la ecuación del compensador en un PIC debemos discretizarla.

En este ejemplo utilizaremos un tiempo de muestreo de 5ms y el metodo de discretización Bilinear ya que es el que utiliza Maple por defecto, por lo tanto de la ecuación anterior obtenemos lo siguiente:

$$C \left( z \right) = 0.01\,{\frac { 7035000001000\,{z}^{2}-13330000000000\,z+ 6301666667000}{ \left( z- 1 \right) \left( 64461247640\,z- 61562696910 \right) }}

El siguiente paso es obtener la ecuación en tiempo discreto k, para ello observemos la figura del compensador en donde la señal de entrada es el Error E(s) y la señal de salida es el voltaje V(s) que se le aplicará a la planta por lo tanto  V(s) será el numerador y E(s) el denomidador de C(s) con lo que obtenemos la siguiente ecuación.

$$C \left( z \right) ={\frac {V \left( z \right) }{E \left( z \right) }}= 0.01\,{\frac { 7035000001000\,{z}^{2}-13330000000000\,z+ 6301666667000}{ \left( z- 1 \right) \left( 64461247640\,z- 61562696910 \right) }}

luego realizamos una multiplicación cruzada y obtenemos

$$64461247640\,V \left( z \right) {z}^{2}- 126023944600\,V \left( z \right) z+ 61562696910\,V \left( z \right) = 70350000010\,E \left( z \right) {z}^{2}- 133300000000\,E \left( z \right) z+ 63016666670\,E \left( z \right)

Como observamos de la ecuación anterior el exponente de mayor orden es 2 por lo tanto dividimos toda la ecuación entre
$${z}^{2}

$$64461247640\,V \left( z \right) - 126023944600\,{\frac {V \left( z \right) }{z}}+ 61562696910\,{\frac {V \left( z \right) }{{z}^{2}}}= 70350000010\,E \left( z \right) - 133300000000\,{\frac {E \left( z \right) }{z}}+ 63016666670\,{\frac {E \left( z \right) }{{z}^{2}}}

Y procedemos a realizar la transformada inverza a cada uno de los términos, sabiendo que

$$Z^{-1} { \left\{ F \left( z \right) {z}^{-n} \right\} =f \left( k-n \right)

Por lo tanto la ecuación queda de la siguiente manera

$$64461247640\,v \left( k \right) - 126023944600\,v \left( k-1 \right) + 61562696910\,v \left( k-2 \right) = 70350000010\,e \left( k \right) - 133300000000\,e \left( k-1 \right) + 63016666670\,e \left( k-2 \right)

y finalmente despejamos v(k)

$$v \left( k \right) = 1.091353373\,e \left( k \right) - 2.067909091\,e \left( k-1 \right) + 0.9775899316\,e \left( k-2 \right) + 1.955034214\,v \left( k-1 \right) - 0.9550342130\,v \left( k-2 \right)

Con lo que hemos encontrado, la ecuacion que introduciremos en el programa del PIC. Lo unico que faltaría es aplicar anti-windup y listo.

Comentarios.
« Última modificación: 02 de Mayo de 2010, 00:33:20 por bigluis »
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA

Desconectado bigluis

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 511
    • Tutoriales de Qt C++
Re: Compensador Optimo
« Respuesta #6 en: 02 de Mayo de 2010, 00:58:04 »
Programación

A continuación escribiré un programa de ejemplo hecho en MikroC v8.2, en el que muestro como utilizar la ecuación del compensador que obtuve anteriormente.

Código: C
  1. //--------------------------------Definicion de Librerias y constantes-------------------------------------------------
  2.  
  3. #include "built_in.h"                   //Libreria para usar Lo() y Hi()
  4.  
  5. #define data_port PORTB                 //Definimos el puerto que manejara los datos del LCD
  6. #define data_tris TRISB                 //Definimos el tris quemanejara al puerto de datos.
  7. #define RS PORTB.F2                     //Definimos el pin del PIC que manejara el pin RS del LCD
  8. #define RSt TRISB.F2                    //Definimos el tris que manejara el pin RS
  9. #define EN PORTA.F1                     //Definimos el pin del PIC que manejara el pin EN del LCD
  10. #define ENt TRISA.F1                    //Definimos el tris que manejara el pin EN
  11. #define column_port PORTB               //Definimos el puerto que manejara las columnas del KEYPAD
  12. #define row_port PORTB                  //Definimos el puerto que manejara las filas del KEYPAD
  13. #include "Lcd_4Bits.h"                  /*Libreria que maneja Lcd creada por mi ya que
  14.                                           la Libreria propia de Mikroelectronica ocupa mucha memoria
  15.                                           y produce muchos errores. por eso decidi hacerla. */
  16. #include "Leer_ADC.h"                   /*Libreria que maneja el ADC desarrollada por mi ya que
  17.                                           la libreria propia de Mikroelectronica configura el reloj
  18.                                           del ADC como RC lo que lo hace muy lento.  */
  19.  
  20. //--------------------------------Declaracion de Variables-------------------------------------------------------------
  21.  
  22. char kp,            //Almacena el valor del KeyPad
  23.      txt[7],        //Para Convertir el valor de los angulos a Cadenas.
  24.      banderas=0;    //Para almacenar si se presionan + - * =.
  25. int O1,             //Almacena el angulo 1
  26.     signo=1,        //Almacena el signo del angulo
  27.     tmp=0,          //Variable temporal para hacer calculos con Angulos
  28.                     //Los angulos se Trabajaran en Grados.
  29.     V, E;           //Almacena el Voltaje de salida y el Error de entrada
  30. float v0,           //Almacena el valor de v(k)
  31.       v1,           //Almacena el valor de v(k-1)
  32.       v2,           //Almacena el valor de v(k-2)
  33.       e0,           //Almacena el valor de e(k)
  34.       e1,           //Almacena el valor de e(k-1)
  35.       e2;           //Almacena el valor de e(k-2)
  36.  
  37. //-----------------------------Interrupcion del Programa----------------------------------------------------------
  38.  
  39. void interrupt(){
  40.   TMR0H=0XF8;           //Hacemos que TMR0 realice 2^16-63660=1875 cambios
  41.   TMR0L=0XAC;           //Equivalente a 5ms.
  42.   e2=e1;e1=e0;    //Actualizamos los valores de los errores
  43.   e0=O1;                //A e0 le asignamos el entero O1
  44.   e0-=Leer_adc();       //y luego le restamos el dato del ADC
  45.                         //Formula del compensador optimo.
  46.   v0 = -2.444376528*e1+1.290036675*e0+1.155562347*e2+1.955990220*v1-.9559902200*v2;
  47.  
  48.   V=v0;                 //Asignamos v0 a V.
  49.         //Aplicamos Anti-windup
  50.   if(V>1023)            //Si el valor de V es mayor a 1023
  51.     V=1023,v0=1024;     //hacemos que V sea 1023 y v0 sea 1024
  52.   if(V<0)V=0,v0=0;      //si V es negativo hacemos que V y v0 sean 0;
  53.         //Mandamos los valores al DAC de salida
  54.   PORTE=Hi(V) & 0B11;   //Luego enviamos los 2 bits menos significativos de la parte
  55.   PORTD=Lo(V);          //Primero enviamos la parte baja de V al ADC
  56.                         //alta de V al ADC
  57.   v2=v1; v1=v0;         //Actualizamos los valores de los voltajes
  58.   INTCON.TMR0IF=0;      //Apagamos el flag de TMR0 para salir de la interrupcion
  59. }
  60.  
  61. //-----------------------------Funcion Principal del Programa----------------------------------------------------------
  62.  
  63. void main(){
  64.     T0CON=0B10000100;  //Enciende TMR0 y le pone preescaler igual a 32.
  65.     INTCON=0B10100000; //Habilita interrupciones generales y la interrupcion del TMR0
  66.     TRISA=0B00000001;  //Pone RA0 como entrada los demas pines de PORTA como salidas
  67.     ADCON0=0;          //Seleccionamos el AN0 como entrada para el ADC
  68.     ADCON1=0b00001110; //Definimos solo AN0 como analogico, Vref+=Vdd y Vref-=Vss
  69.     ADCON2=0b10001110; //Definimos resultado del ADC justificado a la derecha, Tacqt=2 Tad y Tad=16/Fosc*4
  70.     CMCON=7;           //Apagamos los comparadores Analogicos
  71.     TRISB=0XF0;                         //Define RB0..3 como salidas y Rb4..7 como Entradas
  72.     INTCON2.RBPU=0;                       //Habilita Resistencias internas de Pull-up para el Teclado.
  73.     Lcd_Inicia();                       //Inicializa Lcd.
  74.     Lcd_Comando(LCD_CURSOR_OFF);   //Enciende El cursor del Lcd.
  75.     Lo(O1)=EEprom_read(0);              //Valor de EEprom al byte bajo de O1
  76. //    Delay_10ms();
  77.     Hi(O1)=EEprom_read(1);              //Valor de EEprom al byte alto de O1
  78.     INTCON.TMR0IF=1;
  79. //    Lo(O2)=EEprom_read(2);              //Valor de EEprom al byte bajo de O1
  80. //    Hi(O2)=EEprom_read(3);              //Valor de EEprom al byte alto de O1
  81.     TRISD=0; TRISE=0;                   //Define los puertos D y E como salidas
  82. L1: Lcd_printfc(0,0,"O1=");             //Imprime "O1 = " en Lcd posicion 0,0 (Inicio).
  83.     IntToStr(O1,txt);                   //Convierte O1 de entero a Cadena y guarda en txt
  84.     Lcd_print(txt);                     //Imprime el valor de txt
  85. //    Lcd_printfc(1,0,"O2=");             //Imprime "O2 = " en Fila 1, col 2 del Lcd
  86. //    IntToStr(O2,txt);                   //Convierte O2 de entero a Cadena y guarda en txt
  87. //    Lcd_print(txt);                   //Imprime el valor de txt
  88.     do{
  89.         kp=keypad_liberar();            //Almacena el valor de la tecla presionada en kp, no continua hasta soltar tecla.
  90.         switch(kp){                     //Decide que hacer a partir del valor de kp.
  91.             case '-':                   //Si se presiono signo '-'
  92.                 if(!tmp && !banderas.F0){//Si no hay valores en tmp ni en Banderas.F0
  93.                     banderas.F0=1;      //Setea bit banderas.F0 para indicar resta
  94.                     Lcd_Pos(0,9);      //Envia el cursor a Fila SO, col 9.
  95.                     Lcd_caracter('-');} //Imprime el caracter '-'.
  96.                     continue;
  97.             case '+':                   //Si se presiono signo '+'
  98.                 if(!tmp && !banderas.F2)//Si no hay valores en tmp ni en Banderas.F2
  99.                     banderas.F2=1,      //Setea bit banderas.F0 para indicar suma
  100.                     Lcd_Pos(0,9);      //Envia el cursor a Fila SO, col 9.
  101.                     Lcd_caracter('+');  //Imprime el caracter '+' y salta comienzo ciclo.
  102.             case 'c':
  103.             case '*':                   //Si se presiono signo '*' y salta comienzo ciclo.
  104.             case 'ý':continue;          //Si se presiono signo '÷' y salta comienzo ciclo.
  105.             case '=':break;             //Si se presiono signo '=', termina el Switch, y comienza a guardar los datos.
  106.             default:                    //Si no ocurre nada de lo anterior
  107.                 if(!banderas){          //Si no se ha presionado ninguna tecla antes
  108.                     Lcd_printfc(0,3,"      ");//Imprimir en la Fila SO, Col 3, "     " para borrar los numeros escritos
  109.                     Lcd_Pos(0,3);      //Luego ubicar el cursor en la Fila SO, Col 3.
  110.                     banderas.F1=1;}     //Setear banderas.F1 para indicar que se han presionado numeros.
  111.                 if(tmp<3276){           //Si tmp es menor que 3276 (El rango de un entero es -32768 .. 32767)
  112.                 tmp=10*tmp+kp;          //tmp sera 10*tmp+kp (kp=valor de teclado).
  113.                 Lcd_caracter(kp+'0');}  //Imprime el valor de la tecla presionada.
  114.                 continue;               //Comienza el ciclo.
  115.             }                           //Aqui comienza a almacenar los datos en la EEprom.
  116. //        if(!SO){                        //Si SO es 0, guardara angulo1
  117.             if(banderas.F0)O1-=tmp;     //Si banderas.F0=1, se resta tmp a O1.
  118.             else if(banderas.F2)O1+=tmp;//Si banderas.F1=1 y, se suma tmp a O1.
  119.             else O1=tmp;                //Si banderas.F0=0 y banderas.F1=0, solo se asigna tmp a O1.
  120.             EEprom_write(0,Lo(O1));     //Se escribe el valor del byte bajo de O1 en EEprom(0)
  121.             Delay_ms(20);
  122.             EEprom_write(1,Hi(O1));     //Se escribe el valor del byte alto de O1 en EEprom(1)
  123.             Lcd_Pos(1,3);               //Se manda el cursor a fila 1, col 5.
  124. //            SO=1;}             //Seteamos SO.F0, indica que el siguiente dado se almacenara a O2
  125. //        else{                           //Si banderas.F1 es 1, guardara angulo2
  126. //            if(banderas.F0)O2-=tmp;     //Si banderas.F0=1, se resta tmp a O1.
  127. //            else if(banderas.F2)O2+=tmp;//Si banderas.F2=1, se suma tmp a O1.
  128. //            else O2=tmp;                //Si no, se asigna tmp a O1.
  129. //            EEprom_write(2,Lo(O2));     //Se escribe el valor del byte bajo de O1 en EEprom(0)
  130. //            EEprom_write(3,Hi(O2));     //Se escribe el valor del byte alto de O1 en EEprom(1)
  131. //            Lcd_Pos(0,3); }              //Se manda el cursor a fila 0, col 5.
  132.         tmp=0;                          //Limpia tmp, para almacenar un nuevo valor.
  133.         banderas=0;                  //Limpiar Bit banderas.F0
  134.         Lcd_comando(LCD_CLEAR);
  135.         goto L1;
  136.     }while(1);                          //Salta al comienzo del ciclo infinito
  137. }

el código anterior ocupa la librería Leer_ADC.h que solo funciona para la familia PIC18

Código: C
  1. #define Leer_canal(canal) ADCON0=4*(canal);//(sal)=Leer_adc();
  2. int adc;                      //Variable global que guardara el valor del ADC
  3.  
  4. unsigned Leer_adc(){
  5.     ADCON0.ADON=1;            //Encendemos el ADC
  6.     ADCON0.GO_DONE=1;         //Comenzamos la conversion AD
  7.     while(ADCON0.GO_DONE);    //Esperamos hasta que se finalice la conversion
  8.     Lo(adc)=ADRESL;           //Guardamos ADRESL en el registro bajo de adc
  9.     Hi(adc)=ADRESH;           //Guardamos ADRESH en el registro alto de adc
  10. //    ADCON0.ADON=0;          //Apagamos el ADC
  11.     return adc; }             //retornamos el valor de adc
  12.  

y la librería Lcd_4bits.h

Código: C
  1. /*************************************
  2. librería calculadora LCD + teclado
  3. para un nucleo PIC
  4. PORTB= D7..4 y filas teclado por defecto
  5. RB3 = EN
  6. RB2 = RS
  7. PORTA 0..3=columnas teclado
  8. RW =0; sólo escritura...
  9. **************************************/
  10. #ifndef data_port
  11.     #define data_port PORTB
  12. #endif
  13.  
  14. #ifndef data_tris
  15.     #define data_tris TRISB
  16. #endif
  17.  
  18. #ifndef EN
  19.     #define EN PORTB.F3
  20. #endif
  21. #ifndef ENt
  22.     #define ENt TRISB.F3
  23. #endif
  24.  
  25. #ifndef RS
  26.     #define RS PORTB.F2
  27. #endif
  28. #ifndef RSt
  29.     #define RSt TRISB.F2
  30. #endif
  31.  
  32. #define Lcd_Pos(F,C) Lcd_comando(0x80+(F)*0x40+(C))
  33. #define Lcd_Put(F,C,Caracter) Lcd_Pos(F,C);Lcd_caracter((Caracter));
  34. #define Lcd_printf(F,C,Cadena) Lcd_Pos(F,C);Lcd_print(Cadena);
  35. #define Lcd_printfc(F,C,Cadena) Lcd_Pos(F,C);Lcd_printc(Cadena);
  36.  
  37. void Ret_ms(short Time_ms){
  38.   for(;Time_ms>=0;Time_ms--)
  39.     Delay_ms(1);}
  40.    
  41. char guarda_tris;
  42.  
  43. void Lcd_escribe(char dato){
  44.     guarda_tris=data_tris;
  45.     data_tris=data_tris & 0x0f;
  46.     data_port=dato & 0xf0 | data_port & 0x0f;
  47.     EN=1;
  48.     Delay_80us();
  49.     EN=0;
  50.     data_tris=guarda_tris;}
  51.  
  52. void Lcd_envia(char dato){
  53.     Lcd_escribe(dato);
  54.     asm swapf FARG_Lcd_envia,1;
  55.     Lcd_escribe(dato);
  56.     Delay_80us();}
  57.  
  58. void Lcd_comando(char comando){
  59.     RS=0;
  60.     Lcd_envia(comando);
  61.     if(comando==1)Ret_ms(2);}
  62.  
  63. void Lcd_caracter(char caracter){
  64.     RS=1;
  65.     Lcd_envia(caracter);}
  66.  
  67. void Lcd_Inicia(){
  68.     RSt=0;
  69.     ENt=0;
  70.     EN=0;
  71.     RS=0;
  72.     Ret_ms(20);
  73.     Lcd_escribe(0x30);
  74.     Ret_ms(5);
  75.     Lcd_escribe(0x30);
  76.     Delay_500us();
  77.     Lcd_escribe(0x30);
  78.     Delay_500us();
  79.     Lcd_escribe(0x20);
  80.     Lcd_comando(0x28);
  81.     Lcd_comando(LCD_CLEAR);
  82.     Lcd_comando(LCD_FIRST_ROW);}
  83.  
  84. void lcd_print(char *cadena){
  85.     FSR0L=Lo(cadena);
  86.     FSR0H=Hi(cadena);
  87.     do{
  88.         Lcd_caracter(POSTINC0);
  89.         if(!INDF0)return;
  90.     }while(1);
  91.     }
  92. //    asm{MOVFF   FARG_lcd_print+0, FSR0L
  93. //        MOVFF   FARG_lcd_print+1, FSR0H
  94. //        MOVFF   POSTINC0, FARG_Lcd_caracter+0
  95. //        MOVF    FARG_Lcd_caracter+0 ,0
  96. //        BZ      $+3
  97. //        CALL    _Lcd_caracter
  98. //        BRA     $-4}}
  99.  
  100. void lcd_printc(const char *cadena){
  101.     TBLPTRL=lo(cadena);
  102.     TBLPTRH=hi(cadena);
  103.     TBLPTRU=Higher(cadena);
  104.     do{
  105.       asm   TBLRD*+;
  106.       if(!TABLAT)return;
  107.       Lcd_caracter(TABLAT);
  108.     }while(1);
  109.     }
  110. //    asm{MOVFF   FARG_lcd_printc_cadena+0, TBLPTRL
  111. //        MOVFF   FARG_lcd_printc_cadena+1, TBLPTRH
  112. //        MOVFF   FARG_lcd_printc_cadena+2, TBLPTRU
  113. //        TBLRD*+
  114. //        MOVFF   TABLAT, FARG_Lcd_caracter_caracter+0
  115. //        MOVF    FARG_Lcd_caracter_caracter,0
  116. //        BZ      $+3
  117. //        CALL    _Lcd_caracter
  118. //        BRA     $-5}}
  119.  
  120. #ifndef column_port
  121.     #define column_port PORTB
  122. #endif
  123. #ifndef row_port
  124.     #define row_port PORTB
  125. #endif
  126.  
  127. const char Teclas[4][4]={{7,8,9,0xFD},
  128.                          {4,5,6,'*'},
  129.                          {1,2,3,'-'},
  130.                          {'c',0,'=','+'}};
  131.  
  132. char Keypad_polling(){
  133.     char i,j,lu;
  134.     row_port=0xE;
  135.     for (i=0;i<4;i++){
  136.         Delay_50us();
  137.         lu=PORTA;
  138.     if ((lu & 0xf) != 0xf){
  139.         for(j=0;j<4;j++){
  140.             if(lu.F0==0) return Teclas[j][i];
  141.             lu=lu>>1;}}
  142.     row_port=row_port<<1 | 0x10;}}
  143.    
  144. char column;
  145. char Keypad_liberar(){
  146.     char i=0,j=0;
  147.     column_port=0XF0;
  148.     while(column_port==0XF0);
  149.     Delay_500us();
  150.     column=column_port | 0x0F;
  151.     for(row_port |= 0xE;
  152.         (column_port&0xf0)==0xf0;
  153.         row_port<<=1,
  154.         row_port.F0=1,
  155.         i++);
  156.     for(;column.F4;column>>=1,j++);
  157.     column_port = 0xf0;
  158.     while(column_port!=0xf0);
  159.     return Teclas[j][i];}
  160.  

A continuación muestro el esquema del circuito que he utilizado para realizar las pruebas.



Finalmente adjunto el archivo de la simulación y códigos.

Comentarios.
« Última modificación: 02 de Mayo de 2010, 01:25:44 por bigluis »
Tutoriales de Qt C++

No es necesario que hagamos Grandes cosas, sino que lo que hagamos sea importante.

SI la NECESIDAD es la MADRE del CONOCIMIENTO, SEGURAMENTE la PEREZA su TÍA.

Cuando el ARTE requiere de PRECISION le llamamos CIENCIA