Forum: Mikrocontroller und Digitale Elektronik PortPins setzen und halten, Rotation


von KernoKopp (Gast)


Lesenswert?

Hallo Gemeinde.
Ich komme im Moment gar nicht weiter.

Device 8051
Sprache C

Ich möchte die 8 Pins eines Ports schalten.
Jedes gesetzte Pin soll gehalten bleiben.

Bspl.

Alle Pins sind auf Low.
Es wird ein Pin auf High gesetzt. z.B. Pin 5
Danach sollen automatisch die höherwertigen Pins (6 und 7) nacheinander 
gesetzt werden.
Ist Pin 7 erreicht soll es bei Pin 0 weitergehen, bis wieder Pin 5 
erreicht wird.
Dabei sollen die durchlaufenen Pins auf High bleiben.
Ist Pin 5 erreicht geht der ganze Port auf Low und es geht von vorn los.
Quasi wie eine Rotation, oder so. :o)

Hat jemand die zündende Idee?

Im Vorraus vielen Dank.

Kerno

von Peter D. (peda)


Lesenswert?

Im einfachsten Fall über ne Tabelle:
1
#include <reg51.h>
2
3
char code pattern[] = { 0x01, 0x02, 0x04 };  // Hier die Bitmuster eintragen
4
5
6
void main( void )
7
{
8
  char code *p;
9
  unsigned int i;
10
11
  for(;;){
12
    for( p = pattern, i = sizeof(pattern); i; i-- ){
13
      P2 = *p++;
14
    }
15
  }
16
}


Peter

von Drachenbändiger (Gast)


Lesenswert?

Ist vermutlich auch für den 8051 anwendbar:

Für AVR: Wenn es ganz schnell gehen muss, dann mit Inline-Assembler, 
weil Du damit Zugriff auf das Carry hast.

Ansonsten z.B. so:
1
   uint8_t pattern =0x40; // Anfangswert (nur als Beispiel)
2
   uint8_t oldpattern=0x40; // = Anfangswert
3
   
4
   do {     
5
        pattern |= (pattern<<1); 
6
        if (pattern==oldpattern) pattern|=1; // da wir kein Carry haben
7
        oldpattern=pattern;
8
        // hier die Ausgabe einfügen
9
    } while (pattern!=0xff);
10
    pattern=0;
11
    // wieder Ausgabe

von KernoKopp (Gast)


Lesenswert?

Entschuldigt meine späte Antwort.
Danke für eure Denkanstöße.

Ich habe beide Varianten angesehen und mir angepasst.

@Peter:

In dieser Zeile habe ich noch das  "+" eingefügt, da bleiben die 
durchlaufenen Bits auf High. Sicher nur vergessen worden.
1
 P2 = *p++;
 ->
1
 P2 += *p++;

Diese Funktion kann ich mir jetzt nicht so anpassen, wie ichs brauche, 
damit´s bei 0 wieder los geht.
Werde mir aber bei Gelegenheit diese Variante nochmal vornehmen.


@Drachenjäger:

Dein
>> // hier die Ausgabe einfügen
habe ich an den Anfang der do-while Schleife gesetzt, sonst sind schon 
das Anfangsbit und das nächste Bit gesetzt im ersten Durchlauf gesetzt.

Wenn ab dem Anfangswert z.B Pin 5 alle Pins bis Pin7 gesetzt sind, 
dauert es ne weile bis bei Pin 0 weiter gemacht wird. Warum ist das so?
Ok habs: int -> u_char

Muss ich oldpattern mit einem Wert initialisieren?
Nein. Oder?

Ansonsten machte die Funktion auf Anhieb das, wie ich es mir vorgestellt 
habe.
1
#include<stdio.h>
2
#include<at89c51xd2.h>
3
4
sfr port = 0x90;
5
6
int main (void){
7
8
  int k;
9
  unsigned char pattern, oldpattern, startwert = 32; 
10
  pattern = startwert;
11
  
12
  while(1){ 
13
  
14
    if (port==0xff){  
15
      pattern = startwert;
16
    }
17
    port = pattern;   
18
    pattern |= (pattern<<1); 
19
    if (pattern==oldpattern) pattern|=1; // da wir kein Carry haben
20
    oldpattern=pattern;
21
    for(k=20000;k>=0; k--); 
22
  }
23
  return 0;
24
}

Vielen Dank für die Anregungen.
Ich hatte schon nen Knoten in den Fingern.

Oh! Da da sehe ich schon eine weitere Hürde.
Meine "Rotation" darf nur über 7 Pins und nicht über 8 Pins gehen.
Ist Drachenjäger´s Version nur für 8 Pins machbar?

Grüße Kerno.

von Peter D. (peda)


Lesenswert?

KernoKopp schrieb:
> In dieser Zeile habe ich noch das  "+" eingefügt, da bleiben die
> durchlaufenen Bits auf High. Sicher nur vergessen worden.

Nein.
Die Tabelle ist doch nur ein Beispiel.
Du mußt die Tabelle selber erstellen!


> Diese Funktion kann ich mir jetzt nicht so anpassen, wie ichs brauche,
> damit´s bei 0 wieder los geht.

Siehst Du.


Peter

von KernoKopp (Gast)


Lesenswert?

mhh...da bräuchte ich 49 Tabelleneinträge.
Ich habe eine Laufvariable, die nur die Zahl 1-7 annehmen kann.

-> Das ganze sieht aus wie ein Monatsplan. Einmal die Woche findet ein 
Event statt. Welcher Tag das ist, legt der Benutzer fest.

Pin0 = Montag
Pin7 = Sonntag

Es gibt ein Event, welches an einem beliebigen Wochentag passiert.
z.B. Mittwoch = Pin2.

Da leuchtet der Mittwoch.
Den nächsten Tag leuchtet Mittwoch und Donnerstag
dann Mittwoch und Donnerstag und Freitag......

Das läuft dann weiter über den Sonntag bis zum Dienstag.
Dann Mittwoch kommt wieder das Event.


Oder interpretiere ich deine Funkiotn falsch.

Danke Kerno

von Peter D. (peda)


Lesenswert?

KernoKopp schrieb:
> mhh...da bräuchte ich 49 Tabelleneinträge.
> Ich habe eine Laufvariable, die nur die Zahl 1-7 annehmen kann.

???

Den mußt Du mir mal erklären.

Wenn Du nur 7 Möglichkeiten hast, dann kannst Du auch nur 7 Einträge 
zugreifen.
Welche LED nun bei welchem Eintrag leuchtet, legst Du in der Tabelle 
fest.
Egal, ob Du alle 8 LEDs einschaltest (0xFF) oder keine (0x00).


Peter

von Drachenbändiger (Gast)


Lesenswert?

> Meine "Rotation" darf nur über 7 Pins und nicht über 8 Pins gehen.
> Ist Drachenjäger´s Version nur für 8 Pins machbar?

Verstehe ich nicht ... oben hast Du doch von den Bits 0 bis 7 
geschrieben!

Also, wenn Du z.B. die Bits 1-7 rotieren lassen willst (Bit 0 also 
ignorierst), kannst Du
1
 if (pattern==oldpattern) pattern|=3;
 statt  if (pattern==oldpattern) pattern|=1; schreiben.

von Drachenbändiger (Gast)


Lesenswert?

KernoKopp schrieb:
> Muss ich oldpattern mit einem Wert initialisieren?

Ja, am Anfang muss irgendwo "oldpattern=pattern" stehen!

von KernoKopp (Gast)


Lesenswert?

Hallo Peter, Hallo Drachenbändiger,

vielen Dank für eure Mühen.
Jetzt ist der Groschen gefallen.:o)
Ich habe mal wieder viel zu kompliziert gedacht.
Eine solche "Rotation" ist völlig überflüßig.

Eine einfache Bitmaske (like Peter) ist da schon die Lösung.
Meine Laufvariable mit den Werten 1-7 wird ja extern erzeugt.
Da brauche ich mich nicht drum kümmern.

Somit kann ich mit ihr auf die Positionen im Feld zugreifen und mit dem 
nächsten Wert ODER verknüpfen.

Machmal hat man eben Brett vorm Kopp ;o)
1
#include<reg51.h>
2
3
sfr port = 0x90;
4
5
unsigned char code pattern[]  = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40};  //Bitmuster
6
unsigned char wt[]        = { 4, 5, 6, 0, 1, 2, 3};  //simuliert externe Laufvariable (Wochentage)
7
8
9
void main( void ){
10
11
  unsigned char w;
12
  int i,k;
13
  
14
  port=0x00;
15
  
16
  for(;;){
17
  
18
    while(i<= sizeof(wt)){
19
      if (port == 0x7f){    // ist eine Woche um gehts mit dem Startwochentag wieder los    
20
        i=0;
21
        w=0;
22
      }
23
      port = pattern[wt[i++]] | w;
24
      w=port;
25
      for(k=30000;k>=0; k--); 
26
    }
27
  }
28
}

So sollte es gehen.

Danke und Gruß Kerno

von Peter D. (peda)


Lesenswert?

KernoKopp schrieb:
> Somit kann ich mit ihr auf die Positionen im Feld zugreifen und mit dem
> nächsten Wert ODER verknüpfen.

Oh Gott, nein doch.

Du trägst genau alle die LEDs ein, die leuchten sollen !!!

Nix rotieren und nix oder.

Es wird immer der komplette Port gesetzt.
Und wenn nach i == 6 von vorne, dann einfach:
1
if( i == 6 )
2
  i = 0;


Peter

von KernoKopp (Gast)


Lesenswert?

Hallo Peter, vielleicht ist mein TestCodeSchnippsel etwas ungünstig 
gewählt.

Der Code macht vom Prinzip her das, wie ich mir das vorgestellt habe.
Die Werte im Feld wt sind auch nur nachempfunden, wie sie decodiert vom 
DCF77 Signal, für die Wochentage als Dezimalzahl in dieser Reihenfolge, 
kommen könnten.
Diese Dezimalzahlen sind er Index für das "pattern" Feld.

Hier im Code fängt meine Woche z.B. mit Freitag (4), da ein Feld ja bei 
Index 0 anfängt, an. Vom DCF kommt da ja eine 5.
D.h es leuchtet als erstes der Pin für Freitag P1.4 (0x10)
Am Sonnabend soll nicht nur Sonnabend P1.5 (0x20), sondern auch 
weiterhinder Freitag P1.4 leuchten. -> 0x10 | 0x20
Ist der Sonntag P1.6 (0x40)erreicht gehts bei Montag P1.0 (0x01) weiter.
Bis zum Donnerstag P1.3 (0x08)
Die 7 Tage einer Woche können einem belibeigen Tag anfangen zu zählen.
Aber P1.0 ist Montag......und P1.6 ist Sonntag.


Die Schleife und die Incrementierung ist nur um mal alles druchlaufen zu 
lassen.
1
port = pattern[wt[i++]] | w;
2
w=port;

Ich mach mal wieder viel Lärm um Nichts.


Danke und Gruß Kerno

von Peter D. (peda)


Lesenswert?

KernoKopp schrieb:
> D.h es leuchtet als erstes der Pin für Freitag P1.4 (0x10)
1
unsigned char code pattern[]  = { 0x10, ...
> Am Sonnabend soll nicht nur Sonnabend P1.5 (0x20), sondern auch
> weiterhinder Freitag P1.4 leuchten. -> 0x10 | 0x20
1
unsigned char code pattern[]  = { 0x10, 0x30, ...
Nun endlich klar?

Deine Rum-Oderei ist völlig unsinnig.


Die Tabelle sollte aber nicht mit Freitag anfangen, da DCF77 von Montag 
.. Sonntag (1 .. 7) zählt.

Also zuerst den Wert für  Montag in die Tabelle und zuletzt für Sonntag 
und dann:
1
  port = pattern[DCF77_wochentag - 1];
Und fertig ist die ganze Routine.


Peter

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.