Mostrando entradas con la etiqueta Microcontroladores PIC. Mostrar todas las entradas
Mostrando entradas con la etiqueta Microcontroladores PIC. Mostrar todas las entradas

Leer botones e interruptores con microcontroladores PIC.


Los botones e interruptores son dispositivos que nos sirven para introducir datos a algun sistema eléctrico o electrónico. Leer botones (e interruptores) es una tarea muy sencilla, solamente hay que tener en cuenta que estos, al ser dispositivos mecanicos, no cierran (ni abren) instantaneamente sino que presentan un fenomeno conocido como rebote, que no es otra cosa mas que un ruido electrico que genera errores en al detectar que se presionó un botón y que hace que parezca que el botón se presiono muchas veces.

Teniendo en cuenta eso podemos programar algunas rutinas anti-rebotes con el pic. Dos maneras sencillas de lograrlo son: crear un ciclo para verificar el estado de un bit y no salir de este hasta que el estado sea estable; o verificar el estado de un bit, llamar a un retardo (de alrededor de 10ms, aunque este retardo depende del tipo de interruptor y no es un valor fijo) y despues volver a verificar el estado del bit, si el estado es el mismo entonces el boton se presiono.

Para el primer ejemplo vamos a utilizar el primer tipo de anti-rebote. Tenemos conectado un push-button al pin 0 del puerto A (RA0) y ocho leds al puerto B (RB0 a RB7). Para conectar el push-button se utiliza una resistencia de pull-up de 4.7k (es decir una resistencia de 4.7k conectada a Vcc), el push-button se conecta de un lado a la resistencia de pull-up y del otro a tierra de modo que el pic siempre estará leyendo un 1 lógico y al presionar el botón el estado cambiará a un 0 lógico. El programa consiste en llevar la cuenta de cuantas veces se ha presionado el botón, misma que se desplegará en el puerto B del pic, cada vez que se presione el botón la cuenta se incrementará. El codigo es el siguiente:

Código de programa  para leer botones e interruptores

Lo único nuevo aqui es la rutina que detecta que se presiona el botón y  la rutina que elimina el rebote. Para detectar que se presionó el botón se está revisando el estádo del pin 0 del puerto A con la instrucción btfsc, mientras el estado del pin sea 1 la ejecución del programa quedará ciclada en el mismo punto, una vez que el estado cambia a 0, es decir se presionó el botón, el programa salta a la rutina antirrebote. Esta rutina lo que hace es permanecer ciclada hasta que el estado del pin de nuevo sea 1, de este modo se eliminan los rebotes. Una vez que sale de la rutina antirrebotes incrementa la cuenta incrementando el puerto B y de nuevo regresa a checar el botón. Ésta es una imágen del circuito esquemático:

Esquemático para leer botones con microcontroladores PIC

Ahora veamos otro ejemplo, esta vez se conectarán 4 push-buttons en el nibble bajo del puerto B y 4 leds en el nibble alto de modo que al presionar un botón se encienda el led correspondiente. Para eso se configura el nibble bajo del puerto como entrada y el nibble alto como salida. Las rutinas de chequeo de botón y de antirrebotes ahora cambian ya que se tienen que revisar cuatro botones. El código del programa principal cambia de la siguiente manera:

Código de programa para checar botones en el PIC

El programa va checando botón a botón para saber cual se presionó, una vez que detecta que uno fue presionado llama a la rutina antirrebotes, luego llama a la rutina que enciende el led correspondiente y al regresar continua checando los botones. El circuito esquemático es el siguiente:

Diagrama para checar botones en microcontroladores

Estos dos ejemplos tambien servirían si se usan interruptores en lugar de botones, utilizando el mismo código o efectuando alguna pequeña modificación, sobre todo en la rutina antirrebotes. Para el otro tipo de antirrebotes, en el que se utiliza un retardo, se eliminaria la rutina incluida en estos dos ejemplos ya que al momento de detectar el cambio de estado lógico se debe llamar a una rutina de retardo (como ya se dijo de aproximadamente 10ms) y después volver a comprobar el estádo, si sigue siendo el mismo entonces el botón fue presionado, si no es el mismo entonces la detección fue erronea y no se toma en cuenta.

Por ahora es todo, en proximas entradas hablaré sobre las interrupciones del pic, comenzando por las interrupciones externas del puerto B. Por el momento el código de estos dos ejemplos no se puede descargar, espero solucionar ese problema pronto.


Displays de 7 segmentos.


Un display de 7 segmentos no es otra cosa que 7 leds conectados entre si con su ánodo o su cátodo en común. Dependiendo del tipo de display será la manera en que se enciendan sus segmentos, un display de cátodo común requiere un 1 logico para encender mientras que uno de cátodo común un 0 así que dependiendo del display que se utilice cambiará la rutina encargada de controlarlo, pero en cualquier caso al momento de cambiar el tipo de display solo debemos cambiar los ceros por unos y viceversa.

Aqui supondremos que se usa un display de cátodo común así que los segmentos encenderán con un 1. El display estará conectado al puerto B, el segmento A estará conectado al bit RB0, el B al RB1, el C al RB2, el D al RB3 y así sucesivamente hasta llegar al G que estará conectado al bit RB6.

Encender y apagar los segmentos del display es igual que encender y apagar leds, podríamos hacerlo de la misma manera que en el tutorial 1, pero una manera mas eficaz de controlar un display es mdiante una tabla. Haremos que el display muestre los números 0 a 15 en hexadecimal (0 a F) con un retardo de medio segundo entre cada número. Para eso se declara el puerto B como salida. Una vez hecho eso se crea la rutina encargada de mandar llamar el numero correspondiente de una tabla y de desplegar el numero correspondiente por el puerto B. El programa principal es el siguiente:

Control de display de 7 segmentos con microcontrolador pic
Y ese es basicamente el programa. Al principio se declaran 4 variables, una se utiliza para llevar la cuenta del numero a desplegar y las demas sirven para la rutina de retardo. Como ya se dijo se configura el puerto B como salida y despues se limpia la variable Numero (clrf NUMERO). Despues el programa entra en una subrutina que se encarga de leer la tabla y de desplegar el numero en el puerto. Primero se mueve el valor de la variable Numero al registro W (movf NUMERO,w) y despues se manda llamar la tabla (call DESPLIEGA), al volver el registro W tiene el valor del numero a desplegar y simplementa se mueve al puerto B (movwf PORTB). Se llama a la rutina de retardo (call RETARDO) y al volver de esta se incrementa el valor de la variable Numero (incf NUMERO,f) y despues se transfiere ese valor al registro W (movf NUMERO,w). Esto se hace para realizar una comparacion entre W y la literal 0x10 (16 en valor decimal) para saber si la variable Numero ya fue incrementada 16 veces, si es asi se salta la siguiente instruccion y el programa se repite desde la etiqueta Principal, si no es asi el programa regresa a la etiqueta Ciclo. De este modo el numero se incrementa de 0 a F y al llegar a F regresa a 0. La comparacion se realiza mediante la instruccion sublw 0x10 si el resultado es cero (en caso de que NUMERO=16) la bandera ZERO se pone en 1 y es esa la bandera que se revisa en btfss STATUS,Z.

Como ya se dijo antes de llamar la rutina que lee la tabla se carga el valor de la variable Numero en W, esto se hace asi ya que al entrar a la rutina se realiza una suma entre W y el contador de programa PCL para montarlo en un offset, asi el contador apuntara a la direccion que seguia mas el valor de la variable Numero. Asi la rutina de la table queda de la siguiente manera:

Enviando números al display
Y asi, de este modo se decodifica un display de 7 segmentos. La rutina de retardo se omitio en la explicacion ya que los retardos se explicaron anteriormente, de cualquier forma se incluye en el codigo del programa. Descargar codigo.

Como nota final: Las imagenes que contienen el codigo en esta ocasion se ven algo distintas que en los tutoriales pasados, ese descuadre se debe a que el codigo se escribio utilizando MPLAB bajo linux, pero en realidad se conservan los mismos espacios y tabulaciones que en ocasiones anteriores, eso se puede ver al descargar el codigo completo.


Conjunto de instrucciones para los microcontroladores PIC.


Como ya hemos visto, para que el microcontrolador lleve acabo una tarea, debemos indicarle exactamente que debe hacer, o en otras palabras, debemos escribir el programa que el micro ejecutara. Ya hemos visto varios ejemplos y muchas de las instrucciones del pic, pero ahora veremos las 35 instrucciones del ensamblador mpasm. Estas 35 instrucciones son las mismas para toda la gama media de los microcontroladores pic asi que si mas adelante se quiere realizar un programa para un pic 16F877 se usaran las mismas instrucciones.

Antes de continuar es necesario definir algunos terminos que se usaran para explicar las instrucciones:
f: cualquier registro del microcontrolador
W: registro de trabajo
b: posicion de un bit en el registro 'f'
d: destino, puede ser 'f' (d=1) o 'W' (d=0)
etiqueta: grupo de caracteres que marcan el inicio de una parte del programa
[]: opcional
: posicion de un bit dentro de un registro

Instrucciones orientadas a registros

ADDWF: Suma W y f
Suma el contenido del registro 'W' y el registro 'f'. Si "d" es 0, el resultado se almacena en el registro W. Si 'd' es 1 el resutado se almacena en el registro 'f'.
Sintaxis: [etiqueta] ADDWF f,d
Operación: (W) + (f) --> (destino)
Flags afectados: C, DC, Z
Ejemplo: ADDWF REG,1
Antes de la instrucción: W=0x03, REG=0x04
Después de la instrucción: W=0x03, REG=0x07

ANDWF: W AND f
Realiza la operación lógica AND entre el registro W y el registro "f". Si "d" es 0 el resultado se almacena en el registro W. Si "d" es 1, el resultado se almacena en el registro "f".
Sintaxis: [etiqueta] ANDWF f,d
Operación: (W) AND (f) --> (destino)
Flags afectados: Z
Ejemplo: ANDWF REG,1
Antes de la instrucción: W=0x17, REG= 0xC2
Después de la instrucción: W=0x17, REG= 0x02

CLRF: Borra un registro
Borra el contenido del registro 'f' y se activa el flag Z.
Sintaxis: [etiqueta] CLRF f
Flags afectados: Z
Ejemplo: CLRF REG
Antes de la instrucción: REG=0x54
Después de la instrucción: REG=0x00, Z=1

CLRW: Borra el registro de trabajo W
Borra el contenido del registro 'W' y se activa el flag Z. Esta instruccion no tiene operandos.
Sintaxis: [etiqueta] CLRW
Flags afectados: Z
Ejemplo: CLRW
Antes de la instrucción: W=0x54
Después de la instrucción: W=0x00, Z=1

COMF: Complementa el registro f
El contenido del registro 'f' se complementa. Si d=0 el resultado se almacena en el registro W. Si d=1 el resultado se almacena en el registro 'f'.
Sintaxis: [etiqueta] COMF f,d
Flags afectados: Z
Ejemplo: COMF REG,0
Antes de la instruccion: REG=0x13
Después de la instrucción: REG=0x13, W=0xEC

DECF: Decrementa f en 1
De decrementa en uno el contenido del registro 'f'. Si d=0, el resultado se almacena en W. Si d=1, el resultado se almacena en 'f'.
Sintaxis: [etiqueta] DECF f,d
Flags afectados: Z
Ejemplo: DEC CONT, 1
Antes de la instrucción: CONT=0x01, Z=0
Después de la instrucción: CONT=0x00, Z=1

DECFSZ: Decrementa en 1 y salta si el resultado es 0
El contenido del registro 'f' se decrementa. Si 'd=0, el resultado se coloca en el registro W. Si d=1, el resultado se coloca en el registro 'f'. Si el resultado es 0, se salta la siguiente instrucción y se continúa con la ejecución.
Sintaxis: [etiqueta] DECFSZ f,d
Flags afectados: Ninguno

INCF: Incrementa el registro f
Incrementa en uno el contenido del registro 'f'. Si d=0, el resultado se almacena en W. Si d=1, el resultado se almacena en 'f'.
Sintaxis: [label] INCF f,d
Flags afectados: Z
Ejemplo: INCF CONT,1
Antes de la instrucción: CONT=0xFF, Z=0
Después de la instrucción: CONT=0x00, Z=1

INCFSZ: Incrementa en 1 y salta si el resultado es 0
El contenido del registro 'f' se incrementa. Si d=0, el resultado se coloca en el registro W. Si d=1, el resultado se coloca en el registro 'f'. Si el resultado es 0, se salta la siguiente instrucción y se continúa con la ejecución.
Sintaxis: [etiqueta] DECFSZ f,d
Flags afectados: Ninguno

IORWF: W OR f
Realiza la operación lógica OR entre el registro W y el registro 'f'. Si d=0 el resultado se almacena en el registro W. Si d=1, el resultado se almacen en el registro 'f'.
Sintaxis: [etiqueta] IORWF f,d
Flags afectados: Z
Ejemplo: IORWF REG,0
Antes de la instrucción: REG=0x13, W=0x91
Después de la instrucción: REG=0x13, W=0x93

MOVF: Mover el registro f
El contenido del registro 'f' se mueve al destino 'd'. Si d=0, el destino es el registro W. Si d=1, el destino es el propio registro 'f'.
Sintaxis: [etiqueta] MOVF f,d
Flags afectados: Z
Ejemplo: MOVF REG,0
Después de la instrucción: W=REG

RLF: Rota el registro f a la izquierda
El contenido del registro 'f' se rota una posición a la izquierda. El bit de más peso pasa al carry y el carry se introduce por el bit de menos peso de 'f'. Si d=0, el resultado se coloca en el registro W. Si d=1, el resultado queda en el registro 'f'.
Sintaxis: [etiqueta] RLF f,d
Flags afectados: C
Ejemplo: RLF REG,1
Antes de la instrucción: REG=b'11100110', C=0
Después de la instrucción: REG=b'11001100', C=1

RRF: Rota el registro f a la derecha
El contenido del registro 'f' se rota una posición a la derecha. El bit de menos peso pasa al carry y el carry se introduce por el bit de más peso de 'f'. Si d=0, el resultado se coloca en el registro W. Si d=1, el resultado queda en el registro 'f'.
Sintaxis: [etiqueta] RLF f,d
Flags afectados: C
Ejemplo: RLF REG,1
Antes de la instrucción: REG=b'11100110', C=0
Después de la instrucción: REG=b'01110011', C=0

SUBWF: Resta f - W
Resta el contenido del registro 'f' menos el contenido del registro W. Si d=0, el resultado se almacena en el registro W. Si d=1, el resultado se almacena en el registro 'f'.
Sintaxis: [etiqueta] SUBWF f,d
Flags afectados: C, DC, Z
Ejemplo: SUBWF REG,1
Antes de la instrucción: REG=0x01, W=0x02
Después de la instrucción: REG=0xFF, W=0x02

SWAPF: Intercambio de f
El nibble bajo del registro 'f' se intercambia con el nibble alto del mismo. Si d=0, el resultado se coloca en el registro W. Si d=1, el resultado queda en el registro 'f'.
Sintaxis: [etiqueta] SWAPF f,d
Flags afectados: Ninguno
Ejemplo: SWAPF REG,1
Antes de la instrucción: REG=0x54
Después de la instrucción: REG=0x45

XORWF: W XOR f
Realiza la función lógica OR exclusiva entre el contenido del registro W y el registro 'f'. Si d=0, el resultado se almacena en el registro W. Si d=1 el resultado se almacena en el registro 'f'.
Sintaxis: [etiqueta] XORWF f,d
Flags afectados: Z
Ejemplo: XORWF REG,1
Antes de la instrucción: REG=0xAF, W=0xB5
Después de la instrucción: REG=0x1A, W=0xB5

NOP: No operacion
No realiza ninguna operacion, solo consume un ciclo de reloj
Sintaxis: [etiqueta] NOP

Instrucciones orientadas a bits

BCF: Borra un bit
Borra el bit 'b'del registro 'f'
Sintaxis: [etiqueta] BCF f,b
Ejemplo: BCF REG,0
Antes de la instrucción: REG=b'01101101'
Después de la instrucción: REG=b'01101100'

BSF: Activa un bit
Activa el bit 'b' del registro 'f'
Sintaxis: [etiqueta] BSF f,b
Ejemplo: BSF REG,2
Antes de la instrucción: REG=b'01001001'
Después de la instrucción: REG=b'01001011'

BTFSC: Checa un bit y salta si es 0
Si el bit "b" del registro "f" es 0, se salta una instrucción y se continúa con la ejecución.
Sintaxis: [etiqueta] BTFSC f,b

BTFSS: Checa un bit y salta si es 1
Si el bit "b" del registro "f" es 1, se salta una instrucción y se continúa con la ejecución.
Sintaxis: [etiqueta] BTFSS f,b

Instrucciones orientadas a constantes y de control

ANDLW: W AND literal
Realiza la operación lógica AND entre el registro W y la constante "k". El resultado se almacena en el registro W.
Sintaxis: [label] ANDWL k
Flags afectados: Z
Ejemplo: ANDLW 0x5F
Antes de la instrucción: W=0xA3
Después de la instrucción: W=0x03

CALL: Llamada a subrutina
Llamada y salto a subrutina. La dirección de retorno se guarda en el stack. La constante "k" de 8 bits forma la dirección de salto y se carga en los bits del PC. Los bits del PC se cargan con los bits del registro "STATUS". PC se pone a 0.
Sintaxis: [etiqueta] CALL k
Ejemplo: INICIO CALL DESTINO
Antes de la instrucción: PC=INICIO
Después de la instrucción: PC=DESTINO

CLRWDT: Borra el watchdog timer
Esta instrucción borra tanto el "watchdog" como el prescaler. Los bits TO y PD del registro de estado se ponen a "1".
Sintaxis: [label] CLRWDT
Flags afectados: TO, PD

GOTO: Salto incondicional
Se trata de un salto incondicional. Los 9 bits de la constante "k" que forman la instrucción, se cargan en los bits del PC y forman la dirección de salto. Los bits del PC se cargan con los bits del registro de estado.
Sintaxis: [etiqueta] GOTO k
Ejemplo: INICIO GOTO DESTINO
Antes de la instrucción: PC=0
Después de la instrucción: PC=DESTINO

IORLW: W OR literal
Se realiza la función lógica OR entre el registro W y la contante "k". El resultado se almacena en el registro W.
Sintaxis: [etiqueta] IORLW k
Flags afectados: Z
Ejemplo: IORLW Ox35
Antes de la instrucción: W=0x9A
Después de la instrucción: W=0xBF

MOVLW: Carga un literal en W
El registro W se carga con el valor de 8 bits expresado mediante la literal "k".
Sintaxis: [etiqueta] MOVLW k
Ejemplo: MOVLW 0x5A
Después de la instrucción: W=0x5A

RETURN: Regresa de una subrutina
El programa regresa de la subrutina y ejecuta la instruccion que sigue a CALL
Sintaxis: [etiqueta] RETURN

RETLW: Regresa de una subrutina y carga el valor K en W
El programa regresa de la subrutina y carga el valor de 8 bits del registro k en el registro W
Sintaxis: [etiqueta] RETLW,k
Ejemplo: RETLW,0x45
Antes de la instruccion: W=xx
Despues de la instruccion: W=0x45

RETFIE: Regresa de la rutina de servicio
Sintaxis: [etiqueta] RETFIE

SLEEP: Entra en estado de reposo
Al salir, activa el bit de estado TO y borra el PD. El WDT y el prescaler se borran.Al entrar en el modo SLEEP, se detiene el oscilador.
Sintaxis: [etiqueta] SLEEP
Flags afectados: TO, PD, GPWUF

XORLW: W XOR literal
Realiza la función lógica OR exclusiva entre el contenido del registro W y la constante "k" de 8 bits. El resultado se almacena en el registro W.
Sintaxis: [etiqueta] XORLW k
Flags afectados: Z
Ejemplo: XORLW 0xAF
Antes de la instrucción: W = 0xB5
Después de la instrucción: W = 0x1A

SUBLW: Resta L - W
A una constante "k" de 8 bits se le resta el registro W. El resultado es guardado en el mismo registro W.
Sintaxis: [etiqueta] SUBLW k
Flags afectados: C,DC,Z

MOVWF: Mover el valor del registro W al registro f
El contenido del registro ‘W’ se mueve al registro ‘f’.
Sintaxis: [etiqueta] MOVWF f
Flags afectados: Ninguno
Ejemplo: MOVWF REG
Antes de la instrucción: REG=0x03, W=0xA4
Después de la instrucción: REG=0xA4, W=0xA4

Y estas son las 35 instrucciones que podemos utilizar para programar los microcontroladores PIC. La razon para que solo se utilicen 35 instrucciones en la programacion es que los PIC son microcontroladores RISC, y estas instrucciones estan bien optimizadas para tener una mayor velocidad de trabajo, una arquitectura mas simple y un codigo mas compacto.


Retardos por software en los microcontroladores PIC.


La semana pasada, en la segunda parte del tutorial 1, se habló un poco sobre los retardos por software. Ahora vamos a ver esto de la lógica de los retardos un poco más a fondo para poder crear nuestras propias subrutinas.

Como ya se dijo el pic 16F628A tiene un oscilador interno de 4MHz, si utilizamos ese oscilador tenemos que todas las instrucciones se ejecutan en 1uS, exceptuando los saltos que tardan 2 ciclos, es decir 2uS. Tomando en cuenta eso vamos a generar nuestros retardos, pero siempre partiendo de la suposición de que se esta trabajando a una frecuencia de 4MHz, si es así, crear rutinas de retardo para nuestro pic es muy sencillo.

Supongamos que tenemos la siguiente rutina:

Ejemplo de retardo por software en los microcontroladores PIC

A la derecha de cada instrucción aparece el número de ciclos que tomará cada una. Las primeras dos toman solamente 1 ciclo, la tecera decfsz toma (N-1)+2, porque decrementará N-1 veces la variable N y en el último decremento hará un salto, es por eso el +2. La instrucción goto se ejecuta en 2 ciclos y se ejecutará N-1 veces, es por eso que se toma como 2*(N-1). De esta forma tenemos que el número de ciclos, y por lo tanto el tiempo que tendremos de retardo está dado por la siguiente expresión: 1+1+(1)(N-1)+2+(2)(N-1) , ó 4+N-1+2N-2, o lo que es lo mismo 3N+1. Si queremos un retardo de 100uS entonces tenemos que 3N+1=100, despejando tenemos N=(100-1)/3=33, asi que para tener un retardo de 100uS el valor de la variable N debe ser 33. Ahora veamos esta rutina:

Retardo por software

Podemos darnos cuenta que ahora nuestra rutina original (desde CICLO2 hasta goto CICLO) está afectada por la variable M, así que es como si M multiplicara a nuestro retardo. Para saber el nuevo valor del retardo de nuevo sumamos todos los ciclos, tomando en cuenta que M multiplica al retardo original de modo que la expresión ahora queda de la siguiente manera: [3N+1]M+1+1+(1)(M-1)+2+(2)(M-1), o lo que es lo mismo [3N+1]M+3M+1, de manera que tenemos dos retardos anidados. Para saber cuanto sería el retardo total primero calculamos el retardo básico, si queremos que ese retardo sea de 100uS entonces N=33, si ahora queremos que el retardo total sea de 10mS entonces ocupamos completar 10000 ciclos, así que igualamos nuestra expresión a ese número: [(3*33)+1]M+3M+1=10000, despejando tenemos M=(9999)/103, esto es aproximadamente igual a 97, así que para un retardo de 10mS nuestra variable N debe valer 33 y la variable M debe tener un valor de 97.

Así podemos seguir anidando retardos. Para obtener un retardo de 1 segundo utilizaremos la siguiente rutina:

Retardo por software en el PIC 16F628A

Aqui vemos que la variable P afecta a los dos retardos que ya habíamos definido de modo que la expresión para calcular el nuevo retardo total seria [(3N+1)M+3M+1 ]P+1+1+(1)(P-1)+2+(2)(P-1), y reduciendo terminos la expresion seria [(3N+1)M+3M+1]P+3P+1. Queremos un retardo de 1 segundo, esto son 1000000 ciclos, por lo que nuestra expresión del retardo debe ser igual a un millón: [(3N+1)M+3M+1 ]P+3P+1=1000000. Sustituyendo N y M tenemos 9995P+1=1000000, entonces tenemos que P=(999999)/9995 y P entonces es aproximadamente igual a 100.

Esta no es la forma más precisa de realizar retardos, utilizando los valores para las variables N, M y P que calculamos tenemos que al final del retardo solamente se realizaron 999501 ciclos, en tiempo esto es aproximadamente igual a 0.99 segundos pero no el segundo completo, sin embargo para aplicaciones que no necesitan una gran precisión  este metodo funciona, y funciona muy bien!


Tutorial 1 - LED's (tercera parte).


Los ejemplos anteriores ponian en alto o en bajo todos los pines del puerto B del PIC. Para terminar con este tutorial ahora veremos como modificar el estado de un solo pin y así encender o apagar cualquiera de los ocho leds conectados al puerto B. Vamos a ver cuatro formas distintas de hacer esto y así vamos a introducir algunas instrucciones nuevas.

Lo que se va a hacer en estos ejemplos es recorrer un "1" por el puerto B de tal modo que solamente uno de los 8 leds encienda a la vez. El programa utilizado cuando se habló del entorno de desarrollo MPLAB encendía un led utilizando la instrucción bsf, el siguiente ejemplo también utilizará esa instrucción.

Tutorial 1.3 - Encendiendo un led con bsf

bsf sirve para poner en alto el estádo lógido de un bit. En el siguiente ejemplo se utiliza para  encender los leds conectados al puerto B, para apagarlos se utiliza la instrucción bcf que sirve para poner en bajo un bit. La configuración del puerto es la misma que la de los ejemplos anteriores. Lo único distinto es la rutina que enciende y apaga los leds. La rutina la podemos ver en la siguiente imágen.

Utilizando la instrucción BSF

Vemos que lo primero que se hace es limpiar el puerto B con la instrucción clrf, después se pone en alto el bit 7 del puerto B con bsf, se llama a una rutina de retardo y al vovler de esta se pone en bajo el mismo bit con la instrucción bcf, luego se pone en alto el siguiente bit (en este caso el bit 6), se llama a la rutina de retardo y así el programa continúa hasta llegar al bit 0, luego con el goto se vuelve al inicio de la rutina (goto Ciclo). Este programa es muy sencillo y nos sirve para practicar las instrucciónes bsf y bcf. Descargar código.

Tutorial 1.4 -  Encendiendo un led usando movlw y movwf

En las primeras dos partes de este tutorial se utilizaron las instrucciones movlw y movwf para encender y apagar todos los leds conectados al puerto B. Ahora se utilizarán para realizar exactamente la misma tarea que el tutorial 1.3. El resultado se puede ver que es muy parecido.

Utilizando las instrucciones MOVLW y MOVWF

En esta ocasión los leds se encienden a través de la instrucción movwf, después de cargar el registro W con el bit que se desea poner en alto. Descargar código.

Tutorial 1.5 - Recorriendo los bits con rrf

Los dos programas anteriores funcionan sin ningún problema, sin embargo hay otra forma de hacer la misma función con menos código, utilizando la instrucción rrf. Esta instrucción rota a la derecha el contenido de un registro a través del carry. Para rotar a la derecha el puerto B primero se carga el número binario b'10000000' para así encender el led RB7. La instruccion rrf se encargará de rotar el bit desde el 7 hasta el 0 y al final pondrá en alto la bandera de carry, es entonces cuando el programa vuelve a comenzar.

Utilizando la instrucción RRF

Como se ve, el código utilizando rrf es mucho más pequeño y de esta manera el programa final es más ligero y elegante. Descargar código.

En estos tres ejemplos los bits que encienden los leds se recorren desde el bit 7 hasta el 0, o  lo que es lo mismo hacia la derecha. Ese orden se puede cambiar fácilmente. En el primer ejemplo basta con modificar los bits de las instrucciones bsf y bcf, en el segundo se cambia el patrón de los números binarios y en el tercero se logra utilizando la instruccion rlf que tiene el mismo funcionamiento que rrf pero rotando los bits hacia la izquierda.


Tutorial 1 – LED’s (segunda parte)


Tutorial 1.2 - Encendiendo y apagando LED’s... ahora con retardo!

Como ya dijimos hay algo que no funciona bien en el programa anterior. Cada instrucción ocupa 1 ciclo de reloj para ejecutarse. Como utilizamos el reloj interno del 16F628A cada instrucción se ejecuta en (1/4MHZ)*4 o lo que es lo mismo 1uS. El programa ejecuta 5 instrucciones mientras los leds estan encendidos y otras 5 mientras están apagados, asi que encienden 5uS y apagan otros 5uS. Al ver el ejemplo en funcionamiento veremos que los leds nunca se apagan, ¿cómo hacemos para que esto se alcance a ver? La respuesta: utilizando un retardo al encender los leds y otro al apagarlos.

El principio del retardo es contar descendentemente desde un número dado y al momento de que la cuenta llega a cero dejar de contar. El cero indica el fin del retardo y una vez concluido puede continuar la ejecución del programa.

Lo primero es definir una constante que usaremos como contador, llamemosla CUENTA. Es importante aclarar que al momento de definir la constante con la directiva equ lo que hacemos es declarar la dirección del registro que usaremos como CUENTA. Esto es que si declaramos CUENTA equ 0x20 no significa que cuenta vaya a valer 0x20, sino que en esa dirección estará ese registro. Después podremos cargarle a CUENTA cualquier valor que querramos, por ejemplo MOVLW 0xFF y después MOVWF CUENTA, así nuestro registro CUENTA, en la dirección 0x20, tendrá un valor de 255 decimal.

El PIC 16F628A cuenta con algunos registros de propósito general que podemos utilizar directamente en nuestros programas para guardar los datos que estamso usando. Estos registros empiezan desde la dirección 0x20 del banco 0, es por eso que CUENTA la definimos en esa dirección. Cada vez que definamos una constante o una variable debemos definirla después de la dirección 0x20 ya que de otro modo el programa no va a funcionar.

Habiendo declarado la constante CUENTA y después de cargar ese registro con un valor podemos realizar la rutina de retardo. Para eso decrementamos CUENTA por 1 hasta que el valor llegue a 0. De esto se encarga la instrucción decfsz. Su sintaxis es decfsz f,d donde f es el registro que queremos decrementar y d es el destino en el que guardamos el resultado, si d=0 el resultado se guarda en el registro W, si d=1 el resultado se guarda en el mismo registro f. decfsz CUENTA,1 decrementa el valor de CUENTA en 1  y guarda el resultado en el mismo registro CUENTA. Para asegurarnos de que decfsz se ejecute hasta que el registro llegue a 0 utilizamos la instrucción goto para estar volviendo hasta que la cuenta termine.

Entonces el nuevo código queda de la siguiente manera (descargar código):

Código en ensamblador de microcontroladores PIC y LED's

Ahora las únicas instrucciones nuevas son call y return. call se utiliza para mandar llamar una rutina, en este caso la rutina de retardo. Utilizar rutinas hacen que el código sea más pequeño y entendible. call Retardo genera que la ejecución del programa salte hacia la subrutina con la etiqueta Retardo, se ejecuta el código de la subrutina y después la instrucción return se encarga de regresar la ejecución del programa a la línea que seguía de la instrucción call. Así funcionan las subrutinas.

Este tutorial sirve para explicar un poco la lógica de los retardos, sin embargo calcular retardos de esta manera puede ser un poco complicado, lo bueno es que existen algunos generadores de retardo a los que solo se les especifica el reloj que se utiliza y el tiempo que se desea de retardo y con esa información se genera el código necesario para el retardo. Un gerador muy bueno es este: Delay Code Generator.


Tutorial 1 - LED's.


En el tutorial de MPLAB ya vimos un pequeño ejemplo de un programa que encendía un led, ahora vamos a empezar con el primer tutorial de microcontroladores pic. Vamos a hacer algo sencillo, encender y apagar leds. Así, vamos a empezar por lo más básico para ir aprendiendo las instrucciones del micro y ver mas a detalle el funcionamiento del PIC.

Tutorial 1.1 - Encendiendo y apagando LED's

Ya vimos como encender un led, ahora veamos también como apagarlo. Este programa lo que hace es encender ocho leds conectados al puerto B del micro y después apagarlos. El código es el siguiente (descargar código):


Las primeras líneas son directivas al ensamblador. LIST p=16F628a define el micro que se utilizará, radix hex define la raíz numérica por defecto, en este caso será hexadecimal, esto significa que cualquier número que se escriba en el código y no se especifíque que raíz tiene será tomado como hexadecimal. En ensamblador los números se pueden representar en forma decimal, hexadecimal y binaria de la siguiente manera:

  • decimal: .14
  • hexadecimal: 0x0E ó 0Eh
  • binario: b'00001110'
En el código la raíz definida es hexadecimal, si quisieramos que fuera decimal tendriamos que escribir dec, para binaria bin y para octal oct. Después de la definición de la raíz está la directiva __config que se utiliza para definir la configuración del microcontrolador. La palabra de configuración 0x3D18 define que se utilizará el reloj interno del micro, se deshabilitará el watchdog, así como el reset y la protección de código. Más adelante se hablará más a detalle sobre la configuración del pic.

Después se declaran algunas constantes, para esto se utiliza la directiva equ. La sintaxis de la directiva es <nombre_de_la_constante> equ <valor> y lo que hace esta directiva es que cada vez que en el código se escriba la constante definida se tome el valor de constante, por ejemplo "RP0 equ 5", cada vez que en el código aparezca RP0 el valor que se tomará será 0x05.

Después viene el programa principal. Es muy importante comenzar el programa siempre con la  directiva org en la dirección 0x00 ya que esta directiva define la dirección en la que se comenzará a escribir el código. Al momento de encender el micro o al hacer un reset lo primero que el microcontrolador hace es leer la dirección 0x00, si no hay nada en esa dirección lo más probable es que el micro se cicle. Otra cosa importante que debemos tomar en cuenta es que la memoria de programa del PIC 16F628A comienza en la dirección 0x05, es por eso que debemos poner también un org 0x05 para que el código comienze a escribirse a partir de esa dirección.

Ahora si, veamos que instrucciones tenemos. Al inicio, después de org 0x00 tenemos un goto Inicio, goto hace es un salto incondicional hacia la dirección que se le indique, en este caso la dirección es la etiqueta Inicio. bsf se utiliza para cambiar el estado lógico de un bit de un registro a un nivel alto, la sintáxis es bsf f,b donde f es el registro y b el bit que se quiere cambiar (bsf STATUS,RP0), lo que hace esa línea es seleccionar el banco de memoria 1, el micro tiene 4 bancos de memoria y en esos 4 bancos estan repartidos todos los registros (en realidad la mayoria estan repartidos en 2 bancos, los 2 ultimos sirven de espejo a los 2 primeros. En el banco 0 se encuentra el registro STATUS y dentro de ese registro están los bits de selección de banco. Debemos cambiar al banco 1 ya que ahí se encuentra el registro de configuración del puerto B (TRISB) que dependiendo de la configuración que tenga hará que el puerto B se comporte como entrada o como salida. Una vez en el banco 1 configuramos el puerto B como salida, de eso se encarga clrf, esta instrucción borra el contenido de un registro, al estar en el banco 1 clrf PORTB hace que todos los bits del registro TRISB se pongan en un nivel bajo, configurando así el puerto B como salida. Después regresamos de nuevo al banco 0 con bcf STATUS,RP0. bcf realiza la acción contraria de bsf, pone a 0 un bit del registro específicado. Con eso termina la configuración del puerto B.

De las demás instrucciones la única "desconocida" es nop, esta instrucción sólo sirve para consumir un ciclo de instruccion ya que su definición es no realizar ninguna operación. Los nop en el código estan para que las salidas en el puerto B creen una señal cuadrada. Lo que hace la ultima parte del código es primero cargar 0xFF al registro W, luego pasar ese valor al puerto B para poner las salidas en alto, luego limpia el puerto B para tener la salida en bajo y el ultimo goto hace que el ciclo se esté repitiendo y repitiendo.

Al implementar este ejemplo vemos que los leds no encienden y apagan sino que se quedan encendidos y no cambian nunca de estado. Esto no es del todo cierto. Encienden y apagan pero tan rápido que no nos damos cuenta. De eso trata la segunda parte del tutorial.


Tutorial de MPLAB.


MPLAB es una herramienta para escribir y desarrollar código en lenguaje ensamblador para los microcontroladores PIC. MPLAB incorpora todas las herramientas necesarias para la realización de cualquier proyecto, ya que además de un editor de textos cuenta con un simulador en el que se puede ejecutar el código paso a paso para ver así su evolución y el estado en el que se encuentran sus registros en cada momento.

MPLAB es un software gratuito que se encuentra disponible en la página de Microchip, la versión actual (al momento de escribir estas palabras) es la 7.51 y será la versión utilizada en esta guía y en todos los ejemplos de esta página.

Empecemos por el principio. Lo primero es descargar e instalar el programa, para eso solamente se debe seguir el siguiente enlace: Descargar MPLAB 7.51; una vez hecho eso proceder a instalarlo cómo cualquier programa, con todas las opciones que vengan por defecto, también se puede hacer una instalación personalizada pero eso no lo explicaré aqui ya que por el momento no es importante. Al finalizar la instalación ejecutamos el recién instalado MPLAB y tendremos una pantalla como esta:

Proyecto en MPLAB

Una vez instalado podremos comenzar a trabajar, para eso crearemos un nuevo proyecto utilizando el Wizard de MPLAB que se encuentra en el menú Project -> Project Wizard, al hacerlo aparecerá la siguiente pantalla.

project1.jpg

Hacemos click en Siguiente, luego se mostrará una ventana donde debemos escoger el PIC que se vaya a usar, en la lista que aparece seleccionamos PIC16F628A y damos click en Siguiente.

Escogiendo el PIC

El siguiente paso es definir el programa de lenguaje que será usado. En nuestro caso el lenguaje es Ensamblador así que seleccionamos la opción mostrada en la siguiente imágen y de nuevo hacemos click en Siguiente.

Definiendo el lenguaje en MPLAB

En la siguiente ventana tenemos que darle un nombre al proyecto y escoger el directorio en el que se guardará. Es recomendable que la ruta de la carpeta donde se guarda el proyecto no sea muy larga ya que al compilarlo MPLAB marca un error, es por eso que en el ejemplo la ruta escogida se encuentra cerca de la raiz del disco duro, así que recomiendo crear una carpeta directamente en el disco "C:\" o en cualquiera que se use, pero que sea en la raiz del disco. Para este caso la ruta escogida fue C:\micropic\Proyecto1\ pero sientan la libertad de escoger cualquier otro nombre para la carpeta.

Escoger un nombre de proyecto

Una vez dado el nombre al proyecto al hacer click en Siguiente se abrirá una nueva ventana que nos pedirá agregar archivos existentes al proyecto, como aún no hemos escrito ningún archivo simplemente damos click en Siguiente y para terminar en la última ventana hacemos click en Finalizar.

project5.jpg

Ya que creamos el proyecto y habiendo dado click a Finalizar en la ventana anterior debemos ver la ventana del MPLAB más o menos con este aspecto.

project6.jpg

Y ahora si empieza lo bueno, una vez creado el proyecto es hora de crear un archivo y empezar a escribir el código. Lo que hacemos es crear un nuevo archivo y guardarlo con extensión .asm en la carpeta donde tenemos nuestro proyecto, para crear un archivo damos click en File -> New, después y antes de escribir en el archivo hacemos click en File -> Save As. En la ventana que se abra le damos un nombre a nuestro archivo y nos aseguramos de que el tipo de archivo seleccionado sea ensamblador.

Guardar el proyecto

Ahora el archivo creado tiene extensión .asm, pero para el proyecto eso no nos sirve, tenemos que agregar el archivo al proyecto y después comenzar a trabajar en el así que en la ventana del proyecto hacemos click derecho en Source Files y después seleccionamos Add File.

Agregando archivos

Posteriormente se abrirá una ventana donde debemos seleccionar el archivo que queremos agregar al proyecto. Por defecto se abrirá la carpeta del proyecto que acabamos de crear así que seleccionamos el archivo (en este caso led.asm) y hacemos click en Abrir. Hecho eso la ventana del proyecto debe verse asi:

Abrir archivo

Ahora si podemos escribir nuestro código en el archivo led.asm y todos los cambios que hagamos en este se verán reflejados en nuestro proyecto. Escribamos un código sencillo. Un programa que solamente encienda un led conectado al pin 17 del microcontrolador, lo que sería el bit 0 del puerto A. El código sería el siguiente:

led, ejemplo de código en ensamblador

Al final incluiré un enlace para descargar el código en formato PDF que fácilmente se puede copiar y pegar en MPLAB.

Una vez escrito el código podemos compilar el programa, con esto se genera el archivo.hex con el que podremos grabar el PIC. Para compilar el programa podemos usar el menú Project - Build All o usar la combinación Ctrl + F10. El archivo HEX generado se encuentra en el mismo directorio que el proyecto y lleva el mismo nombre que el archivo con el código, en este caso sería led.hex.

Con esto cubrimos la parte de crear un proyecto y realizar un programa en MPLAB, más adelante veremos cómo simular los proyectos utilizando el simulador MPLAB SIM y también como grabar el programa en el PIC utilizando programas como IC-PROG y WinPIC800.

Descargar código fuente: Proyecto 1 - led.asm (PDF)


El lenguaje ensamblador.


El ensamblador que utiliza MPLAB por defecto y el que utilizaremos para programar los PIC es MPASM. Los elementos básicos del lenguaje ensamblador son:
  • Etiquetas
  • Instrucciones
  • Operandos
  • Directivas
  • Comentarios
Para la programación se utiliza una cierta tabulación que se debe respetar, además utilizar una tabulación adecuada hace los programas más claros y legibles. Las etiquetas se escriben en la primer columna de cualquier línea, las instrucciones y directivas en la segunda y por último, en la tercer columna, los operandos. Los comentarios se pueden escribir en cualquier parte del programa.

Etiquetas

Una etiqueta es una palabra utilizada para designar alguna línea o sección del programa, se pueden utilizar para saltar de una parte hacia esa etiqueta. Es importante que las etiquetas empiecen con una letra o con un guión bajo "_". La longitud de una etiqueta puede ser de hasta 32 caracteres y como ya se dijo se deben escribir en la primer colúmna.

Instrucciones

Las instrucciones son las operaciones que realiza el microcontrolador, así que estas ya estan definidas para cada familia de PIC. El 16F628a así como todos los PICs de gama media utiliza un conjunto de 35 instrucciones que están definidas en la hoja de datos del PIC.

Operandos

Son los elementos que emplea la instrucción que se está ejecutando. Usualmente los operandos son los registros, las variables o las constantes.

Directivas

Las directivas son similares a las instrucciones, pero a diferencia de estas las directivas son propias del lenguaje ensamblador e independientes del microcontrolador que se utilice. Las directivas representan algunas  características del lenguaje ensamblador, se utilizan para especificar el procesador empleado así como la configuración de este, también para asignar locaciones de memoria, entre otras cosas.

Comentarios

Los comentarios son las palabras, frases y oraciones que se pueden escribir en el código para hacer el programa más claro y legible, o solo para recordar el momento =P. Los comentarios se pueden escribir en cualquier parte del código pero siempre deben empezar con punto y coma ";".

Un programa de prueba

El siguiente ejemplo es un programa simple escrito en ensamblador donde se muestran los elementos básicos del lenguaje:

Estructura de código en ensamblador

Este ejemplo se escribió usando MPLAB, se puede ver que MPLAB reconoce la sintaxis del lenguaje ensamblador y utiliza diferentes colores para los diferentes elementos del código. Las directivas se muestran en azul, las instrucciones en azul y en negritas, los comentarios son mostrados en verde y por ultimo las etiquetas y los operandos se muestran en color lila.

La primer directiva "list" sirve para especificar el PIC seleccionado, en este caso fue el 16F628a. La directiva "include" se utiliza para incluir un archivo externo en el programa. Con la directiva "__config" se establece la configuración del PIC, el tipo de reloj usado, la configuración del watchdog, el reset interno, etc. "org" define la dirección de memoria a partir de la cual el programa se guarda y "end" es la directiva que marca el final del programa, esta directiva es muy importante y nunca debe faltar en el código, además todo lo que se escriba después de esa directiva directamente será ignorado.

Este es un programa muy simple, comienza con la directiva "org" , después la instrucción goto dirige el flujo del programa hacia la etiqueta "Inicio". El siguiente paso es seleccionar el banco de memoria 1 (bsf STATUS,RPO) para poder configurar el puerto B como salida (clrf PORTB), después volvemos al banco de memoria 0 (bcf STATUS,RPO) y por último ponemos todos los pines del puerto B a "1"(movlw 0xFF, movwf PORTB) y con eso el programa prácticamente está finalizado. Se incluye la etiqueta "Ciclo" y la última instruccion goto para que el programa se quede ciclado en ese punto (goto Ciclo). Al final se incluye la directiva "end" que es necesaria para que el programa ensamblador sepa que no hay más instrucciones que interpretar.

Este programa puede servir de toma de contacto en esto de la programación en ensamblador, más adelante se verán las instrucciones y directivas con mayor detalle.


58 programas en C para microcontroladores PIC.


Para aprender a programar microcontroladores en algún lenguaje de programación necesitaremos, además de una buena guía, un conjunto de programas que nos permita a través del análisis del mismo, entender mejor las características y funciones de nuestro microcontrolador.

Es así como, dándome a la tarea de buscar algunos programas escritos en C para los microcontroladores PIC de Microchip (utilizando el compilador PCW de CCS), me tope con una grandiosa colección de 58 programas escritos por Vszener de foros todopic. Una serie de programas que aunque, escritos para el 16F648A, son fácilmente implementables en otros modelos de PIC. Además, podremos descargar los archivos de código y de simulación en Isis Proteus para cada uno de ellos (previa registración en el foro).

A continuación, algunos de los programas que encontrarás:
- Parpadeo de un LED cada medio segundo.
- Contador ascendente de 0 a 9.
- Dado digital.
- Escribir y leer EEPROM interna del PIC.
- LCD y teclado matricial.

¿Que más se puede pedir para comenzar a programar microcontroladores PIC en C?

Ir a: 58 programas en C para el compilador PCW de CCS.

Programas sencillos para el microcontrolador PIC16F877A.



En esta ocasión te presentaremos dos sencillos programas escritos en ensamblador para el PIC16F877A. El primero de ellos enciende y apaga un LED conectado al pin RA0 del microcontrolador; mientras que el segundo, prende secuencialmente los LEDs que han sido conectados al puerto B del mismo.

Además, aprenderemos a simular nuestro microcontrolador en Isis Proteus e implementaremos físicamente nuestro PIC en el protoboard.

- Para esta práctica utilizaremos un programador de PICs, que seguramente encontrarás en tu centro educativo.
- Usaremos el compilador gratuito de Microchip “MPLAB IDE” para escribir nuestro programa en ensamblador y obtener el archivo .HEX (utilizado por el programador para grabar el micro). Descargar MPLAB IDE.
- Aunque los PICs son resistentes a la estática, debemos tener cuidado de no tocar sus pines.

ENCENDIDO DE UN LED.
El siguiente código nos permitirá encender y apagar un LED conectado al pin RA0 del PIC.

__CONFIG _WDT_OFF&_PWRTE_ON&_XT_OSC&_LVP_OFF&_CP_OFF ; Configuración para 
el programador

LIST p=16F877A
INCLUDE <P16F877A.INC>

ORG 0x00 ;Inicio de programa

N EQU 0x00
cont1 EQU 0x20
cont2 EQU 0x21

BCF STATUS,RP0 ; Accede a banco 0
BCF STATUS,RP1 
CLRF PORTA ; Limpia PORTA
BSF STATUS,RP0 ; Accede a banco 1
CLRF TRISA ; Configura todos las patitas de PORTA como salidas
BCF STATUS,RP0 ; Regresa a banco 0

Encled 
BSF PORTA,0 ; La línea RA0 de PORTA toma el valor de 1, se enciende el LED
CALL Retardo ; Llamada a la rutina de retardo
BCF PORTA,0 ; La línea RA0 de PORTA toma el valor de 0, se apaga el LED
CALL Retardo ; Llamada a la rutina de retardo 
GOTO Encled ; Va a la etiqueta Encled

Retardo ; Rutina de retardo
MOVLW N 
MOVWF cont1
Rep1
MOVLW N
MOVWF cont2 
Rep2
DECFSZ cont2,1
GOTO Rep2 
DECFSZ cont1,1 
GOTO Rep1
RETURN ; Retorno a la llamada de rutina de retardo.

END ; Fin de programa

Y aquí, nuestro circuito implementado en el protoboard simplificado.
Para esta práctica hemos utilizado una resistencia (R1) de 10 Kilo Ohms, un cristal (XTAL) de 4 MHz y una resistencia (R2) de 200 a 300 Ohms para limitar la corriente que llegara a nuestro LED.

ENCENDIDO SECUENCIAL DE LEDs.
Este código nos permitirá encender secuencialmente los LEDs conectados al puerto B del micro, en un ciclo infinito de RB0 a RB7.

__CONFIG _WDT_OFF&_PWRTE_ON&_XT_OSC&_LVP_OFF&_CP_OFF ; Configuración para 
el programador

LIST p=16F877A
INCLUDE <P16F877A.INC>

ORG 0x00 ; Inicio de programa

N EQU 0x00
cont1 EQU 0x20
cont2 EQU 0x21

BCF STATUS,RP0 ; Accede a banco 0
BCF STATUS,RP1 
CLRF PORTB ; Limpia PORTB
BSF STATUS,RP0 ; Accede a banco 1
CLRF TRISB ; Configura todas las patitas de PORTB como salidas
BCF STATUS,RP0 ; Regresa a banco 0

BSF PORTB,0 ; La línea RA0 de PORTB toma el valor 1, se enciende el LED
Encledsec
CALL Retardo ; Llamada a la rutina de retardo
RLF PORTB,1 ; Recorre el bit de RB0 a RB7
GOTO Encledsec ; Va a la etiqueta Encledsec

Retardo ; Rutina de retardo
MOVLW N 
MOVWF cont1
Rep1
MOVLW N
MOVWF cont2 
Rep2
DECFSZ cont2,1
GOTO Rep2 
DECFSZ cont1,1 
GOTO Rep1
RETURN ; Retorno a la llamada de rutina de retardo.

END ; Fin de programa

Y aquí, su correspondiente implementación en el protoboard.
Para esta práctica hemos utilizado una resistencia (R1) de 10 Kilo Ohms, un cristal (XTAL) de 4 MHz, y 7 LEDs.

Es muy importante que entre la salida de los pines del microcontrolador y sus respectivos LEDs, coloquemos una resistencia de aproximadamente 200 Ohms, para evitar averías en nuestro microcontrolador.

IMPLEMENTACIÓN EN PROTEUS.

Seguramente te querrás asegurar de que tu programa funcione correctamente antes de ir a grabar tu PIC en la programadora y darte cuenta de que al implementar físicamente tu circuito, este no hace nada. Para probar el correcto funcionamiento de nuestro circuito existen programas como Isis Proteus que nos permiten simular una gran variedad de microcontroladores de una manera rápida y sencilla.

Para simular nuestros micros en ISIS:

1.- Escoger el modelo de nuestro microcontrolador y colocarlo en el espacio de trabajo.

2.- Hacer doble click sobre él, con lo que nos aparecerá la siguiente ventana:

En ella, simplemente hacemos click sobre la imagen de la carpetita (ubicada en la opción Program File) para buscar y cargar el archivo .HEX.

3.- Y listo, finalmente simularemos el microcontrolador para comprobar que nuestro circuito funcione perfectamente bien.

PARA QUE NUESTRO PIC FUNCIONE FÍSICAMENTE.
Nuestro código parece estar bien, nuestra simulación funciona perfectamente, pero ¡Oh Sorpresa!, a la hora de implementarlo en el protoboard nuestro proyecto no funciona. Aquí una serie de medidas a tomar en cuenta si nuestro microcontrolador PIC16F877A no hace nada.

1. Alimentar correctamente nuestro PIC.
Debemos asegurarnos de que nuestro micro este bien alimentado. Para ello veamos el diagrama de pines del microcontrolador,
En él, podremos apreciar que existen 4 pines marcados con los símbolos VDD y VSS, estas son las patillas de alimentación, donde VDD va conectado a voltaje y VSS a (masa) ó a tierra. Para alimentar a nuestro PIC solo debemos conectar dos de las cuatro patillas, una VDD y una VSS.

2. Realizar las siguientes conexiones.
El pin 1 del microcontrolador (MCLR/VPP) debe estar conectado a voltaje por medio de un resistor de 10 Kilo Ohms.

Además, conectaremos dos capacitores (C1 y C2) junto al oscilador de cristal (XTAL) como lo vemos en la siguiente imagen.
Los valores de los capacitores varían de acuerdo al tipo de oscilador utilizado (LP, XT, HS), en la siguiente tabla podemos ver estos valores.
En nuestras prácticas no hemos utilizado estos capacitores, ya que sin ellos funcionan bien.

3. Configurar correctamente los bits o fusibles de configuración.
Es decir, debemos asegurarnos de activar los bits correctos de acuerdo a las necesidades del proyecto. En muchas de las prácticas solo debemos escoger el tipo de cristal, así que deshabilitaremos todas las demás opciones de configuración. Para estas prácticas hemos utilizado el oscilador de cristal tipo XT.

Más información sobre osciladores.
Más información sobre fusibles de configuración.

Descargar pack1 _ encendido de un LED (Archivo .asm + archivo .hex + simulación en Proteus).
Descargar pack2 _ encendido secuencial de LEDs (Archivo .asm + archivo .hex + simulación en Proteus).

Descargar MPLAB IDE.
Descargar hoja de datos del PIC16F87XA (en inglés).


Iniciando con microcontroladores PIC.



En este post publicaremos documentos y enlaces a sitios en los que encontrarás información clara y detallada para iniciar a programar PICs en los lenguajes ensamblador, Basic y C.

ARCHIVOS PDF.
Descripción detallada del PIC16F877: Aprende a programar en lenguaje ensamblador el microcontrolador PIC16F877, realizando los numerosos y detallados ejemplos presentados en este gran documento.

PÁGINAS Y BLOGS.
Picmicrocontroller877: En este blog encontrarás una clase de minicurso para el microcontrolador PIC16F877A programado en ensamblador. Utilizando un solo ejemplo aprenderás de forma gradual muchas de las funciones del micro, cada una de las prácticas cuenta con su respectivo archivo .asm, .hex, esquemático de la práctica y vídeo.

Monaseza electronic’s: En este blog encontrarás una serie de interesantes proyectos realizados en ensamblador ó Basic, utilizando el microcontrolador PIC16F877A. Cada proyecto tiene su respectiva simulación en Isis Proteus y su código .asm.

Algunos de los proyectos que encontraras en este sitio son:

- Sensor de temperatura con LM35 y PIC16F877 programado en ensamblador.
- LCD + Teclado + PIC16F877
- RS-232: Suma de dos números.
- Secuencia de encendido de LEDs.
- Y algunos proyectos más e información bastante interesante.

Si tienes alguna recomendación de blogs o materiales útiles sobre microcontroladores PIC puedes compartirlo en los comentarios de este post.


Manual para el compilador PCW de CCS.



Escrito por Andrés Cánovas López y reeditado por Víctor Dorado, este manual de referencias para el compilador PCW de CSS nos permite comprender mejor el código utilizado en el lenguaje C enfocado a PICs, y aunque la ayuda del compilador sea mejor, la ventaja de este documento es que esta escrito en español.

Descargar manual.

Librería PIC 16F628a (y todas las demás) para Eagle.

En esta ocasión les traigo la librería para los pics 16f627, 16f627a, 16f628, 16f628a y 16f648a para EAGLE Layout Editor. Al igual que las librerías anteriores esta es una primera versión que solamente incluye el encapsulado PDIP de 18 pines, en futuras acutalizaciones incluiré los demás encapsulados.

También anuncio que todas las librerías que vaya creando estarán disponibles en la página http://thestardestroyer.googlepages.com/libreriaseagle.html así que aunque seguiré publicandolas en este blog no dejen de visitar aquella página para ver las nuevas actualizaciones de las librerías. Hasta pronto.

Descargar: pic16f6xx-v0.1.lbr

Librería 16F87/88 para Eagle Layout Editor.


Ayer publiqué la librería para microcontroladores pic 16F88x, ahora hago lo mismo para los pic 16F87 y 16F88 para poder utilizarlos en Eagle Layout Editor. Esta es la versión 0.1 y solamente se encuentra el paquete DIP y SOIC de 18 pines pero posteriormente la actualizaré para incluir SSOP y QFN.

Sin más por el momento aqui dejo la librería
Descargar: pic16f88-v0.1.lbr

Librería 16F88x para Eagle Layout Editor.


El Eagle Layout Editor es un programa muy potente para crear diagramas esquemáticos y circuitos impresos de manera sencilla. Su uso está muy extendido por lo que no resulta difícil encontrar entre sus librerías el componente que se necesita en un circuito, sin embargo hay casos que aquel componente que se ocupa no se encuentra en ninguna librería como pueden ser algunos microcontroladores PIC.

Ultimamente he dejado este blog abandonado, la razón es que he estado ocupado desarrollando un proyecto utilizando un pic 16F886, la programación ya quedó lista y ahora pretendía realizar el circuito impreso cuando me di cuenta que dentro de las librerías del Eagle no se encontraba ese pic. CadSoft cuenta con una página donde se pueden descargar librerías para su programa, además buscando en google se pueden encontrar muchas más pero no me fue posible encontrar una que incluyera el pic que necesitaba por lo que decidí crear la librería yo mismo.

Crear componentes y librerías para Eagle es muy sencillo, al principio puede ser algo tedioso pero con un poco de práctica las cosas se hacen más rápido. Para crear la librería seguí el tutorial Eagle Library Design y el resultado fue la librería pic16f88x-v0.1.lbr.

Comparto este archivo para que cualquiera que necesite crear un circuito en Eagle utilizando los pics 16F882, 16F883, 16F884, 16F886 y 16F887 lo pueda hacer sin problemas, esta es la primer versión y espero mejorarla en un futuro así como también crear librerías para otros microcontroladores PIC. Como es la primer versión es posible que exista algún error así que si alguien detecta uno por favor hagamelo saber.

Aquí dejo esta librería, lo pueden tomar como un regalo atrasado de navidad o uno adelantado de reyes pero como sea espero que les sea de utilidad.

Descargar: pic16f88x-v0.1.lbr

Instalar Piklab en Ubuntu 7.04.


Por mucho, el post más popular de este blog es en el que explico la instalación y uso de MPLAB. Sin duda porque es un entorno de desarrollo muy potente que permite escribir, ensamblar, simular y programar los pics, todo desde el mismo programa. En linux no existe una herramienta tan poderosa, es por eso que muchos instalan MPLAB en este sistema operativo.

Una buena alternativa a MPLAB en linux puede ser Piklab, un entorno de desarrollo para microcontroladores pic que se integra con muchos compiladores y ensambladores y con un simulador llamado GPSim, y que además permite programar los pics con los programadores más comunes.

Piklab está programado para el entorno de escritorio KDE, por lo que para instalarlo en una distribución como Ubuntu (basada en GNOME) es necesario tener las librerías de KDE y QT instaladas. Esto se hace fácilmente mediante apt-get escribiendo en una terminal:
  • sudo apt-get install xlibs-dev kdebase-dev
Además de esas librerías es necesario tener instaladas dos librerías más, de modo que de nuevo en una terminal se escribe:
  • sudo apt-get install libusb-dev libreadline5-dev
Después de eso ya podemos instalar Piklab, pero primero lo debemos descargar de la siguiente dirección
http://piklab.sourceforge.net/download.php
Para Ubuntu no existe un binario para instalarlo (como si es el caso de otras distribuciones como Slackware) así que tendremos que descargar las fuentes y compilar el programa. Para eso hacemos click en Download Piklab y después descargamos el paquete *.tar.bz2

Una vez descargado lo descomprimimos. Se puede descomprimir usando el gestor de archivos comprimidos o descomprimiendolo desde la terminal, yo prefiero la segunda opción, así que en la terminal nos vamos al directorio donde se haya descargado el archivo y lo descomprimimos:
  • tar -xvf piklab-*.tar.bz2
  • cd piklab*
Una vez dentro del directorio con los archivos fuente procedemos a compilar el programa. Eso es algo muy sencillo aunque dependiendo del tipo de máquina puede ser más o menos lento, y simplemente se utilizan 3 comandos: configure, make y make install, de la siguiente manera:
  • ./configure
  • make
  • sudo make install
Una vez hecho eso Piklab está instalado y casi listo para usarse, solamente falta instalar unas herramientas que nos permitan ensamblar y compilar nuestros archivos en ensamblador desde Piklab, estas herramientas son GPUTILS y se encuentran disponibles en los repositorios de Ubuntu así que fácilmente se instalan vía apt-get:
  • sudo apt-get install gputils
Y listo, ahora si podemos iniciar Piklab (desde el menú Aplicaciones -> Programación -> Piklab o ejecutando el comando piklab). Por último una captura de este entorno de desarrollo.


Esta guía en parte está basada en el tutorial Instalando Piklab en Ubuntu de Cosas de Mecatrónica.


El PIC 16F628.


Para comenzar a programar microcontroladores PIC, el PIC que se utilizará (es decir, el que utilizaré en este sitio) será el 16F628 (16F628a), que como ya se mencionó anteriormente presenta algunas ventajas que lo hacen superior (desde el punto de vista de un principiante) a otros PIC.

Antes que otra cosa es necesario ver algo de "teoría" sobre el PIC, sin embargo aquí solamente mencionaré las características principales, para información más detallada es recomendable consultar la hoja de datos proporcionada por Microchip.

El PIC 16F628 incorpora tres características importantes que son:
  • Procesador tipo RISC (Procesador con un Conjunto Reducido de Instrucciones)
  • Procesador segmentado
  • Arquitectura HARVARD
Con estos recursos el PIC es capaz de ejecutar instrucciones solamente en un ciclo de instrucción. Con la estructura segmentada se pueden realizar simultáneamente las dos fases en que se descompone cada instrucción, ejecución de la instrucción y busqueda de la siguiente.
La separación de los dos tipos de memoria son los pilares de la arquitectura Harvard, esto permite acceder en forma simultánea e independiente a la memoria de datos y a la de instrucciones. El tener memorias separadas permite que cada una tenga el ancho y tamaño más adecuado. Así en el PIC 16F628 el ancho de los datos es de un byte, mientras que la de las instrucciones es de 14 bits.

Características principales
  • Conjunto reducido de instrucciones (RISC). Sólamente 35 instrucciones que aprender a utilizar
  • Oscilador interno de 4MHz
  • Las instrucciones se ejecutan en un sólo ciclo de máquina excepto los saltos (goto y call), que requieren 2 ciclos. Aquí hay que especificar que un ciclo de máquina se lleva 4 ciclos de reloj, si se utiliza el reloj interno de 4MHz, los ciclos de máquina se realizarán con una frecuencia de 1MHz, es decir que cada instrucción se ejecutará en 1uS (microsegundo)
  • Opera con una frecuencia de reloj de hasta 20 MHz (ciclo de máquina de 200 ns)
  • Memoria de programa: 2048 locaciones de 14 bits
  • Memoria de datos: Memoria RAM de 224 bytes (8 bits por registro)
  • Memoria EEPROM: 128 bytes (8 bits por registro)
  • Stack de 8 niveles
  • 16 Terminales de I/O que soportan corrientes de hasta 25 mA
  • 3 Temporizadores
  • Módulos de comunicación serie, comparadores, PWM
Otra característica de los PICs es el manejo de los bancos de registros. En línea general, los registros se clasifican como de uso general (GPR) y de uso específico o de funciones especiales (SFR).
  • Los registros de uso general pueden ser usados directamente por el usuario, sin existir restricciones. Pueden servir para almacenar resultados que se reciben desde el registro W (acumulador), datos que provienen de las puertas de entradas, etc.
  • Los registros de uso específicos no pueden ser usados directamente por el usuario. Estos registros controlan prácticamente todo el funcionamiento del microcontrolador, pues toda la configuración necesaria para funcionamiento del microcontrolador es hecho a través de algún tipo de SFR.
Pines de I/O (Entrada/Salida)

Diagrama de pines del PIC16F628

PORTA: RA0-RA7:
  • Los pines RA0-RA4 y RA6–RA7 son bidireccionales y manejan señales TTL
  • El pin RA5 es una entrada Schmitt Trigger que sirve también para entrar en el modo de programación cuando se aplica una tensión igual a Vpp (13,4V mínimo)
  • El terminal RA4 puede configurarse como reloj de entrada para el contador TMR0
  • Los pines RA0-RA3 sirven de entrada para el comparador analógico
PORTB: RB0-RB7:
  • Los pines RB0-RB7 son bidireccionales y manejan señales TTL
  • Por software se pueden activar las resistencias de pull-up internas, que evitan el uso de resistencias externas en caso de que los terminales se utilicen como entrada (permite, en algunos casos, reducir el número de componentes externos)
  • El pin RB0 se puede utilizar como entrada de pulsos para provocar una interrupción externa
  • Los pines RB4-RB7 están diseñados para detectar una interrupción por cambio de estado. Esta interrupción puede utilizarse para controlar un teclado matricial, por poner un ejemplo
Otros pines
  • VDD: Pin de alimentación positiva. De 2 a 5,5 Vcc
  • VSS: Pin de alimentación negativa. Se conecta a tierra o a 0 Vcc
  • MCLR: Master Clear (Reset). Si el nivel lógico de este terminal es bajo (0 Vcc), el microcontrolador permanece inactivo. Este Reset se controla mediante la palabra de configuración del PIC
  • OSC1/CLKIN: Entrada de oscilador externo
  • OSC2/CLKOUT: Salida del oscilador. El PIC 16F628 dependiendo de cómo se configure puede proporcionar una salida de reloj por medio de este pin
En la próxima entrega se dará una introducción al ambiente de desarrollo MPLAB y se realizará el primer programa. También se verá el conjunto de instrucciones del PIC y las directivas del ensamblador MPASM.

Para más información consultar las hojas de datos de Microchip: 16F628 y 16F628A


Comenzando con los PICs


Los PICs son microcontroladores RISC con una arquitectura harvard modificada fabricados por Microchip Technology Inc. Son dispositivos extremadamente versátiles. Se pueden usar en aplicaciones que van desde hacer parpadear algunos leds o controlar un robot simple hasta proyectos más complejos como un tarificador telefónico, un osciloscopio, un servidor web y prácticamente cualquier proyecto que se pueda imaginar.

El lenguaje de los PICs

Los microcontroladores PIC para su programación utilizan un número de instrucciones reducido (RISC) que varía de 35 instrucciones para la gama baja hasta alrededor de 70 para la gama alta. Este conjunto de instrucciones incluye instrucciones para realizar una variedad de operaciones entre el acumulador y una constante o entre el acumulador y una locación de memoria, así como para ejecución condicional de código, llamadas y saltos a otras rutinas y partes del programa. Para su programación Microchip proporciona un ambiente de desarrollo gratuito llamado MPLAB IDE que además incluye un simulador y un ensamblador.

Además de lenguaje ensamblador los PICs se pueden programar utilizando lenguajes de alto nivel como C y Basic, además es posible programarlos usando Pascal, Jal y Forth. En MicroPIC el lenguaje utilizado será ensamblador en un principio y posteriormente se dará el salto a Basic y C. El IDE utilizado también será MPLAB.

Elegir un PIC

¿Entonces, con qué PIC empezar? Para mí la respuesta es sencilla: 16F628a. Hace algunos años la opción obvia era el pic 16F84, un pic económico y fácil de encontrar que lo convertía en la elección de cualquier aficionado. El 16F628a se puede considerar como una actualización del 16F84, maneja el mismo conjunto de instrucciones y es compatible pin a pin con este pero tiene las ventajas de ser más barato, tiene el doble de memoria de programa, mucha más memoria RAM, 3 pines de I/O más (16 mientras que el 16F84 tiene solamente 13), un módulo USART (puerto serie) y algunas virtudes más, entre ellas un oscilador integrado de 4MHz lo que hace su uso aún más sencillo.

Además del 16F628 otros PICs que merecen la pena son el 16F877 y el 18F452. El 16F877 tiene los mismos periféricos que el 628 y algúnos más (entre ellos un convertidor analógico-digital), además cuenta con mayor capacidad de memoria de programa, más memoria RAM y muchos más pines I/O. El 18F452 forma parte de la nueva serie de microcontroladores PIC de 16-bit, ofrece un conjunto de instrucciones mejorado, mejores periféricos, el doble de memoria y una velocidad de trabajo hasta 2 veces mayor que un 16F877 a un precio no mucho mayor. Sin embargo el 16F628 tiene la ventaja de contar con un oscilador interno, razón por la cual será el PIC utilizado en la mayoría de los ejemplos y tutoriales.

Elegir un programador

Esta puede ser una cuestión complicada ya que existe una cantidad muy grande de programadores disponibles, unos con ventajas sobre otros, pero eso es algo que depende de cada usuario. Microchip comercializa una serie de programadores que se pueden utilizar directamente con MPLAB, algunos de estos programadores son: PICStart Plus, Promate II, MPLAB PM3, ICD2, PICKit 1 y PICKit 2, los primeros 2 con interfaz serial y los últimos 4 con interfaz USB. Además de los programadores de Microchip también existen otros programadores comerciales como el PIC-PG2 (serial), el PIC-PG3 (paralelo), o el PIC-MPC (USB) de Olimex.

No solo existen opciones comerciales, Olimex por ejemplo proporciona gratis los esquemas de  sus programadores. En internet es posible encontrar diagramas para distintos tipos de programadores, algunos con interfaz serial, otros utilizando el puerto paralelo, en los foros de solocódigo.com hay un tema sobre Programadores Para Microcontroladores Pic que vale la pena revisar. Personalmente yo recomiendo estos tres programadores, todos con interfaz serial:
  • Feng's RCD, programador sencillo que programa el 16F628 y el 16F628a
  • Feng's Multi PIC programmer, multiprogramador, funciona con todos los pics que he probado
  • PIC-PG2, al igual que el multiprogramador de Feng este funciona con extensa lista de PICs
Para programar los PICs hace falta algo más que el programador, también se ocupa un software compatible con ese programador. Dos programas muy buenos para dicha tarea son el IC Prog y el WinPic800.

¿Cómo comenzar?

Después de toda esta introducción la pregunta es ¿cómo comenzar? Bueno, eso en la próxima entrega ;-)