Forum: Compiler & IDEs Variable ändert sich nur bei 8. Bit


von spencer (Gast)


Lesenswert?

Hallo Forengemeinde!

Ich möchte PINA auf Änderung beobachten (per TimerInterrupt) und dann 
eine Flankenauswertung der geänderten Pins machen. Controller ist ein 
Mega32, Eingangsbeschaltung low-aktiv mit internen Pullups. Leider wird 
das Änderungschar (e1c) nur auf 0xFF gesetzt, wenn PINA.0 sich ändert. 
Sitze nun schon seit mehreren Stunden an diesem Problem und komme 
einfach nicht weiter. Weiter unten hab ich das UART-Debug gepostet.


MfG

spencer

1
char tempPINA = PINA;
2
3
e1c = 0x00;
4
5
int i;
6
7
for (i=0;i<8;i++) {  // Zustand der Eingänge 1 bis 8 vergleichen und an Array e1 weitergeben
8
9
      if (!(tempPINA == pina_last)){ // Mindestens ein Pin auf E1 hat sich verändert, prüfen!!!
10
      if (!(tempPINA&(1<<i)) == (pina_last&(1<<i))) // Alle Bits durchgehen und vergleichen
11
12
{ 
13
14
    e1c =0xFF;  // Änderungsindex setzen
15
16
  if (!(tempPINA&(1<<i))){
17
      e1hi[i] = 1;
18
          e1lo[i] = 0;
19
}
20
21
else{     e1hi[i] = 0;
22
          e1lo[i] = 1;
23
}
24
25
}}

e1hi = Eingang 1 (PINA) wurde bei n-Bit high (GND)
e1lo = Eingang 1 (PINA) wurde bei n-Bit low (VCC)
e1c = Eingang 1 (PINA) hat sich verändert

Zustand pina_last: 00000000
Zustand tempPINA:  00010000
Zustand e1hi:      00000000
Zustand e1lo:      00000000
Zustand e1c:       00000000

Zustand pina_last: 00000000
Zustand tempPINA:  10000000
Zustand e1hi:      10000000
Zustand e1lo:      00000000
Zustand e1c:       11111111

von spencer (Gast)


Lesenswert?

hm.. ich muss zugeben, das ist kein aussagekräftiger betreff, sorry, zu 
spät gemerkt.

von Fred S. (Gast)


Lesenswert?

Hi spencer,

auf den ersten Blick sehe ich mehrere Probleme mit Deinem Code:

1. Du verrätst uns nicht die Deklaration von pina_last.
2. tempPINA & pina_last sollten vom Typ uint8_t sein -- sonst kann es 
alle möglichen Probleme geben!
3. tempPINA wird bei Deinem jetzigen Code nur einmal (als 
Initialisierung) von PINA gelesen.
4. Irgendwo müsste doch auch
1
pina_last=tempPINA;
 o.ä. stehen!
5.
1
  if (!(tempPINA&(1<<i))){
2
      e1hi[i] = 1;
3
          e1lo[i] = 0;
4
}
5
6
else{     e1hi[i] = 0;
7
          e1lo[i] = 1;
8
}
 könnte man stark vereinfachen!
Gruß

Fred

von spencer (Gast)


Lesenswert?

Hm der Code ließ mir keine Ruhe, also strengte ich nochmal die 
Forensuche an. Daraus wandelte ich mir folgenden Code ab, der wunderbar 
funzt :)
schnipp
1
char tempPINA = PINA;
2
char tempPINC = PINC;
3
4
int i;
5
6
char h = 0;
7
8
if (tempPINA != pina_last) //wenn Änderung
9
 {
10
e1c = 0xFF;
11
12
 for (i = 0x01; i <= 0x80; i = i << 1)
13
14
   {
15
   if ((tempPINA & i) ^ (pina_last & i))  //wenn Unterschied
16
    {
17
18
    if(pina_last & i)    //wenn H-Input
19
     e1hi[h] = 1;    //dann H-Output
20
    else
21
     e1lo[h] = 1;    //L-Output
22
    }
23
h++;
24
   }
25
 }
schnapp

Trotzdessen vielen Dank an Fred! tempPINA und pina_last sind übrigens 
char.
Und hier wird der pina_last gelesen:
1
int reade1(void){    // E1 abgleichen
2
pina_last = PINA;
3
}

Wenigstens hab ich das mit dem shiften jetzt verstanden.

MfG

von Karl H. (kbuchegg)


Lesenswert?

spencer wrote:

> Trotzdessen vielen Dank an Fred! tempPINA und pina_last sind übrigens
> char.

Gewöhn dir an, bei Byte-Werten immer einen unsigned char zu
nehmen.

Bei char überlässt du es dem Compiler, ob ein char ein signed char
oder ein unsigned char ist. Um auf Byte-Ebene zu arbeiten, will
man aber meistens eine unsigned Behandlung haben. Dadurch, dass du
gezielt unsigned angibst, schliesst du eine mögliche Fehlerquelle
aus.

> Und hier wird der pina_last gelesen:
> int reade1(void){    // E1 abgleichen
> pina_last = PINA;
> }

Integrier dieses Setzen des pina_last in deine Auswerteroutine!
Zwischen dem Abfragen des PINA für die Auswertung und dem erneuten
Aufruf dieser Funktion vergeht Zeit! In dieser Zeit könnte dein
Eingang seinen Pegel verändern -> mit deiner Strategie kriegst
diesen Pegelwechsel dann nicht mehr mit. Du willst ja den jetzigen
Pegel des Eingangs mit dem Pegel vergleichen, mit dem du die letzte
Auswertung gemacht hast.
1
  unsigned char tempPINA = PINA;
2
  unsigned char tempPINC = PINC;
3
4
  unsigned char i;
5
  unsigned char h = 0;
6
7
  if (tempPINA != pina_last) //wenn Änderung
8
  {
9
    e1c = 0xFF;
10
11
    for (i = 0x01; i != 0x00; i = i << 1)
12
    {
13
      if ((tempPINA & i) ^ (pina_last & i))  //wenn Unterschied
14
      {
15
        if(pina_last & i)    //wenn H-Input
16
          e1hi[h] = 1;    //dann H-Output
17
        else
18
          e1lo[h] = 1;    //L-Output
19
      }
20
      h++;
21
    }
22
  }
23
24
  pina_last = tempPINA;

Die for-Schleife sieht etwas gewöhnungsbedürftig aus. Aber zusammen
mit dem Wissen, dass i ein unsigned char ist, solltest du rauskrigen
können, wie das läuft.

von spencer (Gast)


Lesenswert?

Dankeschön, ich dachte es ist egal, ob ein char signed oder unsigned 
ist, wenn man sowieso nur hochzählt bzw. sich nur im positiven bereich 
bewegt.

von Karl H. (kbuchegg)


Lesenswert?

spencer wrote:
> Dankeschön, ich dachte es ist egal, ob ein char signed oder unsigned
> ist, wenn man sowieso nur hochzählt bzw. sich nur im positiven bereich
> bewegt.

Bei deiner Anwendung (=letztes Program) ist es tatsächlich egal.
Interessant wird es allerdings dann wenn irgendwann mal Konvertierungen
nach int bzw. umgekehrt ins Spiel kommen. Da wird dann flugs aus einer
255 im char ein -1 im int und dann ist das Suchen groß, was denn
da schief gelaufen sein könnte.

Ein simples

   char c = 255;

   if( c == 255 ) {
     ...
   }

kann dann schnell mal in unvorhergesehene Probleme ausarten.

Das einfachste ist es, einfach nach den Regeln zu spielen:
Du willst Bytes bearbeiten  -> unsigned char
Du willst "Strings" (also Zeichenketten) verarbeiten  -> char

Damit bist du praktisch immer auf der sicheren Seite.

von Fred S. (Gast)


Lesenswert?

Hi,

ich bin da noch mehr Purist und habe deshalb
1
uint8_t
 vorgeschlagen, obwohl man dann
1
inttypes.h
 einbinden muss.

Gruß

Fred

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.