Autor Tema: UART PIC24 Metodos While  (Leído 2114 veces)

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

Desconectado Rikr09

  • PIC16
  • ***
  • Mensajes: 112
UART PIC24 Metodos While
« en: 15 de Septiembre de 2012, 13:55:50 »
Muy Buenas amigos de todoPIC

Estoy usando un PIC24FJ128GA310.

 Nuevamente vengo con preguntas e inquietudes que espero por favor me ayuden a resolver.

En otro foro preguntaba por el protocolos MODBUS, y les comento que tengo un problema o mas bien no se como hacer para recibir la trama que recibo por el UART. La funcion que me permite hacer esto es el siguiente :

Código: [Seleccionar]
void Recibir_Trama_Modbus(){

   
    unsigned int ConRX_1, ConRX_2, Cont;
    ConRX_2 = 0x001F;
    ConRX_1 = 0x00FF; Cont = 0; Cont_valor_trama = 0;


    while (Cont < 256){
        if( int2 > 0){
            Trama[Cont++] = Dato2;
            ConRX_1 = 0x00FF; int2 = 0;
        }
        ConRX_1--;
        if( ConRX_1 == 0 ){ ConRX_1 = 0x00FF; ConRX_2--;
            if( ConRX_2 == 0 ){ Trama[Cont] = 0x00; Cont_valor_trama = Cont; Cont = 256; int2 = 0;}
        }
    }
   
   
//    for(i=0;i<Cont_valor_trama;i++){ U2(Trama[i]); }
    Interpretacion_Trama();
//    for(i=0;i<Cont_valor_trama;i++){ Trama[i]=0; }
   U2MODEbits.WAKE = 1; U1MODEbits.WAKE = 1;
}

Como se daran cuenta mi trama la recibo en el vector "Trama".

Cuando mando un dato por el UART de inmediato se interrumpe el programa y se va para el siguiente metodo de interrupcion del UART2
 
Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) {
    int2 = 1;
    Dato2 = U2RXREG;

    IFS1bits.U2RXIF = 0;
}


Ahora bien, tengo una interrpución por desbordamiento del Timer3 en el que tengo lo siguiente:

Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _T3Interrupt(void){
    Accion_Alarma();

    if( int2 > 0 ){_T3IE = 0; Recibir_Trama_Modbus();}

    _T3IF=0;
}



En el que en teoría he de asegurar que siempre este pendiente de que se active la bandera int2 que me ha de indicar que se ha interrumpido por haber recibido un dato por el UART2 y se haga lo correspondiente.

Mi problema reside en que tengo metodos While donde la unica forma de que se salga es q ue se presione un pulsador o una bandera cambie de valor o algo asi, y cuando estoy dentro de ellos, al momento de mandar una trama, solo recibo UN DATO, el ultimo por lo general, por ende mi Trama[] solo contiene un solo valor y de ahi que no pueda interpretar que fue lo que se me fue enviado. 


Recalco que esto solo me suecede cuando estoy dentro de un While. Mi interes radica en que no quiero que el programa se salga de esos While sino que haga lo que este especificado en ellos y respondan simultaneamente a la trama recibida.


De antemano Agradeciendoles su atención y pronta respuesta.  :-)






Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: UART PIC24 Metodos While
« Respuesta #1 en: 15 de Septiembre de 2012, 15:19:20 »
No me parece la mejor forma de implementarlo. Porque no utilizas dos buffer, uno para recibir y otro para enviar mediante interrupciones?

Por ejemplo para recibir necesitas lo siguiente:

Código: C
  1. struct{
  2.     UINT8 BufferRx[LENGTH_BUFFER_UART_RX];  ///< Buffer para recepcion de datos por medio del uart
  3.     UINT16 PtrRxRData;                      ///< Puntero para lectura de datos del buffer de recepcion
  4.     UINT16 PtrRxWData;                      ///< Puntero para escritura de datos al buffer de recepcion
  5.      UINT16 CountRxData;                     ///< Cuenta la cantidad de datos que hay almacenados en el buffer de recepcion
  6.     struct{
  7.         unsigned FullBufferRx:1;            ///< En 1 indica que el buffer de recepcion esta lleno
  8.     }Flags;
  9. }UARTData;

En la interrupción haces:

Código: C
  1. if(UARTData.Flags.FullBufferRx==0){                                      // Si el buffer no esta lleno almaceno
  2.             UARTData.BufferRx[DNPUARTData.PtrRxWData++]=U2RXREG;
  3.             if(++UARTData.CountRxData==LENGTH_BUFFER_UART_RX){                   // Verifico si se llena buffer
  4.                 UARTData.Flags.FullBufferRx=1;
  5.             }
  6.             if(UARTData.PtrRxWData==LENGTH_BUFFER_UART_RX){                      // Es un buffer circular, reinicio puntero si es necesario
  7.                 UARTData.PtrRxWData=0;
  8.             }
  9.         }

Luego podes hacerte una función que te retorne cuantos datos hay en el buffer:

Código: C
  1. UINT16 UARTIsGetReady(void){
  2.  
  3.     return(UARTData.CountRxData);
  4. }

Y otra para leer x cantidad de bytes del buffer:

Código: C
  1. UINT16 UARTGetArray(UINT8 *PtrData,UINT16 Lenght){
  2.     UINT16 Count,k;
  3.  
  4.     if(UARTData.CountRxData==0){
  5.         return(0);
  6.     }
  7.  
  8.     Count=Lenght;
  9.     if(Lenght>(LENGTH_BUFFER_UART_RX-UARTData.CountRxData)){
  10.         Count=LENGTH_BUFFER_UART_RX-UARTData.CountRxData;
  11.     }
  12.  
  13.     for(k=0;k<Count;k++){
  14.         *PtrData++=UARTData.BufferRx[UARTData.PtrRxRData++];
  15.         UARTData.CountRxData--;
  16.         if(UARTData.PtrRxRData==LENGTH_BUFFER_UART_RX){
  17.             UARTData.PtrRxRData=0;
  18.         }
  19.     }
  20.     UARTData.Flags.FullBufferRx=0;
  21.  
  22.     return(Count);
  23. }

Con eso podes comenzar a esperar tu trama de Modbus, sabiendo que para recibir la cabecera tienes que tener mínimo 12 bytes:

Código: C
  1. // Mirar cuantos bytes podemos leer
  2. wMaxGet = UARTIsGetReady();    
  3. //Al menos recibimos la cabecera
  4. if (wMaxGet<12)return;
  5. // Recibimos posible cabecera, la tratamos...
  6. UARTGetArray(&MODBUS[0], wMaxGet);
  7. ProcesaCabecera();

 ;-)

Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado CR7

  • PIC10
  • *
  • Mensajes: 11
Re: UART PIC24 Metodos While
« Respuesta #2 en: 17 de Septiembre de 2012, 11:38:01 »
Hola Rikr09,

Creo que tu código esta bien, estas recibiendo los datos correctamente. Puedes implementar el código que utiliza suky para que se vea mas organizado. Pero si no estoy mal seguirías teniendo el mismo inconveniente. Sucede que hay varios tipos de programación y al momento de realizar tu programa no tuviste en cuenta el manejo de algunos eventos quizás porque le quisiste agregar esa función de recibir ModBus a ultimo momento del proyecto o algo así.

Pero bueno lo que debes hacer es ingresar en cada uno de los while que tienes el método que revisa la bandera del UART. ;-)

Y para proyectos futuros o si quieres rehacer o empezar de nuevo en el que estas ahora acá te dejo un tutorial de programación Non-Blocking: ENGSCOPE

Hasta la próxima...


 


 
-Solo los grandes son los que se levantan-

Desconectado Rikr09

  • PIC16
  • ***
  • Mensajes: 112
Re: UART PIC24 Metodos While
« Respuesta #3 en: 17 de Septiembre de 2012, 12:47:50 »
Gracias por tu respuesta Suky!!! Muy oportuna y completa.


Pero me he encontrado con dos problemas:

El primero es en:

Código: [Seleccionar]
   struct{
       UINT8 BufferRx[LENGTH_BUFFER_UART_RX];  ///< Buffer para recepcion de datos por medio del uart
       UINT16 PtrRxRData;                      ///< Puntero para lectura de datos del buffer de recepcion
       UINT16 PtrRxWData;                      ///< Puntero para escritura de datos al buffer de recepcion
       UINT16 CountRxData;                     ///< Cuenta la cantidad de datos que hay almacenados en el buffer de recepcion
       struct{
           unsigned FullBufferRx:1;            ///< En 1 indica que el buffer de recepcion esta lleno
       }Flags;
    }UARTData;



Me manda el siguiente error, al declarar LENGTH_BUFFER_UART_RX como UINT8 (unsigned char):

Citar
In file included from system.h:56:0,
                 from Main.c:1:
Protocolos.h:117:14: error: variably modified 'BufferRx' at file scope


Al comentar dicha linea de codigo, me encuentro con el siguiente error:

Citar
uart.c: In function '_U2RXInterrupt':
uart.c:78:20: error: 'struct <anonymous>' has no member named 'BufferRx'
uart.c:78:30: error: 'DNPUARTData' undeclared (first use in this function)
uart.c:78:30: note: each undeclared identifier is reported only once for each function it appears in
make[2]: *** [build/default/production/uart.o] Error 255
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2


Ya que no esta declarada DNPUARTData.


Y entonces procedi a reemplazar esta por UARTData, pero no se si sea correcto.



Nuevamente agradeciendote Suky por tus ayudas, espero pronta respuesta de esta por favor.

Igualmente cualquier ayuda de cualquier colaborador amigo del foro, sera bien recibida. Gracias a Todos y a esta comunidad.  ((:-))



Gracias CR7 por tu aporte, empezare a implementar este tipo de programación, ya que en mi código incurro bastante en el problema descrito.
« Última modificación: 17 de Septiembre de 2012, 13:25:04 por Rikr09 »

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: UART PIC24 Metodos While
« Respuesta #4 en: 17 de Septiembre de 2012, 14:16:36 »
Citar
Me manda el siguiente error, al declarar LENGTH_BUFFER_UART_RX como UINT8 (unsigned char):

LENGTH_BUFFER_UART_RX es una definición del tamaño que quieres que tenga en buffer de recepción, puede ser 50, 100, 200, etc...  ;-) Basta con colocar antes o en su *.h:

#define LENGTH_BUFFER_UART_RX 300 // Por ejemplo



Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado Rikr09

  • PIC16
  • ***
  • Mensajes: 112
Re: UART PIC24 Metodos While
« Respuesta #5 en: 18 de Septiembre de 2012, 12:22:40 »
Excelente Suky!!! Ya recibo mi trama, pero tengo otro problema  :(


Resulta que me di cuenta que estoy recibiendo son 9 Datos, siendo que en realidad mando una trama de la forma: 0B031B5800010397. Hasta el momento lo que llevo implementado para hacer las pruebas de lo que me pasaste, es lo siguiente:
Código: [Seleccionar]
while(1){



            if(!S3){ __delay_ms(200)

            UA2("CONT");U2(UARTDato.CountRxData);UA2("CONT ");
            UA2(" FLAG");U2(UARTDato.Flags.FullBufferRx);UA2("FLAG");

                for(i=0; i<UARTDato.CountRxData; i++){
                    U2(UARTDato.BufferRx[i]);
                }
            }



            if(!S4){__delay_ms(200)
           
                for(i=0; i<UARTDato.CountRxData; i++){                 
                  UARTDato.BufferRx[i]=0;
                }

            UARTDato.CountRxData = 0;
            UARTDato.Flags.FullBufferRx = 0;
            }

        }

y obviamente en la interrupcion tengo:

Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) {
//    int2 = 1;
//    Dato2 = U2RXREG;

    if(UARTDato.Flags.FullBufferRx == 0){                                      // Si el buffer no esta lleno almaceno
        UARTDato.BufferRx[UARTDato.PtrRxWData++]=U2RXREG;
        if(++UARTDato.CountRxData==LENGTH_BUFFER_UART_RX){                   // Verifico si se llena buffer
            UARTDato.Flags.FullBufferRx=1;
        }
        if(UARTDato.PtrRxWData==LENGTH_BUFFER_UART_RX){                      // Es un buffer circular, reinicio puntero si es necesario
            UARTDato.PtrRxWData=0;
        }   
    }
        IFS1bits.U2RXIF = 0;
}

Entonces, como venia diciendo al mandar un trama como la especificada, recibo 9 Datos, y si vuelvo a enviar otra es como si no la recibiera porque me sigue mostrando la misma al presionar !S3. Entonces decidi crear el if con !S4 con el que 'limpio' el buffer (LENGTH_BUFFER_UART_RX=9) y borro las bandera del contador y del Fullbuffer pero no obtengo resultado positivo, porque al leer nuevamente solo me salen los ceros, y no el valor nuevo correspondiente a la nueva trama que le envie.


Disculpa las molestias, y agradezco tu atención.

Gracias!!! :-/

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: UART PIC24 Metodos While
« Respuesta #6 en: 18 de Septiembre de 2012, 15:54:33 »
Es que lo implementas mal. Como te puse anteriormente, la forma de trabajarlo con esas funciones sería:


Código: C
  1. UINT8 wMaxGet, ModBus[50];
  2.  
  3. while(1){
  4.         wMaxGet = UARTIsGetReady();    
  5.         //Al menos recibimos la cabecera
  6.         if (wMaxGet<8)return;
  7.         // Recibimos posible cabecera, la tratamos...
  8.         UARTGetArray(&ModBus[0], wMaxGet); // Esta función trabaja con los punteros, así no tenes que resetearlos
  9.         //      
  10. }

Además en la interrupción falta preguntar por el flag correspondiente y borrarlo además.


Implementarlo de esta forma te va a ser muy sencillo después implementarlo por TCP/IP utilizando el stack de Microchip. Acá tienes un ejemplo: http://blog.sasian.es/2010/01/08/modbus-tcp-para-pic-parte-i/

Saludos!
« Última modificación: 18 de Septiembre de 2012, 15:58:24 por Suky »
No contesto mensajes privados, las consultas en el foro

Desconectado Rikr09

  • PIC16
  • ***
  • Mensajes: 112
Re: UART PIC24 Metodos While
« Respuesta #7 en: 19 de Septiembre de 2012, 12:45:52 »
Listo Suky, hice una serie de modificaciones:

En cuanto a la interrupción:

Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) {

  if( UARTDato.Flags.FullBufferRx == 0 ){                        // Si el buffer no esta lleno almaceno
        D9 = 1;
        UARTDato.BufferRx[UARTDato.PtrRxWData++] = U2RXREG;
        if( UARTDato.PtrRxWData == (LENGTH_BUFFER_UART_RX + 1) ){
            UARTDato.Flags.FullBufferRx = 1;
        }

   }

    IFS1bits.U2RXIF = 0;
}


Así mismo en la parte del método que sigue:

Código: [Seleccionar]
void UARTGetArray(UINT8 *PtrData,UINT16 Lenght){
    UINT16 k;


    for( k=0;k<Lenght;k++ ){
        *PtrData++ = UARTDato.BufferRx[k];
        U2(UARTDato.BufferRx[k]);

    }
    UARTDato.Flags.FullBufferRx = 0;
    UARTDato.PtrRxWData = 0;

}

y en el Timer 3; implemente lo que seria el llamada del método anterior para que éste responda de acuerdo a la trama recibida. Hasta el momento en el que escribo esta cita no he tomado aun mi ' RESPUESTA MODBUS' ya que tan solo muestro lo que estoy recibiendo por el UART2:


Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _T3Interrupt(void){
    UINT16 a;BYTE grup[20];


    a = UARTDato.PtrRxWData;
    UARTGetArray( &grup[0], a );


    _T3IF=0;
}




Hasta el momento funciona bien, quizas no sea la forma mas óptima (pero es que no he podido dar con la mejor) pero trabaja favorablemente. El problema que si veo y que me preocupa es que si le envio tramas muy seguidas con intervalos de tiempo de medio segundo el programa gral se bloquea, se pierde :( :5]


Nuevamente Gracias por tu atención y ayuda Suky!!!!  :-/

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: UART PIC24 Metodos While
« Respuesta #8 en: 19 de Septiembre de 2012, 13:05:58 »
a debe leer UARTDato.CountRxData, que dice la cantidad de datos que hay, el buffer es circular, así que leer el puntero no indica cantidad. Después que prioridades le das a la interrupción? mayor a la del timer? Así si ocurre, que la interrumpa para recibir el dato.  ;-) Puede ser por eso que se pierda  :tongue:


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado Rikr09

  • PIC16
  • ***
  • Mensajes: 112
Re: UART PIC24 Metodos While
« Respuesta #9 en: 20 de Septiembre de 2012, 11:45:38 »
Muy Bien Suky, EXCELENTE GRACIAS!!!

Ya no tengo problemas con los metodos WHILE. El metodo de interrupión quedó omo sigue:

Código: [Seleccionar]
void __attribute__ ((interrupt, no_auto_psv)) _U2RXInterrupt(void) {

    int2 = 1;
    D10 = 1;
    TMR1 = 0;
    if(UARTDato.Flags.FullBufferRx == 0){
        if( UARTDato.Flags.FullBufferRx == 0 ){                        // Si el buffer no esta lleno almaceno
            UARTDato.BufferRx[UARTDato.PtrRxWData++] = U2RXREG;
            if( UARTDato.PtrRxWData == (LENGTH_BUFFER_UART_RX + 1) ){
                UARTDato.Flags.FullBufferRx = 1;
            }
        }
    }

    if(UARTDato.Flags.FullBufferRx == 1){
        //_T1IE = 0;
        UARTDato.Flags.FullBufferRx = 0;
        UARTDato.PtrRxWData = 0;
    }

    IFS1bits.U2RXIF = 0;
   }

 Como se puede observar sigo verificando el estado de la bandera qe me ha de indicar si el buffer esta lleno o no (#define LENGTH_BUFFER_UART_RX 256), y estoy implementado el Timer1 a modo de Time Out de tal modo cada que cada vez que ourra una interrupción por la recepción de un dato por el UART se reinicie el valor del Timer, y asi cuando se deje de recibir, despues de un tiempo de aproximadamente 200 300 ms (no calculado con presición), se pasa a la verificación de los valores qe me han llegado.

Código: [Seleccionar]

void __attribute__ ((interrupt, no_auto_psv)) _T1Interrupt(void){

    Recibir_Trama_Modbus();

    _T1IF = 0;
}

y en la reepción de la trama hago:

Código: [Seleccionar]
void Recibir_Trama_Modbus(){
    BYTE i;
    BYTE grup[20];
    a = UARTDato.PtrRxWData;
    UARTGetArray( &Trama[0], a );


   

    Interpretacion_Trama();


    for(i=0; i<a; i++){
        Trama[i] = 0;
    }

    //Se limpian todas las variables
    D10 = 0;
    UARTDato.PtrRxWData = 0;
    a = 0;
    int2 = 0;
    Cont_Trama_Resp = 0;
    DataAddressMOD = 0;
    LenghtMOD = 0;
    CRCMOD = 0;
    U2MODEbits.WAKE = 1; U1MODEbits.WAKE = 1;
}


Y listo con esto logre solucionar mi problema.  :-)


Gracias de nuevo Suky por tus ayudas!!!!  ((:-)) :-) ((:-)) ((:-)) ((:-)) ((:-)) ((:-)) ((:-)) ((:-)) ((:-))
« Última modificación: 22 de Septiembre de 2012, 12:08:36 por Rikr09 »