-         

Seite 1 von 5 123 ... LetzteLetzte
Ergebnis 1 bis 10 von 45

Thema: Mein erster Code auf dem Mega 32: Lauflicht

  1. #1
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    02.11.2005
    Beiträge
    1.607

    Mein erster Code auf dem Mega 32: Lauflicht

    Anzeige

    Servus

    Ich habe heute mal die Zeit gefunden mir ein kleines Lauflicht zu Programmieren. Ich hab zwar keine Experimentierplatine, macht aber auch nix weil das AVRStudio mir ja erlaubt fröhlich zu Simulieren.

    Erstmal der Code, dann meine Fragen:
    Code:
    #include <avr/io.h>
    #ifndef F_CPU
    /* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert 
       (z.B. durch Übergabe als Parameter zum Compiler innerhalb 
       des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
       "nachträgliche" Definition hinweist */
    #warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
    #define F_CPU 16UL     /* Quarz mit 3.6864 Mhz */
    #endif
    #include <stdint.h>
    #include <util/delay.h> 
    
    struct s_bPORTB{
    	uint8_t PIN;
    }bPORTB[8];
    
    int main (void) {
    
       DDRB  = 0xff;
       DDRA  = 0x00;
    
       bPORTB[0].PIN=PINB0;
       bPORTB[1].PIN=PINB1;
       bPORTB[2].PIN=PINB2;
       bPORTB[3].PIN=PINB3;
       bPORTB[4].PIN=PINB4;
       bPORTB[5].PIN=PINB5;
       bPORTB[6].PIN=PINB6;
       bPORTB[7].PIN=PINB7;
    
       while(1) {
    		if(PINA & (1<<PINA1)){
    			for(int i=0; i<8; i++){
    				PORTB &= (1<<bPORTB[i].PIN);				
    				PORTB |= (1<<bPORTB[i].PIN);
    				_delay_ms(10);
    			}
    		}
       }
     
       /* wird nie erreicht */
       return 0; 
    }
    Sooo, das läuft auch alles soweit. Dennoch macht es zwei drei Problemchen... 1. macht _delay_ms(10); nicht das was es soll^^ die angabe in den Klammern sollte eigentlich eine Verzögerung in Millisekunden darstellen. Ergo: Wenig wert, wenig Pause, viel Wert, viel Pause. Ist der Wert allerdings größer als 10 springt er in der delay.h rum macht aber sonst nix mehr. Und bei 10 ist die Pause ziemlich genau eine Sekunde => Sehr komisch.
    2. Wie kann ich einen Timer Interrupt abfragen? Sprich: Timer Initialisieren, Timer so laufen lassen das zum Beispiel 10Takte/sekunde (sollten dann 100mHz sein oder?) habe und schluss endlich immer dann PINB eins Hochzählen wenn der Timer hochgezählt wird.
    3. Finde ich meine Lösung die Pins an Port B hoch zu zählen nicht sooo Elegant. Ginge das Eleganter?
    4. AVR Studio sagt unter "Prozessor" 4MHz - in den Controller Optionen habe ich 16000000Hz eingestellt ... finde ich etwas Merkwürdig ^^

    Achja, laufen lassen tu ich das immer so:
    Build -> Start Debugging -> AutoStep
    Und dann entsprechen PinA1 anklicken und so auf 1 setzen (was nich wirklich gut funktioniert wie ich finde, das reagiert arg blöd (oder brauch ich auch da einen debounce?)


    So ich hoffe das ist soweit verständlich. Danke fürs lesen und helfen



    edit: die lösung mit der ForSchleife ist auch nicht so schön, einfach der Tatsache wegen das das ganze nicht an Ort und Stelle Stoppt sondern immer bis zum Ende durchläuft (logisch). Die Lösung könnte eine While Schleife sein oder? Also
    Code:
    while(PINA1==1){
    PINB.i=1;
    i++;
    }
    i=0;
    So als halber Pseudocode....

    Oder?

    grüße

  2. #2
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622

    Re: Mein erster Code auf dem Mega 32: Lauflicht

    Hi,

    es ist wichtig, dass Du im AVRStudio die Parameter richtig einstellst. Einmal unter "Project|Configuration Options|Frequency" (siehe erste Anlage) und dann unter "Debug"AVR SimulatorOptions" oder direkt im Frequenzfenster des Simulators. Ich habe Deinen Code simuliert und komme auf knapp über 10ms (siehe Anlage 2). Nimm die ganze FCPU-Sache aus Deinem Code und stelle alles im AVRStudio wie oben gesagt ein. In meinem Beispiel (1. Anlage) habe ich "keine Optimierung (=-O0)" gewählt; typischerweise nimmt man mindestens "-O1".

    Dein Code ist etwas holprig: Statt
    Code:
    PORTB &= (1<<bPORTB[i].PIN);
    
    PORTB |= (1<<bPORTB[i].PIN);
    kannst Du z.B. direkt (1<<i) verwenden. Übrigens: Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen" (20:04 editiert: verkehrt -- muss heißen: "PINx |= KONSTANTE;"), aber bei den neueren ATmegas geht das!

    Hier eine Lösung für Deine Schleife:
    Code:
    while(!(PINA & (1<<PINA1))){ 
             for(int i=0; i<8; i++){ 
                blablabla();
             } 
    }
    Viel Erfolg und Spaß bei der Weiterentwicklung!

    Gruß

    Fred
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken atmega32_avrstudio_fcpu.png   ll_test.png  
    Only entropy comes easy. - Anton Checkhov

  3. #3
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    @ Fred:

    Sorry, aber ich muss da mal zwei Dinge zu sagen:

    In meinem Beispiel (1. Anlage) habe ich "keine Optimierung (=-O0)" gewählt; typischerweise nimmt man mindestens "-O1".
    Wenn man die Funktionen aus util/delay.h verwenden will, ist es sehr wichtig, die Optimierungen einzuschalten. Bei einer halbwegs aktuellen AVR-Libc bekommt man ansonsten auch eine entsprechende Warnung beim Compilieren.

    Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen", aber bei den neueren ATmegas geht das!
    Auch bei neueren ATmegas klappt das so nicht. Mit "PINx |= PINx" bekommt man den Ausgang nur von 1 auf 0, aber nicht wieder zurück.


    @ BlackDevil:

    3. Finde ich meine Lösung die Pins an Port B hoch zu zählen nicht sooo Elegant. Ginge das Eleganter?
    Ich würde ein Lauflicht über den ganzen Port so machen:
    Code:
    while (1) {  // oder solange Taste gedrückt, oder ähnlichens
        PORTB <<= 1;
        if (!PORTB)
            PORTB = 1;
        _delay_ms(10);
    }
    MfG
    Stefan

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Zu 2.:

    Code:
    ISR(TIMER1_COMPA_vect){
            PORTB ^= PORTB;               // invertiert PORTB zB
    }
    
    
    void init_Timer1CompMatch(){       //zB Timer1 Compare Match initialisieren
           TCCR1X = xy;                         // hier die entsprechenden Bit setzen wie im Datenblatt beschrieben, je nach Anwendungsfall
           // und alle weiteren möglichen Register einstellen
           sei();
    }
    
    void init_Ports(){}                         // Ports = Ausgänge usw
    
    int main (void){
          init_Ports();                        
          init_Timer1CompMatch();
          while(1){}
    
    }
    Invertieren so wie im Beispiel
    10Takte/s sind 10Hz !
    Du musst den Simulator separat einstellen mit 16MHz
    Optimierung muss ein sein, wie Sternst sagt.

  5. #5
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622
    Hallo,

    Zitat Zitat von sternst
    ...Wenn man die Funktionen aus util/delay.h verwenden will, ist es sehr wichtig, die Optimierungen einzuschalten.
    Stimmt -- das hätte ich besser dazuschreiben sollen! Mein Beispiel war also nicht 100% treffend, obwohl ich erwähnt habe, dass man eine Optimierungsstufe >0 einschalten sollte!

    Beim ATmega32 kann man die einzelnen Ausgangspins nicht mit Hilfe von PINx |= PINx "togglen", aber bei den neueren ATmegas geht das!
    Auch bei neueren ATmegas klappt das so nicht. Mit "PINx |= PINx" bekommt man den Ausgang nur von 1 auf 0, aber nicht wieder zurück.
    Dass das Toggeln so nicht geht, ist nicht korrekt: siehe Anlage (Datenblatt Atmega3290P); viele andere der neueren AVRs können das auch!
    Hier ein Beispiel zum Ausprobieren im Simulator (Atmega3290P einstellen!):
    Code:
    #include <avr/io.h> 
    
    int main (void) { 
        while(1) {  
            DDRB  = 1;
            PORTB=1; 
            for (uint8_t i=0;i<10;i++) 
                 asm volatile("sbi 3,0");  // = sbi PINB, 0
          }
      return 0; 
    } 
    // -O0, Breakpoint auf die Zeile mit "asm volatile..." setzen;
    Gruß

    Fred
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken atmega_toggle_pin.png  
    Only entropy comes easy. - Anton Checkhov

  6. #6
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Dass das Toggeln so nicht geht, ist nicht korrekt:
    Doch. Zum Toggeln muss man eine 1 in das jeweilige Bit von PINx schreiben (so wie bei deinem 2. Beispiel). Überlege mal, was "PINx |= PINx" macht, wenn der Output gerade 0 ist.
    MfG
    Stefan

  7. #7
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    24.02.2006
    Ort
    3. Planet eines kleinen Sonnensystems in einem Seitenarm der Milchstraße
    Alter
    63
    Beiträge
    622
    Hallo,

    Zitat Zitat von sternst
    Dass das Toggeln so nicht geht, ist nicht korrekt:
    Doch. Zum Toggeln muss man eine 1 in das jeweilige Bit von PINx schreiben (so wie bei deinem 2. Beispiel). Überlege mal, was "PINx |= PINx" macht, wenn der Output gerade 0 ist. ;-)
    Ooops, Entschuldigung - da habe ich tatsächlich Unsinn geschrieben; gemeint war <pre>PINx |= BITS; // BITS ist eine Konstante</pre>, wie ich es im 2. Beispiel ja auch tue...

    Viele Grüße

    Fred
    Only entropy comes easy. - Anton Checkhov

  8. #8
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    PINx |= BITS; // BITS ist eine Konstante
    Aber dann wäre "PINx = BITS;" sinnvoller, denn sonst würdest du Outputs, die unangetastet bleiben sollen, die aber gerade auf 1 sind, in 0 ändern.
    MfG
    Stefan

  9. #9
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    02.11.2005
    Beiträge
    1.607
    Code:
    while (1) {  // oder solange Taste gedrückt, oder ähnlichens
        PORTB <<= 1;
        if (!PORTB)
            PORTB = 1;
        _delay_ms(10);
    }
    Danke, das ist genau das was ich gesucht habe. <<= macht ja nix als PORTB = (1<<PORTB) oder? PortX macht nichts anderes als Pinx - nur auf den ganzen port bezogen oder? Aber eigentlich ist PORTB=1 die Anweisung die Internen PullUps auf 1 zu setzen ^^
    Das braucht noch etwas Erklärung, bitte. Funktioniert aber genauso wie ich das wollte


    Ich hab auch die hälfte der Einstellungen wieder gefunden.
    Projekt Konfiguration steht auf 16000000Hz, die Simulator Konfig hab ich dann auch nach langem suchen gefunden ^^


    Danke. Wie immer klasse Forum!



    Edit: warnt der compiler vor nicht benutzten Variablen wegen Datenmüll?


    edit2:
    hab meinen code jetzt soweit modifiziert
    Code:
    #include <avr/io.h>
    #include <stdint.h>
    #include <util/delay.h> 
    
    
    
    int main (void) {
    
    	DDRB  = 0xff;
    	DDRA  = 0x00;
    	char auswahl='n'; // Zum Nichts tun
    
       while(1) {
       if((PINA & (1<<PINA0))&&!((PINA & (1<<PINA1)))){ auswahl='r'; }
    	if((PINA & (1<<PINA0))&&((PINA & (1<<PINA1)))){ auswahl='b'; }
    	if((!(PINA & (1<<PINA0)))&&((auswahl=='r') || (auswahl=='b'))){
    		auswahl='n'; // Mache nix
    		}
    
    		switch(auswahl){
    		case 'r': // VORWÄRTS FWD
    		  		PORTB <<= 1;
        		if (!PORTB){
            		PORTB = 1;
    			}
    			break;
    		case 'b' :  // RÜCKWÄRTS RWD
    			PORTB <<= 1;
    			if(!PORTB){
    				PORTB=1;
    			}
    			break;
    		}
       }
     
       /* wird nie erreicht */
       return 0; 
    }
    Funktioniert soweit Einwandfrei. Er läuft auch ohne delay schön langsam (warum auch immer).
    Zwei Fragen noch: Wie kann ich den wert eines Pins an eine Variable überegeben? mit uint8_t VAR = PINAX oder? Wenn ja tut das nich ...
    Und: Warum zur Hölle ist der ATmega 32 mit 16MHz angegeben, läuft in der Simulation aber nur mit 8MHz?

    Grüße

  10. #10
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    <<= macht ja nix als PORTB = (1<<PORTB) oder?
    Oder! Es macht PORTB = PORTB << 1;

    PortX macht nichts anderes als Pinx - nur auf den ganzen port bezogen oder?
    Oder! Beides bezieht sich auf den ganzen Port, aber PORTx ist für den Output, während PINx für den Input ist.

    Aber eigentlich ist PORTB=1 die Anweisung die Internen PullUps auf 1 zu setzen ^^
    Nein. PORTx ist für die Pullups nur für die Pins relevant, die als Eingang geschaltet sind. Ist der Pin als Ausgang geschaltet, steht in PORTx einfach das, was ausgegeben werden soll.

    hab meinen code jetzt soweit modifiziert
    Der Code für Vorwärts und Rückwärts ist ja identisch. Die Richtung ändert sich nicht nur durch Willenskraft.
    Andere Richtung:
    PORTB >>= 1;
    if (!PORTB) PORTB = 128;
    MfG
    Stefan

Seite 1 von 5 123 ... LetzteLetzte

Berechtigungen

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