LCD 16×2 con RS485 y PSoC

En algunos proyectos he tenido la necesidad de que algun display este muy lejos (mucho) de la tarjeta del circuito. Esto presenta problemas, porque a medida que la distancia crece, se vuleve dificil que a las señales que van a la clasica pantalla lcd de 16×2 no les “entre ruido”, y bueno, la comunicacion se hace practicamente imposible e incluso podemos dañar nuestro circuito

2015-02-26 22.22.47

Para resolver esto usé el RS485 que me permite ir hasta 1200 metros con una velocitad de hasta 100kbps. Para poder establecer comunicacion por este estandar, use el integrado MAX485, que prácticamente no requiere configuracion externa, lo que ofrece que en la uart del procesador casi no se “sienta diferencia” a la hora de enviar o recibir datos. Lo unico que podria no ser tan bueno, es que este estanda es half-duplex, por lo que no puede haber comunicacion simultanea entre dispositivos. En el max485 hay un par de lineas que hacen el cambio entre recibir y transmitir informacion.

La idea detras del rs485 es enviar comandos para manipular la pantallla lcd, por lo que usando la uart de algun procesador podemos hacer un pequeño protocolo que nos permita interactuar con la pantalla.

El procesador que elegí es de la marca Cypress, un PSoC1, el modelo CY8C27443. ¿Por qué?. Bueno, en lo personal estos procesadores son de mis favoritos por varias razones. Una de estas es que se puede “personalizar” el procesador de tal manera que, puede llegar a “tener” el hardware que necesitemos. Por ejemplo, en la mayoria de los procesadores, el hardware interno esta definido, es decir, tiene una u(s)art, un i2c, un adc, etc. Y dependiendo del modelo del procesador, es el hardware que tienen. Con los PSoC pasa algo curioso, estos procesadores ofrecen una cantidad de bloques digitales/analogicos, que pueden ser configurados para trabajar como se necesite: uart, o como timer o como i2c, tu decides; incluso puedes tener varios i2c o varios uarts, etc. Y cada bloque puede ser “conectado” a los pines que quieras. ¿quieres la comunicacion en los primeros pines? no hay problema 🙂 solo diriges la ruta y listo!

diagrama interno

En fin, tendre que dedicarle algun articulo a estos procesadores. Por ahora, lo que me interesa de este procesador es la facilidad de establecer algun protocolo sencillo para poder hacer el puente entre el rs485 y la lcd.

El PSoC cuenta con API’s bien documentadas para usar los modulos (hardware personalizado) que pueden configurarse. En el caso de la uart, la api, si se habilita, puede reconocer comandos y parametros, que podemos definir al gusto. Esto es de gran ayuda en el sentido que que no espero hacer un programa espectacular, solo una interface para poder enviar comandos a la lcd.

En fin, despues de hacer la configuracion pertinente, el pinout del procesador queda de la siguiente manera:

pinout

Con esto se puede observa que, con la flexibilidad de asignar hardware y la personalizacion de los pines, el PSoC es una herramienta poderosa.

Como mencione, las API’s de los modulos hacen que la programacion sea muy sencilla, como se muestra en el programa a continuacion:

#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules
#include <string.h>

// enable del 485
#define Tx_Enable_On  (pOut_DEN_Data_ADDR |= pOut_DEN_MASK)
#define Tx_Enable_Off (pOut_DEN_Data_ADDR &= ~pOut_DEN_MASK)

// convierte una cadena en numero entero
int mi_atoi(char *cad)
{
int tam, mult=1;
int res=0;

tam = strlen(cad);

while (tam)
{
res += mult * (cad[tam-1]-'0');
tam--;
mult *= 10;
}

return res;
}

void protocolo(void)
{
char * strPtr;
BYTE posx, posy;

// asigna a srtPtr el siguiente parametro del paquete de datos recibido y lo analisa
while(strPtr = UART_szGetParam())
{
switch( strPtr[0] )
{
case 'c':
case 'C':
LCD_Control(1); //CLS - Limpia Pantalla

Tx_Enable_On;   // Habilita la transmision, ya no escucha
UART_CPutString("<Ok\r\n");
while( !(UART_bReadTxStatus() & UART_TX_BUFFER_EMPTY) );
while( !(UART_bReadTxStatus() & UART_TX_COMPLETE) );   // espera a que el ultimo bit haya salido del procesador
Tx_Enable_Off;

break;

case 'i':
case 'I':
strPtr = UART_szGetParam();  // obtiene cadena a imprimir
LCD_PrString(strPtr);

while(strPtr = UART_szGetParam())
{
LCD_PrCString(" ");
LCD_PrString(strPtr);
}

Tx_Enable_On;
UART_CPutString("<Ok\r\n");
while( !(UART_bReadTxStatus() & UART_TX_BUFFER_EMPTY) );
while( !(UART_bReadTxStatus() & UART_TX_COMPLETE) );
Tx_Enable_Off;

break;

case 'p':       // establece la posicion en la lcd para escribir
case 'P':
strPtr = UART_szGetParam();
posx = mi_atoi(strPtr);
strPtr = UART_szGetParam();
posy = mi_atoi(strPtr);
LCD_Position(posy,posx);

Tx_Enable_On;
UART_CPutString("<Ok\r\n");
while( !(UART_bReadTxStatus() & UART_TX_BUFFER_EMPTY) );
while( !(UART_bReadTxStatus() & UART_TX_COMPLETE) );
Tx_Enable_Off;

break;

}

}
}

void main(void)
{

char * strPtr;               // apuntador a la cadena de parametros recibidos
char theStr[] = "Nomadas";

LCD_Start();                  // Inicia la LCD
LCD_Position(0,0);            // Situamos el puntero de la lcd en el origen
LCD_PrString(theStr);         // Impreme "Nomadas"
LCD_Position(1,0);
LCD_PrCString("Electronicos");    // Imprime "Electronicos"

Tx_Enable_Off;      // apaga la transmision, solo escucha

UART_CmdReset();                   // Inicia el interprete de comandos

UART_IntCntl(UART_ENABLE_RX_INT);  // Habiltia las interrupciones para el RX de la uart
UART_Start(UART_PARITY_NONE);      // Habilita la uart

M8C_EnableGInt ;                   // Activa el sistema de interrupciones

while(1)
{
if(UART_bCmdCheck())   // si llego completo un paquete de datos
{
if(strPtr = UART_szGetParam())
{
if( strPtr[0] != '>' )  // Encabezado no valido, comando invalido, desecha el paquete
{
UART_CmdReset();
continue;
}
if( mi_atoi(++strPtr) == 20 )  // si hay encabezado y es la direccion de la lcd (20), analiza lo demas
protocolo();
}
UART_CmdReset();  // pone como nuevo el interprete de comandos
}
}

}

Como se puede observar, los comandos son muy simples:

  • i/I para imprimir algo en la lcd
  • c/C para limpiar pantalla
  • p/P para posicion x,y en la lcd

Para marcar la separacion entre parametros se usa ‘espacio’ y para marcar el final de comando se manda un [LF] o ‘\n’, por lo que se vuelve bastante intuitivo.

Por ejemplo (la “direccion” de la pantalla es 21):

  • “>21 c[LF]” limpia la pantalla y pone el cursor en 0,0 (x,y)
  • “>21 i Hola mundo[LF]” Imprime en la pantalla ‘hola mundo’

Por ahora los comandos son muy “basicos”, mejoraran con el tiempo.

En fin, una vez que esta el programa y la configuracion del procesador, pasamos al diagrama del circuito “completo”

2015-03-01 21.16.49

Como se puede ver, el plan es tener ademas del rs485, tambein i2c. Pero por ahora me interesa tener el sistema en rs485 porque, bueno, es lo que he necesitado. Cuando tenga la version con las dos interfaces de comunicacion, actualizare este post.

El diseño de la placa queda de la siguiente forma:

pcb

Ambos diagramas (esquematico y pcb) estan en diptrace. y el proyecto del software esta en PSoC Designer (gratuito desde Cypress). El combo de diagramas y programa lo dejo aqui.

El “acabado” final de la placa (gracias a Armando, le quedan muy bien):

DSCN0062

Y el circuito ensamblado:

final

Espero que esto les sea de utilidad, por lo menos para mi lo es 😉

************Actualización 4/abril/2015 ***************

Encontre una compañia (http://oshpark.com/) para elaborar pcb’s en baja produccion (desde 3 unidades), asi que el proyecto para esta pcb esta aqui.

Sin mas por el momento…

Argos.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s