# Comunicar pic18f4550 por rs232



## darianpc (Oct 7, 2014)

Como puedo comunicar un pic18f4550 por rs232 hacia la PC. Hice el sig. programa en ccs compiler y lo simule en proteus y si se logra la adquisición de datos por la hiperterminal pero al montarlo físicamente la información que se envía al PC es solo basura.
#include <18f4550.h>
#device adc=10
#FUSES INTHS,MCLR,PUT,BROWNOUT
#use delay(INTERNAL=4MHZ)
#use rs232 (BAUD=9600 , XMIT=PIN_C6 , RCV=PIN_C7)
#include <LCD.C>

void main() {
   int16 q;
   float p;
   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_INTERNAL);
   lcd_init();
   for (;; ) {
      set_adc_channel(0);
      delay_us(10);
      q = read_adc();
      p = 5.0 * q / 1024.0;
      printf(lcd_putc, "\\fADC = %4ld", q);
      printf(lcd_putc, "\\nVoltage = %01.2fV", p);
      printf("ADC = %4ld ", q);
      printf("Voltage = %01.2fV\\r", p);  // El \\r permite cambiar de línea.
      delay_ms(100);
      }



pero cuando hago la coneccion fisica por medio de un max232 solo llega pura basura a la  hyperterminal de la  PC y ya verifique que se reciba la info con codigo ascii espero alguien me pueda decir donde esta el error gracias


----------



## TRILO-BYTE (Oct 7, 2014)

¿tiene bootloader?

si tiene hay que reconfigurar el PLL prescaler


----------



## darianpc (Oct 7, 2014)

esto es lo que me da cuando lo hago fisicamente


----------



## TRILO-BYTE (Oct 7, 2014)

cuando manda basura es por que el reloj interno no esta bien configurado

es decir el pic18f4550 tiene un reloj de 4Mhz pero pasa a un prescaler que lo hace funcionar a mayor frecuencia.

¿por que pasa?

pues por que como tiene un modulo USB este debe trabajar a 48Mhz 
entonces dependiendo el reloj es el prescaler que usa para llegar a los 48Mhz

pero si no estamos confugurando los FUSES del PLL puede que no nos trabaje la velocidad adecuada
y este haciendo lo que se le da la gana.
esta es la imagen de un cristal a 20 Mhz y se ve como sigue la linea para llegar a los 48mhz

Ver el archivo adjunto Dibujo.bmp


si nosotros usamos el FUSE XT indica que trabaja con un cristal de cuarzo
el FUSE CPUDIV1 indica que no habra prescaler y el CPU trabajara a la frecuencia del cristal externo



yo pondria asi los fuses

#FUSES XT,NOWDT,CPUDIV1,PLL1


eso de los fuses puedes revisarlo en la hoja de datos del PIC y en el CCS en donde dice valid fuses el boton que tiene un icono en forma de bomba


----------



## darianpc (Oct 7, 2014)

Muchas gracias TRILO-BYTE si era el problema de el programa y con la configuracion que me recomendaste quedo ahora tengo que comunicar 2 pics pero creo que sera mas facil por que ya le pude sacar datos al 18f4550. ¿Sera posible hacerlo de un 16f876a a un 18f4550? Bueno lo voy hacer aver que ocurre. Muchas gracias!!!...


----------



## TRILO-BYTE (Oct 7, 2014)

de pic, avr ,pc se puede

solo recuerda que cada fuse es especial para cada micro , el 4550 se le reconfigura el reloj por que como ya dije tiene un modulo USB que debe correr a 48Mhz si se esta usando, si no se usa este modulo se reconfiguran los PLL prescaler y el CPUDIV.
en otros modelos de microcontrolador esto no pasa pues no hay modulos USB.


----------



## darianpc (Oct 8, 2014)

TRILO-BYTE dijo:


> de pic, avr ,pc se puede
> 
> solo recuerda que cada fuse es especial para cada micro , el 4550 se le reconfigura el reloj por que como ya dije tiene un modulo USB que debe correr a 48Mhz si se esta usando, si no se usa este modulo se reconfiguran los PLL prescaler y el CPUDIV.
> en otros modelos de microcontrolador esto no pasa pues no hay modulos USB.



OK muchas gracias. Y estoy tratando de comunicar los pics pero el 16f876 esta con un cristal de 4MHZ por lo cual supongo que tendre que tener la misma frecuencia en el 18f4550 pero no se si deverdad lo estoy hciendo bien ya que veo que las diviciones que se hacen en el pll no me dan o mas bien no se como declararlas para que me salgan 4MHZ. El 4550 tiene un cristal de 20MHZ....  . Esta bien lo que estoy tratando de hacer? o eso no es posible jeje


----------



## martin12as (Oct 8, 2014)

por un lado.. para cristales mayores o iguales a 4 mhz, el fuse que tenes que poner es HS, 
XT es para 4mhz para abajo. 4 mhz esta justo en el limite donde podes usar cualquiera de los 2

pero por otro lado hay que aclarar que la velocidad del puerto rs232 la configuras vos, y se configura de forma independiente a la del oscilador.
podes tener un pic funcionando a 4mhz y otro a 20 mhz, sin embargo la velocidad de la uart la configuras en los pic a 9600 baud y no habría ningún problema.

en fin, resumiendo los pasos que tienes que seguir para configurar los 2 pic:

#FUSES dependiendo si usas un cristal de cuarzo o si usas el oscilador interno pones el que corresponda.. por ejemplo hs, xt, intrc_io etc, también podes usar hspll etc. te recomiendo que abras el archivo 18F4550.h y ahí ves todos los fusibles validos, fíjate para que sirve cada uno y usa los que te hagan falta

luego tu usas esta funcion.. #use delay(INTERNAL=4MHZ) yo la escribo de esta forma #use delay(clock=8000000) para un pic que funciona a 8mhz, tendrías que poner la velocidad a la que funciona cada uno de tus pics, teniendo en cuanta el pll, cpudiv, etc, por ejemplo #use delay(clock=48000000) para 48mhz, o #use delay(clock=4000000) para 4mhz

y por ultimo configuras el puerto rs232, esto es bastante simple, solo tenes que usar

#use rs232 (BAUD=9600 , XMIT=PIN_C6 , RCV=PIN_C7)

obviamente cambias el pin de xmit y rcv por el que corresponda en cada pic y el baud si o si tiene que ser el mismo valor en ambos pic, porque sino no van a poder entenderse. esto es lo que define la velocidad de la trasmisión y es independiente del cristal que use cada uno, pero tenes que tener bien las otras configuraciones para que ande


----------



## TRILO-BYTE (Oct 9, 2014)

para :darianpc

si tu micro el 4550 corre con un cristal es independiente que otro micro corra a otra velocidad.

los fuses como dije vienen en la datasheet pero en el CCS estan en un icono que tiene forma de bomba y dice Valid Fuses.

el fuse HS sirve para resonadores que no son cristales de cuarzo son parecidos pero diferentes 
para un cristal de 20 Mhz es el mismo fuse XT

para un micro que tiene un cristal de 20Mhz 

el dibujito que subi sigue la flecha del CPUDIV y este divide a una frecuencia de trabajo independiente a la del cristal

si tienes un cristal de 20Mhz y un CPUDIV1 el CPU trabajara a 20Mhz
pero si tienes el CPUDIV2 el CPU trabajara a 10Mhz siendo el cristal de 20Mhz


----------



## MetalKaiser (Oct 23, 2014)

Bueno, yo estoy haciendo algo similar, pero se trata de comunicar 2 pics (4550 y 2550) a través de rs232. La idea es que el 4550 lea un voltaje y lo envía por rs232 al 2550. Ambos deben mostrar el dato de voltaje en cuestión, y cada pic tiene 2 leds; uno rojo que permanece encendido mientras no haya envío o recepción de datos, y uno verde que enciende cuando ocurre la comunicación. El código que hice funciona perfectamente en Proteus, pero cuando hago el montaje físico, todo funciona menos las pantallas LCD que ni siquiera encienden. Las probé para descartar que estuviesen dañadas, pero las pantallas están perfectamente, por lo que no entiendo cuál es el problema. Les adjunto el código, algunas imágenes y los .hex con la simulación en Proteus para que vean todo en detalle...

Los códigos están en el .rar, pero acá se los dejo:
*MAESTRO:*


```
#include <18F4550.h>
#DEVICE ADC=8
#fuses HSPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7,enable=pin_a1)
#include <lcd.c>

int16 q;

int main(void)
{
 setup_adc_ports(ALL_ANALOG);
 setup_adc(ADC_CLOCK_INTERNAL);
 set_adc_channel(0);
 lcd_init();
while(1)
{
 output_high(pin_a1);
 delay_ms(20);
 q=read_adc();
 if(q>87)
 {
  output_low(pin_a1);
  lcd_gotoxy(1,1);
  printf(lcd_putc,"Enviado= %Lu",q);
  putc(q);
  output_high(pin_a2);
  delay_ms(100);
  output_low(pin_a2);
  lcd_putc("\f");
 }
}
}
```

*ESCLAVO:*

```
#include <18F4550.h>
#fuses HSPLL,MCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48000000)
#use RS232(BAUD=9600, XMIT=PIN_C6, RCV=PIN_C7)
#include <lcd.c>

int16 q;
float volt,b;

#int_RDA
RDA_isr()
{
  q=getc();
  b=q;
  volt=b*5/255;
  output_high(pin_a0);
  output_low(pin_a1);
  lcd_gotoxy(1,1);
  lcd_putc("\f");
  printf(lcd_putc,"Recibido= %f", volt);
  delay_ms(60);
}
int main (void)
{
 lcd_init();
 enable_interrupts(INT_RDA);
 enable_interrupts(GLOBAL);
 for(;;)
 {
  output_low(pin_a0);
  output_high(pin_a1);
 }
}
```


----------



## D@rkbytes (Oct 23, 2014)

MetalKaiser dijo:


> La idea es  que el 4550 lea un voltaje y lo envíe por rs232 al 2550.
> Ambos deben  mostrar el dato de voltaje en cuestión, y cada pic tiene 2 leds; uno  rojo que permanece encendido mientras no haya envío o recepción de  datos, y uno verde que enciende cuando ocurre la comunicación.
> El código  que hice funciona perfectamente en Proteus, pero cuando hago el montaje  físico, todo funciona menos las pantallas LCD que ni siquiera  encienden. Las probé para descartar que estuviesen dañadas, pero las  pantallas están perfectamente, por lo que no entiendo cuál es el  problema.


Trabajar con 48MHz para usar una comunicación por RS-232 a 9600 bps, es un valor muy alto y aparte está mal la palabra de configuración.
Prueba con un valor más bajo, por ejemplo con 8MHz, (Puedes usar el oscilador interno.)

Si vas a usar el ADC a 8 bits, la variable *"q"* no tiene por que ser de 16 bits.
Muestra el valor usando ceros a la izquierda para que no se confunda la lectura.
Y tampoco es recomendable estar borrando constantemente la pantalla, pues se verán parpadeos.

Cuando corrijas la palabra de configuración y trabajes con una frecuencia menor, ya deberá funcionar físicamente.


----------



## MetalKaiser (Oct 24, 2014)

*D@rkbytes*: Cuando dices "palabra de configuración" te refieres a los FUSES cierto? Porque vi que efectivamente tenía un par de errores en esa parte debido a que me distraje. 

Ya le bajé un poco la frecuencia y en la simulación corre mucho más rápido, ahora me falta probar en físico, ya contaré como me va montando en protoboard. El problema antes de consultar acá no era tanto la comunicación rs232, la cual parecía funcionar bien, el problema era que las pantallas LCD ni siquiera encendían, y probé hace 12 horas que ambas pantallas están en perfecto estado.

Dejare adjunto cómo van los códigos y las simulaciones hasta ahora...

Por cierto, si dejo la "*q*" del master en int8, su pantalla LCD en proteus muestra lo que le da la gana; pero si la dejo en int16, entonces muestra el dato correctamente. Obviamente la estoy cagando pero por ahora no me preocuparé tanto por eso, al menos no por ahora...


----------



## D@rkbytes (Oct 24, 2014)

MetalKaiser dijo:


> *D@rkbytes*: ¿Cuando dices "palabra de configuración" te refieres a los FUSES cierto?
> Porque vi que efectivamente tenía un par de errores en esa parte debido a que me distraje.


Sip, los fuses forman parte de la palabra de configuración.


MetalKaiser dijo:


> Ya le bajé un poco la frecuencia y en la simulación corre mucho más rápido, ahora me falta probar en físico, ya contaré como me va montando en protoboard.
> El problema antes de consultar acá no era tanto la comunicación rs232, la cual parecía funcionar bien, el problema era que las pantallas LCD ni siquiera encendían, y probé hace 12 horas que ambas pantallas están en perfecto estado.


Olvidé mencionar que la frecuencia de simulación en ambos microcontroladores la tienes en 4MHz.
Si hubieras realizado las pruebas físicamente y en el supuesto caso que los microcontroladores estuviesen funcionando a 48MHz, simplemente la comunicación serial no se daría.
Se enviarían datos erroneos, pero en proteus muchas cosas funcionan cuando no deberían, y también por estar ambos microcontroladores operando a 4MHz.
La frecuencia de operación en PROTEUS, sí es importante y debes establecerla en sus propiedades.


MetalKaiser dijo:


> Por cierto, si dejo la "*q*" del master en int8, su pantalla LCD en proteus muestra lo que le da la gana; pero si la dejo en int16, entonces muestra el dato correctamente.


Pues debe ser por lo mismo, o por la forma en que estás realizando el programa.
Ya que también en el receptor estás sacando un valor float desde un valor entero de 8 bits.


----------



## MetalKaiser (Oct 24, 2014)

> en proteus muchas cosas funcionan cuando no deberían, y también por estar ambos microcontroladores operando a 4MHz.
> La frecuencia de operación en PROTEUS, sí es importante y debes establecerla en sus propiedades.



^ Tienes mucha razón.



> Pues debe ser por lo mismo, o por la forma en que estás realizando el programa.



^ Me inclino por lo segundo.

Aún no he logrado probar en el protoboard, solo cuento con el programador JDM y mi Pickit2 Clone aún no está listo; es difícil conseguir una PC con puerto COM...


----------



## martin12as (Oct 24, 2014)

MetalKaiser dijo:


> es difícil conseguir una PC con puerto COM...



fijate que hay muchos modelos que traen los pines en la placa madre para conectar un puerto serial


----------



## jaochoam (Nov 19, 2014)

buen dia tengo una duda, haber si alguien pudiera resolvermela, se puede enviar o recibir un vector via putc,getch por el protocolo rs232


----------



## TRILO-BYTE (Nov 20, 2014)

no entendi bien que preguntaste pero supongo que quieres es:

enviar un dato numerico como 123.45
no se puede con putc

enviar 123 tampoco

el RS232 solo envia caracteres mas no numeros

para enviar una cadena debes enviar todo lo que hay en la cadena ejemplo

*char cadena="DAVID C";*

lo puedo enviar caracter a caracter hasta terminar la cadena con putc puesto que putc envia solo 1 caracter asi:

*while(cadena != '\0' )
{
putc(cadena);
i++;
}*_

como dije este algoritmo es para enviar lo que hay en mi cadena hasta llegar a caracter nulo

hay una manera mas facil que es usar el printf donde imprimimos toda la cadena

*printf(%s,cadena);*

para enviar un numero debes enviar toda la cadena y en el receptor debes hacer algo que convierta la cadena en un numero_


----------



## jaochoam (Nov 20, 2014)

por ahi va a lo que me comentas es imposible lo que yo quiero. un poquito mas especifico ejemplo.
salida[0]=123;
salida[1]=123;
salida[2]=123;
salida[3]=123;
enviar salida(completo) via rs232 a labview para en labview descomponer salida en cada uno de sus valores. muchas gracias por responder


----------



## TRILO-BYTE (Nov 20, 2014)

a caray alguien que no tiene idea de como solucionarlo me dice que estoy mal jaja bueno 

es que digamos que quieres enviar 123 
lo debes convertir a cadena de caracteres la forma mas facil es el printf en CCS en otro compilador seria algo asi

char *cadena;
int valor=123;
sprintf(cadena,"%d",valor);

asi se transforma el valor entero a cadena y de ahi se envia al puerto

ahora si queremos enviar un valor numerico sin convertir seria asi:

*unsigned char valor;*
el unsigned es para que valla de 0 a 255 no podemos enviar un int pues es mas grande y ocupa 4 bytes
y seria asi nada mas

*putc(valor);*


----------



## jaochoam (Nov 21, 2014)

jajaja perdon fue un error de gramatica. no queria decir eso perdon. es que lo que yo necesito es enviar varios valores por el mismo buffer. mi proyecto consta de 4 sensores de temperatura. y deceo enviar las lecturas de los ADC, por un mismo buffer y en labview desplegar la informacion de los sensores por separados. y perdon por el comentario esa no era la intencion todavia que busco apoyo. gracias y saludos



y es que sabes que lo habia hecho via usb pero lo migre a rs232 por la compatibilidad de las frecuencias con la lcd. te mando el codigo de usb para haber si logro darme a entender.
   while (TRUE) 
   {
      usb_task();
      if (usb_enumerated()) 
      {
         if (usb_kbhit(1)) 
         {
            output_high(PIN_D2);
            usb_get_packet(1, Entrada, 3);
            if (Entrada[0]==1)
                  {    
                  output_high(PIN_D3);
                  set_adc_channel(0);
                  a=read_adc();
                  Salida[0]=a*0.4883;
                  delay_ms(10);

                  set_adc_channel(1);
                  b=read_adc();
                  Salida[1]=b*0.4883;
                  delay_ms(10);

                  set_adc_channel(2);
                  c=read_adc();
                  Salida[2]=c*0.4883;
                  delay_ms(10);

                  Salida[3]=200;    //valor arbitrario 
                  Salida[4]=200;    //valor arbitrario 
                  Salida[5]=200;    //valor arbitrario 
                  Salida[6]=200;    //valor arbitrario 
                  Salida[7]=200;    //valor arbitrario 
                  usb_put_packet(1, Salida, 8, USB_DTS_TOGGLE);    //ESTO ES LO QUE QUIERO HACER
                  }                                                                    //VIA RS232 ENVIAR LOS 8 BITS
           if (Entrada[0]==0)
                  {      
                  LED_OFF(PIN_D3);
                  }
         }
      }


----------



## TRILO-BYTE (Nov 21, 2014)

es que el buffer del RS232 es de 1 byte y sus bits paro y stop
mientras que el del USB son 64 bytes bueno quitandole el primer byte para hacer cositas

no entendi eso de las frecuencias
nunca he usado el USB en CCS en C18 nadamas y puedo decir que los delay le dan en la torre al codigo en USB

asi que no los uso pues la LCD y el CPU trabajan a una velocidad independiente al puerto USB un delay en el CPU puede truncar la sincronia ,CCS no se como lo soluciono

en USB si puedes hacer esto:

unsigned char buffer[64];

y hacer esto:

buffer[1]=algo;
buffer[2]=algo;
buffer[3]=algo;
buffer[4]=algo;
buffer[5]=algo;

y enviar todo eso de una vez pues tienes 64 bytes para enviar de un golpe en cambio RS232 lo debes enviar de 1 en 1

digamos que tengo esto
buffer[1]=algo;
buffer[2]=algo;
buffer[3]=algo;
buffer[4]=algo;

tengo 2 formas de enviarlo con un putc dentro de un for hasta acabar con todo mi buffer digamos 4 bytes enviamos 4 veces

o enviarlos como cadena de caracteres aunque no contenga caracteres enviamos lo que hay asi:

*printf("%s"buffer);*
siendo que nosotros llenamos previamente los buffer_ con valores numericos el printf se encarga de enviarlos todos hasta llegar a null_


----------



## jaochoam (Nov 21, 2014)

que bien me diste una muy buena solucion, con el ciclo for. yo pensaba que al igual que en usb, podria enviar con rs232. pero este ultimo esta muy limitado. pero en fin hay muchos caminos diferentes para enfrentar esas limitacions. muchas gracias y a seguir aprendiendo. saludos


----------



## TRILO-BYTE (Nov 21, 2014)

es que no pienses que es limitado es alrevez es mas rapido que en modo HID
el problema es que nosotros no lo vemos como un protocolo lo vemos como algo obsoleto

bueno el RS232 es bueno a diferencia del USB se necesita un driver para CDC y en modo HID o mass storage device no se necesita un driver pero la complejidad es mayor, en CCS desconosco como esta construida la capa del USB a ojo de buen cubero se parece a la capa 9 del USB pero no se como le hiso CCS para poder meter cuanto Delay es necesario.

como decia el for te enviara los datos pero digamos que es un 
*unsigned char *cadena;*

donde meteremos cuantos datos sin signo son posibles a la cadena ¿hasta cuando enviaremos los datos?

seria asi:

*
while(cadena!=NULL)
{
putc(cadena);
i++;
}
*_

o con un for tambien ó mas facil
*
printf("%s",cadena);
*
asi enviamos de un tajo toda la cadena
el chiste es tener nociones de programacion antes de culpar a quien te da la mano o culpar al protocolo.

ejemplo:

un coche choco con otro coche ¿cual fue el problema el coche?
solucion 
el problema esta entre el asiento y el volante_


----------



## guti117 (Abr 9, 2015)

hola,
Antes que nada quiero agradecer a Trilo-Byte que me soluciono un problema sin él saberlo, me paso lo mismo que a darianpc. Esto me pasa por ser principiante y no estudiar bien el significado de los FUSES en cada PIC.

Bueno, ahora la consulta.
Quiero recibir datos con el pic18f4550 por rs232 y almacenarlos en un buffer para así poder utilizarlos a mi manera, sean números o letras.
Quisiera saber si alguien me podría dar una mano con esto.

Desde ya muchas gracias.
Saludos.


----------



## D@rkbytes (Abr 11, 2015)

guti117 dijo:


> Quiero recibir datos con el PIC18F4550 por RS-232 y almacenarlos en un buffer para así poder utilizarlos a mi manera, sean números o letras.
> ¿Quisiera saber si alguien me podría dar una mano con esto?


¿Y cuál es el problema o qué es lo que piensas hacer?


----------



## guti117 (Abr 15, 2015)

D@rkbytes, muchas gracias por interesarte en mi problema. Te cuento ya logre hacerlo, pese a que todavia estoy puliendo el programa.
La idea mia es, que al recibir informacion por serial al pic, el pic lo almacene en una variable para luego poder leerla y compararla con otra informacion, por ejemplo recibo una palabra y la comparo con otra palabra guardada en una variable diferente. Buscando informacion, y estudiando un poquito lo logre hacer, ya que soy principiante en esto. Nuevamente te agradesco por ayudar y ya caere con alguna otra pregunta jeje. Saludos!


----------

