# Controlar el encendido de Leds según cadena recibida por puerto serie



## jmbegara (Mar 9, 2014)

Buenos días a todos! 
Quisiera plantearos lo que quiero conseguir: tengo unas máquinas con las que me comunico desde un pc a traves del puerto serie. lo que obtengo desde las maquinas es una de cadena de texto que contiene diversa informacion la cual extraigo con funciones sencillas en visual.basic y que posteriormente uso para otros objetivos. Hasta aquí sin problema.Lo que ahora me gustaria es utilizar ese string de salida y controlar el encendido de varios leds segun la informacion que contiene. Por ejemplo, digamos que obtengo algo \'**130***120***190***\', me gustaria ser capaz de extraer los valores de manera que una serie de leds simulen un rango entre 120 y 190 y se enciendan solo los equivalentes al 130. Obviamente quiero hacerlo sin la intervencion del PC.

Querria saber si creeis si es posible o no llevar a cabo este proyecto, antes de embarcarme en comprar material y demás. Si veis que esposible,agradecería de veras cualquier pista sobre cómo realizarlo. En mi ignorancia sobre microcontroladores se me ha ocurrido que quizá podria hacerlo con algún PIC o algo así, pero jamás he trabajado con ellos, aunque pienso que si puedo programarlo en una PC, tambien podria hacerlo en un microcontrolador investigando lo que hiciera falta.

Espero haberme medio explicado, 
Muchisimas gracias de antemano!

Saludos! ...


----------



## chclau (Mar 9, 2014)

Me parece que una buena solucion para ti y este proyecto es usar una placa Arduino


----------



## TRILO-BYTE (Mar 9, 2014)

con un pic barato como el 16f716 , o el mas barato que encuentres
un max232 para comunicar el pic con el rs232 , quitarte el miedo 
y programar en C como el CCS o algun compilador BASIC por que dices que sabes programar BASIC

ahora leer una cadena de caracteres con CCS no es dificil 

leo la cadena con un gets(); y con atoi la convierto en entero a una variable entera
ejemplo

char cadena[10]; //mi cadena medira 10 caracteres
int numero;          //mi entero

while(1)bucle infinito

{
gets(cadena);                 //leo la cadena con gets
numero=atoi(cadena);    //igualo numero con atoi

//HAGO LO QUE TENGO QUE HACER//
//METER CODIGO AQUI//

}

facil no?


----------



## jmbegara (Mar 10, 2014)

En primer lugar, gracias por la respuesta, Trilo-byte! No parece difícil desde luego... ¿Es posible simular eso que dices con alguna aplicación de PC para luego pasar a diseñar el circuito ya sabiendo que funcionaría?

Muchísimas gracias!


----------



## TRILO-BYTE (Mar 10, 2014)

si con el proteus

descarga el proteus y para simularlo el programa es isis el ares hace los PCB

puedes simular todo con el proteus , hay tutoriales de como hacerlo , es cuestion de quitarse el miedo


----------



## jmbegara (Mar 11, 2014)

Genial!, muchísimas gracias!... descargaré el proteus y comento qué tal

Gracias por todo Trilo-byte!
Saludos!


----------



## jmbegara (Abr 3, 2014)

Hola de nuevo!
He instalado Proteus y el CCS c compiler y he conseguido leer el puerto serie programando en c, pero solo la primera cadena que llega. El problema es que necesito "monitorizar" en todo momento la información que llega desde el ComPim de Proteus (puerto serie),el cual envia información actualizada cada 100 milisegundos. Intento actualizar la variable que la almacena dentro de un bucle infinito, mediante gets(inputData) pero no se actualiza,sino que continúa con el mismo valor que tenía al comienzo. Insertando en el simulador un terminal virtual sí vero todo lo que ocurre, pero necesito tratar esas cadenas desde el código

Siento mi ignorancia en el tema, agradezco de antemano cualquier ayuda!


----------



## TRILO-BYTE (Abr 4, 2014)

sube tu codigo , subraya tu duda y sube la imagen de simulacion


----------



## jmbegara (Abr 7, 2014)

Aquí va el código.
Conseguía obtener alguna información con el PIC18f4550, pero al cambiar al PIC16f877, Proteus no hace absolutamente nada. Si elimino las líneas de código correspondientes a la la comunicación ("gets(testInput)"), si que consigo encender del led D3 que asigno a la condición por defecto dentro de "switch". También subo una captura de pantalla con la simulación de Proteus.



```
#include <16f877.h>
#device adc=8
//fuses  PUT, HS, NOWDT, NOLVP, NOBROWNOUT
#FUSES XT,NOWDT, NOLVP,NOPROTECT                   //No Watch Dog Timer
#use delay(clock=20000000)
//#include <utility.c>
//#use rs232(baud=9600, bits=8, UART1, SYNC_SLAVE)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#define use_portb_lcd true//***
#include <lcd.c>            //***

 
#int_rda
void main()
{
   lcd_init();
   printf(lcd_putc, "\f");
   delay_ms(500);
   char testInput[20];
   gets(testInput);

while(1)
   {
    printf(lcd_putc,"\n %s",testInput);
          //{
             //data = getc();
             gets(testInput);
             delay_ms(100);
             //data=inputData[1];
             switch(testInput[9]){
             //switch(data){
             case 'g':output_high(PIN_A1);
                      output_low(PIN_A2);
                      output_low(PIN_A3);
                      printf(lcd_putc,"%s","g");
             break;
             case 'y':output_low(PIN_A1);
                      output_high(PIN_A2);
                      output_low(PIN_A3);
                      printf(lcd_putc,"%s","y");
             break;
             case 'r':output_low(PIN_A1);
                      output_low(PIN_A2);
                      output_high(PIN_A3);
                      printf(lcd_putc,"%s","r");

             break;
             case 'N':output_high(PIN_A1);
                      output_high(PIN_A2);
                      output_high(PIN_A3);
                      //printf(lcd_putc,"%s","VALUING");
                      printf(lcd_putc,"\n %s","N");

             break;
              default:output_low(PIN_A1);
                      output_low(PIN_A2);
                      output_high(PIN_A3);
                      printf(lcd_putc,"%s","default");
             break;

                           }
    }
}
```

Por cierto, hay alguna manera de mostrar valores de variables procedentes del código ccs en proteus?? (el LCD no me funciona en este caso, con el PIC18F4550 si lo hacia)


Muchas gracias!. 
(Siento las tildes, pero es que estoy escribiendo desde el extranjero)


----------



## luis1234567890 (Abr 7, 2014)

veo  que esta usando la librería lcd.c  entonces esta mal conectado el lcd en tu simulación 
pin6(enable) va al pin  rb0 
pin5(r/w) pin rb2
pin4 (rs)pin rb1

bueno si has modificado la librería estaría  bien entonces 
ademas la interrupción no tiene ninguna función a realizar


----------



## jmbegara (Abr 7, 2014)

Bueno, dado que el lcd me funciona para el PIC18F4550, he decidido continuar con el proyecto con el. El problema que tengo ahora es el siguiente: Consigo extraer la informacion en una cadena de caracteres "testInput", pero no soy capaz de hacer ninguna comparacion, dado que en switch, siempre me salta a la opcion "default". como puedo extraer una subcadena y pasarla a formato "double" para luego comparar con un "switch" y asi poder ejecutar cualquier accion en funcion de ese valor dado?. En codigo c++ normal podria, pero no lo consigo en ccs, ya que son diferentes funciones


Muchas gracias de nuevo!


----------



## jmbegara (Abr 7, 2014)

Basicamente lo que obtengo es una cadena tal como "CD000000NW0.000gTW0.0000, donde los ceros pueden ser cualquier cifra. Yo necesito extraer el "0.000" después de "NW", pasarlo a double y luego encender unos leds u otros según sea ese valor, pero no sé cómo hacerlo en c para el ccs compiler, ya que las funciones que he intentado no funcionan.

Muchas gracias luis por la respuesta, el lcd sigue sin funcionar, pero por el momento necesito centrarme en mi problema principal


----------



## TRILO-BYTE (Abr 7, 2014)

es que tu codigo esta medio raro amigo por eso tienes fallar

no se que quieres hacer exactamente , releyendo veo que quieres leer una cadena y convertirla a entero,
pero aparte metes condiciones si S , no N y asi.

hay 3 eventos S ,N y un numero 1234

el swich escoje si es S ,N y si es diferente a S y N el default es el numero

yo haria esto


char leido[10]; //leo lo que viene
int numero;

while(1)

{
gets(leido);

switch(leido[0]) //leo el primer char
{
case 'N':
 //codigo no
break;

case 'S':
 //codigo si
break;

default:

numero=atoi(leido);
//imprime numero

break;

}



}


no se si te sirva


----------



## jmbegara (Abr 7, 2014)

Por supuesto que me sirve, Trilo-Byte!. La instruccion "switch" que he incluido era solo para comprobar que detectaba el carácter y entraba en en la condición adecuada, ¡pero siempre se me va a "default"!, es como si ignorara todas las demás condiciones del switch ¿tendrá algo que ver con codificación de caracteres?. Mañana comprobaré tu código, pero ¿cómo podría extraer la cadena "0.000" desde la entrada original "CD00000NW0.000gTH0000?, ya que esa es la parte fundamental que contiene el valor a convertir a entero mediante "atoi" 

Muchas gracias por tu ayuda desinteresada!


----------



## TRILO-BYTE (Abr 7, 2014)

desinteresada no es que mi mente vuela tengo muchos problemas en el trabajo hay maquinas que necesitan examinarse y mi aprendiz que quedara en mi lugar.

bueno digamos que tengo CD00000NW0.000gTH0000 que tiene 21 letras y quiero obtener 0.000

digo si siempre conservare el formato X.XXX que tiene 5 letras el punto cuenta 
ejemplo 3.141 puedo sacarlo facilmente


char contador1=0;
char contador2=0;
char numero[6];
char cadena[22]="CD00000NW0.000gTH0000";

float flotante;

// hacemos un conteo con el numer de letras de la cadena 21 letras

for(contador1=0;contador1!=21; contador1++) 
{
   //cuando llega a 9 que es donde esta 0.000 empieza a copiar en la cadena
   if(contador1>=9) 
    {
       //como el numero 0.000 tiene 5 elementos despues de el 6 ya no copiara
       if(contador2<=5)
       {
          numero[contador2]=cadena[contador1]
        } 
      contador2++;
    }
}

flotante=atof(numero);


bueno supongo que debe funcionar  pero si funciona me rife


----------



## jmbegara (Abr 9, 2014)

Bueno, he modificado el código y he conseguido que funcione. Uno de los fallos que he tenido es que al extraer el array debía "cerrarlo" con un 0 al final, pero ya funciona.

Llegado a este punto positivo en que obtengo lo que quería, ahora me surgen varias dudas:

- El circuito con el que funciona es el utilizando el PIC18F4550 (Imagen 1), pero al intentar realizar exactamente lo mismo con el PIC16F877A (que me imagino sera mas barato) no funciona!. He creado una versión muy básica del programa para intentar buscar el problema, pero tampoco funciona (en la imagen 2 muestro una captura del registro de errores), aunque en el Virtual Terminal si que puedo ver la información que viene por el puerto serie.

- En la versión que si me funciona (con el PIC18F4550), si paro la simulación y la reinicio en Proteus, el código deja de funcionar y para resolverlo tengo que reconectar el cable de red, volver a crear el archivo .hex e iniciar la simulación de nuevo ¿alguna pista de por que esto ocurre? Lo que no quiero es que cuando construya el PCB final  me ocurra algo similar

- Finalmente, Trilo-Bite me decías al principio que debería usar un max232 para conectar el PIC con el puerto, pero no me ha hecho falta para la simulación. ¿lo necesitare para construir el circuito real? ¿no podría conectar los cables directamente a los pines del pic, tal y como hago en la simulación?

Y siento tantas preguntas, pero ya que medio he conseguido encarrilar el proyecto, me gustaría terminarlo con una mínima calidad.

Muchísimas gracias por todo, especialmente a Trilo-byte. Cualquier cosa que pueda ayudar, estaría encantado!

Saludos!

-



Olvidé adjuntar las imágenes.

Este el código "básico" que no consigo hacer funcionar con el PIC16F877A:

```
#include <16F877a.h>
#device adc=8
#FUSES XT,NOWDT, NOLVP,NOPROTECT                   //No Watch Dog Timer
//#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#define use_portb_lcd true
#include <lcd.c>

#include <stdio.h>
#include <stdlib.h>

#include <string.h>

/*
 * 
 */
void main() {

    printf(lcd_putc,"%s","hello!");
    char cadena[30];

    lcd_init();                         //Init LCD Display

    delay_ms(500);

    gets(cadena);                       //Read the incoming data
    
    printf(lcd_putc, "\f");
    printf(lcd_putc,"%s","test:!");
    printf(lcd_putc,"\n%s",cadena);     //show the string in the LCD


    output_high(PIN_A1);                //turn on a LED to discard any error in the code above


    while(1) {
    }
}
```


----------



## luis1234567890 (Abr 9, 2014)

Dejaste  tu programa en un bucle sin hacer nada deberías leer los datos que llegan.
Que quieres hacer exactamente recibir un número  binario y prender  una cierta cantidad de led.

El max232 es el mas utilizado ya que puesto que los niveles de voltaje en el pic varían desde 0 hasta 5 voltios, y el puerto serie del PC funciona desde +12V hasta -12V .El max232 cambia los niveles de voltaje que requiere la pc .


----------



## jmbegara (Abr 9, 2014)

Muchas gracias Luis,

El motivo de no hacer nada en el bucle es solo porque es un codigo de prueba, de manera que para el test solo leeria el dato que viene justo en el momento de ejecutar el programa, pero parece ser que se produce un error al leer la cadena de entrada "gets(cadena)", ya que ni siquiera se llega a encender el led. En cualquier caso, si mi programa funciona para el PIC18F4550 podria usar ese y olvidarme del 16f877a no?

Con respecto al max232, realmente el PIC va a recibir la informacion procedente de una balanza, sin intervencion alguna de un PC ¿aun asi seria necesario?. Esto entra ya dentro de lo que es el montaje final, del que seguro que me surgiran mil dudas :S


----------



## TRILO-BYTE (Abr 9, 2014)

aa pues el max232 es totalmente necesario en una comunicacion RS232 
en el proteus funciona sin problemas por que es una SIMULACION no es real

ahora veo que estas usando el PUERTO B en la LCD pero no imprime
eso es un BUG del CCS "el CCS luego da dolores de cabeza por sus famosos bugs "

pero veo que pusiste esto:

*#define use_portb_lcd true*

pero luego el CCS no lo respeta

hay que poner una directiva diferente por ejemplo yo queria poner mi LCD en el puerto D
y tube que usar una directiva diferente
como:

*#define LCD_DATA_PORT getenv("SFRORTD")*

un ejemplo de como escribir es el siguiente :  

#include <16f877.h>  

#fuses XT,NOWDT
#use delay(clock=4M)
#define LCD_DATA_PORT getenv("SFRORTD")
#include <lcd.c>



otra cosa tu codigo deberia ir asi



void main() {

lcd_init(); //Init LCD Display
char cadena[30];


printf(lcd_putc,"%s","hello!");

delay_ms(500);//retardo para mostrar mensaje








/* DEBE IR DENTRO DEL BUCLE PARA LEER REPETIDAMENTE LO QUE LLEGA DEL PUERTO*/


while(1) {

gets(cadena); //Read the incoming data

printf(lcd_putc, "\f");
printf(lcd_putc,"%s","test:!");
printf(lcd_putc,"\n%s",cadena); //show the string in the LCD


output_high(PIN_A1); //turn on a LED to discard any error in the code above
delay_ms(100);



}


}


----------



## Meta (Abr 11, 2014)

Hola:

Te muestro algunos ejemplos del PIC16F886 para el puerto COM.

*Ejemplo 8.1*

```
/*
El módulo USART. 
Transmisión asíncrona

El módulo USART de los dispositivos PIC16F87X incorpora el hardware necesario para implemen-
tar comunicación serie asíncrona full-duplex o sincrona half-duplex. En este último caso el
USART se puede comportar como Master o Slave.

El ejemplo transmite una trama cada segundo con el carácter ASCII de la letra A. */
    
#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (C)
#use delay(clock=4000000)

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
    
main()
{      
    SETUP_ADC_PORTS(NO_ANALOGS);    //Puerta A y B Digitales
    set_tris_c(0b10111111);            //RC7/Rx entrada, RC6/Tx salida
    
    while(1)
    {    
        putc('A');                    //Transmite el caracter
        delay_ms(1000);                //Temporiza 1 segundo
    }
}
```
*Ejemplo 8.2*

```
/*El módulo USART. 
Recepción asíncrona. 

El módulo USART de los dispositivos PIC16F87X incorpora el hardware necesario para implemen-
tar comunicación serie asíncrona full-duplex o sincrona half-duplex. En este último caso el
USART se puede comportar como Master o Slave.

En el ejemplo se provoca una interrupción cada vez que se recibe un carácter vía serie. El
programa de tratamiento visualiza, sobre los leds del laboratorio conectados a la Puerta B,
el código binario del carácter recibido. Igualmente retransmite el carácter recibido, a 
modo de ECO. */
    
#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#int_rda            //Vector de interrupción al recibir por el UART

//Función de tratamiento de la interrupción al recibir

tratamiento()
{    
    int    dato;                        //Variable para almacenar el dato recibido
    dato=getc();                    //Lee el dato recibido
    output_b(dato);                    //Lo saca por la puerta B
    putc(dato);                        //Lo transmite vía RS232    
}    
    
main()
{      
    SETUP_ADC_PORTS(NO_ANALOGS);    //Puerta A y B Digitales
    output_b(0x00);                    //Borra las salidas
    set_tris_b(0x00);                //Puerta B salida
    set_tris_c(0b10111111);            //RC7/Rx entrada, RC6/Tx salida
    enable_interrupts(INT_RDA);        //Activa interrupción en la recepción
    enable_interrupts(global);        //Habilita interrupciones
    
    while(1)
    {    

    }
}
```
*Ejemplo 8.3*

```
/* El módulo EUSART. Auto detección de baudios

El módulo EUSART de los dispositivos PIC18 soporta la auto detección automática de los baudios
del transmisor al que está conectado. Este ejemplo empieza tratando de sincronizar los baudios
y a continuación si limita a retransmitir, a modo de eco, los caracteres que se van recibiendo */

#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)            //Frecuencia de trabajo

#byte BAUDCTL= 0x187                //Registro de control de baudios

//Habilita las funciones RS232, a alta velocidad y generador de baudios de 16 bits

#use rs232(baud=57600,xmit=PIN_C6, rcv=PIN_C7)

//Función de tratamiento de la interrupción al recibir

#int_rda                            //Vector de interrupción al recibir por el UART
tratamiento()
{    
    int    dato;                        //Variable para almacena el dato recibido
    dato=getc();                    //Lee el dato recibido
    output_b(dato);                    //Lo saca por la puerta B
    putc(dato);                        //Lo retransmite    
}    

main()
{      
    SETUP_ADC_PORTS(NO_ANALOGS);    //Puerta A y B Digitales
    output_b(0x00);                    //Borra las salidas
    set_tris_b(0x00);                //Puerta B salida
    set_tris_c(0b10111111);            //RC6/TxD salida de datos y RC7/RxD entrada del EUSART    

/* Esta rutina trata de sincronizar de forma automática los baudios del EUSART con el del 
transmisor al que está conectado. Para ello espera a recibir el carácter 0x55 ("U")como 1er. 
carácter. De no ser así, el ajuste de baudios es totalmente incorrecto */

    bit_set(BAUDCTL,0);
    while(bit_test(BAUDCTL,0)==1);
    getc();

//Sincronismo realizado, activar transmisor e interrupciones    

    enable_interrupts(INT_RDA);        //Activa interrupción en la recepción
    enable_interrupts(global);        //Habilita interrupciones

    while(1)
    {    
    }
}
```
*Ejemplo 8.4*

```
/*
El módulo EUSART. Auto detección de baudios. Transmitiendo mensajes

El módulo EUSART de los dispositivos PIC18 soporta la auto detección automática de los baudios
del transmisor al que está conectado. Este ejemplo empieza tratando de sincronizar los baudios
y a continuación transmite una serie de mensajes almacenados en la memoria de programa */

#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)            //Frecuencia de trabajo

#byte BAUDCTL= 0x187                //Registro de control de baudios

//Habilita las funciones RS232, a alta velocidad y generador de baudios de 16 bits

#use rs232(baud=57600,xmit=PIN_C6, rcv=PIN_C7)

//Almacena en la memoria de programa todos los caracteres de las distinas cadenas o mensajes.

const char Mens_0[3][40]={    "Se ha producido la sincronizacion.   ",
                            "Ahora se transmiten estos mensajes   ",
                            "(c) Mikel Etxebarria (Orozko-Bizkaia)"};

int x;
int y;

main()
{      
    SETUP_ADC_PORTS(NO_ANALOGS);    //Puerta A y B Digitales
    set_tris_c(0b10111111);            //RC6/TxD salida de datos y RC7/RxD entrada del EUSART    

/* Esta rutina trata de sincronizar de forma automática los baudios del EUSART con el del 
transmisor al que está conectado. Para ello espera a recibir el carácter 0x55 ("U")como 1er. 
carácter. De no ser así, el ajuste de baudios es totalmente incorrecto */

    bit_set(BAUDCTL,0);
    while(bit_test(BAUDCTL,0)==1);
    getc();

//Sincronismo realizado, mandar CR y avance de línea inicialmente
    putc(0x0d);putc(0x0a);    //Transmite CR y avance de línea    

    while(1)
    {
        for(y=0;y<3;++y)
            {
            for (x=0;x<40;++x)        
                putc(Mens_0[y][x]);    //Transmite un mensaje
                
            putc(0x0d);putc(0x0a);    //Transmite CR y avance de línea            
            delay_ms(1000);            //Temporiza 1 seg.
            }                        //Siguiente mensaje
        putc(0x0a);                    //Transmite avance de línea
    }
}
```
*Ejemplo 8.5*

```
/* El módulo EUSART. Monitorización remota

Este ejemplo transmite, previa conversión a ASCII, el estado de las líneas de entrada 
RA7:RA0 a modo de monitorización */

#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (A)
#use fast_io (C)
#use delay(clock=4000000)            //Frecuencia de trabajo

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#byte PORTA =0x05                    //Dirección de la puerta A

main()
{  
    signed int Contador;

    SETUP_ADC_PORTS(NO_ANALOGS);                        //Puerta A y B Digitales
    set_tris_a(0b11111111);                                //Puerta A entrada    
    set_tris_c(0b10111111);                                //RC6/TxD salida de datos y RC7/RxD entrada del EUSART    
    putc('\r');                                            //Transmite CR
    putc('\n');                                            //Transmite avance de línea

    while(1)
    {
        for (Contador=7;Contador>=0;Contador--)            //Contador con Nº de bits a chequear
            printf ("%c",bit_test(PORTA,Contador)+'0');    //Transmite los bits convertidos a ASCII
            putc('\r');                                    //Transmite CR
    }
}
```
Ejemplo 8.6

```
/* 
El módulo EUSART. Control remoto y monitorización

Este ejemplo recibe una serie de comandos ('0'-'7') que permiten cambiar de estado las salidas
RB7:RB0. Constantemente se transmite, previa conversión a ASCII, el estado actual de esas salidas 
a modo de monitorización */

#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)            //Frecuencia de trabajo

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#byte PORTB =0x06                    //Dirección de la puerta B

/*Programa de tratamiento de la interrupción que se produce al recibir un carácter. Analiza el
comando recibido ('0' -'7') y actua sobre la salida apropiada haciéndola cambiar de estado */

#int_rda            //Vector de interrupción al recibir por el UART
tratamiento()
{    switch(getc())        //Lee el carácter recibido
    {
        case '0': output_toggle(pin_b0);break;    //Si es el comando '0' , RB0 cambia de estado
        case '1': output_toggle(pin_b1);break;    //Si es el comando '1' , RB1 cambia de estado
        case '2': output_toggle(pin_b2);break;    //Si es el comando '2' , RB2 cambia de estado
        case '3': output_toggle(pin_b3);break;    //Si es el comando '3' , RB3 cambia de estado
        case '4': output_toggle(pin_b4);break;    //Si es el comando '4' , RB4 cambia de estado
        case '5': output_toggle(pin_b5);break;    //Si es el comando '5' , RB5 cambia de estado
        case '6': output_toggle(pin_b6);break;    //Si es el comando '6' , RB6 cambia de estado
        case '7': output_toggle(pin_b7);break;    //Si es el comando '7' , RB7 cambia de estado
    }    
}

main()
{  
    signed int Contador;

    SETUP_ADC_PORTS(NO_ANALOGS);    //Puerta A y B Digitales
    output_b(0x00);                    //Borra las salidas
    set_tris_b(0b00000000);            //Puerta B salida
    set_tris_c(0b10111111);            //RC6/TxD salida de datos y RC7/RxD entrada del EUSART    
    putc('\r');                        //Transmite CR
    putc('\n');                        //Transmite avance de línea

    enable_interrupts(INT_RDA);        //Activa interrupción en la recepción
    enable_interrupts(global);        //Habilita interrupciones

    while(1)
    {
        for (Contador=7;Contador>=0;Contador--)    //Contador con Nº de bits a chequear
            printf ("%c",bit_test(PORTB,Contador)+'0');    //Transmite los bits convertidos a ASCII
            putc('\r');                //Transmite CR
    }
}
```

*Espero que tengas ejemplos que te puedan ayudar de verdad. También los tengo en asm.

Saludo.
*


----------



## jmbegara (Abr 11, 2014)

Meta muchísimas gracias!, este fin de semana intentaré analizar esos ejemplos que me envías, aunque yo de momento no he utilizado UART, porque veo que puedo avanzar sin recurrir a ese sistema, que parece más complicado. Aprecio de veras la molestia en subir los ejemplos.

En cuanto a la última cuestión que planteaba, creo que no me había explicado bien. Básicamente, lo que quería que hiciera mi programa lo he conseguido: leer continuamente una cadena de caracteres provenientes de una balanza y encender o apagar unos LEDs tras analizar los valores numéricos contenidos en esa cadena. Dicho programa lo he llevado a cabo con el PIC18F4550, MPLAB X IDE y el CSS compiler. El tema es que me he dado cuenta de que tengo disponible un PICF16F876A pero el "problema" es que no consigo que se ejecute correctamente el mismo programa para este último microcontrolador, concretamente la instrucción "gets(cadena)", y por eso subí ese código tan básico, para comprobar dónde estaba el problema. ¿hay alguna diferencia en la manera de obtener la información para diferentes PICs??. En cuanto al max232, la báscula a la que conecto el PIC ya me proporciona +5V, por que podría alimentar la PIC sin necesidad de ese circuito adicional no?

Espero haberme explicado bien, y si no lo he hecho antes pido disculpas

Muchas gracias! 

Mencionar por último que he eliminado todo lo que tenía que ver con el LCD, ya que lo coloqué tan solo para verificar los valores numéricos en tiempo real.


----------



## TRILO-BYTE (Abr 11, 2014)

mmm el problema del tiempo real y la LCD 
es que todos o la gran mayoria programa horrible y traban el micro

es decir si yo pongo delay_ms(1000); estoy atorando el micro "1 segundo" 
horrible pero cierto.

la LCD puede usarse sin problemas siempre y cuando no trabes el micro 

ahora UART es lo mismo que el RS232 PERO sin el max232 , eso se usa cuando quieres comunicar 2 micros sin hacer conexion RS232 es decir 0 a 5v

vaz bien solo trata de practicar mas ,con la practica aprendes mas y veras que lo que quieres hacer no es complicado


----------



## jmbegara (May 6, 2014)

Buenas a todos.
Después de una ligera pausa. 
Bueno, he conseguido finalmente programar el PIC16F876a para lo que yo quiero y que funcione para la simulación de Proteus que muestro en pantalla. 
Explico a continuación el montaje que he hecho por el momento: He conectado el oscilador y los condensadores al PIC, así como el pin RX al pin 2 del conector DB9 macho; pin 5 del DB9 directamente a 0V de la placa; MLCR directamente a 5V (4.50V exactamente); he alimentado el PIC con 4.50 Voltios externos (no desde el conector). Finalmente conecto el cable serie desde la bascula (que supuestamente me va enviar la cadena de caracteres) al conector macho.
Conecto la alimentación, pero no detecto nada por los pines de salida. Si tomo tensión entre Vss y el pin RX del PIC, obtengo un voltaje de 0.35V aproximado con la báscula encendida, si la apago baja a -0.85. Obviamente estoy haciendo algo mal porque no consigo lo que quiero, que es tener una salida por los leds en función de la cadena que entre desde la báscula.
En principio estoy alimentando 5 Voltios (aproximadamente) directamente, así que no debería necesitar el Max232 no?

Haciendo algunas pruebas veo que lo que no le gusta al montaje real es el "gets(cadena)", pero en Proteus la simulación funciona perfectamente!

Aquí va el código, por si os sirve de ayuda para ver que puede estar ocurriendo:


```
//*************************************************
/* 
 * File:   PicTest_16F876a_2.c
 * Author: Jose M
 * DEFINITIVE FOR DP
 * Created on 02 May 2014, 15:58
 */
//Proteus Design: ComTest5
//WORKS!!! 


#include <16f876a.h>
#device adc=8
#FUSES XT,NOWDT, NOLVP,NOPROTECT                   //No Watch Dog Timer
//#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <input.c>
#define STRING_SIZE 30


void set_LEDs(int16 NW, int16 LL, int16 LH);

void main()
{

    char cadena[STRING_SIZE];
    
    char numNW[4];
    char numLH[4];
    char numLL[4];

    float floatNW;
    float floatLH;
    float floatLL;


    int16 valorNW;
    int16 valorLH;
    int16 valorLL;

    while (1) {
        //Lectura del string de datos procedente de la balanza
        gets(cadena);
        //Extraccion de los valores numerico: NW, LH, LL
        if (cadena[1]=='N') {
           if (cadena[1+2]=='-') {
           } else{
               numNW[0]= cadena[1+2];
               numNW[1]= cadena[1+4];
               numNW[2]= cadena[1+5];
               numNW[3]= cadena[1+6];
               numNW[4]= 0;
               valorNW=atof(numNW);

               numLH[0]= cadena[1+11+1];
               numLH[1]= cadena[1+13+1];
               numLH[2]= cadena[1+14+1];
               numLH[3]= cadena[1+15+1];
               numLH[4]= 0;
               valorLH=atof(numLH);

               numLL[0]= cadena[1+20+2];
               numLL[1]= cadena[1+22+2];
               numLL[2]= cadena[1+23+2];
               numLL[3]= cadena[1+24+2];
               numLL[4]= 0;
               valorLL=atof(numLL);
           }
        }
    //Llamada a la funcion para el encendido/apagado de leds en funcion de los valores obtenidos
    set_LEDs (valorNW, valorLL, valorLH);
    }
}

void set_LEDs(int16 NW, int16 LL, int16 LH) {
//Encendido/apagado de leds en funcion de los valores de entrada
    //5 GRAMS AT THE MOMENT BY DIVISION (1LED=1division)
    //By default, all leds off
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
if (LH!=0 && LL!=0) {
    if(NW<=5) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>5 && NW<=LL-25) {
        output_high(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LL-25 && NW<=LL-20) {
        output_high(PIN_A0);
        output_high(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LL-20 && NW<=LL-15) {
        output_high(PIN_A0);
        output_high(PIN_A1);
        output_high(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LL-15 && NW<=LL-10) {
        //set_LED2();
        output_high(PIN_A0);
        output_high(PIN_A1);
        output_high(PIN_A2);
        output_high(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LL-10 && NW<=LL-5) {
        //set_LED1();
        output_high(PIN_A0);
        output_high(PIN_A1);
        output_high(PIN_A2);
        output_high(PIN_A3);
        output_high(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LL-5 && NW<LL) {
        output_high(PIN_A0);
        output_high(PIN_A1);
        output_high(PIN_A2);
        output_high(PIN_A3);
        output_high(PIN_A4);
        output_high(PIN_A5);
        output_low(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>=LL && NW<=LH) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_high(PIN_B0);
        output_low(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH && NW<=LH+5) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_low(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH+5 && NW<=LH+10) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_high(PIN_B2);
        output_low(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH+10 && NW<=LH+15) {
//        set_LED1();
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_high(PIN_B2);
        output_high(PIN_B3);
        output_low(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH+15 && NW<=LH+20) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_high(PIN_B2);
        output_high(PIN_B3);
        output_high(PIN_B4);
        output_low(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH+20 && NW<=LH+25) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_high(PIN_B2);
        output_high(PIN_B3);
        output_high(PIN_B4);
        output_high(PIN_B5);
        output_low(PIN_B6);
    }
    if(NW>LH+25) {
        output_low(PIN_A0);
        output_low(PIN_A1);
        output_low(PIN_A2);
        output_low(PIN_A3);
        output_low(PIN_A4);
        output_low(PIN_A5);
        output_low(PIN_B0);
        output_high(PIN_B1);
        output_high(PIN_B2);
        output_high(PIN_B3);
        output_high(PIN_B4);
        output_high(PIN_B5);
        output_high(PIN_B6);
    }
    }
}
//*************************************************
```
Vuelvo a pedir perdón por mi ignorancia en el tema.
Gracias una vez mas de antemano!


----------



## Meta (May 6, 2014)

Hola:

No olvidar para tener ideas esta parte del tema.
https://www.forosdeelectronica.com/...dena-recibida-puerto-serie-113171/#post904567

Saludo.


----------



## jmbegara (May 6, 2014)

Muchas gracias Meta. Mañana quiero probar esos códigos de ejemplo. Sin embargo, el problema que tengo es con el montaje real, ya q en la simulacion de Proteus mi código hace exactamente lo que quiero (según el esquema que he subido antes, pero todo falla al montar el circuito real...crees q hay algo mal en mi código q hace que no pueda llevarlo a la realidad?
Gracias!


----------



## jmbegara (May 7, 2014)

Meta, acabo de probar tu codigo simulandolo en Proteus pero, al igual que me ocurre con el mio, no consigo hacerlo funcionar en el prototipo real. 
La verdad es que estoy bastante frustrado: habia conseguido desarrollar el programa, simularlo, montar un programador para el Pic, programarlo, y ahora en la etapa final me falla

Sigo agradeciendo cualquier ayuda para terminar el proyecto


----------



## jvk85321 (May 7, 2014)

Conectas directo el puerto db9 al micro????

   

atte
jvk85321


----------



## luis30 (May 7, 2014)

jmbegara dijo:


> Meta, acabo de probar tu codigo simulandolo en Proteus pero, al igual que me ocurre con el mio, no consigo hacerlo funcionar en el prototipo real.
> La verdad es que estoy bastante frustrado: habia conseguido desarrollar el programa, simularlo, montar un programador para el Pic, programarlo, y ahora en la etapa final me falla
> 
> Sigo agradeciendo cualquier ayuda para terminar el proyecto



bueno tal ves no puedo dar una opinión exacta ya que no revise tus códigos pero las simulaciones en proteus no siempre funcionan como uno quiere físicamente, verificaste bien los Fuses del micro??, el MCLR el crystal y eso si es así, has una rutina de prueba algo sencilla donde recibas un carácter y envíes uno para probar tu circuito si funciona el problema es como tratas la recepción de datos del micro, para comunicar PIC-PIC no necesitas el max232, para comunicar el PIC-PC necesitas adaptar los niveles de voltaje con el max o con algún arreglo.


```
#int_rda
void rda_isr()
{
caracter=getc();
hay_dato=1;
}

void main()
{
set_tris_c(0b11000000);
set_tris_b(0x00);
set_tris_a(0x00);
PORTB=(0xFF);
PORTC=(0x00);
PORTA=(0x00);
//setup_adc_ports(AN0);
//setup_adc(ADC_CLOCK_INTERNAL);
hay_dato=0;
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);

while(1){

if (hay_dato==1){
hay_dato=0;
switch(caracter){
       case 'a':
       printf("a"); 
       break;
       case 'b':
       printf("b");
       break;
       case 'c':
       printf("c");
       break;
}
}
}
}
```


----------



## jmbegara (Nov 21, 2014)

Hola a todos de nuevo!

Quería comunicaros que finalmente conseguí el objetivo que proponía al comienzo del tema, gracias a todos vuestros comentarios. 

Mi PIC ya es capaz de descifrar la cadena de datos que entra por el pin RC7 (RX) y encender los correspondientes LEDs en función de la información contenida.
He conectado el PCB a la maquina y funciona "casi" perfectamente, y digo "casi" porque hay un pequeño problema, y es que si apago la maquina, los LEDs quedan encendidos según la última cadena de datos que le llegó al PIC (es como si quedara congelado en el último estado), claro, no queda bien.
Si la vuelvo a encender, el PIC vuelve a funcionar correctamente.
He estado buscando información sobre el tema pero no he encontrado nada especifico para esto.
En un intento de solucionarlo, he añadido un código para apagar todos leds si no hay variación en la entrada de datos tras un determinado número de cadenas de entrada:


```
while (1) {
//...
//codificacion del string de datos actual
//...
        if (valorNW==valorNW_Temp) {
            contador=contador+1;
        } else {
            contador=0;
        }

        if (contador<10) {
            //tratamiento de la cadena de texto (encendido de leds)...
        } else {
            //apagar todos los leds...
        }
//...
}
```
Y funciona bien, pero sólo mientras la maquina está encendida (efectivamente he creado un "sleep" mode para los leds), pero si apago la maquina de nuevo, se queda todo como estaba.
Si abro el Hyperterminal para ver que está pasando con la cadena de datos, al apagar la maquina, la lectura sigue siendo la última, pero obviamente no se "refresca".

Con lo que he podido investigar, y dada mi gran ignorancia en el mundo de los microcontroladores, intuyo que la solución puede pasar por el uso de interrupciones, pero sinceramente no veo como aplicarlas a mi problema

Espero haberme explicado bien, agradezco de antemano cualquier ayuda!

Saludos!

PD. Siento la ausencia de tildes y de algún que otro caracter, pero es que me encuentro en el extranjero, todo configurado en ingles.


----------

