Ich programmiere einen ATMEGA328p auf einem Steckbrett und verwende ein Arduino-Board, um die USB-zu-Seriell-Konvertierung durchzuführen. Ein Teil eines Codes, den ich schreibe, beinhaltet eine for-Schleife, die verwendet wird, um die 8-Bit-Ausgabe von der SPI-MOSI-Leitung (verbunden mit einer SD-Karte) zu nehmen und sie in eine 64-Bit-Binärzahl zu stecken, damit ich sie an ausgeben kann Serieller Monitor. Ich habe es getestet, und ich bekomme eine Endlosschleife und ich weiß nicht, was falsch ist. Der Code ist unten gepostet. Machen Sie sich keine Sorgen um den USART-Code, er funktioniert. Der Testfall (das Array lila[5]) wird verwendet, um herauszufinden, warum die for-Schleife unendlich ist.
Wenn Sie auch eine einfachere Möglichkeit kennen, den 40-Bit-Code auszugeben, den eine SD-Karte nach Verwendung der Befehle SEND_IF_COND und SD_SEND_OP_COND ausgibt, wäre dies ebenfalls hilfreich.
#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');
}
In Ihrem Code haben Sie die folgende verdächtige Zeile:
for (int loop_bit=7; ((loop_bit < 8)||(loop_bit < 254)); loop_bit--){
...
}
Das Hauptproblem dabei ist, dass as loop_bit
ein 'int' ist. In avr-gcc ist dies ein 16-Bit-Datentyp mit Vorzeichen. Sie haben eine Schleifenbedingung, die ist loop_bit < 254
(und die redundante loop_bit < 8
). Wenn Sie also weiterhin 1 subtrahieren, müssen Sie den ganzen Weg bis -32768 herunterzählen und dann eine Iteration weiter zählen, damit es auf 32767 umläuft, bevor die for-Schleife beendet wird.
Wenn Sie von 7 bis einschließlich 0 herunterzählen möchten, können Sie eines der folgenden zwei Dinge tun:
Dies kommt dem, was Sie derzeit haben, am nächsten
for (int loop_bit=7; loop_bit>=0; loop_bit--){
...
}
Dies ist auf einem 8-Bit-AVR effizienter
for (int8_t loop_bit=7; loop_bit>=0; loop_bit--){ //assuming avr-gcc understands 'int8_t', if not you can do 'char'
...
}
Als Randnotiz, und nur meine persönliche Meinung, haben Sie in einem anderen Teil des Codes auch diese for-Schleife:
for(bit=7; bit<255; bit--){
...
}
Dies funktioniert gut, da bit als deklariert ist uint8_t
, aber es wäre lesbarer, "bit" als signierten int8_t
Typ zu deklarieren und die folgende Schleife zu verwenden:
for(bit=7; bit>=0; bit--){
...
}
Die Verwendung des vorzeichenbehafteten Typs ermöglicht es, dass die Zahl negativ wird und die Schleife beendet wird. Funktionell (und wahrscheinlich auch in der Montage) sind die beiden Schleifen wie gesagt identisch, aber ich persönlich finde letztere einfacher zu folgen.
int8
Ich bin nicht mit einem Standard-Ganzzahltyp
vertraut . Ist es spezifisch für Arduino? Ich kann es nicht in ihrem Kernquellcode finden ... Ich denke, Sie meinen vielleicht, int8_t
was in definiert ist stdint.h
und wie der Dateiname andeutet, ist eine ST- und D- ARD- INT- Eger-Typdefinition.int_least8_t
eine bessere Wahl als int8_t
. Letzteres existiert nicht auf (zugegebenermaßen seltenen) Systemen, die keinen nativen 8-Bit-Typ haben. Ersteres wird immer funktionieren.
Greg d’Eon
Kat
Greg d’Eon
Kat
Tom Tischler
Kat