USART transmite problemas en un PIC

4

Estoy intentando enviar datos a una tarjeta SD desde un PIC18f4580, pero el PIC no está enviando lo que debería ser.

variables globales relacionadas:

unsigned char TXBuffer[128]; //tx buffer
unsigned char TXCurrentPos = 0x00; //tracks the next byte to be sent
unsigned char TXEndPos = 0x00; //tracks where new data should be put into the array

Estoy agregando datos a un búfer usando la siguiente función:

void addToBuffer(char data){

    TXBuffer[TXEndPos] = data;
    TXEndPos++;
}

Y poniendo los datos del TXBuffer en TXREG con la siguiente interrupción:

else if (PIR1bits.TXIF == 1){

    if((TXEndPos - TXCurrentPos) > 0){         // if there is data in the buffer
        TXREG = TXBuffer[TXCurrentPos];           // send next byte
        TXCurrentPos++;               // update to the new position
    }

Utilizando un osciloscopio puedo ver que el PIC está enviando 0x98, independientemente de lo que coloque en el búfer. De hecho, nunca puse 0x98 en el búfer.

Sin embargo, si sustituyo

TXREG = TXBuffer[TXCurrentPos];

con

TXREG = 0x55;

o

TXREG = TXCurrentPos;

luego obtengo los resultados esperados, es decir, el PIC enviará 0x55 repetidamente o contará desde 0 respectivamente.

Entonces, ¿por qué el PIC tiene problemas para enviar datos desde la matriz, pero en cualquier otro momento está bien? Enfatizaré que la transferencia se maneja en una interrupción, porque siento que esa es la raíz de mi problema.

EDITAR: Es un búfer circular en el sentido de que TXEndPos y TXCurrentPos vuelven a 0 cuando llegan a 127. También deshabilito la interrupción de transmisión cuando TXEndPos - TXCurrentPos == 0, y lo vuelvo a habilitar cuando se agregan datos al búfer. Realmente, mi código funciona completamente como se esperaba, ya que si agrego 13 caracteres a TXBuffer en main, mi PIC transmitirá 13 caracteres y luego se detendrá. El problema es que siempre tienen el mismo carácter (incorrecto): 0x98.

EDIT2: hay funciones más completas aquí: enlace

EDIT3: cambiando nuestro script de vinculador y usando pragmas de manera adecuada, podemos obtener algunos de nuestros datos en nuestro búfer. Ubicamos de forma estática variables relacionadas con el búfer en el mismo banco de memoria, y eso ciertamente ha ayudado, pero no todos nuestros datos están ingresando a nuestro búfer. Lo más extraño de todo es que ejecutar el programa varias veces produce datos diferentes en el búfer, aunque todos los datos que se colocarán en el búfer están definidos en nuestro código. Además, obtenemos resultados drásticamente diferentes cuando la imagen se ejecuta automáticamente después de la programación, cuando cortamos la alimentación y reiniciamos la alimentación con el pickit3 aún conectado, y cuando restablecemos la alimentación con el pickit3 desconectado. Además, la simulación en MPLAB hace que el búfer se llene a la perfección, sin embargo, cuando se ejecuta el código en el PIC y se ve en la memoria, no lo es.

Nuestro código a partir de 5:38 9/22/10 está aquí: enlace

Nuestro archivo de enlace modificado está aquí: enlace

    
pregunta

5 respuestas

4

Es un poco confuso que el código en la pregunta difiera del código en pastebin, pero asumiendo que el código pastebin es correcto, diría que el problema es que estás enviando datos no inicializados desde la matriz en lugar de los caracteres que pones en él.

TXREG = TXBuffer[TXEndPos];           // send next byte

debería ser

TXREG = TXBuffer[TXCurrentPos];           // send next byte

Es importante copiar / pegar el código directamente (¡usar pastebin es genial!) porque realmente lo corrigió usted mismo en la pregunta, lo que dificulta que las personas detecten el problema :)

Esto pudo haber sido más fácil de detectar si inicializó el búfer a un valor conocido en el inicio (por ejemplo, 0x5A).

También menciona que restablece TxCurrentPos & TxEndPos variables a cero en algún punto, pero no puedo ver eso en su código. Es mejor hacer esto cada vez que incremente esos valores. Por ejemplo,

TxCurrentPos++;
TxCurrentPos %= TX_BUFFER_SIZE;

Aparte: me gusta que hayas eliminado la variable TxBufferSize redundante en la pregunta, esto sigue al Principio DRY y elimina la fuente de un error. Tener datos duplicados en dos lugares es un problema.

    
respondido por el Peter Gibson
2

Algunas cosas para probar:
1) Asegúrese de que su búfer esté inicializado; esto le dirá si 0x98 proviene del búfer o de otra parte.
2) Desactive las interrupciones cuando agregue elementos al búfer

    
respondido por el mjh2007
1

No veo nada que haga que tu búfer sea circular. Creo que confías en un desbordamiento para pasar de 127 a 0 ... pero un char sin firma puede representar los valores de 0 a 255. Por lo tanto, tu TXCurrentPos se alejará del final de tu matriz.

También he visto a los compiladores PIC C hacer cosas extrañas antes sin ninguna razón. La mayoría de los compiladores también pueden generar la versión ensamblada del programa; Puede que valga la pena dedicar un tiempo a examinar la lista de ensamblajes y ver cómo se compila la C Dependiendo del tipo de datos, TXREG se declara como, el compilador podría estar intentando hacer una conversión.

Además, en su código de recepción en la interrupción, DEBE comprobar si el receptor ha superado la condición y borrarlo. Cada. Soltero. Hora. El receptor RS232 rechazará recibir datos adicionales mientras se establece el bit de error de saturación.

void ClearRXOverRun()
{
    // If there's a frame overrun, RS232 will refuse to receive
    if (OERR == 1)
    {
        // Clear overrun condition by turning RX off and back on
        CREN = 0;
        CREN = 1;   
    }   
}   
    
respondido por el ajs410
0

Lamento que esto pueda sonar muy simple, pero ¿ha intentado escribir sus datos en la EEPROM y luego leerlos más tarde para verificar que, de hecho, está asignando los datos correctos a la matriz? Si los datos que se asignan al búfer no son datos válidos, ¿ese podría ser su problema?

    
respondido por el onaclov2000
0

Para este tipo de problema, divido el problema aún más y luego miro el ensamblaje. También he visto problemas donde el RX podría corromper o desbordar un búfer, así que deshabilitaría el RX hasta que el TX funcione.

Lo primero que haría es mover

if(waitingForACK == 0){
    PIE1bits.TXIE = 1; //Enable the TX interrupt
} 

fuera de addToBuffer to es función propia. Luego llámalo cuando el búfer esté lleno no a medida que avanzas. Podría ser un problema de tiempo en el que no pueda agregar mientras la interrupción está enviando los datos. Cuando transmito un paquete, generalmente deshabilito la interrupción de TX, lleno el búfer de TX y luego habilito la interrupción de TX.

Luego prueba el búfer circular fuera de la interrupción. En tu función principal, llena el búfer y luego lee los datos.

Luego, a continuación, cambie su código de interrupción para pasar por un volátil intermedio. Así que puedes poner un punto de ruptura en tu interrupción y ver qué está pasando. Lo volátil es para que el complaciente no elimine la variable temporal.

volatile unsigned char temp;
if((TXEndPos - TXCurrentPos) > 0)            // if there is data in the buffer
{                                              
    temp  = TXBuffer[TXCurrentPos]; 
    Nop();                                   // for adding breakpoints
    Nop();
    Nop();
    // add error checking to make sure TXREG is empty.
    TXREG = temp;                            // send next byte
    TXCurrentPos = TXCurrentPos + 0x01;      // update to the new position

Otra cosa pequeña es que también me gustaría cambiar

else if (PIR1bits.TXIF == 1){

a

if (PIR1bits.TXIF == 1){

para asegurarse de que las otras interrupciones no estén muriendo de hambre la interrupción de TX.

Luego, si aún tiene el problema, mire el código del ensamblaje. He visto dónde el complaciente hace algo extraño y, por lo general, es obvio que si observa el ensamblaje.

    
respondido por el Rex Logan

Lea otras preguntas en las etiquetas