Forum: Mikrocontroller und Digitale Elektronik case-Anweisung


von Marco G. (grmg2010)


Lesenswert?

Moin,

ich arbeite gerade mit einem ATMEGA168 und möchte ein 
switch-case-Anweisung verwenden. Interessanterweise funktioniert eine 
der Anweisungen ohne Probleme, die andere, die genauso aufgebaut ist 
allerdings nicht. Hier mal der Code:

Die funktionierende Anweisung
1
void light(int x)
2
  {
3
    switch (x){
4
    
5
      case 0:
6
        PORTC |= (1<<PC5);
7
        break;
8
      case 1:
9
        PORTC &= ~(1<<PC5);
10
        break;
11
    }
12
  }

Die nicht funktionierende Anweisung
1
void led_rt(int x)
2
  {
3
    switch (x)
4
    {
5
    case 0:
6
      PORTB |= (1<<PB1);
7
      break;
8
    case 1:
9
      PORTB &= ~(1<<PB1);
10
      break;
11
    
12
    }
13
  }

Ich sehe den Unterschied (vom Aufbau her) der beiden Anweisungen nicht, 
und kann mir nicht erklären, warum es einmal funktioniert und einmal 
nicht.

Gruß

von Falk B. (falk)


Lesenswert?

Weil du vergessen hast, die Pins an PORTB als Ausgang zu schalten. DDRB 
ist dein Freund.

von OldMan (Gast)


Lesenswert?

PORTB richtig konfiguriert?

von Ahm (Gast)


Lesenswert?

Das Problem ist dass auf deiner Platine die rote LED nicht an Pin PB1 
hängt sondern an PC4...

von Marco G. (grmg2010)


Lesenswert?

Nein, ich habe beide Ports definiert. Ich hatte dies nur bei meiner 
Frage nicht mit aufgeführt.
1
DDRB |= (1<<DDB0) | (1<<DDB1);
2
DDRC |= (1<<DDC5);
Beide Ports sind nach gleichem Muster definiert.
So kann ich auch PB1 beeinflussen, nur nicht in der case-schleife.
1
PORTB &= ~(1<<PB1);
2
PORTB |= (1<<PB1);

von Mark B. (markbrandis)


Lesenswert?

Marco G. schrieb:
> nur nicht in der case-schleife.

Es gibt keine case-Schleife. Genau so wenig wie es eine if-Schleife 
gibt.

von Marco G. (grmg2010)


Lesenswert?

Ok, in der Case-Anweisung

von tastendrücker (Gast)


Lesenswert?

Und die Funktion led_rt(x) wird auch aufgerufen in deinem Code?

von Marco G. (grmg2010)


Lesenswert?

Ja wird sie.:)

von (prx) A. K. (prx)


Lesenswert?

Wenn ein Fehler nicht dort ist, wo du ihn vermutest, dann ist er 
wahrscheinlich dort, wo du ihn nicht vermutest.

Wenn du dann aber die Welt nur über jene Teile des Codes aufklärst, in 
denen du ihn vermutest, dann gibts halt nur die ultimative Antwort:
                                 42

von tastendrücker (Gast)


Lesenswert?

Auch mit x=0 oder x=1 ?

Zeig mal den Aufruf...


Und: ZEIG genau den code, der iche funktioniert (copy&paste)! Nicht im 
Post manuell eintippen!

von jöle (Gast)


Lesenswert?

Marco G. schrieb:
> Nein, ich habe beide Ports definiert. Ich hatte dies nur bei meiner
> Frage nicht mit aufgeführt.

LMA. Mal wieder ein unvollständiges Programm und wahrscheinlich liegt es 
an verpolter LED. Port beeinflussen heißt nicht LED leuchtet. Was heißt 
überhaupt "... es einmal funktioniert und einmal nicht".

von tastendrücker (Gast)


Lesenswert?

jöle schrieb:
> Was heißt
> überhaupt "... es einmal funktioniert und einmal nicht".

Na -ich denke er meint: light(x) fnktioniert und led_rt(x) nicht.

von Mark B. (markbrandis)


Lesenswert?

tastendrücker schrieb:
> jöle schrieb:
>> Was heißt
>> überhaupt "... es einmal funktioniert und einmal nicht".
>
> Na -ich denke er meint: light(x) fnktioniert und led_rt(x) nicht.

Dann einfach mal den Inhalt der beiden Funktionen vertauschen.

Ich tippe auch auf entweder einen Hardware-Fehler (LED falsch 
angeschlossen), oder eine falsche Initialisierung irgendwo in einem 
Stück Code, das man uns hier wie so oft vorenthält.

: Bearbeitet durch User
von eilig (Gast)


Lesenswert?

Was genau funktioniert nicht? Explodiert der Controller?

Bau einen default in die switch cases und leite von da auf eine 
Fehlerbehandlung.

Und poste den vollständigen Code! Der Fehler liegt genau da, wo du 
ihn nicht vermutest.

Und immer dieses 1 << , was soll das? Warum schreibt man nicht einfach 
Bit2 usw.?

von (prx) A. K. (prx)


Lesenswert?

eilig schrieb:
> Warum schreibt man nicht einfach Bit2 usw.?

Das hätte immerhin den Vorteil, dass wir dann sofort wissen, weshalb es 
nicht funktioniert. ;-)

von Marco G. (grmg2010)


Lesenswert?

Nein die LED ist nicht verpolt, da sie außerhalb der Case-Anweisung auch 
leuchtet, wenn ich die Pins manuell setzte.

Hier mal der Code, wobei ich die Initialisierung der Ports bereits 
angegeben hatte.
1
int main(void)
2
{
3
  avr_init();
4
  lcd_init();
5
  //TSIC_INIT();
6
  light(1);
7
  
8
  lcd_clear();
9
  led_bl(1);
10
11
  
12
  
13
  
14
    while(1)
15
    {
16
    
17
    sprintf(Buffer_counter, "%d", counter);
18
    lcd_setcursor(0,1);
19
    lcd_string("Counter: ");
20
21
    
22
//          getTSicTemp(&temperature);          
23
//          temperature = ((temperature * 250L) >> 8) - 500;  
24
//          itoa(temperature, temperature_out, 10);
25
//          celsius = temperature / 10 + (float) (temperature % 10) / 10;
26
//          lcd_setcursor(3,0);
27
//          lcd_string("Temperatur");
28
//          lcd_numbers(celsius, 5, 1);
29
     _delay_ms(500);
30
//     lcd_clear();
31
     light(1);
32
     
33
     
34
     if (counter >= 100)
35
     {
36
      light(0);
37
      lcd_clear();
38
      led_bl(0);
39
      led_rt(1);
40
      
41
      counter = 0;
42
     }
43
 
44
     
45
     counter++;
46
    }
47
}

Und Hier die avr_init():
1
void avr_init(void){
2
  
3
  //Definieren der Ausgänge
4
  DDRB |= (1<<DDB0) | (1<<DDB1);
5
  DDRC |= (1<<DDC5);
6
  
7
  //Definieren der Eingänge
8
  DDRC &= ~(1<<DDC3);
9
  DDRD &= ~(1<<DDD6);
10
  
11
  //Setzen der Pull-Ups der Eingänge
12
  PORTC = (1<<PC3);
13
  PORTD = (1<<PD6);
14
  
15
  //Setzen der Ausgangszustände
16
  PORTB |= (1<<PB0) | (1<<PB1);
17
  PORTC |= (1<<PC5);
18
}

von eilig (Gast)


Lesenswert?

@AK
Warum einfach, wenn es auch schwierig geht? Schönes Motto du da hast.

von Marco G. (grmg2010)


Lesenswert?

Vergessen zu kopieren. Dies steht natürlich noch vor der main:
1
#define F_CPU 1000000UL
2
3
#define Grad 0x80
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <stdio.h>
8
#include "avr.h"
9
#include "lcd.h"
10
#include "tsic.h"
11
12
uint16_t temperature = 0;
13
float celsius = 0;
14
char temperature_out[10];
15
int counter = 0;
16
char Buffer_counter[5];

von (prx) A. K. (prx)


Lesenswert?

Was passiert, wenn du den ganzen LCD Kram weglässt?
Wie lange wartest du um zu sehen, ob was passiert?

von Marco G. (grmg2010)


Lesenswert?

Wenn ich die LCD-Funktionen auskommentiere, ändert sich nichts. Das in 
die if-Anweisung gesprungen wird, sehe ich, da ich mir ja die variable 
Counter anzeigen lasse, die in der if-Anweisung zurückgesetzt wird.

von M. K. (sylaina)


Lesenswert?

Möglicher Weise hat der Compiler Probleme mit dem _ in LED_rt. Den _ 
würde ich mir hier schenken und eher ledRot schreiben oder ähnliches.

int x würde ich so auch nicht verwenden, du weißt hier nämlich nicht wie 
groß x gewählt wird und es könnte hier auch ein 32 bit Integer benutzt 
werden. Hier genügt aber ein 8 bit Integer und der ist für den AVR auch 
leichter zu behandeln. Daher ist es nicht verkehrt immer uint8_t (hier 
wird ein 8 bit unsigned Integer benutzt) und ähnliches zu benutzen.

von (prx) A. K. (prx)


Lesenswert?

Michael Köhler schrieb:
> Möglicher Weise hat der Compiler Probleme mit dem _ in LED_rt.

Nein.

von (prx) A. K. (prx)


Lesenswert?

Michael Köhler schrieb:
> int x würde ich so auch nicht verwenden, du weißt hier nämlich nicht wie
> groß x gewählt wird

Entscheidend ist im derzeitigen Stadium nur, ob es ausreichend gross 
ist. Wieviel es zu gross ist zählt vorläufig nicht.

von Helfer (Gast)


Lesenswert?

Nur mal so, an welchem Port hast du denn das LCD angeschlossen? 
Vielleicht ist der Treiber unsauber geschrieben und lcd_init() 
überschreibt deine Port Konfiguration aus avr_init();

Ich glaube es wäre wirklich sinnvoll, uns den GESAMTEN Code zu geben, 
denn zumindest ich sehe in dem aktuellen Code den Fehler nicht.

von Marco G. (grmg2010)


Lesenswert?

Das lcd ist am PortD. Ich benutze die LCD-Ansteuerung hier aus dem 
Tutorial. Wenn ich den LCD-Part auskommentiere, kann er ja meine 
avr_init() nicht überschreiben und trotzdem funktioniert es auch dann 
nicht.

von Markus (Gast)


Lesenswert?

led_rt(1) wird nur einmal aufgerufen.
Das "Gegenstück" mit led_rt(0) wird gar nie ausgeführt.

von (prx) A. K. (prx)


Lesenswert?

Reduziere den Code auf die beiden Funktionen und die 
Portinitialisierung. Alles andere raus. ALLES.

von M. K. (sylaina)


Lesenswert?

A. K. schrieb:
> Entscheidend ist im derzeitigen Stadium nur, ob es ausreichend gross
> ist. Wieviel es zu gross ist zählt vorläufig nicht.

Und das ist dein Grund nicht von Anfang an ordentlich zu arbeiten? 
Zuviel Zeit oder Spass am optimieren?

von (prx) A. K. (prx)


Lesenswert?

Markus schrieb:
> Das "Gegenstück" mit led_rt(0) wird gar nie ausgeführt.

Aber der Port wird entsprechend initialisiert.

von Marco G. (grmg2010)


Lesenswert?

Markus schrieb:
> Das "Gegenstück" mit led_rt(0) wird gar nie ausgeführt.

Das stimmt, dann soll die LED auch angehen, macht sie aber nicht.

von Helfer (Gast)


Lesenswert?

Also mit im Nebel rumstochern ist dir nicht geholfen und uns nur Zeit 
gestohlen. Reduziere den Code auf die fehlerhaften Funktionen und teste, 
ob es dann funktioniert. Wenn Nein, dann poste hier den reduzierten Code 
hier, aber diesen inklusive Funktions- und Variablendeklaration und 
definition. Dann besteht auch die Chance, dass dir hier schnell und gut 
geholfen werden kann.

von Marco G. (grmg2010)


Lesenswert?

Hier mal der vereinfachte Code. Die blaue LED funktioniert, nur die Rote 
nicht.

avr.h
1
#ifndef AVR_H_
2
#define AVR_H_
3
4
void avr_init(void);
5
void led_rt(uint8_t);
6
void led_bl(uint8_t);
7
void light(uint8_t);
8
9
10
#endif /* AVR_H_ */

avr.c
1
  #define F_CPU 1000000UL
2
  
3
  #include <avr/io.h>                  //einbinden der Bibliothek 'io.h'
4
  #include <util/delay.h>                //einbinden der Bibliothek 'delay.h'
5
 
6
  
7
 
8
  void avr_init(void){
9
  
10
  //Definieren der Ausgänge
11
  DDRB |= (1<<DDB0) | (1<<DDB1);
12
  DDRC |= (1<<DDC5);
13
  
14
  //Definieren der Eingänge
15
  DDRC &= ~(1<<DDC3);
16
  DDRD &= ~(1<<DDD6);
17
  
18
  //Setzen der Pull-Ups der Eingänge
19
  PORTC = (1<<PC3);
20
  PORTD = (1<<PD6);
21
  
22
  //Setzen der Ausgangszustände
23
  PORTB |= (1<<PB0) | (1<<PB1);
24
  PORTC |= (1<<PC5);
25
26
  
27
  
28
  }
29
  
30
  void led_rt(uint8_t x)
31
  {
32
    switch (x)
33
    {
34
    case 0:
35
      PORTB |= (1<<PB1);
36
      break;
37
    case 1:
38
      PORTB &= ~(1<<PB1);
39
      break;
40
    
41
    }
42
  }
43
  
44
  void led_bl(uint8_t x)
45
  {
46
    switch (x)
47
    {
48
    case 0:
49
      PORTB |= (1<<PB0);
50
      break;
51
    case 1:
52
      PORTB &= ~(1<<PB0);
53
      break;
54
    
55
    }
56
  }
57
  
58
  void light(uint8_t x)
59
  {
60
    switch (x){
61
    
62
      case 0:
63
        PORTC |= (1<<PC5);
64
        break;
65
      case 1:
66
        PORTC &= ~(1<<PC5);
67
        break;
68
    }
69
  }

main.c
1
define F_CPU 1000000UL
2
3
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include "avr.h"
7
8
9
10
int counter = 0;
11
12
13
int main(void)
14
{
15
  avr_init();
16
  
17
  led_bl(1);
18
  led_rt(0);
19
20
  
21
  
22
  
23
    while(1)
24
    {
25
 
26
   counter++;
27
28
     if (counter >= 100)
29
     {
30
      
31
      lcd_clear();
32
      led_bl(0);
33
      led_rt(1);
34
      
35
      counter = 0;
36
     }
37
38
     
39
     _delay_ms(500);
40
     
41
    }
42
}

von Geduld (Gast)


Lesenswert?

Der Bengel braucht ein wenig Geduld. Immerhin dauert es 100 * 500ms bis 
zu ersten Reaktion der roten Led.

von Marco G. (grmg2010)


Lesenswert?

Ich weiß, dass es ~50s braucht, bis die LED reagiert. Die Blaue reagiert 
ja auch, nur die Rote nicht.

von Geduld (Gast)


Lesenswert?

Andere einfach die Anfangsbedingung direkt nach Init:
> led_bl(1);
> led_rt(0);

von (prx) A. K. (prx)


Lesenswert?

Marco G. schrieb:
>       lcd_clear();

Und das hat der Compiler gefressen? Hätte eigentlich sagen sollen, dass 
es die Funktion nicht gibt.

M.a.W: Ist das Wort "alles weglassen" so schwer zu verstehen?

: Bearbeitet durch User
von Marco G. (grmg2010)


Lesenswert?

stimmt hat er nicht, sehe ich gerade, ich habe also die alte Version 
einprogrammiert.
So jetzt mal die Zeile rausgenommen und neu kompiliert. Hat sich nichts 
am Verhalten der LED geändert.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Mal abgesehen vom LCD-Code sehe ich hier keinen Fehler. Gib dem Switch 
für die rote LED mal eine default-funktion, sowas wie
1
default:
2
PORTB |= (1<<PB0);
3
_delay_ms(500);
4
PORTB &= ~(1<<PB0);
5
_delay_ms(250);
6
PORTB |= (1<<PB0);
7
_delay_ms(250);
8
PORTB &= ~(1<<PB0);
9
_delay_ms(250);
10
PORTB |= (1<<PB0);
11
_delay_ms(250);
12
PORTB &= ~(1<<PB0);
13
_delay_ms(250);
14
PORTB |= (1<<PB0);
15
_delay_ms(250);
16
PORTB &= ~(1<<PB0);
17
_delay_ms(250);
18
PORTB |= (1<<PB0);
19
_delay_ms(500);
20
PORTB &= ~(1<<PB0);
21
break;

von (prx) A. K. (prx)


Lesenswert?

Marco G. schrieb:
> So jetzt mal die Zeile rausgenommen und neu kompiliert. Hat sich nichts
> am Verhalten der LED geändert.

Dreh mal die 0 und 1 bei den LED-Funktionen in main rum, so dass die 
LEDs genau andersrum leuchten müss(t)en wie vorher. Wenn nicht, dann 
programmierst du seit Stunden immer das Programm von gestern in den 
Controller, oder deine Hardware ist nicht das, was du von ihr erwartest.

von Marco G. (grmg2010)


Lesenswert?

Ok, habe die LEDs jetzt mal anders herum also
1
led_bl(0)
 und
1
led_rt(1)
Beide LEDs bleiben aus, nach ablauf der Zeit geht die Blaue dann an 
(auch dort die 0 und 1 getauscht) Könnte also ein Hardwarefehler sein. 
Werde den uC mal gegen einen anderen austauschen. Vielleicht bringt das 
ja etwas.

von Marco G. (grmg2010)


Lesenswert?

So, uC ist ausgetauscht und es funktioniert wie gewünscht. Scheint also 
wirklich an der Hardware gelegen zu haben, nicht an der Software. Vielen 
Dank an alle für die investierte Zeit und die Hilfe.

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.