Comunicación Serial con Modem Enfora

Hola a todos Agradezco si me pueden colaborar con mi proyecto lo que deseo hacer es conectar mi arduino uno por los pines rx y tx a un modem ENFORA enviar un comando at recibir la info de respuesta del modem adjuntar un dato y devolver la info al modem con otro comando.
Lo que hago es enviar el comando
AT$MDMID? El modem me responde
$MDMID: "AAA001"
OK
Necesito tomar solo el dato AAA001. El primer problema que tengo es con la instrucción Seril.read() no puedo tomar todo el dato solo me toma el primer carácter y lo segundo como hago para tomar solo el dato AAA001?

Agradezco su colaboración

Hola.

Que casualidad, llevo un tiempo haciendo lo mismo y no lo he conseguido, solo por ahora. Ya que su pouerto RS232 es d e3.3V.

Dejo un ejemplo de lo que he hecho hace semanas pero cn PIC, para que te hagas una idea.

; ZONA DE DATOS **********************************************************************


	LIST	P=16F88
	INCLUDE	<P16F88.INC>
	__CONFIG	_CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _FOSC_EC
;_XT_OSC
     	__CONFIG	_CONFIG2, _IESO_OFF & _FCMEN_OFF

	CBLOCK	0x20
	ENDC

ENTER	EQU	.13		; Código de tecla "Enter" o "Retorno de Carro".
CAMBIO_LINEA	EQU	.10		; Código para el cambio de línea.

#DEFINE  Entrada0  PORTB,4			; Define dónde se sitúan las entradas.
#DEFINE  Entrada1  PORTB,5
#DEFINE  Entrada2  PORTB,6
#DEFINE  Entrada3  PORTB,7

; ZONA DE CODIGOS ********************************************************************

	ORG	0
	goto	Inicio
	ORG	4							; Aquí se sitúa el vector de interrupción para 
	goto	LeeEntradasVisualiza	; atender las subrutinas de interrupción.

Mensajes				; Los mensajes no deben sobrepasar las 256 
	addwf	PCL,F		; primeras posiciones de memoria de programa.
MensajeEntradas
	DT ENTER, .1, .2, .3, .4, .5, ENTER, 0x00
MensajeWlanActive1
	DT "wlan active 1", ENTER, 0x00
	goto Salir
MensajeWlanActive0
	DT "wlan active 0", ENTER, 0x00
Salir
	call Retardo_5s
	call Retardo_1s
	DT "exit", ENTER, 0x00
	call Retardo_1s

Inicio
	call	RS232_Inicializa
	bsf	STATUS,RP0				; Configura como entrada las 4 líneas correspondientes
	bsf	Entrada0				; del Puerto B respetando la configuración del
;	bsf	Entrada1				; resto de las líneas.
;	bsf	Entrada2
;	bsf	Entrada3
	bcf	OPTION_REG,NOT_RBPU		; Activa las resistencias de Pull-Up del Puerto B.	
	bcf	STATUS,RP0
	bcf	STATUS,RP1
	call	RS232_LineasBlanco		; Visualiza unas cuantas líneas en blanco
	call	RS232_LineasBlanco		; para limpiar la pantalla.
	call	LeeEntradasVisualiza	; Lee las entradas y visualiza por primera vez.
	movlw	b'10001000'				; Habilita la interrupción RBI y la general.
	movwf	INTCON
Principal
	sleep							; Espera en modo de bajo consumo que se
	goto	Principal				; modifique una entrada.

; Subrutina de Servicio a la Interrupcion" ----------------------------------------------
;
; Lee el estado de las entradas y las monitoriza en la pantalla del HyperTerminal.

LeeEntradasVisualiza
	call	RS232_LineasBlanco	
	movlw	MensajeEntradas			; Nombre de las entradas.
	call	RS232_Mensaje			; Lo visualiza en el ordenador.
;LeeEntrada3
;	btfss	Entrada3				; ¿Entrada = 1?, ¿Entrada = Abierta?
;	goto 	Entrada3Cerrado 		; No, está cerrada.
;	call	VisualizaAbierto
;	goto	LeeEntrada2
;Entrada3Cerrado
;	call	VisualizaCerrado
;LeeEntrada2
;	btfss	Entrada2				; Se repite el procedimiento para las
;	goto 	Entrada2Cerrado 		; demás entradas.
;	call	VisualizaAbierto
;	goto	LeeEntrada1
;Entrada2Cerrado
;	call	VisualizaCerrado
;LeeEntrada1
;	btfss	Entrada1	
;	goto 	Entrada1Cerrado 
;	call	VisualizaAbierto
;	goto	LeeEntrada0
;Entrada1Cerrado
;	call	VisualizaCerrado
LeeEntrada0
	btfss	Entrada0
	goto 	Entrada0Cerrado
	call	VisualizaAbierto
	goto	FinVisualiza
Entrada0Cerrado
	call	VisualizaCerrado
FinVisualiza
	call	RS232_LineasBlanco
	bcf	INTCON,RBIF				; Limpia el flag de reconocimiento de la
	retfie							; interrupción.
;
VisualizaAbierto
	movlw	MensajeWlanActive1			; Visualiza el mensaje "Abierto"
	call	RS232_Mensaje			; en el HyperTerminal.
	return
VisualizaCerrado
	movlw	MensajeWlanActive0			; Visualiza el mensaje "Cerrado"
	call	RS232_Mensaje			; en el HyperTerminal.
	return

	INCLUDE  <RS232.INC>
	INCLUDE  <RS232MEN.INC>
	INCLUDE  <RETARDOS.INC>
	END

En esta parte se envía o recibe los comandos AT.
PAaa los comandos AT.

goto	LeeEntradasVisualiza	; atender las subrutinas de interrupción.

Mensajes				; Los mensajes no deben sobrepasar las 256 
	addwf	PCL,F		; primeras posiciones de memoria de programa.
MensajeEntradas
	DT ENTER, .1, .2, .3, .4, .5, ENTER, 0x00
MensajeWlanActive1
	DT "wlan active 1", ENTER, 0x00
	goto Salir
MensajeWlanActive0
	DT "wlan active 0", ENTER, 0x00
Salir
	call Retardo_5s
	call Retardo_1s
	DT "exit", ENTER, 0x00
	call Retardo_1s

Hace semansa compré Arduino UNo r3, haré pruebas con él si me sale te lo enseño.

El router tiene contraseña, ahy que indicarlo dentro del PIC o Arduino. Pulsas Entere, en realidad lo envías que es 0x13 y salto de línea que es 0x10 para mensajes.

Contraseña en mic aso de ejemplo, 12345, luego Enter. Cuando entres, enviarás comandos y lo leer con el serial terminal o una LCD que pusiste en ARduino.

Saludo.

hola Metaconta gracias por la info la voy a analizar y te agradesco si encuentras la solucion para arduino ya llevo varios dias en lo mismo y no lo he logrado

Hola:

Lo que no se si se puede dejar el router sin contraseña, sería las pruebas más códomas. ¿Tienes un router ZyXEL?

Me he pegado más de un mes y hace menos me copré Arduino, parace ser más fácil. Por lo que tengo entendido, mi router tiene el puerto serie dentro para comunicarse por RS232, lo comunico al PC con HyperTerminal de Windows, el TerraTerm Pro e incluso el minicom de Linux. Ahora me toca comunicarlo con cualquier microcontrolador.

Como el PIC y Arduino funcionan a 5 V y el RS232 del router funcona a 3.3V, se necesita un convertidor de tensión como este:

Hoja de datos o datasheet:
74HC4050

También vale este otro y hay muchos más.
HEF4050BP

No se te ocurre añadirle 5V al pin de 3.3V porque lo quemas. Más bien no le conecté nada y no tuve éxito. Deja ver con Arduuino si me hace caso.

Los comandos mejor enviarlo tipo hexadecimal. Funcionan a la primera.

La idea es así:
Dejar el router que se inicie unos buenos menutos.
No debe tener contraseña, si la tienes, pues debes usarlo a travez de Arduinoy enviarlo como hexadecimal.
Recibirás comando desde el inicio y debes reflejarlo en algún LCD para que te des cuenta, aunque sea el 16x2, se le puede poner el de 20x4.
Envías 0x13 que en Enter.
Sale menús en la LCD o en el ordenador si lo tienes conectado ahí.
Tiene que ser paso por paso.

El ejemplo tonto que quiero hacer es activar y desactivar Wi.fi por ese puerto, si lo logro, ya hago lo que quiero.

Saludo.

Hola. Deberías echar primero un vistazo a la referencia de Serial para entender cómo trabaja read y de paso ver otros comandos útiles.
Quizás te podría servir, tras enviar tu comando algo como:

char comando[21], respuesta[21];
void setup() {
        Serial.begin(9600);
  // put your setup code here, to run once:

}

void loop() {
        if (Serial.available() > 0) {
                comando[Serial.readBytesUntil(':', comando, 20)]=0;
                respuesta[Serial.readBytesUntil('\n', respuesta, 20)]=0;
                Serial.print("Comando: ");
                Serial.println(comando);
                Serial.print("Respuesta: ");
                Serial.println(respuesta);
        }
}

hola noter gracias por la info y me funciona un poco mejor pero sigo con vario problemas soy bastante nuevo en esto y no entiendo bien la sintaxis de las comandos o mejor dicho este

respuesta[Serial.readBytesUntil('\n', respuesta, 20)]=0;

si pudieras explicarmelo me ayudarias mucho y eternamente agradecido jejej

Efectivamente, te he puesto una línea un poco críptica, que condensa varios comandos.
Te la desempaqueto a ver si es más legible:

char comando[21]; // un buffer de 21 caracteres para guardar el comando
int numCaracteresLeidos=Serial.readBytesUntil(':', comando, 20); // Lee caracteres hasta encontrar ':' y devuelve el número de caracteres leídos
comando[numCaracteresLeidos]=0; // agregamos a los caracteres leídos un terminador de cadena (caracter 0 o '\0'

No has mirado este post que colgue hace un tiempo?
http://forum.arduino.cc/index.php?topic=176212.msg1313025#msg1313025

compañeros ante todo gracias por su colaboracion me ha sido muy util ya casi logro el mi objetivo les comento exactamente que es lo que etoy haciendo:

a un modem (equipo de rastreo satelital enfora) le meto el comando AT$GPSRS=10 a lo que el modem me responde:

$GPRMC,153852.00,A,0438.681488,N,07408.994629,W,0.0,0.0,260214,5.4,E,A*2B

de esa cadnea solo necesito el dato de velocidad que es el que esta despues de la W que es la velocidad y devolverlo al modem por medio de otro comando;

aca dejo el codigo que use me funciona bien pero las primeras 6 veces luego me muestra datos raros lo que creo es que tengo que limpiar la varilabes char antes de usarlas nuevamente pero no se como hacer eso

int i = 0;
char GPS_RMC[100];
char *lck; // Creamos un puntero de tipo char

void setup(){
Serial.begin(9600);
Serial.flush();
}

void loop (){
Serial.flush();
Serial.println("AT$GPSRD=10"); // envia comando al modem
delay(2000); // espera respuesta
if(Serial.available()>0){
Serial.readBytesUntil('$',GPS_RMC,80); // lee los datos apartir de $
}
i=0;
lck = strtok(GPS_RMC,","); // corta la cadena recibida por la comas
if(strcmp(lck,"GPRMC")==0){ //si es correcto
while(lck != NULL)
{
lck = strtok (NULL,","); // pasa al siguiente tramo
RMC*=lck;*

  • i++;*
    }

  • Serial.print("AT$MSGSND=4,"); //enviamos el dato nuevamente*

  • Serial.print('"'); // enviar caracter " // al modem*

  • Serial.print(RMC[6]); // mediante el comando envio de mensaje*

  • Serial.println('"'); *

  • delay(5000);*
    }
    }

Hola.
Tu código me da un error de compilación, ya que RMC no aparece definido:

sketch_feb26a:23: error: 'RMC' was not declared in this scope
sketch_feb26a:29: error: 'RMC' was not declared in this scope

No sé si será por eso que no consigo entender el código de búsqueda del parámetro W.
No obstante, hay un par de cosillas que creo que deberías revisar. En primer lugar, donde lees el serial, lees hasta encontrar el carácter $, con lo que la primera vez te va a devolver sólo ese caracter, y hasta no volver a recibir el $ de la segunda trama (o salte un timeout), no va a salir del readBytesUntil con los datos de la primera trama. Yo utilizaría como carácter de final para readBytesUntil el último que envíe la trama, que supongo que sea salto de línea o retorno de carro (puedes analizar la trama para cerciorarte).
En segundo lugar, ese delay de cinco segundos al final podría hacer que, si el modem sigue enviando datos, el buffer serial se llegue a llenar, con lo que vas a perder datos y podría ser la causa de que te empiece a dar valores extraños tras varias repeticiones de loop.
Saludos.

hola noter si ya lo corregi y me funciona bien ya tengo el dato y lo puedo trabajar pero ahora tengo otro problemita pequeñito ese dato tengo que convertirlo a Kilometros por hora me explico.

el dato bien en nudos y lo necesito en kilometros por hora para eso tengo que multiplicarlo por 1.8532 he leido pero no comprendo bien como manejar estas operaciones .

lo que hice fue definir unas variables

int vel = 0;
int conv = 1.8532 ;
int km = 0;

y luego de cortar la trama en pedasitos tomo el que contiene la velocidad para convertirlo

vel = atoi (RMC[6]); // convertir a entero el RMC[6] que es la velocidad extraida de la trama
km = vel*conv; // lo multiplico por la varable de convercion a kilometros

pero la verdad no se si eso es correcto y pues no he podido pobarlo en movimiento para verificar si si da bein la convercion tu me podrias explicar si esta mal el porque?

el codigo final es este y me ha funcionado bien (despues de las dos primeras veces que se envia el comando jejeej)

int i = 0; // variable acumulador
char TrazaGps[100]; // Array donde se almacenan los bytes leidos de la trama gps
char *RMC[15]; // array de punteros de tipo char
char *lck; // Creamos un puntero de tipo char
int vel = 0;
int conv = 1.8532 ;
int km = 0;

void setup()
{
Serial.begin(9600);
Serial.flush();
}

void loop ()
{
Serial.flush();
Serial.println("AT$GPSRD=10");

Serial.readBytesUntil('$',TrazaGps,80);
i=0;
lck = strtok(TrazaGps,",");
if(strcmp(lck,"GPRMC")==0) // verifica si si es la trama GPRMC
{
while(lck != NULL)
{
lck = strtok (NULL,","); // pasa al siguiente tramo
RMC*=lck;*

  • i++;*
    }

vel = atoi (RMC[6]); // convertir a entero el RMC[6] que es la velocidad extraida de la trama
_km = vel*conv; // pasarlo a kilometros _

  • delay(2000);*
  • Serial.print("AT$MSGSND=4,"); //escribimos el comando*
  • Serial.print('"'); // enviar caracter "*
  • Serial.print(km); // Escribimos la velocidad*
  • Serial.println('"'); // enviar caracter " y enter*
  • delay(1000);*
  • }*

}

Hola.
El problema es debido a que has definido las variables como int, por lo que estás multiplicando por 1 y no por 1.8532.
Tal vez te baste con declarar conv como float , y si no basta, tendrás que convertir también a flota vel.
Saludos.

muchas gracias era eso ya me funciona perfecto