Anfängerfrage zu switch case

OP #2393115
Lesenswert?

Hallo,

ich möchte innerhalb einer switch case eine bestimmten Portpin (PB0 oder 
PB1) solange high schalten bis ein Taster an PB3 oder PB4 gedrückt wird.

Wenn ich sc_temp=1 setze bleibt PB0 immer an, auch wenn ich den Taster 
an PB3 drücke...

Wie muss ich das denn umschreiben, dass es klappt?
1
      switch(sc_temp) {
2
      case 1:
3
        while(!(PINB & (1<<PB3))) 
4
        {
5
          PORTB &= ~ (1<<PB1); 
6
          PORTB |= (1<<PB0);
7
        } 
8
        break;
9

10
      case 2:  
11
          while (!(PINB & (1<<PB4)))
12
        {
13
          PORTB &= ~ (1<<PB0); 
14
          PORTB |= (1<<PB1);
15
        }
16
          break;
17

18
      default: 
19
        PORTB &= ~ (1<<PB0); 
20
        PORTB &= ~ (1<<PB1); 
21
        break;
22
      }

Gruß Rocco
Gast #2393168
Lesenswert?

Ja, es fehlen weitere informationen über den restlichen Code, 
insbesondere, wo sc_temp sonst noch gesetzt wird.

Evtl hilft das hier weiter:

      switch(sc_temp) {
      case 1:
        while(!(PINB & (1<<PB3)))
        {
          PORTB &= ~ (1<<PB1);
          PORTB |= (1<<PB0);
        }
-->     sc-temp = 2;
        break;

      case 2:
          while (!(PINB & (1<<PB4)))
        {
          PORTB &= ~ (1<<PB0);
          PORTB |= (1<<PB1);
        }
-->     sc_temp = 1;
        break;

      default:
        PORTB &= ~ (1<<PB0);
        PORTB &= ~ (1<<PB1);
        break;
      }
OP #2393179
Lesenswert?

Der restliche Code
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 2000000
4
#include <util/delay.h>
5
#include <inttypes.h>
6
#include <stdint.h>
7

8
int main(void)
9
{
10
    uint8_t sc_temp = 1;        //Variable für switch case    
11
    DDRB = (1 << DDB0) | (1 << DDB1);   //B0 un B1 als Ausgänge, B2 bis B7 als Eingänge:
12
    PORTB &= ~ (1<<PB1);              //PB1 aus
13
    PORTB &= ~ (1<<PB0);              //PB0 aus
14

15
   while(1)
16
        {
17

18
      switch(sc_temp) {
19
      case 1:
20
         while(!(PINB & (1<<PB3))) 
21
        {
22
          PORTB &= ~ (1<<PB1); 
23
          PORTB |= (1<<PB0);
24
        } 
25
        break;
26

27
      case 2:  
28
         while (!(PINB & (1<<PB4)))
29
        {
30
          PORTB &= ~ (1<<PB0); 
31
          PORTB |= (1<<PB1);
32
        }
33
          break;
34

35
      default: 
36
        PORTB &= ~ (1<<PB0); 
37
        PORTB &= ~ (1<<PB1); 
38
        break;
39
      }
40
  } //Ende While(1)
41
return 0; 
42
} //ENDE main
OP #2393195
Lesenswert?

Volkmar Dierkes schrieb:
> Und Du brauchst den Ausgang nur einmal vor dem Eintritt in die
> While-Schleife setzen:
>
1
   case 1:
2
>         PORTB &= ~ (1<<PB1);
3
>         PORTB |= (1<<PB0);
4
>         while(!(PINB & (1<<PB3)));
5
>         PORTB &= ~ (1<<PB0);
6
>         break;


^^das schein richtig(er) zu sein als das von mir (nicht das mich das 
wundert ;-))

Allerdings Leuchtet die LED mit halber stärke wenn ich den Taster 
bediene und geht nicht ganz aus
Gast #2393235
Lesenswert?

Volkmar Dierkes schrieb:
> case 1:
>         PORTB &= ~ (1<<PB1);
>         PORTB |= (1<<PB0);
>         while(!(PINB & (1<<PB3)));
>         PORTB &= ~ (1<<PB0);
>         break;


Wenn du diesen Code verwendest darfst Du hier natürlich auch nicht 
vergessen wieder sc_temp = 2 einzufügen, also:

> case 1:
>         PORTB &= ~ (1<<PB1);
>         PORTB |= (1<<PB0);
>         while(!(PINB & (1<<PB3)));
>         PORTB &= ~ (1<<PB0);
-->       sc_temp = 2;
>         break;

und "sc_temp = 1;" in case 2.
OP #2393245
Lesenswert?

Bollemx schrieb:
> Volkmar Dierkes schrieb:
>> case 1:
>>         PORTB &= ~ (1<<PB1);
>>         PORTB |= (1<<PB0);
>>         while(!(PINB & (1<<PB3)));
>>         PORTB &= ~ (1<<PB0);
>>         break;
>
>
> Wenn du diesen Code verwendest darfst Du hier natürlich auch nicht
> vergessen wieder sc_temp = 2 einzufügen, also:
>
>> case 1:
>>         PORTB &= ~ (1<<PB1);
>>         PORTB |= (1<<PB0);
>>         while(!(PINB & (1<<PB3)));
>>         PORTB &= ~ (1<<PB0);
> -->       sc_temp = 2;
>>         break;
>
> und "sc_temp = 1;" in case 2.


^^ja, das passt... :-)
Vielen für die Geduld

Gruß Rocco
#2393592
Lesenswert?

Rocco L. schrieb:
> Ich möchte eigentlich follgendes
> case1: P0 an; P1 aus bis Taster an PB3 gedrückt wird
> Case2: P1 an; P0 aus bis Taster an PB2 gedrückt wird
1
enum { RESET, P0_AN, P1_AN };
2

3
int main()
4
{
5
  uint8_t state = RESET;
6

7
  init();
8
  
9
  for(;;){                      // Main-Loop
10
    switch( state ){
11
      case P0_AN:
12
                        PORTB |= 1<<PB0;
13
                        PORTB &= ~(1<<PB1);
14
                        if((PINB & 1<<PB3) && !(PINB & 1<<PB4))
15
                          state = P1_AN;
16
                        break;
17
      case P1_AN:
18
                        PORTB |= 1<<PB1;
19
                        PORTB &= ~(1<<PB0);
20
                        if(!(PINB & 1<<PB3) && (PINB & 1<<PB4))
21
                          state = P0_AN;
22
                        break;
23
      case RESET:
24
      default:
25
                        if((PINB & 1<<PB3) && !(PINB & 1<<PB4))
26
                          state = P1_AN;
27
                        if(!(PINB & 1<<PB3) && (PINB & 1<<PB4))
28
                          state = P0_AN;
29
                        break;
30
    }
31
  }
32
}


Peter
OP #2393728
Lesenswert?

Habe jetzt die switch-case reingefummelt.


Leider haut trotzdem was nicht hin.
Folgender Ausgangszustand:
in w_temp sollten 36°C sein (Laut LED Anzeige)
in k_temp sollten 13°C sein
in p_temp sollten 21°C sein

Die Endanschlagtaster (Damit der Motor nicht über das Ziel hinaus fährt) 
sind alle nicht gedrückt. Hier sollte eine kurze Initialisierung rein, 
etwa so etwas wie fahre erst mal ins Kältebad bis der Endanschlagtaster 
vom Kältebad gedrückt ist.

Wenn er dann im Kältebad ist soll er Richtung Wärmebad fahren wenn die 
Probe die Temperatur vom Kältebad angenommen hat.
Dabei soll er wieder so lange bis in das Wärmebad fahren bis er den 
Endanschlagtaster vom Wärmebad gedrückt hat.

Im Wärmebad dann wieder das gleiche, sobald die Temperatur der Probe mit 
der vom Wärmebad übereinstimmt gehts zurück ins Kältebad und immer so 
weiter.

In dem angehangenen Quelltext ist follgendes seltsamm:
Wenn ich WB (PB3) drücke Fängt der Motor an in die entgegengesetzte 
Richtung mit halber Kraft zu laufen, lass ich wieder los dreht er wieder 
in die Alte Richtung.

Im Quellcode habe ich in den Zeile 73..75 die Temperaturwerte 
invertiert. Ich glaube das das notwendig ist weil ich die Temperatur von 
den DS18S20 so über die LED ausgebe, und somit auch so an den Atmega 16 
weitergebe:
1
// Temperatur in Grad Celsius:
2

3
                //reset (alle LEDs aus)
4
                p = 0x00;
5

6
         //Konfiguration der Pins für LEDs setzen
7
                // (0 = LED an, 1 = LED aus)
8
                if(tC >= 80) { p |=(1<<7); tC -= 80; } //Pin7 f?r 80?C an
9
                if(tC >= 40) { p |=(1<<6); tC -= 40; } //Pin6 f?r 40?C an
10
                if(tC >= 20) { p |=(1<<5); tC -= 20; } //Pin5 f?r 20?C an
11
                if(tC >= 10) { p |=(1<<4); tC -= 10; } //Pin4 f?r 10?C an
12
                if(tC >= 8)  { p |=(1<<3); tC -= 8;  } //Pin3 f?r 8?C  an
13
                if(tC >= 4)  { p |=(1<<2); tC -= 4;  } //Pin2 f?r 4?C  an
14
                if(tC >= 2)  { p |=(1<<1); tC -= 2;  } //Pin1 f?r 2?C  an
15
                if(tC >= 1)  { p |=(1<<0); tC -= 1;  } //Pin0 f?r 1?C  an
16

17
       p = ~p; //notwendig damit die LED leuchten, sonst leuchten alle anderen LED
18
    //p = p-0,5;  //Eichung des Thermometers
19
    LED_OUT = p;

Dabei steckt die Temperatur in der Variablen tC. Die Temperaturen werden 
richtig angezeigt.

Ich entschuldige mich schon mal für den ^^ Roman.
Angehängte Dateien:
#2393914
Lesenswert?

Hallo,

Warum der Motor mit halber Kraft läuft, sehe ich im Moment auch nicht. 
Aber damit der Motor stehen bleibt, wenn er den Endanschlag erreicht 
hat, mußt Du noch 2 weitere States in Deine StateMachine einfügen 
(ungetestet). Momentan springt die StateMachine ja nur zwischen den 2 
Zuständen Linksrum und Rechtsrum hin und her, es gibt aber keine Pause.
1
      switch( state ){
2
          case CW_AN:
3
                        PORTB |= (1<<CW);
4
                        PORTB &= ~(1<<CCW);
5
                        if((PINB & 1<<WB) && !(PINB & 1<<KB))
6
                          state = IM_KAELTEBAD;
7
                        break;
8
          case IM_KAELTEBAD:
9
                        // Motor anhalten
10
                        PORTB &= ~(1<<CW);
11
                        PORTB &= ~(1<<CCW);
12
                        // Temp abfragen
13
                        if(p_temp <= ktemp)
14
                          state = CCW_AN;
15
                        break;
16
          case CCW_AN:
17
                        PORTB |= 1<<CCW;
18
                        PORTB &= ~(1<<CW);
19
                        if(!(PINB & 1<<KB) && (PINB & 1<<WB))
20
                          state = IM_WAERMEBAD;
21
                        break;
22
          case IM_WAERMEBAD:
23
                        // Motor anhalten
24
                        PORTB &= ~(1<<CW);
25
                        PORTB &= ~(1<<CCW);
26
                        // Temp abfragen
27
                        if(p_temp >= wtemp)
28
                          state = CW_AN;
29
                        break;
30
          case RESET:
31
                  
32
          default:
33
                        if((PINB & 1<<WB) && !(PINB & 1<<KB))
34
                          state = CCW_AN;
35
                        if(!(PINB & 1<<WB) && (PINB & 1<<KB))
36
                          state = CW_AN;
37
                        break;
38
    }
Gast #2394096
Lesenswert?

Lief der Motor denn überhaupt schon mit voller Geschwindigkeit? Die 
Controllerausgänge können nicht viel Strom. Musst Du evtl transistoren 
dranhängen und Ubat durchschalten? Mit wieviel Volt betreibst Du Den 
Controller? reicht das dann für den Motor? Z.B. Controllerspg = 2,8V; 
Motorspannung = 5V...???

Mach doch mal das: Schalte einfach einen Ausgang, der den motor treibt 
auf "high" - ohne switch/case usw. einfach nur den Ausgang auf "High" 
und dann mal schauen, wie der Motor fährt.
Oder: Mal mit dem Oszi am Ausgang messen, ob der oszilliert (falls 
vorhanden)
OP #2394111
Lesenswert?

der Motor hängt hinter einer H-Brücke.

Ich denke immer noch das was beim Temperatureinlesen schief läuft.
Die Temperatur wird ja beim Ausgeben mit p=~p; invertiert. Das muss sein 
das die richtigen LED leuchten, sonst würden alle anderen LED leuchten, 
bis auf die die eben leuchten sollen.

Beim Einlesen muss ich doch die Temperatur dann auch invertieren - oder?
OP #2394160
Lesenswert?

die Motroports CW und CCW einfach so high setzen klappt einwandfrei.
In der Switch-Case sind mir nur ein paar Kleinigkeiten aufgefallen. Die 
neue sieht jetzt so aus:
1
                while(1){
2
      if (!(PINB & (1<<KB)))
3
      {
4
        PORTB |= (1<<CW);
5
                PORTB &= ~(1<<CCW);
6
      }else{
7
        PORTB &= ~(1<<CW);
8
              PORTB &= ~(1<<CCW);
9
        break;
10
         }
11
       }//ende Initialisierungs while  
12

13
      switch( state ){
14
              case CW_AN:
15
                        PORTB |= (1<<CW);
16
                        PORTB &= ~(1<<CCW);
17
                        if((PINB & (1<<KB)) && !(PINB & (1<<WB)))
18
                          state = IM_KAELTEBAD;
19
                        break;
20
              case IM_KAELTEBAD:
21
                        // Motor anhalten
22
                        PORTB &= ~(1<<CW);
23
                        PORTB &= ~(1<<CCW);
24
                        // Temp abfragen
25
                        if(p_temp <= k_temp)
26
                          state = CCW_AN;
27
                        break;
28
              case CCW_AN:
29
                        PORTB |= (1<<CCW);
30
                        PORTB &= ~(1<<CW);
31
                        if(!(PINB & (1<<KB)) && (PINB & (1<<WB)))
32
                          state = IM_WAERMEBAD;
33
                        break;
34
              case IM_WAERMEBAD:
35
                        // Motor anhalten
36
                        PORTB &= ~(1<<CW);
37
                        PORTB &= ~(1<<CCW);
38
                        // Temp abfragen
39
                        if(p_temp >= w_temp)
40
                          state = CW_AN;
41
                        break;
42
              case RESET:
43
                  
44
              default:
45
                        if((PINB & (1<<WB)) && !(PINB & (1<<KB)))
46
                          state = CCW_AN;
47
                        if(!(PINB & (1<<WB)) && (PINB & (1<<KB)))
48
                          state = CW_AN;
49
                        break;
50
        }//Ende Switch-Case

Ich habe noch eine Initilisierungs "while" davor gesetzt, wo der Motor 
erst mal grundlegend ins Kältebad fährt um einen definierten Startpunkt 
zu haben.

Jetzt setze ich mal die Temperaturen von Hand:
Erster Versuch:
1
k_temp = 0;          
2
p_temp = 0;          
3
w_temp = 14;

irgendwann drücke ich den Schalter KB, damit ist die Initialiserungs 
"while" abgeschlossen. Der Motor dreht dann wie gewünscht Richtung 
Wärmebad (CCW). Allerdings dreht er auch sofort wieder Richtung 
Kältebad, wenn ich den Taster KB los lasse - das sollte nicht pasieren. 
Der Motor sollte eigentlich solange CCW machen bis der Taster WB 
gedrückt wird und dann erst mal abschalten.

zweiter Versuch:
1
k_temp = 0;          
2
p_temp = 14;          
3
w_temp = 14;

das führt dazu das der Motor wieder zuerst in Richtung Kältebad dreht 
(wegen der Initialisierungs while) und sobald ich den Taster KB betätige 
stoppt der Motor und fährt sofort weiter in Richtung Kältebad wenn ich 
den Taster wieder los lasse. Das ist so auch nicht Richtig.
Eigentlich soll der Motor ja in der Initialisierung erst mal ins 
Kältebad fahren und abgeschaltet werden wenn KB gedrückt wird, das 
funktioniert auch.
Als nächstes müste der Motor nun Richtung Kältebad drehen wenn der 
Taster WB gedrückt wird.
#2394168
Lesenswert?

Rocco L. schrieb:
> Hier sollte eine kurze Initialisierung rein,
> etwa so etwas wie fahre erst mal ins Kältebad bis der Endanschlagtaster
> vom Kältebad gedrückt ist.

Hatte ich übersehen. Hier könnte sowas wie das folgende ergänzt werden:
1
          case RESET:
2
                        if(PINB & (1<<KB))
3
                          // Wenn nicht im Kältebad, dann fahre dort hin
4
                          state = CW_AN;
5
                        else
6
                          // Endschalter schon gedrückt, also bleibe an dieser Stelle
7
                          state = IM_KAELTEBAD;
8
                        break;
#2394189
Lesenswert?

Rocco L. schrieb:
> Ich habe noch eine Initilisierungs "while" davor gesetzt, wo der Motor
> erst mal grundlegend ins Kältebad fährt um einen definierten Startpunkt
> zu haben.

Dann wird sie ständig ausgeführt, d.h. die Statemaschine ist wieder 
zerstört.
Da hat die Initialisierung also nichts zu suchen, sondern im State 
RESET, genau dazu ist er gedacht.

Es dürfen kein Aktionen außerhalb der Statemaschine erfolgen!
Das ist der Trick an der Statemaschine, nur sie hat die Kontrolle, sonst 
funktioniert sie nicht!

Du solltest Dir mal das Zustandsdiagramm aufzeichnen, mit alle Zuständen 
und den Bedingungen zum Übergang in den nächsten Zustand.
http://www.htw-aalen.de/dti/o_mess/stat_mes.gif

Man kann nicht einfach blind drauflos programmieren.


Peter
OP #2394194
Lesenswert?

ok, habe die doofe Initialisierungs "while" erst mal wieder raus 
geschmissen. Damit klappt zumindest der Teil der switch-case wo sie ins 
Wärmebad fahren soll wenn p_temp <= k_temp
dabei fährt der Motor auch erst dann los wenn der Anschlagtaster vom 
Kältebad (KB) gedrückt ist und führt solange Richtung Wärmebad bis der 
Taster vom Wärmebad gedrückt ist.

Leider passiert in die andere Richtung nichts. D.h. wenn
P_temp >= w_temp und WB Taster gedrückt fahre Richtung Kältebad bis KB 
Taster gedrückt
OP #2394273
Lesenswert?

Die "Höllenmaschine" (der Ausdruck passt, schließlich treibt mich das 
Ding zur Weisglut) soll zum Untersuchen Thermoelektrischer Kristalle 
dienen. Dabei sollen die Kristalle imer zwischen 2 Wasserbädern hin und 
her gefahren werden. Dabei soll die Probe jeweils so lange in dem 
Wasserbad hänge bis sie dessen Temperatur angenommen hat.

Wo muss man denn am besten die Entprellroutine in der switch-case 
einbauen?
Angehängte Dateien:
#2395377
Lesenswert?

Rocco L. schrieb:
> Wo muss man denn am besten die Entprellroutine in der switch-case
> einbauen?

Außerhalb des switch-statements. Eigentlich ja am besten in einer 
Timer-Routine, aber das Thema war ja weiter vorne schon mal dran.

Wenn Du die von Dir ausgesuchte Routine nehmen möchtest, dann würde ich 
sie direkt vor das switch-statement setzen. Sie hat aber folgende 
Nachteile:
- Falls ein Schaltkontakt/Eingang mal einen Fehler haben sollte (und 
ständig abwechselnd ein und aus meldet), wird die entprellungs-Routine 
nie beendet und der Motor nie abgeschaltet
- Der ermittelte entprellte Wert wird nicht verwendet, er kann sich also 
bis zum nächste Einlesen wieder verändern

Ich bin mir gar nicht sicher, ob Du an dieser Stelle eine Entprellung 
benötigst. Schließlich handelt es sich hier um einen Endlagenschalter 
und der Motor soll ja abschalten sobald die Endlage erreicht ist. Aber 
das hängt auch davon ab, wie schnell das Ganze abläuft, wenn es langsam 
geht und die Zeitverzögerung (mind. 1,2ms) kein Problem darstellt, dann 
nimm es mit rein.
OP #2396462
Lesenswert?

Die Zeitverzögerunge am Endanschlagschalter stört mich nicht.

Ich habe heute noch mal alles Durchgemessen und habe 2 Sachen 
herausgefunden:
1.) nie wieder mehere Atmegas benutzen wenn es auch einer schaffen 
könnte!
    Die Kabellei, auch wenn ich viele Leiterbahnen unter dem 
Punktraster
    habe ist einfach fieß wenn ein Fehler drin ist.

2.) Ich habe eine Pinreihe falsch angelötet.
Es ist die PINA die gegen PORTB des 2. Atmegas geschaltet ist.
So sollte es sein:
A0---B0
A1---B1
A2---B2
A3---B3
A4---B4
A5---B5
A6---B6
A7---B7

So ist es aber:
A0---B7
A1---B6
A2---B5
A3---B4
A4---B3
A5---B2
A6---B1
A7---B0

Ich kann nur hoffen das man das in Peter's bcd2bin über Programmieren 
lösen kann. Vieleicht könnt Ihr mir dabei noch mal helfen:
1
uint8_t bcd2bin( uint8_t val ) //Temperatur Abholen
2
{
3
return (val & 0x0F) + (val >> 4) * 10;
4
}
5

6
k_temp = bcd2bin( PIND );
7
p_temp = bcd2bin( PINA );
8
w_temp = bcd2bin( PINC );
OP #2397637
Lesenswert?

Ich bin mir mit Funktionen nicht ganz sicher.
Ich habe es jetzt so hinter die bcd2bin Funktion geschoben.
Passt das so?
1
      k_temp = 0;          
2
      p_temp = 0;          
3
      w_temp = 0;
4
    
5
      uint8_t bcd2bin( uint8_t val ) //Temperatur Abholen
6
      {
7
        return (val & 0x0F) + (val >> 4) * 10;
8
      }
9

10
      k_temp = bcd2bin( PIND );
11
      p_temp = bcd2bin( PINA );
12
      w_temp = bcd2bin( PINC );
13

14
      uint8_t mirror( uint8_t n ) //p_temp spiegeln
15
      {
16
        n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa);
17
        n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc);
18
        n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0);
19
        return n;
20
      }
21
      p_temp = mirror(p_temp);
#2397972
Lesenswert?

Prinzipiell sollte es so gehen, aber eigentlich werden Funktionen nur in 
besonderen Fällen innerhalb von anderen Funktionen definiert. Besser Du 
setzt sie vor die main-Funktion:
1
...
2

3
uint8_t bcd2bin( uint8_t val ) //Temperatur Abholen
4
{
5
  return (val & 0x0F) + (val >> 4) * 10;
6
}
7

8
uint8_t mirror( uint8_t n ) //p_temp spiegeln
9
{
10
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa);
11
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc);
12
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0);
13
  return n;
14
}
15

16
int main(void)
17
{
18
...
#2398137
Lesenswert?

Rocco L. schrieb:
1
p_temp = bcd2bin( PINA );
2
...
3
p_temp = mirror(p_temp);

???

Warum denkst Du, daß diese Reihenfolge funktionieren soll?

Stell Dir 2 Türen vor mit 2 Schlüsseln.
Wenn Du wieder raus willst, welchen Schlüssel mußt Du wohl zuerst 
nehmen?
Bestimmmt nicht den zur Außentür.


Programmieren hat nichts mit Trial&Error zu tun, sondern hauptsächlich 
mit logischem Denken, besonders bei Abläufen.


Peter
OP #2398718
Lesenswert?

Ich habe heute noch mal die ganze Sache Richtig herum angelöted.
Zudem habe ich alle Verbindungen mehr als ausgibig überprüft. Die 
Schaltung funktioniert 100%.

Der Code sieht so aus wie im Anhang.
Es ist z.Z. so das die switch-case zum Teil ausgeführt wird.
RESET wird ausgeführt, d.h. Der Motor fährt erst mal ins Kältebad bis 
der Endanschlagschalter vom Kältebad (PINB & (1<<KB)) gedrückt ist. 
Nachdem die Probentemperatur p_temp gleich mit der Temperatur vom 
Kältebad k_temp ist fährt der Motor die Probe ins Wärmebad bis der 
Endanschlagtaster vom Wärmebad gedrückt ist (PINB & (1<<KB)).
Hat dann die Probe die gleiche Temperatur wie das Wärmebad (w_temp) 
sollte der Motor nun eigentlich die Probe wieder ins Kältebad bewegen - 
aber es tut sich absolut nichts. Der Motor bewegt sich nicht. An dem 
entsprechenden PORTB |= (1<<CW); liegt einfach kein Vcc an.
Es ist aber nicht so das das nicht gehen würde - steht in meiner Main 
nur PORTB |= (1<<CW); dreht sich der Motor schön in Richtung Kältebad.

Ich werde daraus einfach nicht schlau - ich hoffe von euch hat noch 
einer eine Idee.
Angehängte Dateien:
Gast #2398754
Lesenswert?

Also zusammengefasst kommt er bis in den Schritt IM_WÄRMEBAD.

Mach doch mal folgendes:

Nimm zwei bisher unbenutzte Portpins, deklariere die als Ausgang und 
schreibe die nur hier dazu:
1
case IM_WAERMEBAD:
2
  // Motor anhalten
3
  PORTB &= ~(1<<CCW);
4
  PORTB &= ~(1<<CW);
5
  => setze unb.Portpin#1
6
  // Temp abfragen
7
  if((p_temp >= w_temp) )  
8
  {
9
    => setze unb.Portpin#2
10
    state = CW_AN;
11
  }
12
  break;
13

14
case CW_AN:
15
  ...

Jetzt siehst du, ob er wirklich in den Schritt geht (was ich denke) und 
das die Weiterschaltbedingung, aus welchem Grund auch immer, nicht 
anspricht...
OP #2398805
Lesenswert?

jetzt leuchtet ein LED gegen GND an dem PORTB |= (1<<TESTA);
TESTB bringt kein LED zum Leuchten.

Nun aber der totale Wahnsinn:
Jetzt fährt der Motor Richtung Kältebad aber macht dies obwohl die 
Temperatur p_temp kleiner ist als die von W_temp
Eigentlich sollte das erst passieren wenn p_temp >= w_temp ist.
Irgendwie ist irgendwas total faul.
1
case IM_WAERMEBAD:
2
// Motor anhalten
3
PORTB &= ~(1<<CCW);
4
PORTB &= ~(1<<CW);
5
PORTB |= (1<<TESTA);
6
// Temp abfragen
7
if((p_temp >= w_temp) )
8
PORTB |= (1<<TESTB);  
9
state = CW_AN;
10
break;
OP #2398836
Lesenswert?

Deklariert habe ich das so:
MOTOR_DDR = (1 << DDB0) | (1 << DDB1) | (1 << DDB4) | (1 << DDB5) | (1 
<< DDB6) | (1 << DDB7) ;

Wobei B4 TestA ist und B5 TestB
Diesemal habe ich mal TestA und TestB einfach vertauscht und es leuchtet 
wie erwartet das LED an dem PORTB |= (1<<TESTB);
1
case IM_WAERMEBAD:
2
// Motor anhalten
3
PORTB &= ~(1<<CCW);
4
PORTB &= ~(1<<CW);
5
PORTB |= (1<<TESTB);
6
// Temp abfragen
7
if((p_temp >= w_temp) )
8
PORTB |= (1<<TESTA);  
9
state = CW_AN;
10
break;

jetzt habe ich mal TESTB wieder ausschalten wollen:
1
case IM_WAERMEBAD:
2
// Motor anhalten
3
PORTB &= ~(1<<CCW);
4
PORTB &= ~(1<<CW);
5
PORTB |= (1<<TESTB);
6
// Temp abfragen
7
if((p_temp >= w_temp) )
8
PORTB &= ~(1<<TESTB);
9
PORTB |= (1<<TESTA);  
10
state = CW_AN;
11
break;

aber es führte dazu das beide LED nun gegen GND leuchteten.
Den Atmega habe ich auch gleich mal getauscht - hat sich aber nichts 
geändert.

Ich beise bald eine Ecke vom Tisch ab.
OP #2398844
Lesenswert?

Habe gleich mal überall nachgeklammert - jetzt ist TESTB high
1
      switch( state ){            //State Maschine
2
          case IM_KAELTEBAD:
3
                        // Motor anhalten
4
                        PORTB &= ~(1<<CW);
5
                        PORTB &= ~(1<<CCW);
6
                        // Temp abfragen
7
                        if((p_temp <= k_temp)  ){
8
                          state = CCW_AN;
9
              }
10
                        break;
11
              case CCW_AN:
12
            //Richtung Wärmebad fahren                    
13
                        PORTB &= ~(1<<CW);
14
            PORTB |= (1<<CCW);
15
                        if((PINB & (1<<WB)) && !(PINB & (1<<KB))){
16
                          state = IM_WAERMEBAD;
17
              }
18
                        break;
19
              case IM_WAERMEBAD:
20
                        // Motor anhalten
21
                        PORTB &= ~(1<<CCW);
22
            PORTB &= ~(1<<CW);
23
            PORTB |= (1<<TESTB);
24
                        // Temp abfragen
25
                        if((p_temp >= w_temp) ){
26
              PORTB |= (1<<TESTA);  
27
                          state = CW_AN;
28
              }
29
                        break;
30
              case CW_AN:
31
            //Richtung Kältebad fahren
32
                        PORTB &= ~(1<<CCW);              
33
            PORTB |= (1<<CW);              
34
                        if((PINB & (1<<KB)) && !(PINB & (1<<WB))){  
35
                          state = IM_KAELTEBAD;
36
              }
37
                        break;
38
              case RESET:
39
             if(!(PINB & (1<<KB))){
40
                          // Wenn nicht im Kältebad, dann fahre dort hin
41
                          state = CW_AN;
42
              }
43
                        else{
44
                          // Endschalter schon gedrückt, also bleibe an dieser Stelle
45
                          state = IM_KAELTEBAD;
46
              }
47
                        break;  
48
              default:
49
                        if((PINB & (1<<WB)) && !(PINB & (1<<KB))){
50
                          state = CCW_AN;
51
              }
52
                        if((PINB & (1<<KB)) && !(PINB & (1<<WB))){
53
                          state = CW_AN;
54
              }
55
                        break;
OP #2398851
Lesenswert?

ist hinter jeder if eine geschweifte Klammer erst mal grundlegend 
richtig und kann aber unter bestimmten umständen weg gelassen werden?

ich habe es mir jetzt so zusammengereimt:
Bei meheren Statements müssen geschweifte Klamern hin
if ()
{
...;
...;
...;
...
}

Bei nur einem Statemment müssen keine geschweiften Klammern hin:

if ()
...;


Richtig?
Gast #2398855
Lesenswert?

>Richtig?

Genau. Um sowas wie gerade zu vermeiden, schreibe ich das eine Statement 
immer hinter das if:
1
if (..) blabla

oder bei mehreren mit Klammern unternander:
1
if (...)
2
{
3
  ..
4
}

>Ach so, TESTB ist high und der Motor dreht nicht in Richtung Kältebad
>obwohl p_temp >= w_temp

Da du die beiden TESTB und TESTA ja nur an der einen Stelle benützt, 
kann das nur heißen, dass die Bedingung:
1
if((p_temp >= w_temp) )
nie erfüllt ist. Auch wenn es so sein sollte oder du das denkst. Also 
ist das zu prüfen.

Achja, ich würde dir empfehlen, vernünftig einzurücken im Code.
Gast #2398860
Lesenswert?

Was mir gerade auffällt:
Das einlesen der Temp erfolgt ja so:
1
val  = PINx;
2
hilf = (val & 0x0F) + (val >> 4) * 10;
3

4
temp = ~hilf;

Sicher, dass das so richtig ist? Wie liegen denn die Daten an den Pins 
vor?

Weil, falls die Daten an den Pins als LOW-aktiv vorliegen, würde ich 
erst invertieren und dann nach binär wandeln:
1
uint8_t bcd2bin( uint8_t val )
2
{
3
  uint8_t  hilf = ~val;
4
  return (hilf & 0x0F) + (hilf >> 4) * 10;
5
}
Und das x = ~x im main weglassen.


Beispiel: AM Pin liegt low-activ in bcd eine 25 an.
also ergibt das einlesen val = ~( (2<<4) | (5<<0)  )  = 0xDA = 218
nach deiner Rechnung kommt jetzt bcd=> nach bin ein 13*10 + 10 = 140 
raus.
Das negiert ergibt 116. Es sollte aber 25 sein...
OP #2398895
Lesenswert?

Ich habe gerade im Kältebad 11°C das kann ich ablesen weil follgende LED 
leuchten:
| | = leuchten nicht
|X| = leuchten

|X|  |X|
| |  | |
| |  | |
| |  | |

dabei haben die LED follgende Wert und führen durch Addition zur 
Temperatur:

|1|  |10|
|2|  |20|
|4|  |40|
|8|  |80|

Im Wärmebad sind es 34°C:

| |  |X|
| |  |X|
|X|  | |
| |  | |

Die Probe hat ebenfals so eine LED Anzeige.

Diese LED Anzeigen werden von 3 Atmega48 betrieben. Zudem sind die LED 
PORTS der Mega48 mit denen des MEGA16 verbunden der die Motorsteuerung 
übernimmt.

Ich habe schon (mitlerweile unendliche male) getestet ob beim Mega16 
auch Strom an dem Beinchen ankommt wenn das entsprechenden LED vom 
Mega48 angesteuert wird. Das ist wirklich alles richtig.

Der Mega48 nutzt PORTB um die LED anzusteuern. Dabei werden die LED so 
angesteuert:
PB0 -- LED 1
PB1 -- LED 2
PB2 -- LED 4
PB3 -- LED 8
PB4 -- LED 10
PB5 -- LED 20
PB6 -- LED 40
PB7 -- LED 80

Zudem sind die B Ports des Mega48 immer entsprechend mit den Ports des 
Mega 16 verbunden hier am Bsp des Mega48 der die Probentemperatur misst 
und die Signale an PINA des Mega16 weiter gibt

Mega48  --  Mega16
PB0     --  A0
PB1     --  A1
PB2     --  A2
PB3     --  A3
PB4     --  A4
PB5     --  A5
PB6     --  A6
PB7     --  A7

Wenn ich messe, messe ich dierekt auf den Beinchen der Mega um zu sehen 
ob ein Signal von einem zum anderen Beinchen übertragen wird.
Das haut alles hin.

Kann ich nicht irgendwie die 3 DS18S20 mit an den MEGA16 klemmen? Leider 
ist mir das zu hoch - ich war nach ewigen Probieren froh als einer lief.
Ich hänge mal den Quelltext der Mega48 mit dran - vieleicht kann man das 
irgendwie auf den Mega16 bekommen. Über Einen Vorschlag würde ich mich 
sehr freuen.
Gast #2398902
Lesenswert?

>|X|  |X|
>| |  | |
>| |  | |
>| |  | |

Das ist doch nichtssagend.

Annahme: Du hast irgendwo 11Grad, die auf der Anzeige korrekt angezeigt 
werden. Welche Pegel misst du jetzt an den entsprechenden Pins des µC 
mit der StateMaschine?
OP #2398910
Lesenswert?

Matthias Lipinsky schrieb:
> Was mir gerade auffällt:
> Das einlesen der Temp erfolgt ja so:
>
>
1
> val  = PINx;
2
> hilf = (val & 0x0F) + (val >> 4) * 10;
3
> 
4
> temp = ~hilf;
5
>
>
> Sicher, dass das so richtig ist? Wie liegen denn die Daten an den Pins
> vor?
>
> Weil, falls die Daten an den Pins als LOW-aktiv vorliegen, würde ich
> erst invertieren und dann nach binär wandeln:
>
>
1
> uint8_t bcd2bin( uint8_t val )
2
> {
3
>   uint8_t  hilf = ~val;
4
>   return (hilf & 0x0F) + (hilf >> 4) * 10;
5
> }
6
>
> Und das x = ~x im main weglassen.
>
>
> Beispiel: AM Pin liegt low-activ in bcd eine 25 an.
> also ergibt das einlesen val = ~( (2<<4) | (5<<0)  )  = 0xDA = 218
> nach deiner Rechnung kommt jetzt bcd=> nach bin ein 13*10 + 10 = 140
> raus.
> Das negiert ergibt 116. Es sollte aber 25 sein...

^^die Fahrt bis ins Wärmebad funktioniert wieder, allerdings bleibt er 
dort wieder hängen und TESTB ist high
OP #2398918
Lesenswert?

Matthias Lipinsky schrieb:
>>|X|  |X|
>>| |  | |
>>| |  | |
>>| |  | |
>
> Das ist doch nichtssagend.
>
> Annahme: Du hast irgendwo 11Grad, die auf der Anzeige korrekt angezeigt
> werden. Welche Pegel misst du jetzt an den entsprechenden Pins des µC
> mit der StateMaschine?

Wenn 11°C angezeigt werden dann messe ich am Atmega 48 gegen Vcc 4,88V 
an den PORTS PB0 und PB4
alle anderen ergeben 0V gegen Vcc

Gleichzeitig messe ich am Mega16 an den PINS PD0 und PD4 4,88V gegen Vcc 
alle anderen haben 0V
Gast #2398919
Lesenswert?

>Wenn 11°C angezeigt werden dann messe ich am Atmega 48 gegen Vcc 4,88V
>an den PORTS PB0 und PB4
>alle anderen ergeben 0V gegen Vcc

>Gleichzeitig messe ich am Mega16 an den PINS PD0 und PD4 4,88V gegen Vcc
>alle anderen haben 0V

Das klingt nach HIGH-aktiv. Dann sollte die ursprüngliche bcd2bin 
Routine richtig sein, aber deine x=~x danach müssten raus.
Gast #2398958
Lesenswert?

Ein Schaltplan sagt mehr al tausend Worte. Nutze mal statt den 
Beschreibungen Vcc und Vcc einfach Ub und GND.

Also lt. Schaltplan ist die LED an, wenn du LOW ausgibst. also gilt 
meine Vermutung im Post 20:15.

>und in der Main
>p_tem = ~p_temp;
>k_tem = ~k_temp;
>w_tem = ~w_temp;
>einfach weglassen ?

Ja. Und als Funktion die nutzen:
1
uint8_t bcd2bin( uint8_t val )
2
{
3
  uint8_t  hilf = ~val;
4
  return (hilf & 0x0F) + (hilf >> 4) * 10;
5
}
Gast #2398992
Lesenswert?

>Es kann auch nicht sein das PINA nicht als inputs zulässig sind sondern
>nur als outputs?!

Nein nein. Dann würde das Register PINA auch keinen Sinn machen.

Hast du alle Vcc und GND Pins des µC verbunden? Weil wir hattens hier 
im FOrum schon, dass PINA ist auch Analogeingang. Und wenn die Pins AVdd 
(oder so) nicht korrekt mit den anderen Versorgungspins verbunden ist, 
das es dann Probleme mit dem Port gibt.
Gast #2399035
Lesenswert?

mach doch mal einen Test:

Den µC, dort gibst du an PortA deine Temperatur von der Anzeige rein und 
an nem anderen Port kommt die Temperatur (also nach der funktion 
bcd2bin) binär wieder raus. Das kannst du testen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren