vergleich der inputs am bort (8Bit)

Gast #3975041
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
Gast #3975238
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
Gast #3976246
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
}
#3976262
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
#3976269
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'.
Gast #3976322
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
}
Moderator (Firma: Titel) Persönliche Seite #3976345
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?
Moderator (Firma: Titel) Persönliche Seite #3976349
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
}
#3976353
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.
Gast #3976396
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
Gast #3976411
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
#3976428
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.

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