- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 4 von 4

Thema: switch-Anweisung springt immer zum selben case X Befehl

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    20.10.2007
    Ort
    Bayern
    Alter
    36
    Beiträge
    116

    switch-Anweisung springt immer zum selben case X Befehl

    Anzeige

    E-Bike
    Hallo

    Mit dem unten stehenden Code habe ich meine Probleme:
    Code:
    // richtige 7-Segment-Anzeige freischalten (Masse schalten)
    		switch(Ziffer)
    		{
    			case 0: break;
    			case 1: PORTB_temp &= ~(1 << PB2); PORTB_temp |= (1 << PB0); break;
    			case 2:	PORTB_temp &= ~(1 << PB0); PORTB_temp |= (1 << PB2); break;
    		}
    Die Variable Ziffer (uint8_t) hat entweder den Wert 0, 1 oder 2. Egal welcher Wert diese hat, es wird immer nur der Teil hinter case 1 ausgeführt, wenn Ziffer eine 2 hat wird trotzdem case 1 ausgeführt.

    Habe euch ein Bild beim Debugen mit angehängt.

    EDIT: Auch wenn cihd as ganze mit IF-Bedingung filtern möchte wird immer davon ausgegangen das Ziffer 1 ist, auch wenn es 2 ist. Folgender Code führt auch wenn Ziffer 2 ist den Teil bei Ziffer 1 aus:
    Code:
    if (Ziffer == 1)
    		{
    			PORTB_temp &= ~(1 << PB2); 
    			PORTB_temp |= (1 << PB0);
    		}
    		if (Ziffer == 2)
    		{
    			PORTB_temp &= ~(1 << PB0); 
    			PORTB_temp |= (1 << PB2);
    		}
    Aber warum funktioniert es dann bei diesem Codeabschnitt ohne Probleme?
    Code:
    // Segmente einstellen
    		switch(StelleZahl[Ziffer - 1])
    		{
    			//		Segment:     gfedcba
    			case 0: SEGMENT = 0b00111111; break;
    			case 1: SEGMENT = 0b00000110; break;
    			case 2: SEGMENT = 0b01011011; break;
    			case 3: SEGMENT = 0b01001111; break;
    			case 4: SEGMENT = 0b01100110; break;
    			case 5: SEGMENT = 0b01101101; break;
    			case 6: SEGMENT = 0b01111100; break;
    			case 7: SEGMENT = 0b00000111; break;
    			case 8: SEGMENT = 0b01111111; break;
    			case 9: SEGMENT = 0b01100111; break;
    			//		Segment:     gfedcba
    		}

    Und falls jemand den kompletten Code einsehen will, hier ist er:
    Code:
    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
    	
    	Projekt: Drehzahlmesser 										
      		
    	Anzeige der Drehzahl auf 5 7-Segment-Anzeigen.
     	Anzeigen werden im Multiplexverfahren angesteuert,
      	die Drehzahl alle 100ms aktualisiert.
     
     	Später sollen noch max. Drehzahlspeicherung sowie eine
     	Begrüßung beim Einschalten hinzukommen.
     
     	AUTOR: Benjamin Ruppert
     	DATUM: 01.11.2007 - gute Frage									
    
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    
    
    #include <avr/io.h>
    #include <stdint.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    /* Variablendeklaration */
    uint8_t Ziffer;			// 1 - 5, 1 links, 5 rechts
    uint16_t Zahl;			// Drehzahl, max 5-stellig
    uint8_t StelleZahl[5] = {1,2,5,7,9};
    uint8_t SEGMENT;
    
    uint8_t PORTB_temp;
    uint8_t PORTC_temp;
    
    
    
    
    /* Prototypendekleration */
    
    
    
    /* Interruptserviceroutinen */
    ISR(TIMER0_OVF_vect)
    {
    	Ziffer++;
    	if (Ziffer > 2) { Ziffer = 1; }
    }
    
    
    
    int main(void)
    {
    	/* Ein- / Ausgänge definieren */
    	DDRC = 0b00111111;		// PC0 - PC5 als Ausgang
    	DDRB = 0b00000111;		// PB0 - PB1 als Ausgang
    
    	/* Timer einstellen */
    	TCCR0 |= (0 << CS00) | (1 << CS01);	// Vorteiler 64
    	
    	/* Interrupts einschalten / festlegen */
    	TIMSK |= (1<<TOIE0);
    	sei();
    	
    
    	// DEBUG Settings
    	Ziffer = 1;
    	//Zahl = 2;
    
    	while(1)
    	{
    		
    		// Segmente einstellen
    		switch(StelleZahl[Ziffer - 1])
    		{
    			//		Segment:     gfedcba
    			case 0: SEGMENT = 0b00111111; break;
    			case 1: SEGMENT = 0b00000110; break;
    			case 2: SEGMENT = 0b01011011; break;
    			case 3: SEGMENT = 0b01001111; break;
    			case 4: SEGMENT = 0b01100110; break;
    			case 5: SEGMENT = 0b01101101; break;
    			case 6: SEGMENT = 0b01111100; break;
    			case 7: SEGMENT = 0b00000111; break;
    			case 8: SEGMENT = 0b01111111; break;
    			case 9: SEGMENT = 0b01100111; break;
    			//		Segment:     gfedcba
    		}
    
    			
    		PORTB_temp = PORTB;	//oder PINB?!?!?!?!?!!?!?
    		PORTB_temp &= ~(1 << PB1);	// PB1 auf 0
    		PORTC_temp = 0x00;
    
    			
    		// Ausgänge setzen, wie 7-Segment angeschlossen ist
    		if (SEGMENT & (1 << 0)) { PORTC_temp |= 0b00001000; }	//a an PC3
    		if (SEGMENT & (1 << 1)) { PORTC_temp |= 0b00010000; }	//b an PC4
    		if (SEGMENT & (1 << 2)) { PORTC_temp |= 0b00000001; }	//c an PC0
    		if (SEGMENT & (1 << 3)) { PORTC_temp |= 0b00000010; }	//d an PC1
    	
    		if (SEGMENT & (1 << 4)) { PORTB_temp |= 0b00000010; }	//e an PB1
    	
    		if (SEGMENT & (1 << 5)) { PORTC_temp |= 0b00000100; }	//f an PC2
    		if (SEGMENT & (1 << 6)) { PORTC_temp |= 0b00100000; }	//g an PC5
    		
    		
    		
    		//PORTC = 0x00;		// PC0 - PC5 auf 0
    		//PORTB &= ~(1 << 1);	// PB1 auf 0
    		
    		// richtige 7-Segment-Anzeige freischalten (Masse schalten)
    		switch(Ziffer)
    		{
    			case 0: break;
    			case 1: PORTB_temp &= ~(1 << PB2); PORTB_temp |= (1 << PB0); break;
    			case 2:	PORTB_temp &= ~(1 << PB0); PORTB_temp |= (1 << PB2); break;
    		}
    
    		PORTC = PORTC_temp;
    		PORTB = PORTB_temp;
    	}
    }

    Ich bekomm es im Moment einfach nicht ein meine Kopf rein warum er immer davon ausgeht das Ziffer 1 ist (alos case 1 ausführt) obwohl doch aus dem Bild ganz klar hervorgeht das Ziffer 2 ist, aber nein es wird trotzdem case 1 ausgeführt.

    Für Hilfe bin ich sehr dankbar.

    mfg
    Benny
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken switchanweisung.jpg  

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    02.11.2005
    Alter
    49
    Beiträge
    1.146
    Der kleine aber feine Unterschied ist, dass "Ziffer" in einer Interruptroutine geändert wird.

    Deklariere die Variable Ziffer mal als

    volatile uint8_t Ziffer;

    dann sollte es klappen.

    Zur Erklärung:
    Wenn eine Variable in einer Interruptroutine ändert und auch außerhalb der ISR verwendet wird, muss diese immer mit "volatile" deklariert werden. Der Compiler versucht, den Programmcode zu optimieren. So will er auch unnötiges neueinlesen von Variablen aus dem RAM in die Arbeitsregister verhindern. Da der Compiler aber nicht vorhersagen kann, wann eine Interruptroutine ausgeführt wird, kann es dabei Probleme geben. Mit "volatile" sagt man dem Compiler, dass er vor jeder Verwendung den aktuellen Wert der Variablen überprüfen soll.

    askazo

  3. #3
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.842
    mmhhh.
    Auf jeden Fall: wenn ISR und normal mit der gleichen Variablen arbeiten sollen, dann:
    "volatile" dazuschreiben.
    Ziffer bekommt am anfang "1" und das ändert sich nie.

    Ich glaub' , da betrügt dich der Debugger/ Simulator.

    ui, da war schon wer.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    20.10.2007
    Ort
    Bayern
    Alter
    36
    Beiträge
    116
    Alles klar so einfach gehts (wenn mans weiß)

    Besten Dank euch beiden.

    mfg
    Benny
    cooming soon...

Berechtigungen

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

12V Akku bauen