Mi bucle For no está saliendo y no sé por qué

2

Estoy programando un ATMEGA328p en una placa de pruebas y estoy usando una tarjeta arduino para hacer la conversión de USB a serie. Parte del código que escribo involucra un bucle for que se usa para tomar la salida de 8 bits de la línea SPI MOSI (conectada a una tarjeta SD) y pegarla en un número binario de 64 bits para que pueda enviarla al monitor de serie. Lo he estado probando, y estoy recibiendo un bucle infinito y no sé qué está mal. El código se publica a continuación. No te preocupes por el código USART, funciona. El caso de prueba (la matriz púrpura [5]) se usa para averiguar por qué el bucle for es infinito.

Además, si conoce una forma más fácil de generar el código de 40 bits que genera una tarjeta SD después de usar los comandos SEND_IF_COND y SD_SEND_OP_COND, eso también sería útil.

#define USART_BAUDRATE 9600
#define F_CPU 16000000
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/power.h>

void Init_USART(void);
void newLine(void);
void transmitByte(uint8_t my_byte);
void printNumber(uint8_t n);
void print64BitNumber(uint64_t bits);
void printBinaryByte(uint8_t byte);
void printString(const char myString[]);

int main(void){
    Init_USART();
    uint8_t purple[5];
    purple[0] = 0b11110111;
    purple[1] = 0b00010000;
    purple[2] = 0b11111111;
    purple[3] = 0b00110000;
    purple[4] = 0b11111111;
    uint8_t counter = 0;
    uint64_t push_bit = 1;
    uint64_t error_codes = 0;
    for (int i=0; i<5; i++){
        for (int loop_bit=7; ((loop_bit < 8)||(loop_bit < 254)); loop_bit--){
            push_bit = 1;
            printNumber(loop_bit);
            print64BitNumber(error_codes);
            newLine();
            printNumber(counter);
            newLine();
            if(bit_is_set(purple[i],loop_bit)){
                error_codes |= (push_bit << (loop_bit+(i*8)));
            }
            else{
                error_codes &= ~(push_bit <<(loop_bit+(i*8)));
            }
        }
        counter += 1;
    }
    return 0;
}
////////////////////////////////////////////////////////////////////////////////
//USART Functions///////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void Init_USART(void)
{
    clock_prescale_set(clock_div_1);
    UCSR0B = (1<<RXEN0)|(1<<TXEN0); //Enables the USART transmitter and receiver
    UCSR0C = (1<<UCSZ01)|(1<<UCSZ00)|(1<<USBS0); //tells it to send 8bit characters (setting both USCZ01 and UCSZ00 to one)
    //now it has 2 stop bits.

    UBRR0H = (BAUD_PRESCALE >> 8); //loads the upper 8 bits into the high byte of the UBRR register
    UBRR0L = BAUD_PRESCALE; //loads the lower 8 bits
}

void printBinaryByte(uint8_t byte){
    uint8_t bit = 0;
    //This code is really efficient.  Instead of
    //using large ints to loop, it uses small uint8_t's.
    for (bit=7; bit<255; bit--){
        if(bit_is_set(byte,bit)){
            transmitByte('1');
        }
        else{
            transmitByte('0');
        }
    }
}
//uint8_t is used for 8bit chars
void transmitByte(uint8_t my_byte){
    do{}while(bit_is_clear(UCSR0A, UDRE0));
    //UDR0 is the transmit register.
    UDR0 = my_byte;
}
void newLine(void){
    printString("\r\n");
}
void printString(const char myString[]){
    uint8_t i = 0;
    while(myString[i]){
        while ((UCSR0A &(1<<UDRE0)) == 0){}//do nothing until transmission flag is set
        UDR0 = myString[i]; // stick Chars in the register.  They gets sent.
        i++;
    }
}
//Prints 64 bit number.
void print64BitNumber(uint64_t bits){
    printBinaryByte(bits >> 56);
    printBinaryByte(bits >> 48);
    printBinaryByte(bits >> 40);
    printBinaryByte(bits >> 32);
    printBinaryByte(bits >> 24);
    printBinaryByte(bits >> 16);
    printBinaryByte(bits >> 8);
    printBinaryByte(bits);
}


void printNumber(uint8_t n){//This function Prints a number to the serial monitor
    //Algorithm to convert 8 bit binary to 3 digit decimal.
    //N=16(n1)+1(n0)
    //N=n1(1*10+6*1)+n0(1*1)
    //N=10(n1)+1(6(n1)+1(n0))
    //Also: N = 100(d2)+10(d1)+1(d0)
    //Then make: a1 = n1 and a0 = (6(n1)+1(n0))
    //Then get rid of the carries since n0 can be from 0-15, etc.
    //c1 = a0/10 This is the number of 10's to carry over
    //d0 = a0%10 This is the decimal that's outputed.
    //c2 = (a1+c1)/10
    //d1 = (a1+c1)%10
    //d2 = c2
    uint8_t d2, d1, q;
    uint16_t d0;
    //0xF is 15
    //00010000 this is 16 (n)
    //d0 = 00010000 & 00001111, d0 = 00000000
    d0 = n & 0xF;
    //If you AND n then the bits in the original number show in d0,d1 and d2
    //d1 = (00010000 >> 4) same as 00000001, & 00001111, d1 = 00000001
    //this sees if there's anything in the second 4 bits
    d1 = (n>>4) & 0xF;
    d2 = (n>>8);
    //this sets d2 to 0.

    d0 = 6*(d2+d1)+d0;
    q = d0/10;
    d0 = d0%10;

    d1 = q + 5*d2 + d1;
    if (d1!=0){
        q = d1/10;
        d1 = d1%10;

        d2 = q+2*d2;
        if (d2!=0){
            transmitByte(d2 + '0');
            //remember to add '0' because its an ASCII char
        }
        transmitByte(d1 + '0');
    }
    transmitByte(d0 + '0');

}
    
pregunta Cate

1 respuesta

7

En tu código tienes la siguiente línea sospechosa:

for (int loop_bit=7; ((loop_bit < 8)||(loop_bit < 254)); loop_bit--){
    ...
}

El problema clave con esto es que como loop_bit es un 'int'. En avr-gcc este es un tipo de datos firmado de 16 bits. Tiene una condición de bucle que es loop_bit < 254 (y el loop_bit < 8 redundante). Como tal, si sigue restando 1, debe contar hasta -32768 y luego una iteración adicional para que se ajuste a 32767 antes de que salga el bucle for.

Si desea contar de 7 a 0 inclusive, puede hacer una de las siguientes dos cosas:

  1. Esto es lo más cercano a lo que tienes actualmente

    for (int loop_bit=7; loop_bit>=0; loop_bit--){
        ...
    }
    
  2. Esto es más eficiente en un AVR de 8 bits

    for (int8_t loop_bit=7; loop_bit>=0; loop_bit--){ //assuming avr-gcc understands 'int8_t', if not you can do 'char'
        ...
    }
    

Como nota al margen, y solo mi opinión personal, en otra parte del código, también tiene esto para el bucle:

for(bit=7; bit<255; bit--){
    ...
}

Esto funcionará bien ya que el bit se declara como uint8_t , pero sería más legible declarar 'bit' como un tipo int8_t firmado y usar el siguiente bucle:

for(bit=7; bit>=0; bit--){
    ...
}

El uso del tipo firmado permite que el número pase a ser negativo y haga que el bucle salga. Funcionalmente (y probablemente en ensamblaje) los dos bucles son idénticos a lo que digo, pero personalmente me parece más fácil seguir estos últimos.

    
respondido por el Tom Carpenter

Lea otras preguntas en las etiquetas