Error al manejar cadenas en un 8051

3

Estoy usando un CC1110 de Texas Instruments, que se basa en el microcontrolador 8051 . Lo estoy programando usando el IAR Embedded Workbench.

He escrito una función llamada sendChar que envía un char de 8 bits a través de la interfaz UART. Ejecutando el siguiente código:

sendChar('H');
sendChar('e');
sendChar('l');
sendChar('l');
sendChar('o');
sendChar(' ');
sendChar('W');
sendChar('o');
sendChar('r');
sendChar('l');
sendChar('d');

Los resultados en el comportamiento esperado de Hello world se envían a través del canal UART. Pero luego definiendo la función sendString como:

void Serial::sendString(char *str) {
  unsigned int i;
  for(i = 0; i < strlen(str); i++) this->sendChar(str[i]);
}

y ejecutando el siguiente código:

sendString("Hello world");

los resultados en 0xFF se envían más de 100 veces.

Me he dado cuenta de que enviar la salida strlen con la función sendChar revela que se está generando la longitud de cadena incorrecta. Por ejemplo, si ejecuto el siguiente código:

char str[100] = "Hello world";
sendChar(strlen(str));

Recibo 101 en lugar de 11 como uno esperaría.

¿Qué estoy haciendo mal?

Editar

Si ejecuto el siguiente código:

char str[100] = "Hello world";
sr.sendChar(str[1]);
sr.sendString(str);

uno esperaría recibir eHellow world , pero en cambio recibo 101 puntos . (0xFF).

Editar 2

Código completo:

#include <ioCC1110.h>
#include <ioCCxx10_bitdef.h>
#include <math.h>
#include <string>

void sendChar(char c);
void sendString(char *str);

void main(void) {
    CLKCON = 0; // Crystal oscillator, no pre-scaler

    U0CSR |= U0CSR_MODE; // USART0 in UART mode
    P0SEL |= BIT3 | BIT2; //P0.2 and P0.3 as peripherials

    // Baud rate = 9600 (9597)
    U0GCR |= 8;
    U0BAUD = 131;

    // Enable Rx and Tx interrupts
    IEN2 |= IEN2_UTX0IE;
    URX0IE = 1;

    while(P0_4); // Wait for P0.4
    char str[100] = "Hello world";
    sr.sendString(str);
    while(1); // Wait so main() never ends

}

void sendString(char *str) {
  while (*str) sendChar(*str++);
}

void sendChar(char c) {
  U0DBUF = c & 0xFF;
  while(!UTX0IF);
  UTX0IF = 0;
}

Editar 3

He ejecutado un principal sencillo:

int main( void ) {
  char str[] = "Hello world";
  CLKCON = 0; // Crystal oscillator, no pre-scaler
  P2DIR = 1; // P2.0 as output
  P2 = 0;
  char l = str[2];
  Serial sr;
  while(P0_4); 
  sr.sendString(str);
  while(1);  
}

y lo depuré. Aquí hay una captura de pantalla del valor de la matriz str . Está lleno de puntos, como informé anteriormente.

¿Alguna idea sobre qué está causando eso?

    
pregunta jagjordi

2 respuestas

2

Creo que tienes más de un problema. Como no identificas tu compilador ni cómo lo configuras, será difícil ayudarte con instrucciones precisas.

Empecemos con el problema # 1.

Dada tu última prueba, me parece que strlen () no está funcionando.

La función sizeof (), que no está utilizando aquí, se evalúa en el momento de la compilación y es posible que haya devuelto un gran número ya que su trabajo consiste en indicarle el tamaño conocido de un búfer como este.

Pero strlen () evalúa en tiempo de ejecución y debería informar técnicamente la longitud real de la cadena después de la inicialización con la cadena. Si esta cadena se coloca estáticamente (fuera de una función en el "nivel de módulo / archivo"), entonces esta inicialización debe tener lugar antes de que se inicie main () (por código de ensamblaje oculto). Si esta cadena se coloca como una función variable local, entonces esta inicialización tiene lugar cada vez que se llama a la función (recuerdo los días, sin embargo, mucho antes de que llegara el primer estándar C cuando se ignoraba dicha inicialización). De cualquier manera, su código no debería poder llamar a strlen ( ) antes de que tenga lugar la inicialización. Por lo tanto, strlen () siempre debería poder "ver" la cadena.

Entonces, o strlen () no está funcionando, o está funcionando. Si no está funcionando, necesitas averiguar por qué. Si está funcionando, entonces la cadena de inicialización no se está inicializando correctamente (o se está inicializando con basura o con algún desorden de varios bytes en un idioma extranjero). Si ese es el caso, también debe rastrearlo.

Una cosa que hay que intentar, para verificar que el búfer de cadena se está inicializando es DEJAR DE INTENTAR usar funciones de cadena en él. Obviamente, eso NO FUNCIONA para ti. Así que ahora, intente y elimine algunos valores de byte como números enteros. Mira lo que hay en ese búfer. Verificar !!!

Tampoco estoy completamente seguro de si su programa receptor está obteniendo el número correcto de bytes, o no. Me gustaría que confirmaras o negaras esa pregunta en mi mente. Creo que estás diciendo que está recibiendo muchos más personajes. Y, si el resultado de strlen () es contar muchos caracteres, entonces tiene sentido que se envíen muchos caracteres. Pero me gustaría que hablaras un poco más sobre esto. Solo porque podría elegir algo de lo que agrega.

El otro problema que veo es que su receptor (sea lo que sea que esté "recibiendo" los caracteres que se envían) no está obteniendo los valores correctos. Esto puede ser por varias razones posibles. Dado que se trata de comunicaciones asíncronas (tal como las obtengo), es posible que las velocidades de bits no coincidan entre el remitente y el receptor. ¿Te aseguraste de inicializar la librería serial correctamente? ¿En ambos extremos? Esto también podría dar cuenta de los diferentes números de caracteres que se envían de los que se reciben, así como de la basura que ve. Es vital que se combinen bien estas cosas.

Otra posibilidad es que su biblioteca emisora esté utilizando un bit de parada y su lado receptor espere dos bits de parada, por ejemplo.

Otra posibilidad es que su código / dispositivo de recepción / lo que sea no pueda manejar los caracteres consecutivos. Tiene un retardo estúpido e idiota dentro de él que evita que analice correctamente un flujo continuo de caracteres asíncronos. Pero puede recibirlos uno por uno, con intervalos de tiempo entre ellos. Así que obtienes cosas que parecen correctas cuando usas una llamada por separado, cada vez. Porque hay un largo retraso en el medio. Pero cuando envías una cadena, el código de envío simplemente SE ENCUENTRA RÁPIDAMENTE, espalda con espalda, y tu receptor simplemente se siente abrumado y no puede seguir el ritmo.

Por ahora, eso es todo lo que puedo imaginar fácilmente. Así que intente estas pocas cosas antes que después:

  1. Verifique que esté inicializando correctamente la tasa de sincronización con la biblioteca que está utilizando en el lado del transmisor.
  2. Verifique que esté utilizando la misma tasa correctamente en el lado del receptor.
  3. Verifique que los relojes usados en ambos lados sean capaces de proporcionar esas tasas dentro de las barras de error apropiadas para async (aproximadamente 2% o menos).
  4. Verifique que la cantidad de bits de parada coincida, o que el lado de transmisión use MÁS tiempo de bit de parada que el lado de recepción, si no coinciden.
  5. Rastrear lo que se está colocando en sus búferes de cadena. No asuma Verificar. Compruebe los primeros 10 bytes. Imprima sus valores de bytes como enteros y vea cuáles son.
  6. Escanee a través del buffer de cadena en busca de un byte 0. Cuando encuentre el primer byte 0, indíquenos en qué índice de búfer se produce:
  7. Conecte su dispositivo receptor a alguna otra fuente. Verifique que pueda recibir una cadena continua sin error.
  8. Díganos qué compilador está utilizando.
respondido por el jonk
2

Uso:

while (*str)
   sendChar(*str++);

Es posible que desee agregar retornos de carro si la cadena tiene feeds de línea:

while (*str)
{ if (*str==0x0A)
      sendChar(0x0d);
   sendChar(*str++);
}

Sus últimos datos de depuración muestran lo que he estado esperando todo el tiempo: su cadena de cadenas no se inicializa. Aunque esto no es estrictamente correcto según el código C / C ++, no me sorprende. Cuando se trabaja con microcontroladores, a menudo hay limitaciones para lo que soporta el compilador. Sospecho que su compilador no admite la inicialización de variables en la llamada de función.

Sugerí hace un tiempo para hacer que la cadena sea global. La razón es que la mayoría de las MCU tienen código en crt0.s para copiar los valores de la ROM a la RAM en el inicio para las variables inicializadas. La copia debe hacerse porque usted especificó la cadena como 'modificable', por lo tanto, debe residir en la RAM. Si haces el valor

const char str[100] = ".."; 

Es probable que la cadena se asigne al área de la ROM, ya que nunca es necesario cambiarla. Consulte el manual de su compilador, que debería tener una sección sobre cómo se asignan las variables según cómo las defina.

    
respondido por el Oldfart

Lea otras preguntas en las etiquetas