Construye tu propio metrónomo

Un metrónomo es un instrumento que permite indicar el compás de las composiciones musicales mediante alguna señal acústica o visual. Si has tocado algún instrumento musical, como la guitarra o el piano, probablemente conoces la importancia que tienen estos aparatitos. Tú puedes construir tu propio metrónomo mediante este sencillo esquema electrónico:

esquema proyecto electrónico metrónomo
circuito metrónomo protoboard

circuito metrónomo protoboard

Los materiales que se utilizan se consiguen fácilmente y son muy económicos, aquí está la lista completa:

1 CI 555
3 resistencias de 1 K Ohm
2 capacitores de 22 uF 16 V
2 leds
1 batería de 9 Volts
1 parlante de 8 Ohms
1 Potenciómetro de 250 k Ohms

Y finalmente aquí está el video del circuito en funcionamiento:


Visto en: Daniel Andrade.

Introducción al lenguaje ensamblador - parte 2


A continuación  veremos la segunda parte de un gran curso sobre el lenguaje ensamblador (puedes checar la primera parte aquí), escrito por el técnico en electrónica César Antonio Saldías Caro, de Valparaíso, Chile. Puedes encontrar más información en su blog ingenieropic.wordpress.com.

Este curso incluye una carpeta con el código fuente compilado del programa que analizaremos.


Programa de ejemplo
Probablemente, el encendido y apagado de un LED es lo primero que todos intentan conseguir cuando se inician en la programación en Assembler, por esa razón decidí comenzar la segunda parte de mi curso explicando precisamente un programa que realice tal acción.

Comencemos:

ejemplo programa ensamblador 1

La primera línea se utiliza simplemente para indicarle al programa el modelo de PIC que vamos a utilizar.

La segunda línea es para agregar a nuestro programa la librería del PIC 16F628A que contiene datos de direccionamiento para que no tengamos que escribirlos manualmente.

*Entiéndase por librería como un programa escrito previamente, el cuál agregamos a nuestros programas para que sean más manejables. Podríamos decir entonces que cualquier programa que escribamos podría ser denominado librería si lo agregáramos a otro programa a futuro.

ejemplo programa ensamblador 1.1

En esta línea estamos configurando los fusibles. Esto fue explicado en la sección de “directivas”.

ejemplo programa ensamblador 1.2

Con esta línea le estamos indicando al programa que ignore los posibles errores cuando almacene en banco. Cuando compilamos, a veces aparecen mensajes que dice “Warning” o “Message” advirtiendo de posibles errores en nuestro programa, cada uno de estos errores tiene un número (este número aparece junto al mensaje). El aviso 302 es el que indica que un registro puede haber sido configurado en un banco equivocado. Al escribir “errorlevel -302” estamos diciéndole al programa que ignore ese posible error.

ejemplo programa ensamblador 1.3

Los registros o variables que se usarán se declaran entre estos dos reglones, el 0X20 indica que usaremos los espacios disponibles para registros a partir de la posición 0x20 de la memoria.

*Para mayor información puedes ver la sección “Memory Map” en la datasheet del PIC.

Las variables que utilizaremos se declararán entre estos dos reglones, pero eso lo haremos más adelante.
ejemplo programa ensamblador 1.4

La línea org 0x0 (origen 0) es el Vector de Reset, lo cual quiere decir que siempre que se resetee, o se encienda el PIC, el programa se comenzará a ejecutar a partir de esta posición.

El goto es una instrucción que se utiliza para saltar a una parte específica de nuestro programa, en este caso le decimos que vaya a la etiqueta “reg”, que obviamente puede tener cualquier otro nombre.

Como ya deberás saber, el PIC 16F628A tiene cuatro bancos, en cada uno de ellos hay registros, y en cada registro hay 2 Nibbles, que es lo mismo que 8 bits.

*Nibble: Conjunto de 4 bits.

Para moverse de un banco a otro debemos utilizar el registro STATUS. En este registro tenemos RP0 y RP1, los cuales deben tener un 0 o un 1 para poder posicionarnos en un determinado banco. La siguiente tabla (extraída de la datasheet) muestra la configuración que debe tener RP0 y RP1 para moverse a un determinado banco:
cuadro acceso bancos registros PIC16F628A

Vale decir que para movernos al banco 0, debemos poner en 0 el RP0 y el RP1, y para movernos por ejemplo al banco 3 debemos poner en 1 el RP1 y en 0 el RP0.

Teniendo esto en cuenta, analicemos las siguientes líneas.

ejemplo programa ensamblador

BCF es la instrucción para poner un 0 y BSF es para poner un 1. Lo dije de una manera poco técnica pero se entiende la idea.

Entonces, necesitamos configurar los registros TRIS ubicados en el banco 1, estos registros se utilizan para definir si los puertos A y B serán entradas o salidas. Por lo tanto, y según la tabla de arriba, para movernos al banco 1 debemos poner un 0 en RP1 y un 1 en RP0.

La línea org 0x5 se utiliza para saltarse el vector de interrupciones (esto será analizado en la segunda parte de este curso).

Luego estamos poniendo en 1 el RP0, no hace falta poner en 0 el RP1 porque por defecto todo bit está en cero.

Ahora ya estamos ubicados en el Banco 1 de la memoria de nuestro PIC.

ejemplo programa ensamblador

Ahora, en la tercera línea dice clrf trisa. La instrucción clrf es para mandar puros ceros a un registro, en este caso estamos mandando puros ceros al registro TRISA lo cual configura al puerto A como salida.

*TRISA direcciona al puerto A y TRISB direcciona al puerto B.

La instrucción clrf nos ahorra espacio, ya que manda puros ceros, pero sería lo mismo escribir esto:

ejemplo programa assembler 1.7

De esta forma cargamos puros ceros y luego los mandamos al registro TRISA. Es lo mismo.


Bueno, volvamos a este trozo de código fuente. Luego de poner en 0 el TRISA estamos utilizando la instrucción movlw que carga un valor literal en W, en este caso el valor literal es binario (por eso ponemos una b en minúscula).

El número binario que estamos cargando es 10000000 lo que significa que RB7 está configurado como entrada, y de RB6 a RB0 están siendo configurados como salidas.

Pero hasta este momento solo hemos cargado el valor binario, pero ahora hace falta enviarlo a algún registro, para ello utilizamos la instrucción movwf y escribimos TRISB, o sea que le estamos diciendo que mueva el valor binario cargado al registro TRISB.

En seguida, debemos regresar al Banco 0, puesto que el PIC debe mantenerse en este banco para poder trabajar. Para ello únicamente ponemos en 0 el RP0 (como se explicó más arriba) y ya estamos en el Banco 0.


Las dos líneas que siguen clrf porta y clrf portb están mandando puros ceros a los registros porta y portb para “apagar” ambos puertos, por si alguno de ellos se encontrase con un nivel de voltaje alto a la hora de comenzar a funcionar el programa.

Como los registros porta y portb se encuentran en el Banco 0, debemos estar posicionados en ese banco para poder configurarlos.

ejemplo programa ensamblador

Aquí ya entramos de lleno en el programa principal, la parte “difícil” era la configuración de los registros, pero el programa principal propiamente tal, es mucho más fácil y aburrido, porque si no es difícil no es divertido.

Haremos un programa que encenderá un LED conectado en RB0 cuando presionemos un pulsador conectado en RB7.

Primeramente, escribimos una etiqueta a la que yo he llamado inicio.

Luego nos topamos con la instrucción btfss que es como una condición if then en programación con otros lenguajes que son de alto nivel. Esta instrucción pregunta si se ha cumplido una determinada condición, si esta condición es falsa el programa hace una cosa, y si es verdadera entonces hace otra.

En este caso yo puse btfss portb,7 lo cual está preguntando si hay o no un nivel del voltaje alto en el pin RB7, si la condición es falsa se ejecuta la instrucción que le sigue al btfss, en este caso un goto que nos está enviando de regreso al inicio para que vuelva a comprobar la condición, y estará dando vueltas en este bucle hasta que la condición sea verdadera.

*PORTB,7 hace referencia al RB7, así como por ejemplo PORTA,4 haría referencia al pin RA4.

Ahora bien, si la condición es verdadera (o sea que hay un nivel alto en RB7), entonces el programa se salta la instrucción goto y continúa leyendo el resto de instrucciones.

ejemplo programa ensamblador

Ahora que la condición se hizo verdadera, la instrucción que sigue es bsf que se utiliza para poner un 1, en este caso yo coloco en 1 el pin RB0, o sea que se encenderá el diodo LED conectado en dicho pin.

Luego, llamo a una rutina de tiempo (que haremos más adelante) para que el programa espere un tiempo antes de continuar. Para esto utilizamos la instrucción call y nuestra rutina se llama PDelay.

Terminando la rutina de espera, utilizamos la instrucción bcf para poner en 0 el RB0 y así apagar el LED.

Después, volvemos a llamar a la rutina y finalmente utilizamos la instrucción goto para regresar al inicio y realizar todo el programa nuevamente infinitas veces.

Eso es todo, ahora veamos la subrutina de tiempo. Esta se puede confeccionar manualmente empleando una formula, pero ya son las 0:34, tengo sueño y no tengo ganas de explicar eso, así que haremos nuestra rutina con un lindo programa que se llama PIC Delayer, más conocido como PIC Delay o PIC Del.

icono programa pic delayer

Bueno, ejecuta el PIC Delayer y se verá está ventana:

abriendo programa pic delayer

En donde dice Frequency debes escribir la frecuencia del oscilador que estás utilizando, el programa trae por defecto 4MHz.

Luego, donde dice Delay Time debes escribir el tiempo que deseas (ponlo en milisegundos). Y presiona el botón Calculate Cycles.

Yo puse 500mS. Luego presionas el botón Generate Code y espera a que el programa genere la rutina de tiempo solicitada.

Deberás ver esto:

código ensamblador programa pic delayer

Ahí ya está la subrutina creada, ahora cópiala y pégala en tu código fuente. De esta manera:

subrutina pic delayer

No olvides escribir end al final del programa. Yo aquí arreglé la rutina borrando los comentarios y alineándola con mi código fuente. Te sugiero que hagas lo mismo, no hay un programador más mediocre que el que escribe desordenado. Si te fijas la palabra PDelay aparece encerrada con rojo en nuestra rutina. Ese es el nombre de la etiqueta de nuestra rutina y a ella debemos llamar para que el programa salte hacia allá. Call PDelay.

Ojo con un detalle. Cuando creamos la rutina con el programa PIC Delayer, aparecieron unos requerimientos en la parte de abajo: 

requerimientos código pic delayer

Nuestra rutina necesita un lugar en el cual almacenarse, a estos lugares denominaremos variables. Estas variables se llaman PDel0 y PDel1 y hay que declararlas entre los reglones cblock y endc.


De esta forma nuestra rutina funcionará de forma correcta. Si te fijas hay un tercer requerimiento, 1 stack level. El stack es una cosa del PIC que no voy a explicar ahora, pero no te preocupes por eso ya que no es relevante saberlo para que la rutina funcione. Por ahora ignora eso del stack

Introducción al lenguaje ensamblador - parte 1

A continuación  veremos la primera parte de un gran curso sobre el lenguaje ensamblador, escrito por el técnico en electrónica César Antonio Saldías Caro, de Valparaíso, Chile. Puedes encontrar más información en su blog ingenieropic.wordpress.com.

Este curso incluye una carpeta con el código fuente compilado del programa que analizaremos.

En la primera parte de este curso aprendiste los conceptos básicos sobre microcontroladores. En esta ocasión te enseñaré los conceptos básicos sobre programación en lenguaje Assembler y analizaremos nuestro primer programa… El encendido y apagado de un LED.

El código fuente
El código fuente está constituido por una sujeción de líneas de programa. Cada línea suele estar compuesta por cuatro campos diferentes los cuales están separados por una o más tabulaciones. Estos campos son los siguientes:

- Campo de etiquetas.
- Campo de instrucciones.
- Campo de operandos y datos.
- Campo de comentarios.

A continuación podemos ver un ejemplo:

línea código lenguaje ensamblador

La siguiente tabla nos explica mejor la imagen de arriba para poder entender mejor el asunto:

desmenuzando línea código lenguaje assembler


Etiquetas: Las etiquetas (también denominadas “label”) son expresiones alfanuméricas escogidas por el usuario, su función principal es identificar a una instrucción dentro del programa. Sin embargo, a pesar de que el nombre de las etiquetas lo determina el usuario, estas no pueden llevar el nombre de una instrucción del assembler o de un operando. Por ejemplo sería erróneo ponerle el nombre “bsf” a una etiqueta. Tampoco es admitido que el primer caracter de una etiqueta sea un número o un espacio, siendo incorrecto por ejemplo ponerle “10inicio”.

Las etiquetas suelen utilizase para realizar saltos. Por ejemplo:

saltos lenguaje ensamblador

En este ejemplo, le estamos diciendo al programa (con la instrucción goto) que salte hasta donde se encuentra la etiqueta “inicio”.

Instrucciones: El segundo campo es para las instrucciones, las cuales le indican al microcontrolador la tarea que debe realizar. Suele ser una instrucción del microcontrolador que es directamente traducida a código máquina por el ensamblador.

Operandos y Datos: Esta columna contiene los operandos para las instrucciones. Este campo puede tener uno o más operandos separados por comas. Es importante destacar que algunos operandos no llevan dato.

Comentarios: Los comentarios se escriben generalmente en el último campo, pero solo es por una cuestión de orden y estilo, puesto que pueden ir escritos en cualquier parte (excepto entremedio de una etiqueta, instrucción u operando).

Los comentarios son palabras, frases o textos escritos por el programador, con el fin de explicar o hacer una breve descripción de lo que se está realizando, de manera tal que posteriormente no sea dificultoso entender el programa o modificarlo.

Los comentarios se escriben siempre anteponiendo punto y coma (“;”) y no son traducidos a código máquina por el ensamblador. En otras palabras, los comentarios no son parte del programa propiamente tal.

Importante
Un detalle importante y de interés, es que, no todas las líneas de programa están conformadas por los cuatro campos descritos anteriormente. Por ejemplo, las etiquetas solo se usan de vez en cuando. También hay instrucciones que no llevan operando, y hay operandos que no llevan dato. Pero nunca encontraremos un operando que no lleve instrucción, ni tampoco un dato que no lleve operando.

El repertorio de instrucciones
El PIC 16F628A posee un repertorio de 35 instrucciones que pueden ser agrupadas de la siguiente manera:
- Instrucciones de carga.
- Instrucciones de salto.
- Instrucciones aritméticas.
- Instrucciones para manejar subrutinas.
- Instrucciones lógicas.
- Instrucciones especiales.
- Instrucciones de bit.

Las características principales de este repertorio de instrucciones son:
- Es un juego de instrucciones reducido (RISC) rápido y sencillo.
- La mayoría de las instrucciones se ejecutan en 4 ciclos de reloj.
- Son ortogonales (casi todas pueden usar cualquier operando).
- Todas tienen una longitud de 14 bits, y los datos son de 8 bits.

He aquí el set de instrucciones del PIC 16F628A:

set instrucciones pic 16f628A


Las directivas
Para el correcto ensamblado del programa, es necesario escribir directivas. Estas no son parte del programa ya que no son traducidas a lenguaje máquina, por eso se les suele llamar pseudoinstrucciones.

END: Esta directiva indica el fin del programa. Es la única directiva obligatoria, y se utiliza siempre al final del programa para indicar en donde se termina el proceso.

ORG: Esta directiva le indica al programa la dirección desde la que deben ensamblarse las instrucciones escritas. Si las instrucciones del programa son ensambladas sin especificar ORG, el ensamblador toma por defecto ORG 0x0.

__CONFIG: Esta directiva le indica al programa la configuración elegida para la grabación del programa. Se le denomina también “Palabra de Configuración”

Ejemplo:

ejemplo directiva lenguaje assembler

Esta directiva está formada por varios “fusibles” que se utilizan para definir una serie de parámetros que a continuación explicaré.

La forma de escribir estos parámetros es tal como se ve en la imagen de arriba, se coloca un guión bajo entre cada fusible y su configuración, y se separa cada configuración con la letra “&”.

WDT: Watch Dog Timer, o Temporizador Perro Guardián. Este temporizador resetea el PIC cada determinado tiempo para evitar enciclamientos por error en el programa. Preferentemente hay que apagarlo (OFF).

OSC: Define que tipo de oscilador se usara. RC es para Capacitor y resistencia, XT es para cristal de 4Mhz, HS para cristales mayores a 4Mhz.

BODEN: Se emplea para que el PIC se resetee cuando exista una caída de tensión.

CP: Código de Protección de programa, si lo habilitamos (ON) evita que otras personas puedan leer el programa contenido en el PIC.

PWRT: Bit de Permiso para el Timer de conexión de alimentación. Se usa para resetear el PIC cada vez que se conecta la fuente de alimentación de nuestra aplicación.

WRT: Permiso para escritura en Modo FLASH. Se usa cuando en nuestro programa accedemos a la memoria de datos EEPROM.

CPD: Código de Protección de Datos. Se usa para evitar que terceros lean lo que hemos escrito en la memoria EEPROM del PIC.

LVP: Voltaje de programación bajo. Si esta en ON permite programar el PIC con 5V, si esta en OFF programa el PIC con 12V.

Hay un detalle muy importante con respecto al último fusible llamado LVP. Una de las funciones del pin RB4 del PIC16F628A es la de programación en bajo voltaje, y por defecto es la función que viene habilitada de fábrica. Esto significa que si queremos utilizar el pin RB4 como entrada o salida debemos poner el fusible LVP en OFF para desactivar la función que trae de fábrica.

LIST: Esta directiva indica el modelo de microcontrolador que se va a utilizar.

INCLUDE: Esta directiva se utiliza para incluir una librería dentro de nuestro programa.

CBLOCK y ENDC: Este par de directivas cumplen la función de asignar direcciones, generalmente de la memoria RAM de datos. La lista queda enmarcada entremedio de las directivas CBLOCK y ENDC.

#DEFINE: Esta directiva define una cadena de sustitución de texto.

Las subrutinas
Una subrutina es un trozo de código fuente que suele estar apartado del resto del programa para hacer más sencilla la revisión y lectura del programa. Para llamar a una subrutina se utiliza la instrucción call, y para salir de una subrutina se utiliza la instrucción return.

Al llamar a una subrutina, el programa ejecuta las instrucciones que forman parte de ella, y luego retorna una posición más abajo desde donde fue llamada la subrutina. Mira esta representación:

ejemplo subrutina ensamblador

Las subrutinas generalmente se utilizan cuando un mismo trozo de código fuente se debe repetir demasiadas veces, entonces se escribe ese trozo de código a modo de subrutina, y posteriormente se le llama cada vez que se necesite.

La memoria del microcontrolador
Para poder realizar las acciones que ejecuta el microcontrolador, es necesario escribir y leer datos en alguna parte… Para eso está la memoria del PIC, la cuál está dividida en cuatro bancos (del 0 al 3), en cada banco hay una cierta cantidad de registros, y cada registro está dividido en 8 bits (1 byte). Veamos el mapa de memoria del PIC 16F628A:

mapa memoria microcontrolador PIC16F628A

Aquí puedes checar la segunda parte del curso sobre el lenguaje ensamblador.

¿Cómo usar el osciloscopio?

El osciloscopio digital es un instrumento de medición, de gran importancia en el campo de la electrónica, que nos permite visualizar señales eléctricas que varían en el tiempo. Esta herramienta es fundamental para determinar diversas características de una señal como su frecuencia, período y voltaje, además de determinar si se trata de una señal de DC o AC. En el área laboral normalmente se utiliza para localizar averías en un circuito.

Para aprender a manejar el osciloscopio podemos leer algunas guías escritas, aunque son mucho más efectivas las explicaciones visuales, como las del siguiente video:



Probador de controles remoto.


El siguiente circuito te permitirá verificar la correcta operación de los controles remoto. Su funcionamiento se basa en el sensor infrarrojo TSOP1738. Cuando éste recibe ondas infrarrojas en las frecuencias cercanas a los 38Khz, banda en la que trabajan casi todos los controles, su salida pasa a estado bajo.

Esquema de circuito probador de control remoto

En el esquema, en la salida del sensor se encuentra la base del transistor Q1 con sus respectivas resistencias de polarización. La presencia de un nivel bajo de tensión a la salida de IR1 genera una corriente de base saliente del transistor Q1, lo que a su vez produce una corriente por el colector del transistor, suficiente para encender el LED. El control remoto funcionará correctamente si el LED parpadea de distintas maneras según la tecla presionada.

El sensor TSOP está preparado para ser alimentado con una tensión de 5v. Sobre el diodo D1 se produce una caída de tensión de 0,7 V quedando 5,3 V para el sensor de los 6 V que entrega la batería. El resistor R1 es un elemento de protección y sirve para limitar la corriente.

pcb del probador de control remoto


Esta es la lista de componentes a utilizar:
1.- Batería B1 - 6 V.
2.- Diodo D - 1N4004.
3.- Diodo D2 - LED.
4.- Sensor IR1 - TSOP1738TB1.
5.- Transistor Q1 - BC558B.
6.- Resistencia R1 - 47 Ohm.
7.- Resistencia R2 y R4 - 1 K.
8.- Resistencia R3 - 10 K.

En los siguientes enlaces puedes consultar el pinout del sensor y el transistor utilizados: TSOP1738 y BC558.

Puedes descargar el PCB de este circuito aquí.