- Labornetzteil AliExpress         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 22

Thema: Das Gleiche ist nicht das Selbe - Laufzeitunterschiede

  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652

    Das Gleiche ist nicht das Selbe - Laufzeitunterschiede

    Anzeige

    Praxistest und DIY Projekte
    Hallo alle,

    bei zwei sehr kurzen, prinzipiell gleichen Codestücken habe ich Laufzeitunterschiede festgestellt.

    Im Thread von copius über die empfohlene Vorgehensweise für Programmaufbau wurde ein hübsches Beispiel zur Erleichterung der Les- und Schreibbarkeit von C durch askazo vorgestellt. Es betrifft einfache Bitoperationen zum Setzen und Löschen von Port-/Registerpins. Hier mal 1:1 kopiert:

    Zitatanfang:
    Code:
    #define SetBit(ADDRESS,BIT) 	((ADDRESS) |= (1<<(BIT)))			//!< Setzt ein bestimmtes Bit eines Registers
    #define ClrBit(ADDRESS,BIT) 	((ADDRESS) &= ~(1<<(BIT)))			//!< Löscht ein bestimmtes Bit eines Registers
    #define ToogleBit(ADDRESS,BIT) 	((ADDRESS) ^= (1<<(BIT)))			//!< Toogelt ein bestimmtes Bit eines Registers
    #define IsBitSet(ADDRESS,BIT) 	(((ADDRESS) & (1<<BIT))?1:0)		//!< Fragt ein bestimmtes Bit eines Registers ab
    So wird zum Beispiel aus der recht kryptischen Abfrage eines Eingangs auf PB4
    if (PINB &(1<<PB4)) {}
    ein recht einfaches
    if (IsBitSet(PINB,4)) {}
    und das ohne dass der Compiler einen anderen Code draus macht.
    (Ende des Zitates)

    Klasse - sagte ich, und verwendete die beiden ersten #defines auch in meinem Programm.

    In meinen Programmen habe ich anfangs, vor allem ausführbaren Code - insbesondere vor irgendwelchen Interrupts, eine for-Schleife, die mit rund 10 Hz eine StatusLED 50 x blinken lässt. Das hat sich bei mir in der Entwicklungsphase bewährt, um ungewollte Resets zu erkennen; diese Blinksequenz tritt nur und ausschließlich hier auf.

    Leider stellt sich beim Verwenden der hübschen #defines von askazo heraus, das nun die Blinkfrequenz nicht mehr stimmt. Also Suchen und Vergleichen - nicht sooo pfiffig in zwei *.lls mit 144 KB resp. fast 3400 Zeilen. Code gekürzt auf ein Minimum - und verglichen. Vielleicht habe ich ein wichtiges Detail übersehen, aber ich sehe keinen Unterschied. Auffällig ist, dass die beiden Schleifen hintereinander geschrieben mit unterschiedlicher Frequenz blinken.

    Frage: Hat bitte jemand eine Erklärung dafür?

    Mein Code - vollständig. WinXP-SP3, AVRStudio 4.16, Build 638, mega328 mit 20 MHz, Platine in meinem MiniD0.
    Code:
    /* >> 
      Sicherung 28Okt09 0850   ..\C2\tst328_10\tst328_10.c   war   D01_21x00.c
     ===================================================================================
      Target MCU        : ATmega368P
      Target Hardware   : miniDO = R3D01
      Target cpu-frequ. : 20 MHz, externer Quarzoszillator
     ===================================================================================
      Enthaltene Routinen :
                    
      void waitms(uint16_t ms)      // Delay
      int main(void)
     ===================================================================================
      *** Versionsgeschichte:
     ==================== 
     x10 28Okt09 0850 Test Startblink mit und ohne defines
     x00 27Okt09 2330 Test des Startloops
     ===================================================================================
     ================================================================================ */
                                      
     #include <stdlib.h>               
     #include <avr/io.h>               
    // #include <avr/interrupt.h>        
                                      
     #define MCU = AVR_ATmega368p      
     #define F_CPU  20000000        // Quarz 20 Mhz-CPU
                                      
    // ===  #defines der PortPins beim 328p  ===========================================
    // =================================================================================
     #define    PC5     5           // Pindefinition _ _ _ PortC/PDIP328p nur bis PC5
                                      
     #define SetBit(ADDR,BIT)       ((ADDR) |= (1<<(BIT)))          // Setzt Bit
     #define ClrBit(ADDR,BIT)       ((ADDR) &= ~(1<<(BIT)))         // Löscht Bit
                                      
    // =================================================================================
    // =====  Subroutinen  =============================================================
    // =================================================================================
    /*### Programm pausieren lassen  !! Der Pausenwert ist nur experimentell !*/ 
    
    void waitms(uint16_t ms) 
    { 
       for(; ms>0; ms--) 
       { 
          uint16_t __c = 4000; 
          __asm__ volatile ( 
             "1: sbiw %0,1" "\n\t" 
             "brne 1b" 
             : "=w" (__c) 
             : "0" (__c) 
          ); 
       } 
    }               
    /* ============================================================================== */
    /* =====  ENDE    Subroutinen  ================================================== */
    /* ============================================================================== */
    
    
    
    // =================================================================================
    // ===  HAUPTProgramm ==============================================================
                             
      int main(void)
    {        
      uint8_t i;
                   
    // Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
    //   A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
                            //
      DDRC  = 0b01110000;   // PC3 ist ADC3, PC0 .. 6 , kein PC7-Pin bei m168
      PORTC = 0b00000111;   // Beachte für ADC: PC3 ist ADC-Eingang ##>> OHNE Pullup !!
                            //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                             
      for(i=0; i<50; i++)   // gLED auf PC5 i-fach blinken lassen OHNE Interrupts
      {                       
        PORTC |=  (1<<PC5);  // LED auf PC5 schalten EIN, HELL
        waitms(3);           //    ... damit man kurze resets besser erkennt
        PORTC &= ~(1<<PC5);  // LED auf PC5 schalten AUS, Dunkel
        waitms(97);           
      }                       
                              
    
      for(i=0; i<50; i++)   // gLED auf PC5 i-fach blinken lassen OHNE Interrupts
      {                       
        SetBit(PINC, 5);    // LED auf PC5 schalten EIN, HELL
        waitms(3);          //    ... damit man kurze resets besser erkennt
        ClrBit(PINC, 5);    // LED auf PC5 schalten AUS, Dunkel
        waitms(97);           
      }                       
                                     
      return 0;                      
    }                              
    // =====  Ende  =====
    // ================================================================================
    Ciao sagt der JoeamBerg

  2. #2
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    PORTC |= (1<<PC5); // LED auf PC5 schalten EIN, HELL
    ...
    SetBit(PINC, 5); // LED auf PC5 schalten EIN, HELL
    MfG
    Stefan

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Danke Stefan. Jetzt weiß ich, warum bei mir immer alles so lange dauert - und warum ich mich immer noch als C-Anfänger sehe. Kann mich nicht mal auf gestern Mitternacht berufen, weil ich es heute morgens noch mal geprüft hatte .

    Nun laufen beide Versionen gleich schnell. Danke.
    Ciao sagt der JoeamBerg

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.02.2008
    Beiträge
    130
    Ist das jetzt ein C Problem oder eines der Controller-Architektur?

  5. #5
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Zitat Zitat von GeoBot
    Ist das jetzt ein C Problem oder eines der Controller-Architektur?
    Das ist doch jetzt eine Scherzfrage, oder?

    Es ist das Problem des Software-Autors mit der meist bekannten Konvention, dass Pinnausgänge, also Datenrichtung, d.h. Pindefinition als Ein- oder Ausgang, mit der Kurzbezeichnung PORTx identifiziert werden, während Pinzustände, d.h. Abfrage, ob ein Pin auf GND oder Vcc oder irgendwo dazwischen ist, üblicherweise mit PINx identifiziert werden. PINx war also mein Fehler, da ich ein- und ausschalten wollte. Durch PORTx läuft alles bestens. Im Prinzip ist mir das klar, aber ich hatte ein Brett vorm Kopf. Merke: selbst noch so dünne Bretter wollen gebohrt werden, auf lateinsich: mea culpa.
    Ciao sagt der JoeamBerg

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    28.02.2008
    Beiträge
    130
    Ja und Nein

    Es ist also nicht wirklich ein C-Problem. Denn es
    würde auch in jeder anderen Sprache wohl den
    gleichen (selben) Effekt bewirken.

    Allerdings hatte ich nur mit einer Phasenver-
    schiebung gerechnet.

    Aus dem Datenblatt (Rev. 8161D–AVR–10/09)

    " Three I/O memory address locations are allocated
    for each port, one each for the Data Register – PORTx,
    Data Direction Register – DDRx, and the Port Input
    Pins – PINx. The Port Input Pins I/O location is read
    only, while the Data Register and the Data Direction
    Register are read/write.

    However, writing a logic one to a bit in the PINx
    Register, will result in a toggle in the corresponding
    bit in the Data Register. "

    Ok: Im zweiten Fall blinkt die LED mit einer
    Periode von 200 ms und einer Duty-Cycle von 50%.

    "logic zerro" tastet das Data Register nicht an. Ich denke
    immer noch zu sehr "PIC".

  7. #7
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    In der Makrodefinition von "IsBitSet(...)" sollte noch ein Klammer mehr hin: 1<<Bit kann sonst unerwartete ergebnisse geben wenn man z.B. schreibt: IsBitSet(PINB,1+3). Kommt wahrscheinlich selten vor, kann aber sehr schwer zu findene Fehler geben.


    Edit:
    Ups, da ist noch ein Fehler: Der Controller ist wohl eher Mega328 nicht Mega368. Das könnte einiges an Fehler verurschen. Eigentlich sollte es dann aber auch Warnungen geben, oder der in der IDE eingestelle µC wird benutzt.

  8. #8
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    48
    Beiträge
    1.146
    Zitat Zitat von Besserwessi
    In der Makrodefinition von "IsBitSet(...)" sollte noch ein Klammer mehr hin: 1<<Bit kann sonst unerwartete ergebnisse geben wenn man z.B. schreibt: IsBitSet(PINB,1+3). Kommt wahrscheinlich selten vor, kann aber sehr schwer zu findene Fehler geben.
    Uups, stimmt, danke für den Hinweis.
    Bei den anderen drei Makros hab ich's auch gemacht, bei dem letzten wohl vergessen...

  9. #9
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Erstmal allen vielen Dank für die ausführlichen Informationen. Schon nach dem Posting von stefan lief ja das Ganze korrekt - aber nun weiß ich ein bisschen mehr.

    Zitat Zitat von Besserwessi
    ... noch ein Fehler: Der Controller ist wohl eher Mega328 nicht Mega368 ...
    Ohhhh - stimmt, der Mega368 wird ja noch garnicht gebaut/ausgeliefert. Zum Glück wurde der 328p in der IDE eingestellt - das AVRStudio bringt ja sein eigenes Device-Flyout mit. Das rettet mich vor Auswirkungen durch diesen dämlichen Fehler.

    Danke allen.
    Ciao sagt der JoeamBerg

  10. #10
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.652
    Hallo alle,

    zur falschen Definition der MCU im Code als nichtexistener 368P gibt es eine Vermutung: Die Vorgänger MCU war ein mega168, da ist es wahrscheinlich, dass die mittlere Ziffer nicht aktualisiert wurde.

    Der Grund, warum der falsche Code vom Compiler nicht angemeckert wird, ist mir noch nicht klar. Der ist aber auch weniger wichtig, als die Antwort auf die Frage, warum der ausführbare Code a) läuft und b) in der inkorrekten Variante zu einer längeren Einschaltdauer des betreffenden Pinns führt. Da muss ich bei Gelegenheit die *.lls nochmal durchforsten. Ein Durchgehen der iom328p.h (zu WinAVR-20090313) hatte keinen Hinweis gebracht.

    [OT]Es ist nicht möglich, dass die fehlerhafte MCU-Bezeichnung auf eine bayerische Zifferntastatur zurückzuführen ist, da die bekanntlich keine 6 enthält. Ihr kennt die bayerische Zifferntastatur nicht? Bild hier   [/OT]
    Ciao sagt der JoeamBerg

Seite 1 von 3 123 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen