{"id":358,"date":"2018-01-01T03:52:28","date_gmt":"2018-01-01T03:52:28","guid":{"rendered":"https:\/\/garikoitz.info\/blog\/?p=358"},"modified":"2018-01-02T02:11:46","modified_gmt":"2018-01-02T02:11:46","slug":"pic16f84-control-pid","status":"publish","type":"post","link":"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/","title":{"rendered":"PIC16F84 &#8211; Control PID"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">\u00cdndice<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Alternar tabla de contenidos\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/#Problema_propuesto\" >Problema propuesto<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/#Solucion\" >Soluci\u00f3n<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/#Diagrama_de_flujo\" >Diagrama de flujo<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/#Codigo\" >C\u00f3digo<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Problema_propuesto\"><\/span>Problema propuesto<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Emular un Controlador Discreto PID con el PIC16F84.<\/p>\n<p><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid_01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-361 size-full\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid_01.png\" alt=\"\" width=\"436\" height=\"151\" \/><\/a><\/p>\n<p>Utilizar una gesti\u00f3n de tiempos con interrupci\u00f3n por temporizador. Se supone que la referencia es un valor interno, Referencia. Para simplificar se supone que el actuador y el sensor manejan la informaci\u00f3n en complemento a 2.<\/p>\n<ul>\n<li>Cada 0.01 debe leer el sensor, LeerPortB.<\/li>\n<li>Cada 0.1s debe:\n<ul>\n<li>Calcular MedidaFiltrada como un promedio de las 8 \u00faltimas lecturas del sensor. Se puede realizar la media sumando dos elementos y un desplazamiento a la derecha y as\u00ed sucesivamente hasta cerrar el \u00e1rbol binario de medias, por eso he elegido 8 elementos.<\/li>\n<li>Calcular el Control.\n<ul>\n<li>ErrorAnterior=Error<\/li>\n<li>Error= Referencia &#8211; MedidaFiltrada<\/li>\n<li>Integral= Integral + Error<\/li>\n<li>Derivativa= Error- ErrorAnterior<\/li>\n<li>Control= Kp*Error+Ki*Integral+Kd*Derivativa<\/li>\n<\/ul>\n<\/li>\n<li>Guardar telemetr\u00edas en la EEPROM.<\/li>\n<\/ul>\n<\/li>\n<li>Simular el sistema (en lazo abierto) inyectando est\u00edmulos en PortB que contengan ruido.<\/li>\n<li>El PIC16F84A no es el adecuado para implementar un PID, pues adem\u00e1s de su ALU tan limitada, no dispone ni de conversores anal\u00f3gico-digital ADC para manejar sensores anal\u00f3gicos, ni de generadores de modulaci\u00f3n de ancho de pulsos (PWM) para manejar actuadores. Un microntrolador muy b\u00e1sico que ya dispone de estos recursos es el PIC16F87.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"Solucion\"><\/span>Soluci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Este programa ya supone 326 l\u00edneas de c\u00f3digo, y en \u00e9l se puede decir que se exprime la capacidad del microcontrolador al m\u00e1ximo. En resumen, programaremos para que haya una interrupci\u00f3n cada cent\u00e9sima de segundo (0,01s) en la que leeremos el sensor a trav\u00e9s del puerto B e iremos guardando las lecturas realizadas a trav\u00e9s de la subrutina <strong>LECTURAS<\/strong>. Debido a que solamente disponemos de un temporizador, utilizaremos un contador decreciente para saber cu\u00e1ndo han transcurrido 0,1\u00a0segundos (10 cent\u00e9simas o 10 desbordamientos) y aprovecharemos para llamar a tres subrutinas. Primeramente filtraremos la medida realizando una media de las ocho \u00faltimas lecturas recogidas mediante la subrutina <strong>CALCFIL<\/strong>\u00a0Como no disponemos de instrucci\u00f3n para dividir valores debemos improvisar con su equivalente en ensamblador, rotar a la derecha. Para ello sumaremos por parejas y rotaremos a la derecha guardando el resultado en la variable par mayor.<\/p>\n<figure id=\"attachment_359\" aria-describedby=\"caption-attachment-359\" style=\"width: 269px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_arbolbin.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-359\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_arbolbin-269x300.png\" alt=\"\u00c1rbol binario del c\u00e1lculo de la medida filtrada\" width=\"269\" height=\"300\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_arbolbin-269x300.png 269w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_arbolbin-242x270.png 242w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_arbolbin.avif 334w\" sizes=\"auto, (max-width: 269px) 100vw, 269px\" \/><\/a><figcaption id=\"caption-attachment-359\" class=\"wp-caption-text\">\u00c1rbol binario del c\u00e1lculo de la medida filtrada<\/figcaption><\/figure>\n<p>A continuaci\u00f3n realizaremos el c\u00e1lculo del control PID mediante la subrutina <strong>CALCONTROL<\/strong>\u00a0En realidad no tratamos nada nuevo, pero supone unas cuantas l\u00edneas de c\u00f3digo simplemente para realizar tres productos y tres sumas. Ya que es una simple simulaci\u00f3n con limitaciones y en lazo abierto hay que tener en cuenta las siguientes consideraciones:<\/p>\n<ul>\n<li>Las constantes Ki, Kp, Kd se dejan con un valor de 1.<\/li>\n<li>No se corrige el Windup.<\/li>\n<li>No se tienen en cuenta ni el overshoot ni el undershoot.<\/li>\n<li>No se tiene en cuenta el error negativo.<\/li>\n<\/ul>\n<p>Finalmente guardamos las telemetr\u00edas en la eeprom mediante la subrutina <strong>GUARDAR<\/strong>. Aunque es algo que tratamos por primera vez, no supone mayor complicaci\u00f3n ya que el propio fabricante indica la manera correcta de leer y escribir de\/en la eeprom.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Diagrama_de_flujo\"><\/span>Diagrama de flujo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<figure id=\"attachment_360\" aria-describedby=\"caption-attachment-360\" style=\"width: 200px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-360\" src=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid-200x300.png\" alt=\"Diagrama de flujo\" width=\"200\" height=\"300\" srcset=\"https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid-200x300.png 200w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid-683x1024.png 683w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid-180x270.png 180w, https:\/\/garikoitz.info\/blog\/wp-content\/uploads\/2018\/01\/pic16f84_pid.png 740w\" sizes=\"auto, (max-width: 200px) 100vw, 200px\" \/><\/a><figcaption id=\"caption-attachment-360\" class=\"wp-caption-text\">Diagrama de flujo<\/figcaption><\/figure>\n<h3><span class=\"ez-toc-section\" id=\"Codigo\"><\/span>C\u00f3digo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"asm\">;------------------------------------------------------------------\r\n\t\t__CONFIG   _CP_OFF &amp;  _WDT_OFF &amp; _PWRTE_ON &amp; _XT_OSC\r\n\t\tlist \tp=16f84a\r\n\t\tinclude \"p16f84a.inc\"\r\n;------------------------------------------------------------------\r\n;CBLOCK   \t\t\t0x0C\r\n;Telemetria\r\n;ENDC\r\nORG\t\t\t0x2100\t\t; Direcci\u00f3n 0 de la EEPROM\r\nDE\t\t\t0x00\t\t; Telemetr\u00eda a cero.\r\nDato1\t\tequ\t0x0C\r\nDato2\t\tequ\t0x0D\r\nDH\t\tequ \t0x0E \t\t; byte alto\r\nDL\t\tequ \t0x0F \t\t; byte bajo\r\nNumA\t\tequ\t0x10\r\nNumB\t\tequ\t0x11\r\nAxB\t\tequ \t0x12\r\nConta\t\tequ\t0x13\t\t; Contador\r\nRegW\t\tequ\t0x14\t\t; Registro W\r\nRegS\t\tequ\t0x15\t\t; Registro Status\r\nFlagL\t\tequ\t0x16\t\t; Flag Lecturas\r\nn1\t\tequ\t0x17\t\t; 1\u00aaLectura\r\nn2\t\tequ\t0x18\t\t; 2\u00aaLectura\r\nn3\t\tequ\t0x19\t\t; 3\u00aaLectura\r\nn4\t\tequ\t0x20\t\t; 4\u00aaLectura\r\nn5\t\tequ\t0x21\t\t; 5\u00aaLectura\r\nn6\t\tequ\t0x22\t\t; 6\u00aaLectura\r\nn7\t\tequ\t0x23\t\t; 7\u00aaLectura\r\nn8\t\tequ\t0x24\t\t; 8\u00aaLectura\r\nError\t\tequ\t0x25\t\t; Error\r\nErrorAnt\tequ\t0x26\t\t; Error Anterior\r\nInteg\t\tequ\t0x27\t\t; Integral\r\nDeriv\t\tequ\t0x28\t\t; Derivada\r\nControl\t\tequ\t0x29\t\t; Control\r\nReferen\t\tequ\t0x30\t\t; Referencia\r\nMedFil\t\tequ\t0x30\t\t; Medida filtrada\r\nkp\t\tequ\t0x31\t\t; Kp\r\nki\t\tequ\t0x32\t\t; Ki\r\nkd\t\tequ\t0x33\t\t; Kd\r\n;------------------------------------------------------------------\r\n\t\t\torg \t0x00\r\n\t\t\tgoto \tINICIO\r\n\t\t\torg \t0x04\r\n\t\t\tgoto\tINT_Timer\r\nINICIO \r\n\t\t\tbsf\tstatus,5\t; Banco 1 (RP0)\r\n\t\t\tmovwf\tb'00000000'\r\n\t\t\tmovwf\tTRISB\t\t; Puerto B como salida\r\n\t\t\tmovwf\tb'00011111'\r\n\t\t\tmovwf\tTRISA\t\t; Puerto A como entrada\r\n\t\t\tclrw\t\t\t; Borro W\r\n\t\t\tmovlw \t0x07 \t\t; Cargo W con 00000111 (PSAx,1,1,1)\r\n\t\t\tmovwf \toption_reg \t; Divisor = 256\r\n\t\t\tbcf \tstatus,5\t; Banco 0 (RP0)\r\n\t\t\tmovlw \t0x88 \t\t; Cargo W con 10101000\r\n\t\t\tmovwf \tintcon \t\t; Habilitamos GIE y RBIE\r\n\t\t\tclrf \tportb \t\t; Borro PORTB\r\n\t\t\tclrf \tporta \t\t; Borro PORTA\r\n\t\t\tclrf\tConta\t\t; Borro Conta\r\n\t\t\tclrf\tDato1\t\t; Borramos\r\n\t\t\tclrf\tDato2\t\t; Borramos\r\n\t\t\tclrf\tNumA\t\t; Borramos\r\n\t\t\tclrf\tNumB\t\t; Borramos\r\n\t\t\tclrf\tAxB\t\t; Borramos\r\n\t\t\tmovlw\t0xA\t\t; 10cs = 0,1s\r\n\t\t\tmovwf\tConta\t\r\n\t\t\tmovlw \t0xD9 \t\t; Cargo W con 0x00-0x27\r\n\t\t\tmovwf \ttmr0 \t\t; Lo paso a TMR0\r\n\t\t\tmovlw \t0x1 \t\t; Cargo W con 1\r\n\t\t\tmovwf \tFlagL \t\t; Inicializo FlagL\r\nPRINCIPAL\r\n\t\t\t; Pasamos el c\u00e1lculo al actuador (PORTA)\r\n\t\t\tmovf\tControl,W\t; W = Control\r\n\t\t\tmovwf\tPORTA\t\t; Lo pasamos a PORTA\r\n\t\t\tgoto\tPRINCIPAL\r\n;GESTIONO INTERRUPCI\u00d3N-------------------------------------------------\r\n;0,01S = 10MS = 1CS --&gt; LEER PORTB ------------------------------------\r\n;0,1S = 100MS = 10CS -&gt; CALC MED.F -&gt; CALC CONTROL -&gt; GUARDAR DATO ----\r\n;----------------------------------------------------------------------\r\nINT_Timer\r\n\t\t\tbcf \tINTCON,GIE \t; Deshabilitar interrupciones\r\n\t\t\tmovwf \tRegW\t\t; Guardamos W\r\n\t\t\tswapf\tSTATUS,W\t; Invertimos nibbles\r\n\t\t\tmovwf\tRegS\t\t; Guardamos estado\r\n\t\t\tcall\tLECTURAS \t; Leo puerto B\r\n\t\t\tdecfsz\tConta,F\t\t; Conta -=1\r\n\t\t\tgoto\tSIGO\t\t; No hemos acabado\r\n\t\t\tmovlw\t0xA\t\t; 10cs = 0,1s\r\n\t\t\tmovwf\tConta\t\t; Conta = 0xA\r\n\t\t\tcall\tCALCFIL\t\t; Calculo Medida filtrada\r\n\t\t\tcall\tCALCONTROL\t; Calculo Control\r\n\t\t\tmovf\tControl,W\t; W = Control\r\n\t\t\tcall\tGUARDAR\t\t; Guardo telemetr\u00edas\r\nSIGO\r\n\t\t\tmovlw \t0xD9 \t\t; Cargo W con 0x00-0x27\r\n\t\t\tmovwf \ttmr0 \t\t; Lo paso a TMR0\r\n\t\t\tbcf \tINTCON,T0IF ; Limpiar bandera de interrupci\u00f3n\r\n\t\t\tswapf\tRegS,W\t\t; Invertimos nibbles de RegS\r\n\t\t\tmovwf\tSTATUS\t\t; Restauramos estado\r\n\t\t\tswapf\tRegW,fin\t; Invertimos nibles\r\n\t\t\tswapf\tRegW,W\t\t; Restauramos W\r\n\t\t\tbsf \tINTCON,GIE \t; Habilitar interrupciones\r\n\t\t\tretfie\t\t\t; Vuelvo de la interrupci\u00f3n\r\n;-------------------------------------------------------------------------\r\n;SUBRUTINA COGER LECTURAS-------------------------------------------------\r\n;-------------------------------------------------------------------------\r\nLECTURAS\r\n\t\t\tmovf\t1,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGUNO\t\t; 1\u00aaLectura\r\n\t\t\tmovf\t2,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGDOS\t\t; 2\u00aaLectura\r\n\t\t\tmovf\t3,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGTRES\t; 3\u00aaLectura\r\n\t\t\tmovf\t4,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGCUATRO\t; 4\u00aaLectura\r\n\t\t\tmovf\t5,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGCINCO\t; 5\u00aaLectura\r\n\t\t\tmovf\t6,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGSEIS\t; 6\u00aaLectura\r\n\t\t\tmovf\t7,W\t\t;\r\n\t\t\tsubwf\tFlagL,W\t\t;\r\n\t\t\tbtfsc\tstatus,Z\t;\r\n\t\t\tgoto\tFLAGSIETE\t; 7\u00aaLectura\r\n\t\t\tgoto\tFLAGOCHO\t; 8\u00aaLectura\r\nFLAGUNO\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn1\t\t; 1\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGDOS\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn2\t\t; 2\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGTRES\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn3\t\t; 3\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGCUATRO\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn4\t\t; 4\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\t\t\t\r\nFLAGCINCO\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn5\t\t; 5\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGSEIS\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn6\t\t; 6\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGSIETE\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn7\t\t; 7\u00aa lectuta\r\n\t\t\tincf\tFlagL,1\t\t; FlagL +=1\r\n\t\t\tgoto\tFIN\t\t;\r\nFLAGOCHO\r\n\t\t\tmovf\tportB,W\t\t;\r\n\t\t\tsublw \t0x00000000 \t; Complemento a 2\r\n\t\t\tmovwf\tn8\t\t; 8\u00aa lectuta\r\n\t\t\tmovf\t1,W\t\t; Reinicio flag\r\n\t\t\tmovwf\tFlagL\t\t;\r\nFIN\r\n\t\t\treturn\t\t\t; fin subrutina\r\n;-------------------------------------------------------------------------\r\n;SUBRUTINA FILTRAR MEDIDA-------------------------------------------------\r\n;-------------------------------------------------------------------------\r\nCALCFIL\r\n\t\t\t;(n1+n2)\/2\r\n\t\t\tmovf\tn1,W\t\t; W = n1\r\n\t\t\taddwf\tn2,1\t\t; n1+n2 y guardo en n2\r\n\t\t\trrf\tn2,1\t; roto a dcha y guardo en n2\r\n\t\t\t;(n3+n4)\/2\r\n\t\t\tmovf\tn3,W\t\t; W = n3\r\n\t\t\taddwf\tn4,1\t\t; n3+n4 y guardo en n4\r\n\t\t\trrf\tn4,1\t\t; roto a dcha y guardo en n4\r\n\t\t\t;(n5+n6)\/2\r\n\t\t\tmovf\tn5,W\t\t; W = n5\r\n\t\t\taddwf\tn6,1\t\t; n5+n6 y guardo en n6\r\n\t\t\trrf\tn6,1\t\t; roto a dcha y guardo en n6\r\n\t\t\t;(n7+n8)\/2\r\n\t\t\tmovf\tn7,W\t\t; W = n7\r\n\t\t\taddwf\tn8,1\t\t; n7+n8 y guardo en n8\r\n\t\t\trrf\tn8,1\t\t; roto a dcha y guardo en n8\r\n\t\t\t;(n2+n4)\/2\r\n\t\t\tmovf\tn2,W\t\t; W = n2\r\n\t\t\taddwf\tn4,1\t\t; n2+n4 y guardo en n4\r\n\t\t\trrf\tn4,1\t\t; roto a dcha y guardo en n4\r\n\t\t\t;(n6+n8)\/2\r\n\t\t\tmovf\tn6,W\t\t; W = n6\r\n\t\t\taddwf\tn8,1\t\t; n6+n8 y guardo en n8\r\n\t\t\trrf\tn8,1\t\t; roto a dcha y guardo en n8\r\n\t\t\t;(n4+n8)\/2\r\n\t\t\tmovf\tn4,W\t\t; W = n4\r\n\t\t\taddwf\tn8,1\t\t; n4+n8 y guardo en n8\r\n\t\t\trrf\tn8,0\t\t; roto a dcha y guardo en W\r\n\t\t\tmovwf\tMedFil\t\t; Guardo la Medida Filtrada\r\n\t\t\treturn\t\t\t; fin subrutina\r\n;-------------------------------------------------------------------------\r\n;SUBRUTINA CALCULAR CONTROL-----------------------------------------------\r\n\t;ErrorAnterior=Error\r\n\t;Error= Referencia - MedidaFiltrada\r\n\t;Integral= Integral + Error\r\n\t;Derivativa= Error- ErrorAnterior\r\n\t;Control= Kp*Error+Ki*Integral+Kd*Derivativa\r\n;-------------------------------------------------------------------------\r\nCALCONTROL\r\n\t\t\t; Valores regulaci\u00f3n PID\r\n\t\t\tmovlw\t0x1\t\t; w=1\r\n\t\t\tmovwf\tkp\t\t; Kp=1\r\n\t\t\tmovlw\t0x1\t\t; w=1\r\n\t\t\tmovwf\tki\t\t; Ki=1\r\n\t\t\tmovlw\t0x1\t\t; w=1\r\n\t\t\tmovwf\tkd\t\t; Kd=1\r\n\t\t\t; Error = Referencia - MedidaFiltrada\r\n\t\t\tmovf\tError,W\t\t; W = Error\r\n\t\t\tmovwf\tErrorAnt\t; ErrorAnt = Error\r\n\t\t\tmovf\tMedFil,W\t; W = MedFil\r\n\t\t\tsubwf\tReferen,0 \t; f - w \u2192 Referen - MedFil\r\n\t\t\tmovwf\tError\t\t; Error = Referen - MedFil\r\n\t\t\t; Integral = Integral + Error\r\n\t\t\taddwf\tInteg,1\t\t; Integ += Error\r\n\t\t\t; Derivativa = Error - ErrorAnterior\r\n\t\t\tmovf\tErrorAnt,W\t; W = ErrorAnt\r\n\t\t\tsubwf\tError,0 \t; f - w \u2192 Error - ErrorAnt\r\n\t\t\tmovwf\tDeriv\t\t; Deriv = Error - ErrorAnt\r\n\t\t\t; Control = Kp*Error+Ki*Integral+Kd*Derivativa\r\n\t\t\tmovf\tkp,W\t\t; W=Kp\r\n\t\t\tmovwf\tDato1\t\t; Dato1 = Kp\r\n\t\t\tmovf\tError,W\t\t; W=Error\r\n\t\t\tmovwf\tDato2\t\t; Dato2 = Error\r\n\t\t\tcall\tPRODUCTO\t; Multiplico\r\n\t\t\taddwf\tControl,1\t; Control = Kp*Error\r\n\t\t\tmovf\tki,W\t\t; W=Ki\r\n\t\t\tmovwf\tDato1\t\t; Dato1 = Ki\r\n\t\t\tmovf\tInteg,W\t\t; W=Integ\r\n\t\t\tmovwf\tDato2\t\t; Dato2 = Integ\r\n\t\t\tcall\tPRODUCTO\t; Multiplico\r\n\t\t\taddwf\tControl,1\t; Control = Kp*Error+Ki*Integral\r\n\t\t\tmovf\tkd,W\t\t; W=Kd\r\n\t\t\tmovwf\tDato1\t\t; Dato1 = Kd\r\n\t\t\tmovf\tDeriv,W\t\t; W=Deriv\r\n\t\t\tmovwf\tDato2\t\t; Dato2 = Deriv\r\n\t\t\tcall\tPRODUCTO\t; Multiplico\r\n\t\t\taddwf\tControl,1\t; Control = Kp*Err+Ki*Inte+Kd*Deriv\r\n\t\t\treturn\t\t\t; fin subrutina\r\n;-------------------------------------------------------------------------\r\n;SUBRUTINA GUARDAR TELEMETR\u00cdAS--------------------------------------------\r\n;-------------------------------------------------------------------------\r\nGUARDAR\r\n\t\t\tCBLOCK\r\n\t\t\tGuardaINTCON\r\n\t\t\tENDC\r\n\t\t\tbcf\tSTATUS,5\t\t; Banco 0\r\n\t\t\tmovwf\tEEDATA\t\t\t; El byte a escribir\r\n\t\t\tmovf\tINTCON,W\t\t; Valor anterior de INTCON\r\n\t\t\tmovwf\tGuardaINTCON\r\n\t\t\tbsf\tSTATUS,5\t\t; Banco 1\r\n\t\t\tbcf\tINTCON,GIE\t\t; Deshabilita interrupciones\r\n\t\t\tbsf\tEECON1,WREN\t\t; Habilita escritura\r\n\t\t\tmovlw\t0x55\r\n\t\t\tmovwf\tEECON2\r\n\t\t\tmovlw\t0xAA\r\n\t\t\tmovwf\tEECON2\r\n\t\t\tbsf\tEECON1,WR\t\t; Inicia la escritura.\r\nTERMINA\r\n\t\t\tbtfsc\tEECON1,WR\t\t; \u00bfFin de la escritura?\r\n\t\t\tgoto\tTERMINA\t\t\t; No\r\n\t\t\tbcf\tEECON1,WREN\t\t; No escritura en EEPROM\r\n\t\t\tbcf\tEECON1,EEIF\t\t; Limpia flag\r\n\t\t\tbcf\tSTATUS,5\t\t; Banco 0\r\n\t\t\tmovf\tGuardaINTCON,W \t; Restaura INTCON\r\n\t\t\tmovwf\tINTCON\r\n\t\t\treturn\t\t\t\t; fin subrutina\r\n;-------------------------------------------------------------------------\r\n;SUBRUTINA MULTIPLICACI\u00d3N-------------------------------------------------\r\n;-------------------------------------------------------------------------\r\nPRODUCTO\r\n\t\t\tclrf \tDH\r\n\t\t\tclrf\tDL\r\n\t\t\tmovf \tDato1,W\t\t; W = multiplicador\r\n\t\t\tbtfsc\tstatus,Z\t; Salta si Z=1\r\n\t\t\treturn\t\t\t; Z=0 hemos terminado\r\n\t\t\tmovf \tDato2,W\t\t; W = multiplicador\r\n\t\t\tbtfsc\tstatus,Z\t; Salta si Z=1\r\n\t\t\treturn\t\t\t; Z=0 hemos terminado\r\nSIGUE\r\n\t\t\tmovf\tDL,W\t\t; W=DL\r\n\t\t\taddwf\tDato1,W\t\t; W += multiplicando\r\n\t\t\tmovwf\tDL\t\t; DL=W\r\n\t\t\tbtfsc\tstatus,C\t; Salta si C=0\r\n\t\t\tincf\tDH,F\t\t;\r\n\t\t\tdecfsz\tDato2,F\t\t; multiplicador-1\r\n\t\t\tgoto\tSIGUE\t\t; no hemos acabado\r\n\t\t\tmovwf\tDL\t\t; DL=W\r\n\t\t\tmovwf\tAxB\t\t; Producto=W\r\n\t\t\t;movwf \tPORTB\t\t; Puerto B=W\r\n\t\t\tclrf\tDato2\r\n\t\t\treturn\t\t\t; fin subrutina\r\n;------------------------------------------------------------------\r\n\t\t\tend\t\t\t; fin\r\n;------------------------------------------------------------------\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Problema propuesto Emular un Controlador Discreto PID con el PIC16F84. Utilizar una gesti&oacute;n de tiempos con interrupci&oacute;n por temporizador. Se supone que la referencia es un valor interno, Referencia. Para simplificar se supone que el actuador y el sensor manejan la informaci&oacute;n en complemento a 2. Cada 0.01 debe leer el sensor, LeerPortB. Cada 0.1s debe: Calcular MedidaFiltrada como un promedio de las 8 &uacute;ltimas lecturas del sensor. Se puede realizar la media sumando dos elementos y un desplazamiento a&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/garikoitz.info\/blog\/2018\/01\/pic16f84-control-pid\/\"> Leer m\u00e1s<span class=\"screen-reader-text\">  Leer m\u00e1s<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":381,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","wpupg_custom_link":[],"wpupg_custom_link_behaviour":[],"wpupg_custom_link_nofollow":[],"wpupg_custom_image":[],"wpupg_custom_image_id":[],"footnotes":""},"categories":[33],"tags":[35,34,17],"class_list":["post-358","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pic16f84","tag-micro","tag-pic16f84","tag-pid"],"_links":{"self":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/358","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/comments?post=358"}],"version-history":[{"count":5,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/358\/revisions"}],"predecessor-version":[{"id":367,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/posts\/358\/revisions\/367"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media\/381"}],"wp:attachment":[{"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/media?parent=358"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/categories?post=358"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/garikoitz.info\/blog\/wp-json\/wp\/v2\/tags?post=358"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}