2.1 Defining workgroups
2.3.2 Newer forms of workgroups
Ahora vamos a echar un vistazo a un temporizador interno, llamado "Watchdog Timer" [Nota de la traducción: En castellano sería, "temporizador perro guardián"] Así que, ¿Qué es un watchdog timer?
Supón que has escrito un programa que está continuamente corriendo en un PIC. Ahora, quieres asegurarte de que el programa sigue ejecutándose siempre, y no hay manera de que se pare nunca. La primera cosa que tienes que hacer, por supuesto, es un bucle que desde el final del programa te lleve hasta el principio. Pero ten en cuenta esto. Digamos que el PIC está monitorizando una entrada. Cuando esta entrada se pone a nivel alto, salta a otra parte del programa y espera por otro pin para que se ponga a nivel alto. Si el
segundo pin no se pone a nivel alto, el PIC simplemente "se sentará a esperar". Solo saldrá de ahí si el segundo pin se pone a nivel alto.
Consideremos otro ejemplo. Supón que has escrito un programa, lo has compilado con éxito, e incluso lo has simulado una y otra vez utilizando un simulador como MPLAB. Todo parece funcionar bien. Programas el PIC y lo colocas en tu circuito. Sin embargo
después de un largo periodo el programa se atasca en algún punto y el PIC se queda enganchado en un bucle.
Lo que se necesita en ambos casos es alguna clase de reset(o reinicio) si el programa se quedó atascado. Este es el propósito del watchdog timer.
Un circuito watchdog no es nada nuevo. Muchos microprocesadores y
microcontroladores lo tienen. Pero, ¿cómo funciona? Bien, dentro del PIC hay una red resistencia-condensador. Esta proporciona un reloj único, que es independiente de cualquier reloj externo que proporciones al circuito. Ahora cuando el watchdog timer (abreviado como WDT) está habilitado, un contador comienza en 00 y se incrementa en 1 hasta que alcanza FF. Cuando pasa de FF a 00 (lo cual es FF+1) el PIC será reiniciado, independientemente de lo que esté haciendo. La única manera de evitar que el WDT reinicie el PIC es reiniciar el propio WDT poniéndolo de vuelta a 00 durante el programa. Ahora puedes ver que si tu programa se atasca por cualquier razón, entonces el WDT no será puesto a 00 nunca. Eso hará que el WDT llegue a FF y reinicie tu PIC, causando a nuestro programa que se reinicie desde el comienzo.
Para utilizar el WDT, tenemos que saber tres cosas:
La primera, cuanto tiempo tenemos antes de tener que hacer un reinicio al WDT. ■
Segundo, como lo ponemos a cero. ■
Finalmente, tenemos que decirle al software programador del PIC que habilite el WDT dentro del PIC.
■
Vamos a ver esto de manera separada:
Tiempos de WDT
La hoja de datos del PIC especifica que el WDT tiene un periodo desde su inicio hasta el final de 18 ms. Esto depende de varios factores, como el voltaje aplicado, la temperatura del PIC, etc... La razón de esta aproximación es debida a que el reloj del WDT es
suministrado por una red RC interna. El tiempo de carga de la red RC depende del voltaje de alimentación. También depende de los valores de los componentes, los cuales cambian ligeramente dependiendo de su temperatura. Así que por razones de simplicidad,
tomaremos los 18 ms como el tiempo de reinicio del WDT.
Sin embargo, podemos hacer este tiempo mayor. Dentro del PIC hay un elemento llamado Prescaler [Nota de la Traducción: "Prescaler" se puede traducir como "etapa
previa de ajuste de escala"]. Podemos programar este prescaler para dividir el reloj
interno de la red RC. Cuanto mayor sea el factor de división, más tiempo tardará el WDT en reiniciarse.
El prescaler está localizado en el registro OPTION en la dirección 81h, los bit del 0 al 2 inclusive. Más abajo hay una tabla que muestra las asignaciones de los bits para cada ratio de división y el tiempo de reinicio del WDT:
Bit 2 Bit 1 Bit 0 Ratio Tiempo de WDT
0 0 0 1:1 18ms 0 0 1 1:2 36ms 0 1 0 1:4 72ms 0 1 1 1:8 144ms 1 0 0 1:16 288ms 1 0 1 1:32 576ms 1 1 0 1:64 1.1 Segundos 1 1 1 1:128 2.3 Segundos
Recuerda que estos tiempos son independientes de la frecuencia de tu reloj externo. Piensa en estos tiempos como en tiempo real, en lugar de como tiempos de reloj. Para ayudar a clarificar esto, vamos a suponer que queremos que el WDT reinicie nuestro PIC después de cerca de medio segundo como tiempo de seguridad ante fallo. El valor más próximo que tenemos es 576 ms o 0,576 segundos. Todo lo que hacemos es enviar b'101' a nuestro registro OPTION, tal y como sigue:
movlw b’101’ ; Esto es 0x05 en hexadecimal.
movwf 81h ; Este es el registro OPTION.
Realmente sencillo. Ahora, hay una trampa. Por defecto el prescaler está asignado a otro temporizador interno [Nota de la Traducción: Se refiere al temporizador TMR0.]. Esto significa que tenemos que cambiar el prescaler al WDT [Nota de la Traducción: Para
asignar el Prescaler al WDT hay que poner el bit 3 del registo OPTION a 1. Es decir, para poner el prescaler a 576 ms como decíamos antes y asignarlo al WDT, Hay que enviar al registro OPTION el valor b'1101]:
Primero, tenemos que reiniciar el otro contador (TMR0) y ponerlo a 0. ■
Después tenemos que cambiar al banco 1 para asignar el prescaler al WDT y configurar el tiempo.
■
Y después volver al banco 0. ■
El código esta aquí, donde xxx es el valor del prescaler:
bcf STATUS,0 ; Nos aseguramos de que estamos en el banco 0
clrf 01h ; Dirección del otro temporizador – TMR0. Lo ponemos a 0.
bsf STATUS,0 ; Cambiamos al banco 1switch to bank 1
clrwdt ; reiniciamos el WDT y el ''prescaler''
movlw b’1xxx’ ; Seleccionamos el valor del nuevo ''preescaler''(bits 0 al 2)
; y lo asignamos al WDT(ver bit 3 puesto a 1).
movwf OPTION ; y se lo asignamos al WDT
bcf STATUS,0 ; Vuelve al banco 0
La instrucción anterior CLRWDT es la que se utiliza para reiniciar el WDT antes de que este reinicie al PIC. Así que todo lo que tenemos que hacer es calcular donde en nuestro programa ocurrirá la finalización del tiempo del WDT, y enviar el comando CLRWDT justo antes de este punto, para que nos aseguremos de que el PIC no se reinicia. Si tu programa es largo, ten en cuenta que puede que necesites más de un CLRWDT. Por ejemplo, si utilizas el tiempo por defecto 18 ms, entonces tenemos que asegurarnos de que el programa ve un CLRWDT cada 18 ms.
Así que ahora llegamos al punto donde tenemos que trabajar en cuanto tiempo tarda nuestro código en ejecutarse, en tiempo real. El principio es muy simple, pero ¡puede que te tires de los pelos!
Temporización de las instrucciones
Como probablemente ya sabrás, el PIC toma el reloj externo y lo divide por 4. Este tiempo interno es llamado ciclo de instrucción. Como hemos dicho que conectamos un cristal de 4 Mhz a nuestro PIC, internamente el PIC irá a 1Mhz. En términos de
temporización, esto es 1/(4Mhz/4) = 1 µS. Entonces algunas instrucciones lleva ejecutarlas un solo ciclo de instrucción, p. ej. 1 µS utilizando un cristal de 4Mhz, mientras que otras emplearán 2 µS en ser ejecutadas.
La hoja de características nos dice cuantos ciclos lleva cada instrucción. La forma mas sencilla para recordarlo es muy simple. Asume que todas las instrucciones tardan 1 ciclo. Pero si una instrucción causa que el programa vaya a algún otro sitio, este se tomará 2 ciclos. Permite que te darte un par de ejemplos.
La instrucción "movwf" tarda solo 1 ciclo, porque solo mueve un dato de un lugar a otro. La instrucción "goto" tarda 2 ciclo, porque está causando que el contador de programa
(PC) vaya a otro sitio del programa. La instrucción RETURN tarda 2 ciclos, porque causa que el PC vuelva al programa principal. Al menos creemos que con esto ya puedes ver por donde va el tema.
Sin embargo, hay cuatro instrucciones que pueden tardar 1 ó 2 ciclos. Estas son
DECFSZ, INCFSZ, BTFSC y BTFSS. Estas instrucciones tienen una cosa en común. Se saltan la siguiente instrucción en caso si se cumple cierta condición. Si no se cumple la condición, entonces se lleva a cabo la siguiente instrucción. Por ejemplo, la instrucción DECFSZ decrementará en 1 el valor almacenado en el registro F. Si el resultado es 0, entonces la siguiente instrucción será ejecutada. Esta instrucción por tanto tarda 1 ciclo. Si el resultado es 0, entonces la instrucción siguiente se la salta, y la siguiente a la anterior será ejecutada. En este ejemplo la instrucción tarda 2 ciclos. La razón es que la instrucción altera el PC. Necesita 1 ciclo para ejecutar la función, y necesita otro para cambiar el PC por uno mas extra.
Para aclarar esto, vamos a mirar un código simple, y trabajaremos sobre los ciclos de instrucción que tarda:
;
movlw 02 movwf CONTADOR Bucle decfsz CONTADOR goto Bucle end
Nuestra primera instrucción simplemente mueve el valor 02 a W. Esto no causa ningún salto, por tanto es solo 1 ciclo. La siguiente instrucción es similar, mueve los contenidos del registro W a CONTADOR. De nuevo, esto tardará 1 ciclo. Ahora, la siguiente
instrucción primero decrementa CONTADOR en 1. Esto es 1 ciclo. Después hará una comprobación para ver que CONTADOR es igual a 0. En este momento no lo es, por tanto vamos a la siguiente instrucción. La siguiente instrucción es una de "goto", y por tanto tarda 2 ciclos. Volvemos a nuestra instrucción DECFSZ, la que decrementa CONTADOR en 1 de nuevo. Esto tarda otro ciclo. Hace una comprobación para ver si CONTADOR es igual a 0. Esta vez lo es, y por tanto se salta la siguiente instrucción. Para saltarse la siguiente instrucción se requiere otro ciclo. Alcanzamos el final del programa. Así que en total, con el valor de 02 para CONTADOR, este programa tarda 7 ciclos en total. Si estamos usando un cristal de 4MHz para nuestro reloj, entonces el programa tarda:
Software Programador
Dentro del PIC hay elementos llamados "Fusibles" [Nota de Traducción: En ingles
"Fuses"]. No son los mismos que puedes encontrar en los enchufes, sino que son
conmutadores electrónicos que se pueden "fundir" por el programador. Uno de estos fusibles tiene que ser 'fundido' para que el WDT pueda operar. Hay dos formas de hacerlo. Una es escribiendo un par de lineas al comienzo de tu programa para decirle al software programador del PIC que habilite o deshabilite ciertos "fusibles". La otra forma de hacerlo es decirle al software programador del PIC manualmente que fusibles
habilitar. Echaremos un vistazo a nuestro programa para instruir al software programador del capítulo pasado, cuando veamos como incluir otros ficheros y macros. El cómo
hacerlo manualmente varía dependiendo del software de programación. La
documentación que viene con el programador suele decir como hacerlo. Como estoy utilizando el [software PICALLW (http://www.picallw.com/) ], explicaremos como cambiar los "fusibles" con este programa:
Los fusibles se configuran pulsando la tecla F3, o haciendo 'click' sobre el botón de configuración. Después seleccionas el fusible que quieres habilitado, en ese caso el WDT, haciendo una marca en la caja que está junto a él.
Programa de ejemplo
Vamos a escribir un programa, donde modifiquemos el WDT, y permitamos al PIC ejecutar una función. Primero borraremos el WDT periódicamente para mostrar que el programa funciona, y después quietaremos la instrucción CLRWDT para mostrar que efectivamente el PIC se reinicia.
El programa que hemos elegido es el utilizado en el capítulo Operadores Aritméticos y Lógicos donde hacíamos que una fila de LEDs se encendiesen a un tiempo de izquierda a derecha y de derecha a izquierda. El circuito se muestra más abajo, y con los valores RC que mostramos le daremos una frecuencia de reloj de 8KHz. Esta velocidad de reloj nos permitirá realmente ver los LEDs moviéndose uno a uno. Elegimos este programa porque es suficientemente lento para que podamos jugar con el WDT, y que puedas ver
fácilmente como se reinicia el PIC. Hemos quitado los comentarios originales, y los hemos sustituido por una descripción de las lineas del WDT, y en cada linea del tiempo total desde el inicio (asumiendo 8KHz), y el número total de ciclos de reloj de cada linea.
TIEMPO equ 9FH ; Variable para el bucle de retardo.
PORTB equ 06H ; Dirección del Port B.
TRISB equ 86H ; Dirección del registro tri-estado del Port B.
PORTA equ 05H ; Dirección del Port A.
TRISA equ 85H ; Dirección del registro tri-estado del Port A.
STATUS equ 03H ; Registro para seleccionar el banco.
CONTADOR1 equ 0CH ; Registro para el bucle.
CONTADOR2 equ 0DH ; Registro para el bucle.
bsf STATUS,5 ; 1 ciclo, 0.5mS
movlw 00H ; 1 ciclo, 1.0mS
movwf TRISB ; 1 ciclo, 1.5mS
movlw 00H ; 1 ciclo, 2.0mS
movwf TRISA ; 1 ciclo, 2.5mS
bcf STATUS,5 ; 1 ciclo, 3.0mS
movlw 00H ; 1 ciclo, 3.5mS
movwf PORTA ; 1 ciclo, 4.0mS ; Comienzo del programa principal
CorreLuz
movlw 01H ; 1 ciclo, 4.5mS
movwf PORTB ; 1 ciclo, 5.0mS
call RETARDO ; 2 ciclos, 486mS
call RETARDO ; 2 ciclos, 967mS ; Mueve el bit por la izquierada del puerto B, después pausa.
rlf PORTB,1 ; 1 ciclo, 967.5mS
call RETARDO ; 2 ciclos, 1.45S
call RETARDO ; 2 ciclos, 1.93S
rlf PORTB,1 ; 1 ciclo, 1.93S
call RETARDO ; 2 ciclos, 2.41S
call RETARDO ; 2 ciclos, 2.89S
rlf PORTB,1 ; 1 ciclo, 2.89S
call RETARDO ; 2 ciclos, 3.37S
call RETARDO ; 2 ciclos, 3.85S
call RETARDO ; 2 ciclos, 4.34S
call RETARDO ; 2 ciclos, 4.82S
rlf PORTB,1 ; 1 ciclo, 4.82S
call RETARDO ; 2 ciclos, 5.30S
call RETARDO ; 2 ciclos, 5.78S
rlf PORTB,1 ; 1 ciclo, 5.78S
call RETARDO ; 2 ciclos, 6.26S
call RETARDO ; 2 ciclos, 6.74S
rlf PORTB,1 ; 1 ciclo, 6.74S
call RETARDO ; 2 ciclos, 7.22S
call RETARDO ; 2 ciclos, 7.70S
rlf PORTB,1 ; 1 ciclo, 7.70S ; Ahora mueve lo al puerto A, al bit de la izquierda.
rlf PORTA,1 ; 1 ciclo, 7.70S
call RETARDO ; 2 ciclos, 8.19S
call RETARDO ; 2 ciclos, 8.67S
rlf PORTA,1 ; 1 ciclo, 8.67S
call RETARDO ; 2 ciclos, 9.15S
call RETARDO ; 2 ciclos, 9.63S
rlf PORTA,1 ; 1 ciclo, 9.63S
call RETARDO ; 2 ciclos,10.11S
call RETARDO ; 2 ciclos,10.59S
rlf PORTA,1 ; 1 ciclo, 10.59S
call RETARDO ; 2 ciclos,11.07S
call RETARDO ; 2 ciclos,11.55S ; Mueve el bit de vuelta al puerto A.
rrf PORTA,1 ; 1 ciclo, 11.55S
call RETARDO ; 2 ciclos,12.04S
call RETARDO ; 2 ciclos,12.52S
rrf PORTA,1 ; 1 ciclo, 12.52S
call RETARDO ; 2 ciclos,12.99S
call RETARDO ; 2 ciclos,13.48S
rrf PORTA,1 ; 1 ciclo, 13.48S
call RETARDO ; 2 ciclos,13.96S
call RETARDO ; 2 ciclos,14.44S
rrf PORTA,1 ; 1 ciclo, 14.44S ; Ahora mueve el bit de vuelta al puerto B.
rrf PORTB,1 ; 1 ciclo, 14.44S
call RETARDO ; 2 ciclos,14.92S
call RETARDO ; 2 ciclos,15.40S
rrf PORTB,1 ; 1 ciclo, 15.40S
call RETARDO ; 2 ciclos,15.89S
call RETARDO ; 2 ciclos,16.37S
rrf PORTB,1 ; 1 ciclo, 16.37S
call RETARDO ; 2 ciclos,16.84S
call RETARDO ; 2 ciclos,17.33S
rrf PORTB,1 ; 1 ciclo, 17.33S
call RETARDO ; 2 ciclos,17.81S
call RETARDO ; 2 ciclos,18.29S
rrf PORTB,1 ; 1 ciclo, 18.29S
call RETARDO ; 2 ciclos,18.77S
call RETARDO ; 2 ciclos,19.25S
rrf PORTB,1 ; 1 ciclo, 19.25S
call RETARDO ; 2 ciclos,19.73S
call RETARDO ; 2 ciclos,20.22S
rrf PORTB,1 ; 1 ciclo, 20.22S
call RETARDO ; 2 ciclos,20.70S
call RETARDO ; 2 ciclos,21.18S ;
goto CorreLuz ; 2 ciclos,21.18S
; Subrutina para introducir un retardo entre los movimientos de los bits.
; Ciclos totales 957, 480mS
RETARDO
movlw TIEMPO ; 1 ciclo
movwf CONTADOR1 ; 1 ciclo
BUCLE1 ;
decfsz CONTADOR1 ; 9F x 1 ciclo + 1 ciclo = 160 ciclos
goto BUCLE1 ; 9E x 2 ciclos = 316 ciclos
movwf CONTADOR2 ; 1 ciclo
BUCLE2 ;
decfsz CONTADOR2 ; 9F x 1 ciclo + 1 ciclo = 256 ciclos
goto BUCLE2 ; 9E x 2 ciclos = 316 ciclos ;
return ; 2 ciclos
END ;
Con un reloj de 8KHz, tarda algo menos de 1 segundo en que el siguiente LED se ilumine, y tarda en total 21 segundos en ir de un extremo al otro y volver (es decir, lo que tarda le rutina en ejecutarse una vez solamente). El retardo de la subrutina es de 480ms, y la estamos llamando dos veces antes de mover el bit por los puertos. Ahora, tenemos que hacer el reinicio periódico del WDT. El mayor tiempo que podemos configurar para el WDT es de 2,3 segundos, y el siguiente en la tabla es de 1,1 segundos. Tenemos dos opciones. Podríamos hacer una llamada a la subrutina y reiniciar el WDT después de que los dos Retardos hayan terminado, o podríamos incorporar el CLRWDT dentro del retardo mismo. Hemos decidido, sin ninguna razón importante, poner el CLRWDT dentro de la subrutina de retardo. TIEMPO equ 9FH ; Variable para el bucle de retardo.
PORTB equ 06H ; Dirección del Port B.
TRISB equ 86H ; Dirección del registro tri-estado del Port B.
PORTA equ 05H ; Dirección del Port A.
TRISA equ 85H ; Dirección del registro tri-estado del Port A.
STATUS equ 03H ; Registro para seleccionar el banco.
CONTADOR1 equ 0CH ; Registro para el bucle.
CONTADOR2 equ 0DH ; Registro para el bucle.
OPT equ 81h ; Registro Option para controlar el WDT ;************* Configura los puertos, el WDT y el preescaler****************** clrf 01h ; Pone a cero el TMR0 bsf STATUS,5 ; Cambia al banco 1 clrwdt ; reinicia el WDT y el prescaler movlw b’1101’ ; Selecciona un nuevo valor para el prescaler y movwf OPT ; se lo asigna al WDT ; movlw 00H ; Ahora configura los puertos movwf TRISB ;
movlw 00H ;
movwf TRISA ;
bcf STATUS,5 ; Vuelve al banco 0 movlw 00H ;
movwf PORTA ;
;************* Comienzo del programa principal ***************************** CorreLuz movlw 01H ;
movwf PORTB ;
call RETARDO ;
call RETARDO ;
; Mueve el bit por la izquierada del puerto B, después pausa. rlf PORTB,1 ; call RETARDO ; call RETARDO ; rlf PORTB,1 ; call RETARDO ; call RETARDO ; rlf PORTB,1 ; call RETARDO ; call RETARDO ; rlf PORTB,1 ; call RETARDO ; call RETARDO ; rlf PORTB,1 ; call RETARDO ; call RETARDO ; rlf PORTB,1 ; call RETARDO ;
call RETARDO ;
rlf PORTB,1 ;
call RETARDO ;
call RETARDO ;
rlf PORTB,1 ;
; Ahora mueve lo al puerto A, al bit de la izquierda.
rlf PORTA,1 ; call RETARDO ; call RETARDO ; rlf PORTA,1 ; call RETARDO ; call RETARDO ; rlf PORTA,1 ; call RETARDO ; call RETARDO ; rlf PORTA,1 ; call RETARDO ; call RETARDO ;
; Mueve el bit de vuelta al puerto A. rrf PORTA,1 ; call RETARDO ; call RETARDO ; rrf PORTA,1 ; call RETARDO ; call RETARDO ; rrf PORTA,1 ; call RETARDO ; call RETARDO ; rrf PORTA,1 ;
; Ahora mueve el bit de vuelta al puerto B. rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; rrf PORTB,1 ; call RETARDO ; call RETARDO ; ; goto CorreLuz ;
; Subrutina para introducir un retardo entre los movimientos de los bits.
RETARDO
movlw TIEMPO ; 1 ciclo
movwf CONTADOR1 ; 1 ciclo
BUCLE1 ;
decfsz CONTADOR1 ; 9F x 1 ciclo + 1 ciclo = 160 ciclos
goto BUCLE1 ; 9E x 2 ciclos = 316 ciclos
movwf CONTADOR2 ; 1 ciclo
BUCLE2 ;
decfsz CONTADOR2 ; 9F x 1 ciclo + 1 ciclo = 256 ciclos
goto BUCLE2 ; 9E x 2 ciclos = 316 ciclos
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Esta parte reinicia el WDT ;;
;; Quita o comenta este comando para ver que hace el WDT. ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; clrwdt ; Esto simplemente reinicia el WDT. ; *************** Retorna desde nuestra rutina Retado*************** return ;
; END ;
Si comentas o quitas la instrucción CLRWDT, verás que el PIC no pasa de iluminar el segundo LED. Esto es debido a que el WDT hace que se reinicie el PIC. Con el
CLRWDT en su sitio, el programa funcionará como debe.
Referencias
MICROCHIP (http://www.microchip.com) ■
Microchip: El PIC 16F84 (Datasheet, Información adicional, etc...)
(http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010229) ■
Microchip: El PIC 16F84A (Datasheet, Información adicional, etc...)
(http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010230) ■
Microchip: Páginas de documentación sobre MPASM (http://www.microchip.com/stellent/idcplg?
IdcService=SS_GET_PAGE&nodeId=2123¶m=en022517) . ■
MPLAB IDE (Entorno Integrado de Desarrollo) (http://www.microchip.com/stellent/idcplg?
IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002) ■
MPASMWIN: Descarga de versión Windows (http://www.picbook.com/downloads.html) ■
Más Información: Lenguaje Ensamblador (en castellano). (http://perso.wanadoo.es/pictob/ensamblador.htm)
■
Obtenido de «http://wiki.webdearde.com/index.php?title=Tutorial:_Programaci%C3% B3n_de_PICs_en_Ensamblador&oldid=3694»
Categoría: Tutorial
Esta página fue modificada por última vez el 6 feb 2009, a las 19:32. ■
Esta página ha sido visitada 64.276 veces. ■