Forum: Mikrocontroller und Digitale Elektronik Simulation einer for-schleife (Software SPI)


von hilflos (Gast)


Lesenswert?

Guten Tag,

Zu allererst: Ich habe kein Ozilloskop und versuche mich deshalb gerade 
mit dem Simulator vom AtmelStudio 6.1.2440 beta.

Die Funktion, die aufgerufen wird, sieht folgendermaßen aus:
1
void send_spi(uint8_t byte){
2
uint8_t i=0;
3
//PB 7 = clock; , auf low ziehen
4
PORTB &= ~(1 << PB7);
5
6
  for (i=0;i<8;i++) {
7
    if (byte &(1 << (7-i))) {
8
      PORTB |= (1 << PB5);
9
    }      
10
    else {
11
      PORTB &= ~(1 << PB5);
12
    }
13
          
14
    PORTB |= (1 << PB7);
15
    _delay_ms(1);
16
    PORTB &= ~(1 << PB7);
17
    _delay_ms(1);
18
  }
19
20
PORTB &= ~(1 << PB5);
21
}

Letzendlich soll eine Art Software SPI realisiert werden. Der Simulator 
von Atmel geht allerdings bei i=0 nicht mehr in die if-Bedingung. Mir 
fehlt also in der Simulation das letzte Bit. Warum? Letzendlich würde 
ich dann ja haben:
if (byte &(1 << 0))
Mag das der Simulator nicht? Oder mag das der compiler schonmal 
garnicht?

Ich bin ratlos und weiß also nicht, ob der Fehler im Simulator oder im 
Code liegt.

Danke für jeden Hinweis!

von Falk B. (falk)


Lesenswert?

@  hilflos (Gast)

>Die Funktion, die aufgerufen wird, sieht folgendermaßen aus:

>void send_spi(uint8_t byte){
>uint8_t i=0;
>//PB 7 = clock; , auf low ziehen
>PORTB &= ~(1 << PB7);

>  for (i=0;i<8;i++) {
>    if (byte &(1 << (7-i))) {

Ist ungünstig. Besser so.

http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Schiebeoperationen

>Letzendlich soll eine Art Software SPI realisiert werden.

Sieht OK aus.

> Der Simulator
>von Atmel geht allerdings bei i=0 nicht mehr in die if-Bedingung.

Doch.

> Mir
>fehlt also in der Simulation das letzte Bit.

Nö, i fängt ja mit 0 an!

> Warum? Letzendlich würde
>ich dann ja haben:
>if (byte &(1 << 0))
>Mag das der Simulator nicht?

Das sollte kein Problem sein.

>Ich bin ratlos und weiß also nicht, ob der Fehler im Simulator oder im
>Code liegt.

Möglicherweise am Simulator. Schalte mal im Compiler die Optimierung 
aus, in den Projektoptionen.

von hilflos (Gast)


Lesenswert?

Hallo Falk!

Hab das Problem gelöst. Undzwar hab ich den Code mit Hilfe deines Links 
und ein bisschen google umgebaut und nun simuliert er einwandfrei. Mit 
den Optimierungsoptionen hab ich garnichts weiter getan. Zur 
Vollständigkeit hier einmal der Code:
1
void send_spi(uint8_t byte){
2
uint8_t i=0;
3
//PB 7 = clock;
4
uint8_t mask = 0x80;
5
6
  for (i=0;i<8;i++) {
7
    if (byte &(mask)) {
8
      PORTB |= (1 << PB5);
9
    }
10
    else {
11
      PORTB &= ~(1 << PB5);
12
    }
13
14
    PORTB |= (1 << PB7);
15
    _delay_ms(1);
16
    PORTB &= ~(1 << PB7);
17
    _delay_ms(1);
18
    mask = (mask >> 1);
19
  }
20
21
PORTB &= ~(1 << PB5);
22
}

Danke!

von Fallobst (Gast)


Lesenswert?

Anstatt der Maske kann man gleich das zu sendende Byte schieben. Das ist 
noch ein bisschen effizienter.

von Falk B. (falk)


Lesenswert?

@  hilflos (Gast)

>Vollständigkeit hier einmal der Code:

Das kann man noch ein klein wenig effizienter machen, ohne 
Schleifenzähler. Die Maske reicht. Siehe unten. Und byte ist kein guter 
Name für eine Variable.

1
void send_spi(uint8_t data){
2
3
  uint8_t mask;
4
5
  for (mask=0x80; mask !=0; mask >>= 1;) {
6
    if (data & mask) {
7
      PORTB |= (1 << PB5);
8
    }
9
    else {
10
      PORTB &= ~(1 << PB5);
11
    }
12
13
    PORTB |= (1 << PB7);
14
    _delay_ms(1);
15
    PORTB &= ~(1 << PB7);
16
    _delay_ms(1);
17
    mask >>= 1;
18
  }
19
20
PORTB &= ~(1 << PB5);
21
}

von Falk B. (falk)


Lesenswert?

@  Fallobst (Gast)

>Anstatt der Maske kann man gleich das zu sendende Byte schieben. Das ist
>noch ein bisschen effizienter.

Das ist egal, man braucht so oder so einen Schleifenzähler.

von Fallobst (Gast)


Lesenswert?

Die Maskierung data & mask spart man sich aber.

von Wusel D. (stefanfrings_de)


Lesenswert?

Ich habe die Erfahrung gemacht, dass optimierter Code sich schlecht im 
simulator debuggen lässt. Also simuliere ich immer erst mit -O0 und 
hoffe, dass das Programm später mit -Os oder -O1 noch richtig 
funktioniert. Bis jetzt hatte es stets geklappt.

von Falk B. (falk)


Lesenswert?

@  Fallobst (Gast)

>Die Maskierung data & mask spart man sich aber.

Eine Maskierung mit einer Konstanten ist hier auch nicht schneller.
Einen Zugriff auf das Carry-Bit wie unter Assembler hat man in C nicht.

von Fallobst (Gast)


Lesenswert?

Falk Brunner schrieb:
> Eine Maskierung mit einer Konstanten ist hier auch nicht schneller.
> Einen Zugriff auf das Carry-Bit wie unter Assembler hat man in C nicht.

Richtig, mit dem Carry wäre es noch schneller. Aber selbst ohne ist die 
Version besser. Die Maskierung benötigt zwei Assembler-Befehle (mov, 
and) + Sprungbefehl. Ein konstantes Bit lässt sich entweder mit 
sbrc/sbrs oder mit bst+brts/brtc prüfen. Außerdem wird ein Register 
weniger benötigt (spielt hier keine Rolle).

von Falk B. (falk)


Lesenswert?

OK, es noch einen Tick effizienter ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.