Autor Tema: Cómo almacenar en una variable una trama con longitud descon.  (Leído 4188 veces)

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

Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
Cómo almacenar en una variable una trama con longitud descon.
« en: 27 de Septiembre de 2004, 05:43:00 »
Sigo como siempre más que liado, cuando creo resolver algo me sale otro problema por otro lado.
El problema que me surge es que quiero recibir una serie de caracteres números incluidos, que no sé su tamaño exacto, aveces pueden llegar  10 caracteres, 15, etc...Lo único que sé es como empieza esta trama, empieza por:AgAAAAAAABA y luego continua.

Tiene alguien alguna solución?                                

Desconectado MarquesSalsero

  • PIC18
  • ****
  • Mensajes: 467
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #1 en: 27 de Septiembre de 2004, 09:22:00 »
A veces llegan 10 y otras 15, pero sabes cuantos han llegado? hay algun marcador de fin de trama?

Si es asi simplemente empieza a leer hasta que encuentres el fin de tramay ve poniendo los datos en una matriz sobredimensionada. Yo tengo un cacharrito en el que puedo recibir bloques de comandos que pueden ser desde 4 a 12 bytes y he creado un array de 12 bytes y luego simplemente busco hasta fin de trama.

A veces el problema es que el basic no es demasiado versatil en esos casos y necesitas leer caracter a caracter e ir poniendolos en el buffer de forma manual. Es una buena oprtunidad para implementar una rutina de recepcion por hardware ( si tu pic tiene USART ) con un buffer circular. Hay una cadena de mensajes iniciada por Abago en la que se trató el tema a fondo.

http://miarroba.com/foros/ver.php?foroid=8826&temaid=1673107

Hay 10 tipos de personas las que entienden binario y las que no

Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #2 en: 30 de Septiembre de 2004, 14:31:00 »
Hola Marques,

Al final si que puedo saber mi final de trama, puesto que lo he planteado de otra manera. Cuando me llega la trama de datos, almaceno ésta en la memoria de la tarjeta SIM luego mediante el comando AT+CMGL="REC UNREAD" el móde me devuelve toda la información es decir:
+CMGL:1,"REC UNREAD","675434334",,"02/03/04,18:....ETC...la
trama recibida de datos y termina por Ok, es decir interrogando al módem el mensaje lo termina mediante Ok, por lo que sé por donde empieza la trama que le puedo llamar X, y llamando a la  longitud de la trama completa "y" la simple ecuación sería:
y=X+n-2(caracteres).
Ponme algún ejemplo tonto -si quieres claro- sobre como almacenar una matriz y poder leerla hasta llegar hasta el final de la trama.
Te lo agredecería mucho.
Un saludo.

Desconectado MarquesSalsero

  • PIC18
  • ****
  • Mensajes: 467
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #3 en: 01 de Octubre de 2004, 04:01:00 »
Mi gramatica no es muy buena asi que espero que lo de tonto es sobre el ejemplo

Yo el sistema que llevo usando desde hace mucho es el que se decribe en le cadena de mensajes que te indicaba un poco antes.

Primero crou un sistema de recepcion de datos por hardware byte a byte por interrupción, cavez que me llaga un caracter lo meto en un buffer FIFO circular de unos 10 a 64 bytes dependiendo de la aplicación y luego voy leyendo de ese buffer y evaluando los datos recibidos.

Si no te aclaras bien leyendo directamente del buffer lo que puedes hacer es crearte otra matriz independiente y copiar los datos del buffer circular a la matriz de trabajo.

p.ej
start:
leo dato buffre circular
dato=comienzo_de_cadena
si comienzo de cadena then bucle
sino comienzo de cadena apunto a siguiente caracter y start


bucle:
si caracter="O" and carater+1="k" entonces fin
copio caracter a matriz de trabajo
apunto a siguiente caracter
goto bucle

Por supuesto may que incrementar contadores de la posicion en la que estas leyendo del buffer circular, verificar si has llegado al final y en ese caso volver al principio, el contador de donde escribes en la matriz de trabajo, etc... pero esa es la parte mas sencilla de todo.

Yo uso esas rutinas que se indican en la mencionada cadena de mensajes y me funcionan perfectamente ( son de melabs asi que no tengo eningun merito, solo el de saber buscar ).
Hay 10 tipos de personas las que entienden binario y las que no

Desconectado Abago

  • PIC24F
  • *****
  • Mensajes: 792
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #4 en: 03 de Octubre de 2004, 23:54:00 »
Como bien dice Marques, la mejor solución es al crear el buffer fifo...
en el tema que planteé hace unos meses, le dimos muchas vueltas al tema, y es la mejor solución...
creamos la rutina de recepción por interrupción de la usart que  almacene los datos en el buffer FIFO temporal y gestionamos la posición de los punteros de inicio y fin de buffer.

luego solo tenemos que hecer una pequeña rutina, que rastree el buffer en busca de comandos válidos...

Espero no haber liado el tema...
Ahora las cosas las veo muy claras, pero cuando empecé, la cosa no era tan sencilla....

De todos modos, en el tema, que plantea marques, hay cantidad de código que te pede ser de utilidad.  


Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #5 en: 04 de Octubre de 2004, 11:36:00 »
Hola Abago,

He seguido todos tu post, en el dilema.
He intentado compilar algunos de tus programas y me han dado errores. La verdad es que estoy un poco despistado en cuanto a las interrupcciones. No sé si utilizar la orden INTERRUPT por asm o PBP. Estoy intentando hacerlo por PBP pero no veo ejemplos claros, incluso los de melania me dan error al compilarlos.
Mi problema es que cuando recibo un mensaje no sé cuantos bytes o caracteres me van a llegar por serie, a través de un módem GSM. Entonces tengo que crear una rutina que cuando compruebe que no hay ningun caracter más, almacene la trama en una variable para luego descodificarla.
Marques me ha ayudado mucho en el tema, pero me falta un pequeño empujón -más tiempo,jejejeje- para empezar ha entenderlo mejor.

Tienes alguna solución?.¿Cómo lo harías tú?,porque de otra forma que no sea por interrupción serie no la hay verdad?

Un saludo a todos los que lean este mensaje.

Desconectado MarquesSalsero

  • PIC18
  • ****
  • Mensajes: 467
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #6 en: 04 de Octubre de 2004, 14:47:00 »
Yo tengo el sistema de entrada por interrupción funcionando en mi casa desde hace mas de un año y no ma da ningun problema, de hecho decodifico directamente desde el buffer de entrada.

Porque no nos muestras tu programa a ver si vemos por donde anda el error?

ya sabes que cuatro ojos ven mas que dos y si son varias docenas las que miran pues imaginate.

Lo que no te ayuda a ti lo mas minimo, porque nosotros no podemos decirte nada, es si solamente nos dices que "te da error al compilar".

Eso es tan abstracto que o eres pediatra ( eso si que es jodido ) o no hay manera de saber cual puede ser el error.
Hay 10 tipos de personas las que entienden binario y las que no

Desconectado Abago

  • PIC24F
  • *****
  • Mensajes: 792
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #7 en: 04 de Octubre de 2004, 14:57:00 »
La solución que te ha dado marques, es la mejor que se te pueda ocurrir...
el tema, está en que tienes que pensar que tu programa va a ir siempre mas rápido que el puerto serie, y si te creas un buffer RX lo suficientemente grande, no tendrás problemas en ir decodificando la trama en tiempo real...
puedo decir, que incluso tendrás que hacer retención al programa principal, porque el buffer lo limpia hechando leches...

en el siguiente link, aparece el código que marques en su día me pasó, y en el que puedes basar tu programa...

http://www.melabs.com/resources/samples/x1/pbp/serbufAx.bas

solo tienes que modificarlo a tu gusto y eliminar la parte en la que se trabaja con el transpaso de datos al display...

y como último, creo que tienes que hecharle un ojo a
buffer_size     CON     32  
el valor depende de los datos que tengas que almacenar en el buffer....

de todos modos ves estudiandote el código del link, y te iremos ayudando en lo que esté en nuestras manos....


Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #8 en: 05 de Octubre de 2004, 13:00:00 »
BUeno os cuento como va el tema. Me ha pasado una cosa rarísima.
Al final me he declinado por hacerlo con la orden ON INTERRUPT de PBP. He modificado un poco el programa como pongo abajo, y me ha funcionado. Cada vez que enviaba una trama de datos ASCII p cadena de caracteres me la devolvía por la consola con la orden hserout[bufchar], era lo que quería, según la trama de datos sin tener que estar pendiente de la longitud de la misma.
BUeno os pongo el código:
***********************************************
INCLUDE "bs2defs.bas"
DEFINE LOADER_USER 1
DEFINE OSC 20
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 24h
DEFINE HSER_BAUD 9600




ADCON1 = 6                              " Set PortA to digital operation

RCIF    VAR     PIR1.5          " Alias RCIF (USART Receive Interrupt Flag)
OERR    VAR     RCSTA.1         " Alias OERR (USART Overrun Error Flag)
CREN    VAR     RCSTA.4         " Alias CREN (USART Continuous Receive Enable)
LED     VAR     PORTB.7         " Alias LED to PORTB.7

buffer_size     CON     32              " Sets the size of the ring buffer
buffer          VAR     BYTE[buffer_size]       " Array variable for holding received characters
index_in        VAR     BYTE    " Pointer - next empty location in buffer
index_out       VAR     BYTE    " Pointer - location of oldest character in buffer
bufchar         VAR     BYTE            " Stores the character retrieved from the buffer
i               VAR     BYTE            " loop counter
col             VAR     BYTE            " Stores location on LCD for text wrapping
errflag         VAR     BYTE
codigo          VAR     BYTE          " Holds error flags

" Initialize variables

index_in = 0
index_out = 0
i = 0
col = 1



Pause 100               " Wait for LCD to start

"LCDOut $fe,1                    " Clear LCD


INTCON = %11000000              " Enable interrupts
On INTERRUPT GoTo serialin              " Declare interrupt handler routine
PIE1.5 = 1                            " Enable interrupt on USART



" Main program starts here - blink an LED at 1Hz

Loop:  
       
   
        High LED        " Turn on LED connected to PORTD.0
        For i = 0 To 250        " Delay for .5 seconds (250*2mS)
                Pause 2         " Use a short pause within a loop
                Next i                  " instead of one long pause
        Low LED         " Turn off LED connected to PORTD.0
        For i = 0 To 250        " Delay for .5 seconds (250*2mS)
                Pause 2         " Use a short pause within a loop
                Next i    
             
                goto loop            " instead of one long pause

display:                                " dump the buffer to the LCD
                IF errflag Then error   " Handle error if needed
                If index_in = index_out    Then Loop       " loop if nothing in buffer

                GoSub getbuf
                hserout [bufchar]  " Get a character from buffer
                                           
GoTo display                    " Check for more characters in buffer



" Subroutines

Disable                                 " Don"t check for interrupts in this section

getbuf:                                 " move the next character in buffer to bufchar
        index_out = (index_out + 1)                     " Increment index_out pointer (0 to 63)
        If index_out > (buffer_size - 1) Then index_out = 0     " Reset pointer if outside of buffer
        bufchar = buffer[index_out]       " Read buffer location
Return


error:                                  " Display error message if buffer has overrun
        IF errflag.1 Then error1      " Determine the error
        error1:
                serout2 portc.6,84,["Buffer Overrun"] " Display buffer error on line-2
        "Else
                serout2 portc.6,84,["USART Overrun"]  " Display usart error on line-2
        "End If
       
        "LCDOut $fe,2            " Send the LCD cursor back to line-1 home
        "For i = 2 To col        " Loop for each column beyond 1
                "LCDOut $fe,$14  " Move the cursor right to the right column
        "Next i
       
        errflag = 0                     " Reset the error flag
        CREN = 0                        " Disable continuous receive to clear overrun flag
        CREN = 1                        " Enable continuous receive

        GoTo display            " Carry on
       
       
" Interrupt handler
"disable
serialin:    
        HIGH PORTB.3
                               " Buffer the character receive
        If OERR Then usart_error                        " Check for USART errors
        index_in = (index_in + 1)                       " Increment index_in pointer (0 to 63)
        If index_in > (buffer_size - 1) Then index_in = 0 "Reset pointer if outside of buffer
        If index_in = index_out Then buffer_error       " Check for buffer overrun
        HSerin [buffer[index_in]]
        LOW PORTB.3
        IF RCIF then serialin                     " Read USART and store character to next empty locationIf RCIF Then serialin                          " Check for another character while we"re here
       
Resume          
enable                        " Return to program

buffer_error:
        errflag  = 1         " Set the error flag for software
" Move pointer back to avoid corrupting the buffer. MIN insures that it ends up within the buffer.
        index_in = (index_in - 1) MIN (buffer_size - 1)
        HSerin [buffer[index_in]]       " Overwrite the last character stored (resets the interrupt flag)
usart_error:
        errflag = 1          " Set the error flag for hardware
       
Resume                                  " Return to program


End
************************************************
Pues lo hecho asi y me ha funcionado. Pero al modifcarlo ya no funciona, es muy curioso. Yo me pregunto a ver si se ha quedado el buffer de tanto programarlo colapsado, ya que he intentado meter el comando write. Esa ha sido la modificación.
También como vereís en serialin he puesto que se encienda un led cuando entre en la interrupcón, y se enciende y se apaga como. Por lo que deduzco que la interrrupción la crea, el problema es que no saca por hserout[bufchar] la cadena de caracteres. Os prometo que me ha funcionado antes.
Qué puede ser?
He intentado con los enable y disable cambiandolos pero ni asi.
He pasado de este estado a este en 10 minutos.
Que disilusión, pensaba que estaba hecho ya.
Por cierto estoy con un PIC16F876.

Saludos.

Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #9 en: 05 de Octubre de 2004, 13:36:00 »
Perdonad ya esta solucionado
resulta que no había quitado el Loop de la rutina de al principio, y claro no entraba en la etiqueta display:

Bueno ahora, -es que no me lo creo-, no sé si es de coña o que, pero cuando envio cualquier cadena de menos de 32 caracteres me la saca por puerto serie. eso esta bien?. Voy por el buen camino.?

Griacias y no haced caso al mensaje anterior, no quiero liar a la gente que lea los mensajes.
BUeno ya me contaís.


Saludos.

Desconectado MarquesSalsero

  • PIC18
  • ****
  • Mensajes: 467
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #10 en: 05 de Octubre de 2004, 13:54:00 »
A ver por partes

El -INCLUDE "bs2defs.bas"- si no te es absolutamente necesario no lo pongas, es mejor que tu definas tus aliases

Si defines -DEFINE HSER_RCSTA 90h- y -DEFINE HSER_TXSTA 24h- es mejor definir -SPBRG=$129- que -DEFINE HSER_BAUD 9600- no se porque pero a mi a veces me ha dado problemas.

por cierto puedes poner:

RCSTA=$90
TXSTA=$24
SPBRG=$129

y funciona correctamente

La parte donde procesas los errores:

error: " Display error message if buffer has overrun
IF errflag.1 Then error1 " Determine the error
error1:
serout2 portc.6,84,["Buffer Overrun"] " Display buffer error on line-2
"Else
serout2 portc.6,84,["USART Overrun"] " Display usart error on line-2
"End If

me parece confusa y no se que tel funcionara, pero es axactamente lo mismo que:

error: " Display error message if buffer has overrun
IF errflag.1 Then" Determine the error  
serout2 portc.6,84,["Buffer Overrun"] " Display buffer error on line-2
Else
serout2 portc.6,84,["USART Overrun"] " Display usart error on line-2
End If

en cuanto a la logica y el descomentado del ELSE y ENDIF, pero ademas... ¿No estas usando HSEROUT?

Luego la parte:

buffer_error:
errflag = 1 " Set the error flag for software
" Move pointer back to avoid corrupting the buffer. MIN insures that it ends up within the buffer.
index_in = (index_in - 1) MIN (buffer_size - 1)
HSerin [buffer[index_in]] " Overwrite the last character stored (resets the interrupt flag)
usart_error:
errflag = 1 " Set the error flag for hardware

Resume " Return to program

me parece aun mas confusa ya que no consigo entenderla, tienes un

errflag=1

al principio y al final ¿?

Pero, y eso es lo mas importante a mi parecer , tienes un bucle cerrado -loop- del que no sales nunca para evaluar si tienes algun carcter para imprimir.

No tienes ninguna manera de llegar a la rutina display.

el bucle loop deberia ser mas o menos asi:

Loop:


High LED " Turn on LED connected to PORTD.0
For i = 0 To 250 " Delay for .5 seconds (250*2mS)
Pause 2 " Use a short pause within a loop
Next i " instead of one long pause
Low LED " Turn off LED connected to PORTD.0
For i = 0 To 250 " Delay for .5 seconds (250*2mS)
Pause 2 " Use a short pause within a loop
Next i
If index_in <> index_out then display "**** LO VES
goto loop " instead of one long pause

display: " dump the buffer to the LCD
IF errflag Then error " Handle error if needed
GoSub getbuf
hserout [bufchar] " Get a character from buffer
If index_in = index_out Then Loop " loop if nothing in buffer
GoTo display " Check for more characters in buffer


asi por encima eso es lo que he visto si me doy cuenta de algo mas te pongo otro mensaje.
Hay 10 tipos de personas las que entienden binario y las que no

Desconectado MarquesSalsero

  • PIC18
  • ****
  • Mensajes: 467
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #11 en: 05 de Octubre de 2004, 14:00:00 »
Escrito originalmente por egds
Perdonad ya esta solucionado
resulta que no había quitado el Loop de la rutina de al principio, y claro no entraba en la etiqueta display:




Saludos.


En lo que yo he tardado en escribir la contestacion te has dado cuenta, pero mira otros comentarios que te hago que te pueden despejar alguna otra cosilla.

Ademas aunque vas por el buen camino no des nada por bueno sin forzarle todos los errores posibles.
Hay 10 tipos de personas las que entienden binario y las que no

Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #12 en: 05 de Octubre de 2004, 14:31:00 »
Gracias Marques,

La verdad es que este foro es de los más activos que yo he visto hasta ahora, asi da gusto. Y más cuando encima te ayudan y te apollan.
La verdad es que poco a poco voy dando pasitos, aunque aun me queda bastante por recorrer. He depurado un poquito el código que he puesto antes. Ahora me saca bien los errores por Overflow.

Ahora lo que necesito es almacenar los datos en una matriz y luego procesarlos, segun venga la información ya que ahora la longitud de la trama no me preocupa, aunque se pueden meter el comando Skip y wait en la interrupción por USART no?.
Es que necesito que cuando vengan las tramas gurdar solo lo que me interesa.

BUeno voy a ver si ceno y luego me conectaré un ratillo, a ver que dice Abago que estará poniendo copillas, a ver si un día nos dice donde esta su bar y cuando vaya a Madrid me paso.
Que aún estoy en la oficina y la mujer me ha llamado dos veces al móvil, pero cuando te enganchas quieres mas y mas....

Voy a cerrar ya el portatil y dejarlo descansar un poquito.

salu2.

Saludos y gracias

Desconectado Abago

  • PIC24F
  • *****
  • Mensajes: 792
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #13 en: 06 de Octubre de 2004, 11:13:00 »
Escrito originalmente por egds
Ahora lo que necesito es almacenar los datos en una matriz y luego procesarlos, segun venga la información ya que ahora la longitud de la trama no me preocupa, aunque se pueden meter el comando Skip y wait en la interrupción por USART no?.
Es que necesito que cuando vengan las tramas gurdar solo lo que me interesa.



tienes un pequeño atasco de información...
el skip y el wait, se usan con el serout/hserout....
al usar la interrupción, tendrás que gestionar tus propias paradas y esperas de datos con tu propio código....
esto es una de las cosas que te da un gran juego...

mientras tu código principal va leyendo los datos del buffer, e interpretándolos, el handler de interrupción de la usart va llenando ese mismo buffer...(con el buffer, no me refiero al buffer de la usart, que creo recordar que es de 2 bytes... sino que me refiero a la matriz buffer fifo que tambien creo recordar que está definida a 32 bytes o 32 caracteres ascii )

es muy probable, que a tu programa principal, le de tiempo a ir interpretando los datos que tiene almacenados en el buffer fifo en tiempo real, sin necesidad de tener que crear otra matriz temporal...
ten en cuenta que el buffer fifo, es una matriz, que tiene dos punteros que indican el inicio y el fin de datos a leer...

Espero no haberte liado demasiado con tanta matriz...
a ver si tengo un ratito. y me empapo lo que hace el código que dejaste anteriormente...

Un saludo

PD: intenté responderte a las 6:00 de la madrugada, pero  no fuí capaz...
miarroba, o mejor dicho laarroba, se cae cada dos por tres...

Desconectado egds

  • PIC12
  • **
  • Mensajes: 76
RE: Cómo almacenar en una variable una trama con longitud descon.
« Respuesta #14 en: 06 de Octubre de 2004, 13:06:00 »
Escrito originalmente por Abago
Escrito originalmente por egds
Ahora lo que necesito es almacenar los datos en una matriz y luego procesarlos, segun venga la información ya que ahora la longitud de la trama no me preocupa, aunque se pueden meter el comando Skip y wait en la interrupción por USART no?.
Es que necesito que cuando vengan las tramas gurdar solo lo que me interesa.



tienes un pequeño atasco de información...
el skip y el wait, se usan con el serout/hserout....
al usar la interrupción, tendrás que gestionar tus propias paradas y esperas de datos con tu propio código....
esto es una de las cosas que te da un gran juego...

mientras tu código principal va leyendo los datos del buffer, e interpretándolos, el handler de interrupción de la usart va llenando ese mismo buffer...(con el buffer, no me refiero al buffer de la usart, que creo recordar que es de 2 bytes... sino que me refiero a la matriz buffer fifo que tambien creo recordar que está definida a 32 bytes o 32 caracteres ascii )

es muy probable, que a tu programa principal, le de tiempo a ir interpretando los datos que tiene almacenados en el buffer fifo en tiempo real, sin necesidad de tener que crear otra matriz temporal...
ten en cuenta que el buffer fifo, es una matriz, que tiene dos punteros que indican el inicio y el fin de datos a leer...

Espero no haberte liado demasiado con tanta matriz...
a ver si tengo un ratito. y me empapo lo que hace el código que dejaste anteriormente...

Un saludo

PD: intenté responderte a las 6:00 de la madrugada, pero  no fuí capaz...
miarroba, o mejor dicho laarroba, se cae cada dos por tres...


He intentado insertar algo parecido a lo que tú hacias en tu código
para guardar o almacenar datos en la epromm con el getbuf,cont, write,cont=cont+1,bufchar, etc... Pero no logro guadar datos en el bufchar, qué puede ser?
Es decir, cuando intento leer la variable bufchar no me lee nada, en cambio si leo datos del bufer y lo sco con hserout me muestra todo.
Saludois


 

anything