Forum: Compiler & IDEs serielle Daten über einen Pin einlesen


von Thomas (Gast)


Lesenswert?

Halli hallo nochmal an Alle!

Und zwar bin ich auf folgendes Problem gestoßen. Ich bekomme an einem
Eingang (PORTC, PIN=0) serielle Daten. Diese möchte ich nun bitweise
einlesen und abspeichern.

Meine Idee sieht so aus:

for (BitCounter=0;BitCounter<80;BitCounter++)
  {
   Speicher[ChipIdBitCounter] = inp(PINC);
  }

Speicher[]ist ein int array....nur so wird ja immer der ganze Port
gelesen und abgespeichert oder? Welche Lösung nimmt man überlicherweise
für so ein Problem. Hab schon diese Funktion gefunden,

for (j=0;j<=7;j++)  //Schleife zum einlesen der 8 Bits
  {
     daten<<=1;         // Variable einmal schieben
     if ( bit_is_set(PIND,2)   // Prüfen ob Bit = 1
  { daten++;}   //wenn Bit = 1 dann Daten + 1. LSB wird dann 1
  }

aber ich versteh ich nicht so recht und denke auch nicht das es bei mir
so funktioniert. Wer hat Vorschläge und Lösungen. Wäre Euch sehr
dankbar.

Ciao Thomas

von Jörg Wunsch (Gast)


Lesenswert?

Bitoperatoren in C
Bitoperatoren in C
Bitoperatoren in C

Lies und verstehe alles, was zu & | ^ << >> ~ in einem guten C-Buch
geschrieben steht.

for (ByteCounter = 0, mask = 1; ByteCounter < 80 / 8;) {
  if ((PINC & (1 << yourbitnumber)) != 0)
    Speicher[ByteCounter] |= mask;
  if (mask == 0x80) {
    mask = 1;
    ByteCounter++;
  } else {
    mask <<= 1;
  }
}

Verstehen mußt Du es aber bitte selbst. ;-)

von Jörg Wunsch (Gast)


Lesenswert?

Achso:

Nachdem Du verstanden hast, wie die Bitoperatoren in C funktionieren
;-) kannst Du noch überlegen, ob nicht die hardware-SPI was für Dich
wäre.

von Peter D. (peda)


Lesenswert?

@Jörg,

das ist aber nicht das selbe.

Wenn Du mit einer Maske arbeitest, mußt Du sie in die andere Richtung
schieben:

unsigned char daten = 0;
unsigned char mask = 0x80:
do{
  if ((PINC & (1 << yourbitnumber)) != 0)
     daten |= mask;
}while( mask >>= 1 );



@Thomas,

in allen Beispielen fehlt aber noch der Teil zur Synchronisation,
entweder mit einem 2. Clockpin oder per Timerintervall.


Peter

von Jörg Wunsch (Gast)


Lesenswert?

> Wenn Du mit einer Maske arbeitest, mußt Du sie in die andere
> Richtung schieben:

Nicht zwingend, das hängt ja davon ab, in welcher Folge die Bits im
Byte gespeichert werden sollen.  Darüber hat sich Thomas schlicht
nicht ausgelassen.  In meinem Fall wird das erste eingelaufene Bit im
LSB gespeichert (das wäre ``true little-endian'' ;-), in Deiner
Variante im MSB.

von Thomas (Gast)


Lesenswert?

Hallo Jörg/Peter,

danke für die Antworten. Werde es mir morgen mal in Ruhe anschauen.
Vorallem die Bitoperatoren ;-)))

ich würde die Bits einfach so abspeichern wie sie kommen. Also 1.Bit
ist dann wohl auch MSB. Eigentlich auch erstmal egal ;-)))...Hauptsache
ich komm an die Daten.

schönen Abend noch

Ciao Thomas

von Thomas (Gast)


Lesenswert?

Guten Morgen Freunde,

also ich habe mich mal mit den Bitoperatoren beschäftigt und versucht
Euren Code zu verstehen. Aber so ganz bin ich noch nicht dahinter
gekommen.
(ByteCounter = 0, mask = 1; ByteCounter < 80 / 8;)

Wieso teilst Du da hinten nochmal durch 8???

if ((PINC & (1 << yourbitnumber)) != 0)

Diese Zeile verstehe ich soweit erstmal ganz gut. yourbitnumber in
Verbindung mit Pinc und dem 1 << ergibt das Pin, wo ich lesen will.
!= bedeutet soviel wie ungleich Null wenn ich mich nicht irre.

Speicher[ByteCounter] |= mask;

dann wird ne 1 in den Speicher an der Stelle von ByteCounter
geschrieben

if (mask == 0x80) {



Und das ist mir jetzt zu hoch. Also 80hex sind 1000 0000. mask ist 1.
Wie soll das also == sein??


mask <<= 1;

<< bedeutet linksschieben aber in Verbindung mit =????
Was macht das genau??

Sorry, wenns nervt....aber bin nicht so der C-Guru ;-))

Ciao Thomas

von Jörg Wunsch (Gast)


Lesenswert?

> Wieso teilst Du da hinten nochmal durch 8?

Weil es ein *byte*counter sein soll, Du aber (Deinem Ursprungsposting
nach) 80 bits hast.

Allerdings fehlt in meinem Code die innere Schleife für jeweils 8
Bits, die ist bei Peter dafür da.

> if (mask == 0x80) {

> Und das ist mir jetzt zu hoch. Also 80hex sind 1000 0000. mask ist
> 1.

Nicht mehr, wenn diese if-Anweisung erfüllt sein soll.  Denn:

> mask <<= 1;

> << bedeutet linksschieben aber in Verbindung mit =?

Nun, ganz normal wie in C üblich:

a <foo>= b;

ist ein Äquivalent für

a = a <foo> b;

mask wird also um ein Bit nach links verschoben.  Damit sollte Dir
auch klar sein, warum sie irgendwann 0x80 werden kann.

Wie gesagt, um die Bitschieberei fehlt bei mir noch eine innere
Schleife, außerdem mußt Du, wie Peter richtig bemerkte (war mir erst
nach meinem Posting aufgefallen) in der inneren Schleife noch
irgendwas haben, was an PINC den Empfang des nächsten Bits triggert.
Das kann z. B. sowas sein wie:

PORTC |= (1 << yourtriggerbit);
PORTC &= ~(1 << yourtriggerbit);

um einen kurzen Impuls des yourtriggerbit-sten Bits in PORTC
auszulösen.  Die Schreibweise ist so ganz und gar gängig (bspw. in den
Quellen von Betriebssystemtreibern), nur damit Du ein wenig in der
Übung mit den Bitoperatoren bleibst. :-)  Sofern yourtriggerbit zur
Compilezeit konstant ist, würde der AVR-GCC daraus übrigens (bei
eingeschalteter Optimierung) SBI und CBI Anweisungen zimmern.

von Thomas (Gast)


Lesenswert?

@Jörg

also die Schleife habe ich jetzt erstmal verstanden. Nur wieso ist das
mit der Maske gut. Geht das nicht einfacher? Sonst muss man doch das
Feld vorher mit Nullen intitialisieren?

for (ChipIdBitCounter=0;ChipIdBitCounter< 80;ChipIdBitCounter++){

 if ((PINC & (1 << 0)) != 0 {

    Speicher[ChipIdBitCounter] = 1;}

 else {

    Speicher[ChipIdbitCounter] = 0;}
}

Geht diese Schleife oder ist das zu simpel?

Das mit den nächsten Bit triggern ist noch so ein Problem, da ich noch
nicht weiss wie die Daten ankommen. Die Frage ist doch eher in welcher
Zeit der Pin C abgefragt wird. Wenn man das in der gleichen Frequenz
kann wie die ankommenden Daten müßte es doch gehen?


Ciao Thomas

von OldBug (Gast)


Lesenswert?

Damit speicherst Du jedes Bit in einem Byte, das wären dann 7 Bit
verschwendung pro Empfangenem Bit!

von Thomas (Gast)


Lesenswert?

@ OldBug

hm, da ist was dran. aber bei dieser operation:siehe auch weiter oben

Speicher[ByteCounter] |= mask;


werden doch immer nur "1" gespeichert oder?

Ahoi Thomas

von Jörg Wunsch (Gast)


Lesenswert?

Jaja, hast Recht, noch ein Bug, der in Peters Code gefixt war. ;-)

von Thomas (Gast)


Lesenswert?

Hallo nochmal in die Runde!

ich habe jetzt mal noch einen Vorschlag für die Schleife(ohne
Trigger):

for(ByteCounter=0;mask=0x80,ByteCounter<10) {

 do {
      if ((PINC & (1 << yourbitnumber)) != 0){
          Speicher[ByteCounter] |= mask; }
      mask >>=1;
 while {mask != 0 )

 Bytecounter++;
}

Was meint Ihr dazu? Theoretisch müßten jetzt genau 10 Bytes also 80
Bits im Speicher liegen. Und zwar 1 Bit ist MSB. Der Trigger müsste
dann wohl noch in die do-while Schleife.

Ciao Thomas

von Jörg Wunsch (Gast)


Lesenswert?

Die Zuweisung im zweiten Teil der for-Anweisung ist verwirrend. ;-)

Außerdem bleibt natürlich das Problem, daß die entsprechende
Speicherstelle erstmal auf 0 gesetzt werden muß.  Das kannst Du
natürlich auch außerhalb der Schleife (z. B. mit einem memset()) tun.

Ansonsten:

for (ByteCounter = 0; ByteCounter < 10; ByteCounter++) {
  uint8_t data = 0;
  uint8_t mask = 0x80;

  do {
    ...
    data |= mask;
    mask >>= 1;
  while (mask != 0);

  Speicher[ByteCounter] = data;
}

Damit bist Du effektiv bei Peters Vorschlag. :-)

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.