Forum: Mikrocontroller und Digitale Elektronik vergleich der inputs am bort (8Bit)


von marten (Gast)


Lesenswert?

Hallo,

ich wuede gerne im uC prufen ob ich mehrere einsen oder nullen anliegen 
habe (8bit). kenn mir jemand einen tip geben.
Machs mir glaub irgendwie bisschen umstaendlich.

Ich wuerde alle zusammenzaehlen und entweder:

>4  mehr einsen
<4  mehr nullen
==4 anzahl gleich

gehts irgendwie einfacher mit maskieren oder spezielle befehle. ich 
programmiere in.

gruss

von schreiber (Gast)


Lesenswert?

Du hast vergessen die Programmiersprache zu nennen ;P

Und dann wäre die Info welche ControllerFamilie auch nett. :)

von marten (Gast)


Lesenswert?

Ou.. "C". Sorry

von marten (Gast)


Lesenswert?

Ou... 8051

von Peter D. (peda)


Lesenswert?

1
char count_ones( char val )
2
{
3
  char i;
4
  for( i = 0; val; val <<= 1 )
5
    if( val & 0x80 )
6
      i++;
7
  return i;
8
}

: Bearbeitet durch User
von Georg (Gast)


Lesenswert?

Hallo,

Einem Byte kann man die Werte nach folgneder Tabelle zuordnen:
1
0000 0000 <
2
0000 0001 <
3
0000 0010 <
4
0000 0011 <
5
0000 0100 <
6
0000 0101 <
7
0000 0110 <
8
0000 0111 <
9
0000 1000 <
10
0000 1001 <
11
...
12
0000 1110 <
13
0000 1111 =
14
0001 0000 <
15
...
16
0001 1110 =
17
0001 1111 >
18
0010 0000 <
19
....

Also stell eine Tabelle (array, 256 Bytes) auf mit den korrekten 
Einträgen <,=,>, lies das Portbyte ein und verwende es als Index für den 
Zugriff auf die Tabelle. Geht maximal schnell, verbraucht dafür 256 
Byte.

Georg

von marten (Gast)


Lesenswert?

Vielen Dank,

funktioniert super.
Könntest du mir noch erklären was da genau passiert?

von marten (Gast)


Lesenswert?

Also hier:

char count_ones( char val )
{
  char i;
  for( i = 0; val; val <<= 1 )
    if( val & 0x80 )
      i++;
  return i;
}

von marten (Gast)


Lesenswert?

verstanden :)

von marten (Gast)


Lesenswert?

hallo,
habs jetzt nochmal auf dem bard probiert.
become nicht dass richtige ergebnis.
mache ich was falsch?

1
int tmp = 0x00;                                         // Global variable cnt with starting values
2
3
void External_ISR()org 0x0003 ilevel 0 {    // Interrupt rutine
4
  EA_bit = 0;                               // Disable all Interrupts
5
  tmp = 1;                                  // Set variable tmp
6
  EA_bit = 1;                               // Enable all Interrupts
7
}
8
9
int count_ones(int val)
10
{
11
  int i;
12
  for( i = 0; val; val <<= 1 )
13
    if( val & 0x80 )
14
      i++;
15
  return i;
16
}
17
18
void main() {                               // Main program
19
20
  int val = 0x00;                           // Variable for value of the port
21
  int result = 0x00;
22
  
23
  
24
  P0 = 0xFF;                                // Set P0 as high impedance input
25
  P1 = 0xFF;                                // Set P1 as input
26
  P2 = 0xFF;                                // Set P2 as input
27
  P3 = 0xFF;                                // Set P3 as input
28
29
  IE = 0x81;                                // Setting the Interrupts: EA=1, EX0=1 --> just external interrupt enabled
30
31
32
  while (1)
33
  {
34
35
        while (tmp == 1)
36
        {
37
        val = P0;
38
        result = count_ones(val);
39
        
40
        P1 = result;
41
        
42
        tmp = 0;
43
        }
44
  }
45
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Kannst du mir verraten, warum du mit dem externen Interrupt die Dinge 
schon wieder komplizierter machen musst, als unbedingt notwendig?
Warum nicht beim ersten Versuch alles so einfach wie möglich, so dass 
man möglichst wenig Chancen auf Fehler hat? Hauptschleife { P0 einlesen 
- Anzahl Bits bestimmen - auf P1 ausgeben }. Fertig. Mehr braucht es für 
den ersten Versuch nicht. Alles darüber hinausgehende birgt nur wieder 
neue Möglichkeiten für Fehler, die mit dem eigentlich zu Testenden 
nichts zu tun haben.
1
int tmp = 0x00;

da fehlt ein volatile.

FAQ: Was hat es mit volatile auf sich

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Abgesehen davon solltest du dir mal über Datentypen Gedanken machen. 
Einfach für alles "int" zu verwenden ist nicht nett dem µC gegenüber. Du 
treibst ihn damit in 16 Bit Verarbeitung rein, die nicht sein müsste.
Dein Programm handelt im wesentlichen von Bytes. Dafür ist 'unsigned 
char' der Datentyp der Wahl, oder wenn du hast 'uint8_t'.

von marten (Gast)


Lesenswert?

Tag,

weil ich den Interrupt vorher getestet hatte.
Interrupt raus gemacht, volatile rein gemacht. Keine Veraenderung...

von Karl H. (kbuchegg)


Lesenswert?

marten schrieb:

> Interrupt raus gemacht, volatile rein gemacht. Keine Veraenderung...

... die jetzige Version erneut zeigen.

Aus eigener Erfahrung: Es gibt kein Programm, das einfach genug wäre als 
das man nicht blöde Fehler machen kann, die man dann auch selbst nicht 
sieht.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ich weiss ja nicht, wei die 8051 das sehen. Aber ...
1
  P1 = 0xFF;                                // Set P1 as input
2
3
...
4
        
5
        P1 = result;

ich würde das zumindest soweit korrigieren, dass ich P1 auf Ausgang 
setze, wenn ich was ausgeben will.

von Achim S. (Gast)


Lesenswert?

Karl Heinz schrieb:
> ich würde das zumindest soweit korrigieren, dass ich P1 auf Ausgang
> setze, wenn ich was ausgeben will.

no passt schon, so macht man das bei 8051ern.
Beitrag "Re: Ports AT89S8253"

@Marten: was legst du denn an P0 an und was kommt an P1 raus? Hast du 
die Pegel mal nachgemessen?

von Georg (Gast)


Lesenswert?

Karl Heinz schrieb:
> dass ich P1 auf Ausgang
> setze

Das gibt es bei den OC-Pins eines 8051 garnicht.

Georg

von marten (Gast)


Lesenswert?

1
unsigned char count_ones(unsigned char val)
2
{
3
  unsigned char i;
4
  for( i = 0; val; val <<= 1 )
5
    if( val & 0x80 )
6
      i++;
7
  return i;
8
}
9
10
void main() {                               // Main program
11
12
  unsigned char val = 0x00;                 // Variable for value of the port
13
  unsigned char result = 0x00;
14
15
16
  P0 = 0xFF;                                // Set P0 as high impedance input
17
  P1 = 0xFF;                                // Set P1 as input
18
  P3 = 0xFF;                                // Set P3 as input
19
20
21
  while (1)
22
  {
23
24
        if (P3.B2 == 0)
25
        {
26
        while (P3.B2 == 0)
27
        val = P0;
28
        result = count_ones(val);
29
        P2 = result;
30
        }
31
  }
32
}

: Bearbeitet durch User
von marten (Gast)


Lesenswert?

Wir arbeiten an einem Experimentierboard Easy8051B.
An P0 sind Pushbuttons angeschlossen. Wir wollen die einsen, die an 
Port0 anliegen zaehlen und den wert dan an P1 ausgeben.
Wenn ich z.B. zwei buttons druecke, habe ich zwei nullen und 6 einsen 
anliegen. dass heist ich will die binaere 2 an port1 ausgeben.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

marten schrieb:
1
   P0 = 0xFF;        // Set P0 as high impedance input
Das kann 1. der Compiler nicht und 2. der Controller nicht
1. weil der Compiler Kommentare ignoriert
2. weil der 8051 einen Pullup eingebaut hat und nur nach GND treiben 
kann

Es könnte natürlich bei den vielen 8051 Derivaten durchaus auch eines 
mit Richtingsregister geben. Das wäre aber ungeschickt...

BTW: Welche Pegel hast du tatsächlich am P0?

von Achim S. (Gast)


Lesenswert?

was du willst, ist klar. Was du konkret als Fehler beobachtest ist 
unklar.

Also nochmal:
welches konkretes Bitmuster liegt an Port0 (mit Multimeter nachmessen)
welches konkrete Bitmuster wird an Port2 ausgegeben?

Dir ist auch klar, dass du B2 von Port 3 toggeln musst, damit was 
passiert?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

marten schrieb:
> Wenn ich z.B. zwei buttons druecke, habe ich zwei nullen und 6 einsen
> anliegen. dass heist ich will die binaere 2 an port1 ausgeben.
Wäre es dann nicht sinnvoll, die Nullen zu zählen?

Wozu das Rumgehampel mit dem P3?
Ich würde da einfach mal das hier vorschlagen:
1
while (1)
2
{
3
   val = P0;
4
   result = count_ones(val);
5
   P2 = 8-result; // Anzahl der Nullen(!) berechnen...
6
}

: Bearbeitet durch Moderator
von Karl H. (kbuchegg)


Lesenswert?

marten schrieb:

Ich gebs auf

>   while (1)
>   {
>
>         if (P3.B2 == 0)
>         {
>         while (P3.B2 == 0)
>         val = P0;
>         result = count_ones(val);
>         P2 = result;
>         }
>   }
> }


da hast du doch schon wieder Nebenbedingungen!

Was ist so schwer an
1
    while (1)
2
    {
3
      val = P0;
4
      result = count_ones(val);
5
      P2 = result;
6
    }

und wenn DAS funktioniert, dann wird ausgebaut! Aber nicht vorher.


Ich meine das absolut und 100%-ig Ernst mit: so einfach wie nur 
irgendwie möglich!

Im Grunde wäre ein
1
    while (1)
2
    {
3
      P2 = count_ones( P0 );
4
    }
noch einfacher. Aber - geschenkt.

: Bearbeitet durch User
von TomA (Gast)


Lesenswert?

Hallo marten,

die Ports sind beim 89S8253 nach Reset automatisch auf 0xFF (Eingang), 
sie nochmal damit zu überschreiben schadet aber nicht.

Ich weiß nicht welchen Compiler du verwendest, beim Keil werden die 
Portbit nicht P3.B2, sondern P3_2 beeichnet (in AT89S8253.h festgelegt).

Habe dein Programm mal mit Keil ausprobiert. In der "if --- while" 
Kombination frißt es sich fest. Ohne das "while" läuft es wie gewollt.

        if (P3_2 == 0)
        {// while (P3_2 == 0)   ;ausklammern oder löschen
          val = P0;
          result = count_ones(val);
          P2 = result;
oder:
          P2 = count_ones(P0);
        }

Ich hoffe es hilft dir weiter. Gruß. Tom

von marten (Gast)


Lesenswert?

Ok. Habs geschnallt.

unsigned char count_ones(unsigned char val)
{
  unsigned char i;
  for( i = 0; val; val <<= 1 )
    if( val & 0x80 )
      i++;
  return i;
}

void main() {                               // Main program

  P0 = 0xFF;                                // Set P0 as high impedance 
input
  P2 = 0xFF;                                // Set P2 as input


   while (1)
    {
      P2 = count_ones( P0 );
    }

}



Das funktioniert nicht.

von marten (Gast)


Lesenswert?

Nullen zeahlen aber wohl :).
Vielen viel dank fuer eure hilfe.
Ich habe glaube einen Denkfehler mit der umgekehrten logic...

unsigned char count_ones(unsigned char val)
{
  unsigned char i;
  for( i = 0; val; val <<= 1 )
    if( val & 0x80 )
      i++;
  return i;
}

void main() {                               // Main program

  P0 = 0xFF;                                // Set P0 as high impedance 
input
  P2 = 0xFF;                                // Set P2 as input


   while (1)
    {
      P2 = (8 - count_ones( P0 ));
    }

}

Das geht.


P0 high Pegel 3,1 V Taster nicht gedrueckt
P0 low Pegel 0,1 V Taster gedrueckt

P2 high Pegel 4,7 V Taster nicht gedrueckt
P2 low Pegel 0,1 V Taster gedrueckt

von TomA (Gast)


Lesenswert?

Hallo marten,

du hast weiter oben mal geschrieben "ich will die binaere 2 an port1 
ausgeben". Dann mußt du P1 anstatt P2 schreiben:

      P1 = count_ones( P0 );

Das  8 - ... brauchst du nicht, die Routine von Peter gibt direkt die 
Anzahl der "1" zurück.

Gruß. Tom

von marten (Gast)


Lesenswert?

Mann es tut mir leid!!!
Es funktioniert alles einwandfrei!!!
Sorry, ich hab mich einfach von leuchten und nichtleuchten verwirren 
lassen!

von Karl H. (kbuchegg)


Lesenswert?

TomA schrieb:

> ausgeben". Dann mußt du P1 anstatt P2 schreiben:

Das P1 anstelle von P2 ist optional. Anscheinend hat er zwischendurch 
seine Meinung geändert, an welchem Port ausgegeben werden soll.

> Das  8 - ... brauchst du nicht, die Routine von Peter gibt direkt die
> Anzahl der "1" zurück.

Allerdings will er eigentlich die Anzahl an 0-en zählen. Denn er will 
gedrückte Tasten feststellen und die liefern ihm eine 0 am Portpin.
Daher die Subtraktion von 8.

von marten (Gast)


Lesenswert?

I knowwwww!!!

von TomA (Gast)


Lesenswert?

Jetzt habe ich es auch gescnallt. Danke!

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.