Display 7seg - Mensaje con Desplazamiento (Scroll)

Al igual que en la nota anterior http://electgpl.blogspot.com.ar/2013/11/matriz-8x8-mensaje-con-desplazamiento.html En este caso cambie la matriz de 8x8 por 8 displays de Cátodo Común, que en este caso ya se encuentran interconectados de forma matricial, pero se puede realizar con displays comunes interconectándolos.
El circuito es igual de simple que el comentado anteriormente de la matriz (Tener en cuenta el consumo de los leds, y las resistencias limitadoras que deben ir al menos en todo un puerto del microcontrolador).
En la simulación no son necesarias pero en la realidad si.
El programa es el mismo que el anterior pero en lugar de crear cada caracter con los puntos de la matriz, creamos cada caracter (limitado por el display) con un solo byte es posible crear un caracter.
Como podemos ver en el programa no hice todo el abecedario sino que algunas letras fltan y lo dejo a la imaginación de cada uno ya que hay letras que se complican para formar en un display de 7 segmentos.
Luego el otro cambio que podría decirse que es una pequeña mejora, es que le agregue la macro FRAMES que tiene el valor 50, esto lo que hace es poner 50 en todas las partes del programa donde aparezca FRAMES, al igual que la otra macro que se llama LARGO.
Los frames son la cantidad de veces que refresca la pantalla, pero si lo hace muchas veces, el movimiento sera mas lento, y si lo hace menos veces el movimiento sera mas veloz. No es exactamente como debería funcionar un Frame, pero esta ligado a la velocidad de desplazamiento, por ende en estos displays para que se pueda leer se le aumento la cantidad de frames, pero pueden variarla modificando ese numero.
El gif animado se ve relativa mente sincronizado aunque en la vida real se ve mucho mejor.



#include <16F883.h>
#use delay(int=4000000)
#define LARGO 28                      //Longitud de la tabla
#define FRAMES 50                     //Cant. de muestras (velocidad)
int const tabla[LARGO+16]={
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio   
                          0b01110111, //Dato de tabla A
                          0b01111100, //Dato de tabla b
                          0b00111001, //Dato de tabla C
                          0b01011110, //Dato de tabla d
                          0b01111001, //Dato de tabla E
                          0b01110001, //Dato de tabla F
                          0b00111101, //Dato de tabla G
                          0b01110110, //Dato de tabla H
                          0b00000110, //Dato de tabla I
                          0b00011110, //Dato de tabla J
                          0b00111000, //Dato de tabla L
                          0b01010100, //Dato de tabla N
                          0b00111111, //Dato de tabla O
                          0b01110011, //Dato de tabla P
                          0b10111111, //Dato de tabla Q
                          0b00110011, //Dato de tabla R
                          0b01101101, //Dato de tabla S
                          0b00110001, //Dato de tabla T
                          0b00111110, //Dato de tabla U
                          0b01101110, //Dato de tabla Y
                          };
void main(){
   byte const bitMask[8]={1,2,4,8,16,32,64,128}; //Mascara
   int i,j,k;                         //Variables contadores
   while(TRUE){                       //Ciclo infinito
      for(i=0;i<LARGO+16;i++){        //Recorrido de tabla
         for(k=0;k<FRAMES;k++){       //Refresco de matriz
            for(j=0;j<8;j++){         //Barrido de columnas
               output_a(~bitMask[j]); //Columnas ponderadas
               output_b(tabla[j+i]);  //Desplazamiento de tabla
               delay_ms(1);           //Demora de multiplexado
            }  
         }
      }
   }  
}   




Amplificador de 3 transistores a 5V

Circuito simple y rápido para amplificar una señal de audio a 1/4W desde una alimentación de 5V.
El circuito es muy simple, se basa en una configuración PushPull clásica con un pre-amplificador de entrada.
Los transistores pueden ser reemplazados por cualquier otro de uso general (ECG123AP).





Matriz 8x8 - Mensaje con Desplazamiento (Scroll)

Una de las aplicaciones mas comunes cuando uno utiliza una matriz de leds, es escribir caracteres o mostrar mensajes desplazándose por ella de forma tal que se pueda leer fácilmente un mensaje.

Como en post anteriores se mostró que la forma de que se pueda presentar una imagen estática en la matriz es mediante la técnica de multiplexado, es decir como en una matriz de 8x8 tenemos 64 puntos los cuales claramente no podemos acceder individualmente porque seria muy poco practico y extremadamente lleno de conexiones, la técnica para este es la de controlarlo de forma matricial con solo 16 pines, es decir 8 para las filas y 8 para las columnas, de esta forma si se activa una fila y una columna se encenderá el punto donde estas hacen intersección.
Ejemplo:
 
Como podemos ver en la imagen de arriba, al activar la columna E y la fila 4, logramos que la intersección entre estos encienda el punto de color azul, esta seria la forma en la que podemos encender un punto en una matriz.
Para que esto sea posible el multiplexado funciona de la siguiente forma:
Se activa la columna A, y se muestra el dato completo de las 8 filas. es decir Columna A, Filas (1,2,3,4,5,6,7,8), luego se repite lo mismo pero con la Columna B, y las 8 Filas nuevamente, y de esta forma hasta llegar ala columna H, entonces de esta forma se hace un recorrido de todas las columnas.
Ahora si el dato es siempre el mismo por ejemplo en el dibujo podemos ver que el único bit en 1 es el 4, y el resto están en cero, Filas(1,2,3,4,5,6,7,8) lo que seria en el dibujo como (000100000), y en este caso si nosotros hacemos el proceso de arriba de ir barriendo las columnas y el dato de las filas es siempre el mismo lo que se vera es una linea en toda la fila
Podemos ver en camara lenta como seria con el mismo dato en las filas.
Ahora en la realidad si nosotros realizamos este desarrollo tendremos que hacer que el barrido entre columnas sea lo suficientemente rápido como para que el ojo humano no perciba el multiplexado, lo cual como vemos en la imagen, el 4017 tendrá que conmutar mas rápido las columnas.
Bueno aquí aumente la frecuencia a 100Hz para que se pueda ver en velocidad, por un tema del gif animado no se puede apreciar el efecto, pero al generar un barrido de columnas de 100Hz la fila 4 queda encendida totalmente. Esto como mencionaba antes se debe a que el dato en las filas es siempre el mismo, como pueden ver en los seteos de estado de arriba de la imagen siempre mantiene el mismo encendido.
Pero en la realidad cuando requiere realizar un dibujo o una letra, tiene que variar estos datos de las filas, (las columnas siempre realizan el mismo trabajo de conmutación) pero en este nuevo concepto las columnas tienen que variar. La forma de esta variación sera en función de lo que se desee mostrar. 
Si uno quiere mostrar un circulo dibujado, tendrá que mostrar en cada columna el dato que corresponda, es decir observen la siguiente tabla de valores binarios:

COLUMNAS  
00011000  
00100100 F
01000010 I
10000001 L
10000001 A
01000010 S
00100100  
00011000  

Bueno analizando esta tabla, lo que tendríamos que haces es que para la columna A, el dato a mostrar en las filas sera 00011000, en la columna B, el dato sera 00100100, en la columna C, sera 01000010, luego seguirá como se muestra en la tabla. 
Nuevamente de forma lenta para comprender como se recorre la tabla:
Ahora al igual que antes vamos a verlo con una frecuencia de 100Hz pero gracias al gif otra vez se va a ver medio cortado. pero imaginen que lo hace rapido como se debe, conformando así el pseudo circulo sin que se pueda percibir por el ojo humano esta conmutación de columnas.
 
Bueno ahora la idea de hacer esto con un microcontrolador que pueden verlo en otro post en este blog [http://electgpl.blogspot.com.ar/2012/05/adaptador-de-matriz-de-5-x-7-puntos.html] aquí se muestra todo lo mencionado hasta ahora. 
En este otro post se puede ver como mediante una secuencia de tablas, es posible ir cambiando cada imagen estática [http://electgpl.blogspot.com.ar/2012/05/control-de-matriz-estatica.html]

Ahora el motivo de este nuevo post es el de crear una matriz dinámica, es decir que el texto que contenga no se muestre letra por letra de forma estática sino de forma dinámica como un desplazamiento o como se le dice en el resto del mundo Scroll.
A pesar de que la forma de generar un muestreo, conmutación o multiplexado de columnas se suele realizar mediante el uso de Timers en el microcontrolador, en este ejemplo lo haré de la forma mas sencilla sin ningún timer, simplemente con lazos for.
El uso de Timers se requiere para que de forma independiente se pueda generar el barrido de las columnas o el muestro (cantidad de frames) de la imagen a mostrar en la matriz, sea de forma independiente al resto del programa, esto es porque el muestreo de columnas suele ser mucho mas rápido que el desplazamiento del texto en la matriz, entonces se soluciona muy sencillo con el uso de los timers, pero en mi caso intento hacer lo mas sencillo posible este post para que sea muy fácil de entender.

Para esto veremos el programa y luego lo explicare.

#include <16F883.h>
#use delay(int=4000000)
#define LARGO 28                      //Longitud de la tabla
int const tabla[LARGO+8]={
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          0b00000000, //Espacio 
                          0b11111111, //Dato de tabla H
                          0b00001000,
                          0b00001000,
                          0b11111111,
                          0b00000000, //Espacio
                          0b01111110, //Dato de tabla O
                          0b10000001,
                          0b10000001,
                          0b01111110,
                          0b00000000, //Espacio
                          0b11111111, //Dato de tabla L
                          0b00000001,
                          0b00000001,
                          0b00000000, //Espacio
                          0b01111111, //Dato de tabla A
                          0b10001000,
                          0b10001000,
                          0b01111111,
                          0b00000000, //Espacio
                          0b00000000, //Espacio
                          };
void main(){
   byte const bitMask[8]={1,2,4,8,16,32,64,128}; //Mascara
   int i,j,k;                         //Variables contadores
   while(TRUE){                       //Ciclo infinito
      for(i=0;i<LARGO+8;i++){         //Recorrido de tabla
         for(k=0;k<20;k++){           //Refresco de matriz
            for(j=0;j<8;j++){         //Barrido de columnas
               output_a(~bitMask[j]); //Columnas ponderadas
               output_b(tabla[j+i]);  //Desplazamiento de tabla
               delay_ms(1);           //Demora de multiplexado
            }  
         }
      }
   }  
}   

Bueno aqui podemos ver principalmente la tabla con los caracteres realizados en funcion a las filas que forma la palabra HOLA, ahora lo mas importante que son los for anidados.
Notemos desde el for que se encuentra mas profundo hacia al for que se encuentra en la superficie.
El for(j=0;j<8;j++)cumple la función de recorrer las columnas que se encuentran en el puerto A, por eso encontramos la sentencia output_a(~bitMask[j]), donde bitMask[j] es el vector definido mas arriba que contiene los valores {1,2,4,8,16,32,64,128}, esto hace referencia a 00000001, 00000010, 00000100, 00001000, 00010000, 00100000, 01000000, 10000000. De esta forma activamos cada columna una a una. Luego como podemos ver tenemos la salida del puerto B la cual posee el vector de la tabla donde su indice dice j+i, bueno esto es clave para que la matriz desplace la palabra dentro de ella. 
Ahora el for(i=0;i<LARGO+8;i++)lo que hace es recorrer la tabla, como pueden ver el valor constante LARGO que se carga en la parte de arriba del programa es la longitud de la tabla, es decir el largo del vector, pero se le suma 8, esto es porque la matriz posee 8 columnas las cuales debe mostrar apagadas al finalizar dicho mensaje para que no se solape cuando se repita.
Volviendo a lo mencionado anterior que era clave el j+i lo que hace es que cada vez que se refrescan las columnas, se recorre toda la tabla, pero por cada refresco, la tabla se recorre desde un inicio distinto, es decir, para crear el movimiento de la matriz, lo que se hace es mostrar el contenido de la tabla desde su primer byte hacia el ultimo, pero cada vez que se genera un muestreo en lugar de comenzar del primero se comienza del segundo, luego del tercero, y por eso el j+i, lo que nos genera la ilusion óptica del movimiento. Ahora se mostrara en el siguiente gif animado, a velocidad lenta para la comprensión y a velocidad normal para ver el resultado obtenido.
Por ultimo el for(k=0;k<20;k++) lo que hace es la cantidad de frames, es decir la cantidad de veces que refresca la pantalla por cada barrido de columnas, lo que quiere decir es que realizara 20 barridos de matriz completa por cada movimiento del desplazamiento de la palabra en la matriz.
Tener en cuenta que el gif animado no se muestra en tiempo real, pero servirá para tener en cuenta el funcionamiento.
Esta sera la versión final a velocidad aceptable para leer y sin parpadeos.


 





Transmisor ASK de 80m a 5V

Este es un transmisor de ASK en la banda de 80m alimentado con 5V, de todas formas por la forma en que se encuentra construido la frecuencia de operación puede variar, ya que la base de tiempo del oscilador de portadora se encuentra realizada con cristal de cuarzo.
En este caso el Oscilador local está construido con compuertas Schmitt Trigger (40106), donde simplemente se requieren pocos componentes pasivos para conformar el oscilador.
Se implementa un cristal de 3.58MHz pero es posible utilizar otros valores.
El transistor de abajo cumple la función de amplificar la señal de salida del oscilador a cristal, la alimentación de este amplificador se encuentra acoplada mediante el inductor de 100uHy al transistor de modulación que se encarga de variar la amplitud del amplificador en función del nivel de señal de la entrada de modulación.
De esta se modifica la amplitud de la portadora amplificada, lo cual da como resultado una Amplitud Modulada. Aunque como los datos son digitales y la amplitud se modula por el desplazamiento de dichos pulsos, el transmisor se convierte en ASK, el circuito está calculado para que el transistor modulador funcione en un hibrido entre la clase A y la clase E.
La antena se acopla mediante los condensadores de 10nF y 330pF, debe ser de 50ohms.
Es posible aumentar la tensión de alimentación pero solo lo he probado con 5V, claramente aumentara el alcance de este transmisor al aumentar la alimentación, pero se deben recalcular las resistencias de polarización del punto Q del transistor de arriba.



Generador RTTY Baudot con PIC


Aquí les traigo un sencillo generador de caracteres en código Baudot con modulación en doble tono para conformar el protocolo RTTY, el mismo posee el generador de tonos integrado y la generación de Baudot en el mismo.

El circuito no está en el post porque en si es solo el micro controlador y un pin de salida que en este caso se elige un 16F84A y se usa el pin RA2 como salida. Pero claramente por la sencillez del programa puede usarse cualquier micro controlador.

El programa es muy sencillo de comprender.

Básicamente tenemos dos funciones, freq1 y freq0, esto es para generar dos frecuencias (de ahí viene el doble tono) donde la freq1 "del 1 lógico" la calcule yo a 800Hz y la freq0 "del 0 lógico" a 970Hz, nótese que la distancia es de 170Hz por ende si quieren usar otros valores de frecuencia (que es totalmente valido) deben tener una distancia de 170Hz entre una frecuencia y la otra.

La norma RTTY aparte de exigir estos 170Hz también exige que cada dato se envié a 22ms por ende aquí vienen las cuentas.

tomamos como ejemplo la función freq1, observamos que ponemos el pin de salida a 0 y después a 1, la velocidad que usamos son 625us de Ton y 625us de Toff, quedando así una periodo T de 1250us lo cual si lo pasamos a frecuencia nos da 800Hz, ahora hasta ahí todo bien logramos los 800Hz que queríamos, pero cada dato debe enviarse a 22ms entonces debemos hacer que se demore durante 22ms, para ello usamos un loop del tipo while donde cuenta 17 veces y luego sale del loop, si multiplicamos 17 * 1250us nos dará 21,2ms (es casi el valor de 22ms, gracias a que existe una tolerancia no tendremos problemas). 

La función freq0 es lo mismo que esto pero calculado para 970Hz.

Estas dos funciones forman parte de la generación de doble tono, lo que sería nuestro "modem".

Ahora viene la generación de baudot, para esto se crea un vector de 18 posiciones (lo cual son 18 porque use 18 caracteres para formar "  ELECTGPL  RTTY  ").

El protocolo dice que debe ser 1 bit de start a 0 lógico, seguido de esto 5 bit del dato o el carácter y por ultimo 2 bit de Stop a 1 lógico. Notaran que en el programa está al revés, es decir primero el stop y por último el start, eso es por la forma en la que el micro entrega los bit de forma serie (pero pueden cambiarlo, yo lo he dejado así porque ya lo había codificado así).

Tenemos otro vector que es para la máscara, es decir tiene los valores ponderados de un valor binario de 8 bit, esto es simple, la forma de enviar el dato de forma serial, debe ser bit a bit, entonces esto lo hacemos comparando el dato a enviar con la máscara. Por ejemplo en el loop que tiene un for que itera 8 veces lo que se hace es comprar el byte a enviar (start, dato, stop, stop) con el byte de la máscara. Entonces si aplicamos la operación lógica AND, donde exista un 1 lógico dará verdadero y donde exista un 0 lógico dará falso, entonces si tenemos por ejemplo el primer byte a enviar "11001000" y lo comparamos contra la máscara 8 veces (mediante el incremento del índice del vector) nos dirá como resultado lo siguiente:


11001000 & 00000001 = False

11001000 & 00000010 = False

11001000 & 00000100 = False

11001000 & 00001000 = True

11001000 & 00010000 = False

11001000 & 00100000 = False

11001000 & 01000000 = True

11001000 & 10000000 = True


Esto es lo que hace el for que itera 8 veces, de esta forma recorre bit a bit todo el byte del dato y lo compara contra la máscara. Ahora, seguido de este tenemos la condición, si es verdadero llama a la función freq0 y si es falso a la función freq1, entonces como quedaría esto modulado?, de la siguiente forma.

800Hz 22ms 800Hz 22ms 800Hz 22ms 970Hz 22ms 800Hz 22ms 800Hz 22ms 970Hz 22ms 970Hz 22ms. Esta sería la salida del micro, que luego se repetirá como dice el while unas 18 veces que coincide con los 18 valores vector de datos.

La salida puede ser acoplada como en mi práctica a un transmisor de AM de 80m pero es posible acoplarla a cualquier entrada de AF.

#include <16F84A.h>
#fuses XT
#use delay(clock=4000000)
#define AUDIO PIN_A2
freq1(){        //625us + 625us = 1250us = 800Hz
   int q=0;
   while(q<17){ //22ms / 1250us = 17 veces.
      output_low(AUDIO);
      delay_us(625);
      output_high(AUDIO);
      delay_us(625);
      q++;
   }  
}
freq0(){        //515us + 515us = 1030us = 970Hz
   int p=0;
   while(p<21){ //22ms / 1030us = 21 veces.
      output_low(AUDIO);
      delay_us(515);
      output_high(AUDIO); 
      delay_us(515); 
      p++;
   }  
}
void main(){
   int i,j;     
   byte valor;
   byte const bitMask[8]={1,2,4,8,16,32,64,128};
   byte const ByteDatosSalida[18]={
      0b11001000, //11 00100 0, STOP STOP ESPACIO START
      0b11001000, //11 00100 0, STOP STOP ESPACIO START
      0b11000010, //11 00001 0, STOP STOP "E" START
      0b11100100, //11 10010 0, STOP STOP "L" START
      0b11000010, //11 00001 0, STOP STOP "E" START
      0b11011100, //11 01110 0, STOP STOP "C" START
      0b11100000, //11 10000 0, STOP STOP "T" START
      0b11110100, //11 11010 0, STOP STOP "G" START
      0b11101100, //11 10110 0, STOP STOP "P" START
      0b11100100, //11 10010 0, STOP STOP "L" START
      0b11001000, //11 00100 0, STOP STOP ESPACIO START
      0b11001000, //11 00100 0, STOP STOP ESPACIO START
      0b11010100, //11 01010 0, STOP STOP "R" START
      0b11100000, //11 10000 0, STOP STOP "T" START
      0b11100000, //11 10000 0, STOP STOP "T" START
      0b11101010, //11 10101 0, STOP STOP "Y" START
      0b11001000, //11 00100 0, STOP STOP ESPACIO START
      0b11001000};//11 00100 0, STOP STOP ESPACIO START
   while(true){
      delay_ms(3000);              //delay de repeticion 3s
      i=0;
      while(i<18){                 //cantidad de caracteres 18
         valor=ByteDatosSalida[i]; //carga valor con dato de salida
         for(j=0;j<8;j++){         //recorre los 8 bit del baudot
            if(valor&bitMask[j])   //aplica la mascara
               freq0();            //si es verdadero envia 970Hz
            else
               freq1();            //si es falso envia 800Hz
         }i++; 
      }
   }
}