Forum: Mikrocontroller und Digitale Elektronik Code Optimierung


von Dennis (Gast)


Lesenswert?

Ich habe einen ATtiny45 der mittels SPI Daten gefüttert bekommt, die die 
zwei PWM ausgänge steuern. Da es zu Doppelbelegung der Pins kommen würde 
nutze ich nicht die SPI Hardware Schnittstelle sondern toggle in 
Software, der Controller hat eh nichts anderes zu tun. Der Bus sollte am 
Ende natürlich schnellstmöglich sein. Ich frage mich vor allem bei 
folgendem Code ob man die Erkennung des Endes der Übertragung nicht noch 
verbessern kann. Ganz allgemein: Geht es schneller, gibt es 
optimierungen?

(Ich nutze den Arduino als Programmer und daher die IDE zum 
programmieren)
1
void setup() {
2
  //Pins 2,3 and 4 are input ports
3
  //DDRB2 is ChipSelect
4
  //DDRB3 is MOSI
5
  //DDRB4 is CLK
6
  DDRB &= ~( (1<<DDB4) | (1<<DDB3) | (1<<DDB2) );
7
  //Pins 0 and 1 are Output ports for PWM
8
  DDRB |= (1<<DDB1) | (1<<DDB0);
9
10
  //Set up timer to fast PWM operation (both Channels)
11
  TCCR0A = (1 << COM0A1) | (1<< COM0B1) | (1 << WGM00) | (1<<WGM01);
12
  //Top at 0xFF, noPrescaler
13
  TCCR0B = (1<<CS00);
14
}
15
16
void loop() {
17
  //While CS is low
18
  SPI_loop:
19
  while( !(PINB & (1<<PINB2)) ){
20
    //Wait for a rising edge at clk
21
    while( !(PINB & (1<<PINB4)) ){
22
      //Check again for CS low (end of transmission detection)
23
      if( PINB & (1<<PINB2) ){
24
        goto SPI_loop;
25
      }
26
    }
27
    //Move MOSI bit to data  
28
    data <<= 1;    
29
    data |= ( PINB >> PINB3 ) & 1;
30
    //Wait for a falling edge at clk
31
    while( PINB & (1<<PINB4) ){}  
32
  }
33
  //Refresh PWM
34
  OCR0A = 128; //50% duty cycle
35
  OCR0B =  63; //25% duty cycle
36
  
37
}

von Julian B. (julinho)


Lesenswert?

Dennis schrieb:
> Geht es schneller, gibt es
> optimierungen?

Warum soll der Code schneller werden, wenn du eh auf den SPI Takt warten 
mußt?

von Dennis (Gast)


Lesenswert?

Naja ich möchte den Bus natürlich so schnell wie möglich laufen lassen, 
wenn der Mikrocontroller jedoch gerade in der behandlung der if 
bedingung steckt während der Takt kommt hab ich momentan sorge das er da 
Bits nicht erwischt.

Ich habe es aber tatsächlich noch nicht ausprobieren können, dachte mir 
aber ich frag direkt doch mal die Profis um Fehler direkt aus der Welt 
zu schaffen.

von dunno.. (Gast)


Lesenswert?

Wenn der controller eh nix anderes tut, ist optimieren irgendwie 
unsinnig.

Es gibt aber schon dinge, die deinen code lesbarer machen würden..

Defines für die pinfunktionen statt bezeichner der pins nutzen.

Kein goto für so eine simple Funktion verwenden. Ein Break sollte es da 
tun..?

Mehr könnte man eh erst sagen wenn der code auch sinnvoll wäre, so 
passiert ja nix. Streng genommen wäre das was du gepostet hast ja 
komplett wegoptimierbar, weil nie verwendet....

von Peter II (Gast)


Lesenswert?

dunno.. schrieb:
> Kein goto für so eine simple Funktion verwenden. Ein Break sollte es da
> tun..?

nein, break springt nur aus der innersten schleife.

von Dennis (Gast)


Lesenswert?

Ja data kommt natürlich noch an OCR0A/B ran. Da stehen nur zum PWM 
funktionstest fixe Werte atm.

Das goto fand ich auch unschön, mir fiel aber keine bessere Lösung für 
die Endbedingung ein.

von nicht“Gast“ (Gast)


Lesenswert?

Moin,

Du benutzt den Arduino, den Arduino Bootloader, die Arduino IDE. Gibt's 
eigentlich einen tieferen Sinn, warum du dann nicht auch die API von 
Arduino benutzt?

Erscheint mir irgend wie unlogisch.

Grüße

von Dennis (Gast)


Lesenswert?

nicht“Gast“ schrieb:
> Du benutzt den Arduino, den Arduino Bootloader, die Arduino IDE. Gibt's
> eigentlich einen tieferen Sinn, warum du dann nicht auch die API von
> Arduino benutzt?
>
> Erscheint mir irgend wie unlogisch.



Naja die IDE benutze ich da ich keinen anderen Programmer für den Attiny 
habe. Aber sowas wie digitalRead/digitalWrite ist einfach viel langsamer 
als die direkten Zugriffe auf die Ports/Register. Und hier kommt es 
nunmal auf Geschwindigkeit an

von nicht“Gast“ (Gast)


Lesenswert?

Dennis schrieb:
> Naja die IDE benutze ich da ich keinen anderen Programmer für den Attiny
> habe. Aber sowas wie digitalRead/digitalWrite ist einfach viel langsamer
> als die direkten Zugriffe auf die Ports/Register. Und hier kommt es
> nunmal auf Geschwindigkeit an

Du sollst ja auch nicht SPI mit digitalRead/Write implementieren. Da 
gibt's bereits weint Klasse für. Die sollte schon schnell genug sein.

von chr (Gast)


Lesenswert?

passt schon, wenn es um Geschwindigkeit geht ...
Die Arduino-IDE ist an manchen Stellen iemlich lahm.

VG,C.

von Ich (Gast)


Lesenswert?

Dennis schrieb:
> Das goto fand ich auch unschön, mir fiel aber keine bessere Lösung für
> die Endbedingung ein.

Ich würde sogar eine extra Statusvariable einführen um das goto 
loszuwerden, denn mit goto sollte man nicht zurück springen, nur 
vorwärts. Zudem ist das Problem auch ohne goto ganz gut lösbar, daher 
würde ich es ersetzen.

von Grobi (Gast)


Lesenswert?

Ich schrieb:
> denn mit goto sollte man nicht zurück springen, nur
> vorwärts.
Bitte Quelle oder kurze Erläuterung dazu angeben, oder ist das eher nur 
soetwas wie eine "urbane Legende"? Habe noch nirgendwoe gelesen / gehört 
das man mit goto nicht zurück springen sollte.
Der Ensatz von goto wird ja im allgemeinen in einer "strukturierten" 
Sprache wie C ja eher vermieden da es sich in 99,999999% der Fälle mit 
einer der Kontrollstrukturen ersetzen läßt.

von Sebastian L. (der_mechatroniker)


Lesenswert?

> Bitte Quelle oder kurze Erläuterung dazu angeben, oder ist das eher nur
> soetwas wie eine "urbane Legende"? Habe noch nirgendwoe gelesen / gehört
> das man mit goto nicht zurück springen sollte.

Ich kenne das so als Merksatz auch nicht, aber ich kann mir denken, wie 
es zustandekommt:

Normalerweise programmiert man strukturiert, sprich, man nutzt für 
Schleifen, Verzweigungen und try-catch-finally-Konstrukte immer die 
entsprechenden Strukturen der verwendeten Programmiersprache und nur 
dann evtl. ein goto, wenn die Programmiersprache die gefragte 
Kontrollstruktur nicht bietet.

C bietet gleich 3 Schleifenkonstrukte, womit der Bedarf für 
"zurückspringende" gotos nicht gegeben sein dürfte. C (und schlanke 
C++-Implementierungen ohne Exceptions, etwa auf µC) bietet kein 
try-catch-finally, damit ist ein legitimer Bedarf für vorwärtsspringende 
gotos da.

von Ich (Gast)


Lesenswert?

Sebastian L. schrieb:
> C bietet gleich 3 Schleifenkonstrukte, womit der Bedarf für
> "zurückspringende" gotos nicht gegeben sein dürfte. C (und schlanke
> C++-Implementierungen ohne Exceptions, etwa auf µC) bietet kein
> try-catch-finally, damit ist ein legitimer Bedarf für vorwärtsspringende
> gotos da.

Genau so ist es. Try catch Ersatz ist auch im Grunde der einzige 
Einsatz, wo man goto sinnvoll verwenden kann. Aber auch das kann man mit 
einem do{}while(0); und entsprechenden breaks eleganter lösen, da die 
Sprunggrenzen hier enger gesteckt sind nämlich nur genau an das Ende der 
Schleife. Wildes zurückspringen im Code verhindert im Allgemeinen nur 
eine saubere Lesbarkeit.

von Peter D. (peda)


Lesenswert?

Es könnte auch helfen, sich erstmal einen Programmablaufplan zu 
erstellen, statt stur drauflos zu schreiben.
Dann kann man viel leichter programmieren und Gotos lösen sich oft in 
Luft auf.

von avr (Gast)


Lesenswert?

Ich schrieb:
> Aber auch das kann man mit
> einem do{}while(0); und entsprechenden breaks eleganter lösen

Wenn man dann auch noch Statusveriablen dafür benötigt, finde ich ein 
goto kürzer und damit lesbarer und eleganter.

Das mit den gotos nach vorne steht übrigens in den neueren MISRA-Regeln. 
Ich meine es war 2008?

von Ich (Gast)


Lesenswert?

avr schrieb:
> Das mit den gotos nach vorne steht übrigens in den neueren MISRA-Regeln.
> Ich meine es war 2008?

Stimmt, sind die MISRA 2012 Regeln:
Rule 15.2
The goto statement shall jump to a label declared later in the same 
function

Als Erklärung steht im Prinzip das oben genannte, dass Sprachkonstrukte 
genutz werden sollten statt goto.

von Daniel A. (daniel-a)


Lesenswert?

Ich hatte bisher erst einen Anwendungsfall für gotos nach oben, bei 
welchem ich diese nicht sinvoll ersetzen konnte, das war hier: 
https://github.com/Daniel-Abrecht/DPA-UCS/blob/5e5378128d4e73b9449782cfe64f4a19588ab918/src/server/protocol/tcp.c 
zeile 555

Ich denke gewisse Dinge lassen sich einfach nur mit gotos schön lösen.

von Ich (Gast)


Lesenswert?

Daniel A. schrieb:
> Ich hatte bisher erst einen Anwendungsfall für gotos nach oben,
> bei
> welchem ich diese nicht sinvoll ersetzen konnte, das war hier:
> https://github.com/Daniel-Abrecht/DPA-UCS/blob/5e5...
> zeile 555
>
> Ich denke gewisse Dinge lassen sich einfach nur mit gotos schön lösen.
Meiner Meinung nach ist das nachbilden von Exceptions so ein Fall aber 
auch das kann man wie unten mit do{...}while(0); umschiffen

Bin mir nicht sicher, ob es das gleiche tut aber auf die Schnelle kam 
das raus:
1
  DPAUCS_tcp_fragment_t** it = tcb->fragments.first;
2
  {
3
    do {
4
      do
5
      {
6
        if( chunck_len <= offset ){
7
          offset -= chunck_len;
8
          continue;
9
        }else{
10
          chunck_len -= offset;
11
          payload = (char*)payload + offset;
12
          offset = 0;
13
        }
14
        tcp_processDatas( tcb, payload, chunck_len );
15
      }
16
      while(0);
17
18
      if(!it){
19
        break;
20
      }else{
21
        it=(*it)->next;
22
      }
23
      if(it){
24
        payload = DPAUCS_getFragmentData(&(*it)->fragment);
25
        chunck_len = (*it)->fragment.size;
26
      }else{
27
        payload = last_payload;
28
        chunck_len = last_length;
29
      }
30
      continue; // Nicht nötig
31
    }
32
    while(1);
33
  }

von avr (Gast)


Lesenswert?

Das ist nicht wirklich besser. Continue um eine do ... while(0) Schleife 
verlassen ist nicht wirklich gut lesbar. Da sollte eher ein break hin.

Ich finde das ist eher ein gutes Beispiel für Spaghetti-Code. Die 
meisten gotos kann man gut eliminieren. Ein unschönes break bleibt, wenn 
die Umformung stimmt.
1
DPAUCS_tcp_fragment_t** it = tcb->fragments.first;
2
      while(1)
3
      {
4
        if( chunck_len <= offset ){
5
          offset -= chunck_len;
6
        }else{
7
          chunck_len -= offset;
8
          payload = (char*)payload + offset;
9
          offset = 0;
10
          tcp_processDatas( tcb, payload, chunck_len );
11
        }
12
13
        if(!it)
14
          break;
15
        it=(*it)->next;
16
        
17
        if(it){
18
          payload = DPAUCS_getFragmentData(&(*it)->fragment);
19
          chunck_len = (*it)->fragment.size;
20
        }else{
21
          payload = last_payload;
22
          chunck_len = last_length;
23
        }
24
      }

von Daniel A. (daniel-a)


Lesenswert?

Nungut, so wie's aussieht geht es auch ohne goto, aber welche variante 
ist Lesbarer und einfacher zu verstehen? Ist dies wirklich die bessere 
lösung?

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.