Autor Tema: VARIOS PUERTOS SERIALES EN 16F877  (Leído 4317 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado jpaler

  • PIC10
  • *
  • Mensajes: 7
VARIOS PUERTOS SERIALES EN 16F877
« en: 22 de Noviembre de 2005, 00:49:00 »
Hola a todos los del f0r!t0 ....

...les cuento, necesito utilizar 3 puertos seriales en el pic 16f877 en c y no he podido encontrar un ejemplito que me pueda ayudar.

esto es muy urgente, ya llevo mucho rato en estas y no consigo adelantar nada, les AGRADESERIA MUCHISIMO si ustedes hechan un empujoncito en esto.

me imagino, q seria utilizar una por hardware y las otras dos por software, pero no se exactamente como...una ayudita porfis...

AMIGOS, MUCHAS GRACIAS POR SU ATENCION....

Desconectado RaDoN

  • Moderadores
  • PIC24H
  • *****
  • Mensajes: 1498
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #1 en: 22 de Noviembre de 2005, 08:23:00 »
No estoy muy seguro si eso se puede hacer, nunca lo he probado, pero mientras contesta alguien que si le haya picado el gusanillo en esto, prueba a poner varias direcctivas de CC para el RS232 (#use ...) con distintos pines, aver que pasa loco

Edito: ahora que lo pienso, como le indicas por cual envias, si las funciones son iguales IdeaRollEyes
Si juegas contra el mejor, pierdes como los demás.

Desconectado roc364

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 108
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #2 en: 22 de Noviembre de 2005, 15:16:00 »
Hola jpaler!!  Como bien dice radon, es posible hacerlo en ccs, utilizando un puerto por hardware ( en los pines C6 y C7 del 877 ) y los demas que declares seran por software.
Para identificar de que puerto entran o salen datos, tenes que usar la opcion STREAM del #use rs232.
mas o menos asi:

#use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7,STREAM=PUERTO1) //este seria por hardware
#use rs232(baud=9600, xmit=PIN_D4,rcv=PIN_D5,STREAM=PUERTO2) //este seria por soft
#use rs232(baud=9600, xmit=PIN_D6,rcv=PIN_D7,STREAM=PUERTO3) //este seria tambien por software.

y por ejemplo:

while (!kbhit(PUERTO1)))
{
      //lo que sea
}

ahi detectas solamente caracteres del puerto1.

bueno, saludos!!
Hay solo 10 tipos de personas, los que entienden el codigo binario, y los que no.

Viva La Patagonia Argentina!!

Desconectado pic_patagonia

  • PIC10
  • *
  • Mensajes: 21
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #3 en: 22 de Noviembre de 2005, 16:09:00 »
Me parece correcto lo que menciona el amigo roc364, identificando a las conexiones a través de los Streams debería poder usarse más de un puerto serie. Ahora una pregunta, en el caso del stream relacionado al puerto usado con la Uart del micro, podría usar la interrupción de llegada de caracter, y para los otros streams relacionados a puertos implementados por soft, deberían monitorearse todo el tiempo el nivel de la patilla configurada como Rx no?.
Siempre usé la Uart del micro, nunca otro puerto simulado por soft..¡¡¡

Desconectado roc364

  • Colaborador
  • PIC16
  • *****
  • Mensajes: 108
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #4 en: 22 de Noviembre de 2005, 20:11:00 »
Pic_patagonia: Hola!   Mira, yo hasta ahora siempre me las ingenie para usar los kbhit() con los STREAM, pero tengo entendido que se puede usar perfectamente la INT_RDA, con el puerto de hardware. Lo que no estoy seguro es de si se puede usar tambien la INT_EXT suponiendo que uno de los puertos por soft tenga configurada esa pata en RX.
Es una buena a prueba a realizar. capaz funcione!
Saludos!!
Hay solo 10 tipos de personas, los que entienden el codigo binario, y los que no.

Viva La Patagonia Argentina!!

Desconectado jpaler

  • PIC10
  • *
  • Mensajes: 7
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #5 en: 24 de Noviembre de 2005, 06:24:00 »
MUCHISIMAS GRACIAS, MUCHASCHOS POR SU COLABORACION...
...HARE UNAS PRUEBAS Y LUEGO LES COMENTO...

GRACIAS

Desconectado omibaya

  • PIC12
  • **
  • Mensajes: 57
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #6 en: 24 de Noviembre de 2005, 15:49:00 »
Bueno yo estoy trabajando en mi tesis, y estoy conectando una PC con un PIC maestro y 4 pics esclavos por medio del puerto serial y protocolo orientado a caracter, y los puertos virtuales del pic maestro (programados en CCS) funcionan correctamente, avisa si te funciona, para poner el codigo de mi programa, aunque mas adelante lo voy a poner

Desconectado jpaler

  • PIC10
  • *
  • Mensajes: 7
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #7 en: 24 de Noviembre de 2005, 17:22:00 »
omibaya, no importan mis pruebas, por favor si no es mucha molestia y publica el codigo que estoy seguro que servira para salir de muchas dudas, no solo a mi si no tambien muchos novatillos por hay...

en micaso necesito conectar el 16f877 con otro pic igual, un modem celular gsm/gprs y otro dispositivo raro,  y todo esto por serial...

publica tu codigo q estoy seguro me sera muy pero muy util
gracias amigo....

Desconectado omibaya

  • PIC12
  • **
  • Mensajes: 57
RE: VARIOS PUERTOS SERIALES EN 16F877
« Respuesta #8 en: 26 de Noviembre de 2005, 19:36:00 »
Aqui te paso el programa, bueno no lo he modificado, es tal como lo estoy usando, lo unico que havria que quitarle en la interrupcion por puerto serial seria el pin que uso para rs485, por lo demas esta correcto, hay 4 puertos virtuales, y uno que recepciona de la PC, cualquier pregunta, haganmela, aqui lo pongo, ya que no lo puedo subir como adjunto, sale que no hay espacio

/*--------------------------------------------------------------------------------------
           Funciones para recepcionar o enviar tramas
  --------------------------------------------------------------------------------------
  ----------------------------
   TRAMAS MAESTRO / ESCLAVOS:
  ----------------------------

  Trama de transmision a los canales RS232-A a RS232-C:

    *------------------------------------*
    |SOH|STX|ENQ|RS|D1|D0|ETX|CHECKSUM|CR|
    *------------------------------------*

  Trama de recepcion de los RS232-A a RS232-C. Es la misma para la PC. La diferencia es
  que los PIC D1 y D0 van de 00 a 16. En el caso de PC es de 00 a 47.

    *--------------------------------------*
    |SOH|STX|D1|D0|RS|C|D|U|ETX|CHECKSUM|CR|
    *--------------------------------------*

  Trama de comando que envia la el maestro a un esclavo indicando un PUERTO, una LINEA y
  el valor que puede tener la misma (0 ó 1)
    *-----------------------------------------------------*
    |SOH|STX|DC1|RS|PORT|RS|LINEA|RS|VALOR|ETX|CHECKSUM|CR|
    *-----------------------------------------------------*

   ----------------------
    TRAMAS PC / MAESTRO:
   ----------------------

   Trama que envia la PC para solicitar algun dato del buffer de los esclavos. Similar
   al comando que se emplea para solicitar los datos a los esclavos desde el maestro.

    *------------------------------------*
    |SOH|STX|ENQ|RS|D1|D0|ETX|CHECKSUM|CR|
    *------------------------------------*

   Trama de comando que envia la PC al maestro indicando en el campo CANAL el destinatario
    *--------------------------------------------------------*
    |SOH|STX|DC1|CANAL|PORT|RS|LINEA|RS|VALOR|ETX|CHECKSUM|CR|
    *--------------------------------------------------------*

    Caracteres de control. Tabla de codigos ASCII

     SOH - Comienzo de encabezamiento
     STX - Comienzo de texto
     D1 - Indicador de decenas del buffer
     D0 - Indicador de unnidades del buffer
     ETX - Final de texto
     ENQ - Pregunta
     Checksum - Suma en 8 bits de los valores anteriores
     CR - Retorno de carro
     RS - Separador de registros
     C  - Centenas
     D  - Decenas         
     U  - Unidades
     CANAL- Canal al cual se envia un comando desde la PC   

/*------------------------------------------------------------------------------------
            Definiciones y declaraciones
 -----------------------------------------------------------------------------------*/

  #define SOH 0x01          // Definicion de los caracteres. Tabla de codigo ASCII   
  #define STX 0x02
  #define ETX 0x03
  #define CR  0x0D
  #define LF  0x0A
  #define RS  0x1E
  #define EOT 0x04
  #define ACK 0x06
  #define NAK 0x15
  #define ENQ 0x05
  #define DC1 0x11

//-------------------------------------------------------------------------------------

  #define MAX_BUFFER     10      // Buffer para los datos de los esclavos
  static char buffer[MAX_BUFFER*3];

//-------------------------------------------------------------------------------------

  #define MAX_RX    11      // Buffer de recepcion. 11 posiciones
  static char buffer_rx[MAX_RX];   
  static int ptro_buffer_rx=0;      // Ptro a la sgte posicion que esta vacia

//-------------------------------------------------------------------------------------

  #define MAX_PREGUNTA   9           // Nro caracteres de la pregunta de la PC
  #define MAX_CONTROL1  12           // Nro caracteres del comando a un esclavo
  #define MAX_USART     12           // Buffer para Rx del Usart
  static char buffer_usart[MAX_USART];
  static int ptro_buffer_usart=0;   // Ptro a la sgte posicion que esta vacia

//-------------------------------------------------------------------------------------

  char truefalse;
  #bit flag      =truefalse.0      // Bandera de tx/rx en canales
  #bit tx_comando   =truefalse.1    // Indica si hay comando disponible en un canal
  #bit timeout_error   =truefalse.2   // timeout en la lectura de un canal

  char canal_comando;   // Indica a que canal se va a eniar un comando

//-------------------------------------------------------------------------------------

  #bit BIT_RS232A=PORTD.7   // Led indicador de actividad en el canal: RS232-A
  #bit BIT_RS232B=PORTD.6   // RS232-B
  #bit BIT_RS232C=PORTD.5   // RS232-C
  #bit BIT_RS232D=PORTD.4    // RS232-D, canal para transmitir los valores a la PC

/*-------------------------------------------------------------------------------------
             INTERRUPCION SERIAL
 -------------------------------------------------------------------------------------*/

  #byte   SPBRG_C=SPBRG      // Definicion de los registros que controlan el USART
  #byte   TXREG_C=TXREG
  #byte   RCREG_C=RCREG
  #bit   BRGH_C =TXSTA.BRGH   // Definicion de los bits. Registros Tx/Rx
  #bit   SYNC_C =TXSTA.SYNC
  #bit   TXEN_C =TXSTA.TXEN
  #bit   TX9_C  =TXSTA.TX9
  #bit   RX9_C  =RCSTA.RX9   
  #bit   CREN_C =RCSTA.CREN
  #bit   SPEN_C =RCSTA.SPEN
  #bit   TXIF_C =PIR1.TXIF   // Definicion de flag de Tx/Rx
  #bit   RCIF_C =PIR1.RCIF
  #bit   OERR_C =RCSTA.OERR   // Definicion de los bits de estado del USART en Rx
  #bit   FERR_C =RCSTA.FERR

/*-------------------------------------------------------------------------------------
                FUNCIONES
 -------------------------------------------------------------------------------------*/

// Rutina para la recepcion serial por interrupcion

static int dir_int;      // Convierte de ASCII a Nro. Dir de buffer a enviar
static char centenas_int;   // Centenas, decenas y unidades del dato a Tx
static char decenas_int;
static char unidades_int;   

#int_rda
rda_isr()
{
   // Recepcion de valores via interrupcion que son almacenados en buffer_usart

   if(ptro_buffer_usart < MAX_USART){
      if(!OERR_C && !FERR_C ){   // Revisa los bits de errores
            if( RCREG_C == EOT) ptro_buffer_usart=0;            
            else
               buffer_usart[ptro_buffer_usart++]=RCREG_C;
      }   
      else{            // Control de errores en USART
         CREN_C = 0;      // Reset OERR
         CREN_C = 1;         
         dir_int = RCREG_C;   // Reset del FERR
         ptro_buffer_usart=0;   // Reset del buffer del usart
      }   
   }
   else
      ptro_buffer_usart=0;

   // Verifica si tiene un mensaje de la PC tipo pregunta

   if(buffer_usart[2] == ENQ && ptro_buffer_usart == MAX_PREGUNTA){
            
      // Verifica checksum de la trama   
      if(buffer_usart[0]+buffer_usart[1]+buffer_usart[2]+buffer_usart[3]+
         buffer_usart[4]+buffer_usart[5]+buffer_usart[6]==buffer_usart[7]){   

         dir_int=( buffer_usart[4]-"0" ) * 10 + ( buffer_usart[5]-"0" );

         // Pasa a texto el contenido de buffer[dir]
         centenas_int = (buffer[dir_int] / 100)+"0";   
         decenas_int  = buffer[dir_int] % 100;
         unidades_int = (decenas_int % 10) +"0";
         decenas_int  = (decenas_int / 10) +"0";

         // Envio del mensaje a la PC
         #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ENABLE=PIN_C5)
         putc(SOH)         ;delay_ms(2);
         putc(STX)         ;delay_ms(2);
         printf("%02u",dir_int)      ;delay_ms(2);
         putc(RS)          ;delay_ms(2);
         printf("%03u",buffer[dir_int])   ;delay_ms(2);
         putc(ETX)         ;delay_ms(2);
         putc(SOH+STX+buffer_usart[4]+
              buffer_usart[5]+
              RS+centenas_int+decenas_int+
              unidades_int+ETX)
                     ;delay_ms(2);
         putc(CR);         ;delay_ms(2);

         // Hace cambio en el led indicador
         BIT_RS232D=0;delay_ms(100);BIT_RS232D=1;delay_ms(100);BIT_RS232D=0;
      }

      ptro_buffer_usart=0;   // Reset del buffer del USART
   }

   // Verifica si tiene un mensaje de la PC tipo pregunta

   if(buffer_usart[2] == DC1 && ptro_buffer_usart == MAX_CONTROL1){   

      // Verifica checksum de llegada
      if(buffer_usart[0]+buffer_usart[1]+buffer_usart[2]+buffer_usart[3]+
         buffer_usart[4]+buffer_usart[5]+buffer_usart[6]+buffer_usart[7]+
         buffer_usart[8]+buffer_usart[9]==buffer_usart[10]){
      
         if(buffer_usart[3]=="A") canal_comando=1;   // Elije el canal
         if(buffer_usart[3]=="B") canal_comando=2;
         if(buffer_usart[3]=="C") canal_comando=3;

         buffer_usart[3]=RS;   // Prepara trama que va a enviar al canal

         buffer_usart[10]=buffer_usart[0]+buffer_usart[1]+buffer_usart[2]+
                buffer_usart[3]+buffer_usart[4]+buffer_usart[5]+
                buffer_usart[6]+buffer_usart[7]+buffer_usart[8]+
                buffer_usart[9];

         tx_comando=TRUE;   // Indica en el bucle principal que hay
                  // mensaje. Esto para evitar colisiones
                  // en los accesos concurrentes

         // Hace cambio en el led indicador
         BIT_RS232D=0;delay_ms(100);BIT_RS232D=1;delay_ms(100);BIT_RS232D=0;
      }
      ptro_buffer_usart=0;   // Reset del buffer del USART
   }
}

void configurar_usart()
{   
   BRGH_C   = 1;   // 9600 para un XTAL de 4MHz
   SPBRG_C = 25;
   SYNC_C   = 0;   // Configuracion del TXSTA y RCSTA
   SPEN_C   = 1;   // Habilita pines de salida del USART
   TX9_C   = 0;   // 8 bits de datos en Tx
   TXEN_C   = 1;   // Habilita la transmision
   RX9_C   = 0;   // 8 bits de datos en Rx
   CREN_C   = 1;   // Recepcion continua
}

/*-------------------------------------------------------------------------------------
                FUNCIONES
 -------------------------------------------------------------------------------------*/
static int canal=0,posicion=0;

void valida_rs232()
{
   if(ptro_buffer_rx >= MAX_RX){   // Si hay mensaje completo
      // Calculamos el checksum de los datos que han llegado
      if(buffer_rx[0]+buffer_rx[1]+buffer_rx[2]+
         buffer_rx[3]+buffer_rx[4]+buffer_rx[5]+
         buffer_rx[6]+buffer_rx[7]+buffer_rx[8]==buffer_rx[9])
            buffer[canal*MAX_BUFFER+posicion]=(buffer_rx[5]-"0")*100+
                   (buffer_rx[6]-"0")*10+buffer_rx[7]-"0";
   }
}

static unsigned long timeout;      // Varibles para generar el timeout de un mensaje

int solicita_dato()
{   
   ptro_buffer_rx=0;      // Inicializa valores y calcula checksum  
   timeout_error=FALSE;
   timeout=0;

   if(canal==0){         
      #use rs232(baud=9600,xmit=PIN_B3,rcv=PIN_B2)   // RS232-A
      BIT_RS232A=0;      // Led que indica Tx
      putc(EOT);      delay_ms(2);      
      putc(SOH);      delay_ms(2);
      putc(STX);      delay_ms(2);
      putc(ENQ);      delay_ms(2);
      putc(RS);      delay_ms(2);
      putc(posicion / 10+"0");delay_ms(2);
      putc(posicion % 10+"0");delay_ms(2);
      putc(ETX);      delay_ms(2);
      putc(SOH+STX+ENQ+RS+ (posicion / 10+"0") + (posicion % 10+"0") +ETX);
               delay_ms(2);
      putc(CR);         
      do{
         while(!kbhit()&&(++timeout<50000)) delay_us(10);// Espera rpta con timeout
         if(kbhit()) buffer_rx[ptro_buffer_rx++]=getc();
            else timeout_error=TRUE;
         if(ptro_buffer_rx >= MAX_RX || timeout_error == TRUE)break;      
      }while(1);
      if(timeout_error == FALSE) BIT_RS232A=1;   // Led que indica Tx
   }

   if(canal==1){
      #use rs232(baud=9600,xmit=PIN_B4,rcv=PIN_B5)   // RS232-B   
      BIT_RS232B=0;         
      putc(EOT);      delay_ms(2);      
      putc(SOH);      delay_ms(2);
      putc(STX);      delay_ms(2);
      putc(ENQ);      delay_ms(2);
      putc(RS);      delay_ms(2);
      putc(posicion / 10+"0");delay_ms(2);
      putc(posicion % 10+"0");delay_ms(2);
      putc(ETX);      delay_ms(2);
      putc(SOH+STX+ENQ+RS+ (posicion / 10+"0") + (posicion % 10+"0") +ETX);
               delay_ms(2);
      putc(CR);         
      do{
         while(!kbhit()&&(++timeout<50000))delay_us(10);   // Espera rpta con timeout
         if(kbhit()) buffer_rx[ptro_buffer_rx++]=getc();
            else timeout_error=TRUE;   
         if(ptro_buffer_rx >= MAX_RX || timeout_error == TRUE)break;      
      }while(1);
      if(timeout_error == FALSE) BIT_RS232B=1;   
   }

   if(canal==2){
      #use rs232(baud=9600,xmit=PIN_D3,rcv=PIN_D2)   // RS323-C
      BIT_RS232C=0;   
      putc(EOT);      delay_ms(2);      
      putc(SOH);      delay_ms(2);
      putc(STX);      delay_ms(2);
      putc(ENQ);      delay_ms(2);
      putc(RS);      delay_ms(2);
      putc(posicion / 10+"0");delay_ms(2);
      putc(posicion % 10+"0");delay_ms(2);
      putc(ETX);      delay_ms(2);
      putc(SOH+STX+ENQ+RS+ (posicion / 10+"0") + (posicion % 10+"0") +ETX);
               delay_ms(2);
      putc(CR);            
      do{
         while(!kbhit()&&(++timeout<50000))delay_us(10);   // Espera rpta con timeout
         if(kbhit()) buffer_rx[ptro_buffer_rx++]=getc();
            else timeout_error=TRUE;
         if(ptro_buffer_rx >= MAX_RX || timeout_error == TRUE)break;      
      }while(1);
      if(timeout_error == FALSE) BIT_RS232C=1;   
   }

   if(timeout_error == TRUE || ptro_buffer_rx < MAX_RX) return 1;
   delay_ms(10);
   return 0;
}

/*--------------------------------------------------------------------------------------
             Fin de la libreria
--------------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------------
             Funcion principal
--------------------------------------------------------------------------------------*/

#zero_ram
void main()
{
     set_tris_a(0x00);     // Configura los puertos
     set_tris_b(0x24);
     set_tris_c(0x80);
     set_tris_d(0x04);
     set_tris_e(0x00);

     #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,ENABLE=PIN_C5)
     putc(SOH);   
     delay_ms(2);    // Envia un caracter para indicar que el equipo esta operativo

     configurar_usart();    // Configura el usart
     enable_interrupts(INT_RDA); // Habilita la interrupcion del Rx Serial
     enable_interrupts(global);    // Habilita el GIE      
     tx_comando=FALSE;   

     do{

   // Lectura de los valores que estan en los esclavos
   flag=FALSE;         
   for(posicion=0;posicion<MAX_BUFFER;posicion++){
      flag = solicita_dato();
      if(flag==FALSE) valida_rs232();
         else    
         for(posicion=0;posicion<MAX_BUFFER;posicion++)
            buffer[canal*MAX_BUFFER+posicion]=0x00;   
   }

   canal++;       // Representa el cambio de canal que leemos (0,1,2)
   if(canal==3) canal=0;

   if(tx_comando==TRUE){      // Si hay comando para transmitir
      if(canal_comando==1){   
         #use rs232(baud=9600,xmit=PIN_B3,rcv=PIN_B2)   // RS232-A
         putc(EOT);
         delay_ms(2);
         for(posicion=0;posicion<MAX_CONTROL1;posicion++){
            putc(buffer_usart[posicion]);
            delay_ms(2);
         }
         putc(EOT);
         delay_ms(2);
      }
      if(canal_comando==2){      
         #use rs232(baud=9600,xmit=PIN_B4,rcv=PIN_B5)   // RS232-B   
         putc(EOT);
         delay_ms(2);
         for(posicion=0;posicion<MAX_CONTROL1;posicion++){
            putc(buffer_usart[posicion]);
            delay_ms(2);
         }
         putc(EOT);
         delay_ms(2);
      }
      if(canal_comando==3){
         #use rs232(baud=9600,xmit=PIN_D3,rcv=PIN_D2)   // RS323-C
         putc(EOT);
         delay_ms(2);
         for(posicion=0;posicion<MAX_CONTROL1;posicion++){
            putc(buffer_usart[posicion]);
            delay_ms(2);
         }         
         putc(EOT);
         delay_ms(2);
      }
      tx_comando=FALSE;   // Resetea bandera de transmision de comando
   }
     }while(TRUE);   
}