Forum: Mikrocontroller und Digitale Elektronik Einlesen von Bits am Pin und ausgeben auf Display


von Loo (Gast)


Lesenswert?

Hallo,
Bei mir im Code hat sich ein Fehler eingeschlichen, oder ich habe vll 
irgendeine Eigenschaft der Controllers nicht verstenden.
Ich benutzen einen ATMega8.
Am Pin PC5 will ich Bits mit jedem Takt einlesen und in ein array 
speichern. Dazu benutze ich diese Funktion in der ich den gesamten Port 
C einlese.
1
volatile uint8_t result[16]={0};
2
3
void datenLesen(){
4
//Hier wird pro Takt das ganze PINC in jeweils ein Register gespeichert und anschliessend
5
//in dem Array result[] gespeichert  
6
uint8_t data0=0, data1=0, data2=0, data3=0, data4=0, data5=0, data6=0, data7=0;
7
8
        asm volatile(
9
            "in %[r0], %[pinc]\n"
10
            "in %[r1], %[pinc]\n"
11
            "in %[r2], %[pinc]\n"
12
            "in %[r3], %[pinc]\n"
13
            "in %[r4], %[pinc]\n"
14
            "in %[r5], %[pinc]\n"
15
            "in %[r6], %[pinc]\n"
16
            "in %[r7], %[pinc]\n"
17
                
18
      : [r0] "=r" (data0),
19
              [r1] "=r" (data1),
20
              [r2] "=r" (data2),
21
              [r3] "=r" (data3),
22
              [r4] "=r" (data4),
23
              [r5] "=r" (data5),
24
              [r6] "=r" (data6),
25
              [r7] "=r" (data7)
26
            : [pinc] "M" (_SFR_IO_ADDR (PINC)));
27
28
result[0] = data0;
29
result[1] = data1;
30
result[2] = data2;
31
result[3] = data3;
32
result[4] = data4;
33
result[5] = data5;
34
result[6] = data6;
35
result[7] = data7;
36
37
}


Um dann die eingelesenen Bits von PC5 auf einem Display auszugeben 
benutze ich diese Funktion.
1
volatile uint8_t maskierbyte=0b00100000; //Daten kommen am PC5
2
volatile uint8_t pin5=0;
3
4
void datenAusgeben(){
5
  for(int i=0; i<=7;){
6
  pin5 = maskierbyte&result[i];  //Es werden alle Bits ausser dem 5. ausgeblendet. Wenn es 1 ist, dann ist pin5=0b00100000
7
  setDisplayCursorTo(i+1);
8
9
  if(pin5==0b00100000){
10
    writeCharToDisplay('1');
11
  }else{
12
    writeCharToDisplay('0');
13
  }
14
15
  i++;
16
  }
17
18
  _delay_ms(300);
19
20
}

Ich legen an PC5 eine alternierende Bitfolge, also 1010101010101......

Das alles funktioniert ganz gut so das auf dem Display auch 10101010
ABER
Zwischendurch tauchen auf dem Display nur Einsen auf 11111111.
Es tritt auch unregelmäßig auf.

Kann es sein, dass irgendeine Variable einen Überlauf hat oder irgend 
ein interner Prozess im uC die register zwischendurch überschreibt oder 
so?

PS: Ich lese eigentlich 16 Bit ein. Der Übersicht halber hab ich den 
Code gekürzt auf 8 Bit.

Ich bin dankbar für jede Hilfe
Danke

von holger (Gast)


Lesenswert?

Soviel Aufwand für so eine kleine Sache;)
1
 mask = 0x80
2
 data = PINC;
3
 for(uint8_t i=0; i<8; i++)
4
  {
5
   if(data & mask) writeCharToDisplay('1'); 
6
   else writeCharToDisplay('0');
7
   mask >>=1;
8
  }

von Loo (Gast)


Lesenswert?

Hallo holger,
ist das eine Shift-Operation in der letzten Zeile?

von Loo (Gast)


Lesenswert?

Ich brauche nur Pin5 und nicht den ganzen PINC, wie in deinem Code. Und 
das mit jedem Takt neu einlesen.
Aber es geht bei meinem Problem nicht darum. Ich würde eher gerne 
erfahren wo der Fehler ist. Für optimierungen bin ich natürlich offen ;)

von holger (Gast)


Lesenswert?

>ist das eine Shift-Operation in der letzten Zeile?

Ja, aber die brauchst du eigentlich nicht.
Mein Beispiel passt nicht zu deinem. Das zeigt alle
8 Bit von PORTC an.

Das hier wäre wohl besser für dich:
1
void datenAusgeben(){
2
  for(uint8_t i=0; i<=7; i++){
3
  setDisplayCursorTo(i+1);
4
5
   if(PINC & (1<<PC5)) writeCharToDisplay('1'); 
6
   else writeCharToDisplay('0');
7
  }
8
9
  _delay_ms(300);
10
11
}

Da sparst du dir den Inline Assembler.
Und ja, man nimmt nicht ungestraft die Register
vom AVR wenn man C programmiert. Der Compiler fummelt da ständig dran 
rum.

von Loo (Gast)


Lesenswert?

Aber schon wie gesagt,
dein Code ist für meine zwecke ungeeignet.
Ich muss mit jedem Takt einlesen. Ich bezweifele, das deine for-Schleife 
das hinkrigt, da allein das zurückspringen und das vergleichen eine 
ewigkeit dauert.....
Ausserdem muss ich die data irgendwo speichern, weil ich damit noch 
weiter arbeiten will (auf Bitfehler prüfen, usw....).

Zum eigentlichen Problem:
Bei meinem Inline Code werden die Daten ja in 8 Register geschrieben. 
Danach werden die inhalte auf dem SRAM gespeichert und so die Register 
nicht mehr benötigt. das sieht man dan dem Listing:
1
000000d4 <datenLesen>:
2
int summe=0;
3
volatile uint16_t counterL=0;
4
volatile uint16_t counterF=0;
5
6
7
void datenLesen(){
8
      d4:  ef 92         push  r14
9
      d6:  ff 92         push  r15
10
      d8:  0f 93         push  r16
11
      da:  1f 93         push  r17
12
//Hier wird pro Takt das ganze PINC in jeweils ein Register gespeichert und anschliessend
13
//in dem Array result[] gespeichert  
14
uint8_t data0=0, data1=0, data2=0, data3=0, data4=0, data5=0, data6=0, data7=0;
15
16
        asm volatile(
17
      dc:  83 b3         in  r24, 0x13  ; 19
18
      de:  93 b3         in  r25, 0x13  ; 19
19
      e0:  23 b3         in  r18, 0x13  ; 19
20
      e2:  33 b3         in  r19, 0x13  ; 19
21
      e4:  43 b3         in  r20, 0x13  ; 19
22
      e6:  53 b3         in  r21, 0x13  ; 19
23
      e8:  63 b3         in  r22, 0x13  ; 19
24
      ea:  73 b3         in  r23, 0x13  ; 19
25
26
        [r5] "=r" (data5),
27
              [r6] "=r" (data6),
28
        [r7] "=r" (data7)
29
            : [pinc] "M" (_SFR_IO_ADDR (PINC)));
30
31
result[0] = data0;
32
      fc:  80 93 7f 01   sts  0x017F, r24
33
result[1] = data1;
34
     100:  90 93 80 01   sts  0x0180, r25
35
result[2] = data2;
36
     104:  20 93 81 01   sts  0x0181, r18
37
result[3] = data3;
38
     108:  30 93 82 01   sts  0x0182, r19
39
result[4] = data4;
40
     10c:  40 93 83 01   sts  0x0183, r20
41
result[5] = data5;
42
     110:  50 93 84 01   sts  0x0184, r21
43
result[6] = data6;
44
     114:  60 93 85 01   sts  0x0185, r22
45
result[7] = data7;
46
     118:  70 93 86 01   sts  0x0186, r23
47
48
49
50
}

Im dem lezten Block werden die Inhalte in das Array geschrieben und 
haben nichts mehr mit den registern zu tun.
Also ich denke nicht , dass es daran liegt.


Noch ne andere Idee???

von holger (Gast)


Lesenswert?

>Ich muss mit jedem Takt einlesen. Ich bezweifele, das deine for-Schleife
>das hinkrigt, da allein das zurückspringen und das vergleichen eine
>ewigkeit dauert.....

Und das braucht keine Zeit?

      d4:  ef 92         push  r14
      d6:  ff 92         push  r15
      d8:  0f 93         push  r16
      da:  1f 93         push  r17

>Ausserdem muss ich die data irgendwo speichern, weil ich damit noch
>weiter arbeiten will (auf Bitfehler prüfen, usw....).

Wie synchronisierst du eigentlich den ganzen Kram?

von thomas (Gast)


Lesenswert?

Du willst mit jedem Takt etwas einlesen? Was soll das werden? Du weisst 
schon das dann mein µC zu 100% mit einlesen beschäftigt wär?

von Flo (Gast)


Lesenswert?

Wenns wirklich zeitkritisch wird, nimm direkt Assembler ;-)

von Loo (Gast)


Lesenswert?

@Holger
>Und das braucht keine Zeit?

Ich muss direkt acht mal hinter einander den pin5 abtasten, mit jedem 
Takt. Was davor oder danach passiert ist unwichtig.
deswegen hab ich die datenLesen()-Funktion im Inline-Assambler 
geschrieben
Das wichtige ist das:
1
      dc:  83 b3         in  r24, 0x13  ; 19
2
      de:  93 b3         in  r25, 0x13  ; 19
3
      e0:  23 b3         in  r18, 0x13  ; 19
4
      e2:  33 b3         in  r19, 0x13  ; 19
5
      e4:  43 b3         in  r20, 0x13  ; 19
6
      e6:  53 b3         in  r21, 0x13  ; 19
7
      e8:  63 b3         in  r22, 0x13  ; 19
8
      ea:  73 b3         in  r23, 0x13  ; 19
der in-Befehl braucht genau einen Takt zum absrbeiten!

Dein Code würde wahrscheinlich einmal abtasten, dann würden mehrere 
Takte vergehen für die if-Abfrage und für den Rücksprung der 
for-Schleife.

>Wie synchronisierst du eigentlich den ganzen Kram?
Ich synchronisier da gar nichts. Der pin5 ist mit dem RxD eines Flexray 
Transceiver verbunden. Diese Chip detektiert auf einem Bus die Bits und 
legt entweder eine 1 oder eine 0 an pin5 des uC...

@Flo
>Wenns wirklich zeitkritisch wird, nimm direkt Assembler ;-)
Alles in Assambelr zu schreiben wäre mir zu umständlich. Ich hab hier 
nur die beiden Funktionen zum abtasten und auf dem Display ausgeben 
gepostet, weil das die Funktionen sind die den Fehler verursachen 
können.
Deswegen hab ich auch für den Zeitkritischen teil den Inline-Assambler 
verwendet.

Ich hoffe das sind genung Infos für das bessere Verständnis meines 
Codes.

Nochmal zur erinnerung:
Das ganze funktioniert eigentlich. Aber manchmal passiert es, dass er 
nur 11111111 auf dem Display ausgibt, obwohle er eine 10101010-Folge am 
pin5 anliegen hat (das kann ich mit 100%iger sicherheit sagen, da ich 
das messen kann, also kanns nicht am Tranceiverchip liegen).

Es muss eine der einden Funktionen liegen.

vll ist irgendwas mit den Variablen nicht i.O. oder etwas stimmt mit dem 
maskierbyte nicht???

Danke

von Marcus O. (marcus6100)


Lesenswert?

Wenn du das nicht synchronisierst kann es passieren das du genau
während einer Flanke den Wert einliest. Das Ergebnis ist dann
zufällig, da hilft auch kein Assembler.

von Peter D. (peda)


Lesenswert?

Loo schrieb:
> Ich muss direkt acht mal hinter einander den pin5 abtasten, mit jedem
> Takt.

Das geht schonmal garnicht.

Ein Signalpegel muß >1 CPU-Zyklus anliegen, damit er sicher erkannt 
wird.
Wenn Du z.B. einen Timer extern taktest, muß die Frequenz <XTAL/2 sein.
Wenn das Signal sehr flankensteil und symmetrisch ist, kann man bis etwa 
XTAL/2.5 zählen.

Außerdem spezifiziert Atmel nirgends den genauen Abtastzeitpunkt 
innerhalb des Zyklus.

Du brauchst eine Hardware, die deutlich schneller ist, als das Signal.
Selbst wenn Du ein externes 16Bit Schieberegister nimmst (2*74HC595), 
kann das nur funktionieren, wenn neben dem Signal auch der exakt 
synchrone Takt verfügbar ist und die entsprechende Datensetz- und 
Haltezeit eingehalten wird.

Wenn Du ohne Takt abtastest, sollte jedes Bit mindestens 4-mal 
abgetastet werden, damit Du es eindeutig zuordnen kannst.
Daß Z.B. bei UART-Empfang das Signal 8-mal oder 16-mal angetastet wird, 
hat schon seinen Grund und ist keine Laune der MC-Hersteller.


Peter

von Loo (Gast)


Lesenswert?

ok, klingt einleuchtend...
Könntet Ihr mir anhand eines Timing-Diagramms genauer erläutern, wie es 
passiert, dass er nur die Einsen Abtastet?

Ich bekomme die Daten mit 10MBit/s. Das entspricht 100ns Bitdauer
Und der uC arbeitet mit 10MHz. Das sind ebenfalls 100ns pro Takt.



Hab noch im Anhang einen Auszug aus dem Datenblatt des ATmega8 zum 
einlesen von Daten über einen pin.
So wie ich das verstehe, braucht der uC genau einen halben Takt ein 
stabielen pegel auf dem pin, oder?

von holger (Gast)


Lesenswert?

>Ich bekomme die Daten mit 10MBit/s. Das entspricht 100ns Bitdauer
>Und der uC arbeitet mit 10MHz. Das sind ebenfalls 100ns pro Takt.

Irgendwie hatte ich mir schon gedacht das da ne tote
Kopfgeburt hinter deinem Programm steckt;)

von Hans (Gast)


Lesenswert?


von Loo (Gast)


Lesenswert?

Hör mal zu Kollege Holger. Dein Ton ist echt nicht angebracht.

Ich habe um eine Erklärung gebeten und nicht um irgendwelche 
beleidigenden Kommentare.

von Loo (Gast)


Lesenswert?

Ich kenne das Theorem. Aber das Ding ist halt ne studienarbeit von einem 
anderen typen und ich soll es zuende bringen. er hat es laut dem prof so 
augelegt, dass es noch ausreicht mit dem abtasten.

was auch stimmt. denn wenn man sich das datenblatt anschaut, dann Tastet 
er innerhalb einen taktes von 100ns genau 50ns ab. das entschpricht 
einer doppelten Abtastfrequenz, oder? ist halt zeimlich grenzwertig...

von holger (Gast)


Lesenswert?

>Hör mal zu Kollege Holger. Dein Ton ist echt nicht angebracht.
>
>Ich habe um eine Erklärung gebeten und nicht um irgendwelche
>beleidigenden Kommentare.

Das sollte keine Beleidigung sein.
Ist nur meine persönliche Einschätzung von dem was du vorhast.
E-Techniker sind halt mal etwas rau im Ton;)

von Loo (Gast)


Angehängte Dateien:

Lesenswert?

hier der Anhang...

von holger (Gast)


Lesenswert?

>was auch stimmt. denn wenn man sich das datenblatt anschaut, dann Tastet
>er innerhalb einen taktes von 100ns genau 50ns ab. das entschpricht
>einer doppelten Abtastfrequenz, oder? ist halt zeimlich grenzwertig...

Nö, mit 10MHz Takt kannst du auch nur mit 100ns abtasten.
Die 50ns kannst du dir an die Backe schmieren.

von Loo (Gast)


Lesenswert?

Warum? erklär mir das bitte.

Wieso gibt dann das Display immer 10101010 aud und ganz plötzlich nur 
noch 11111111. Das geschieht ca. 4 von 100 mal datenLesen.

Ne vernünftige Erklärung. An die backe schmieren bringt mir nicht viel. 
davon werd ich nicht schlauer.

von Peter D. (peda)


Lesenswert?

Loo schrieb:
> hier der Anhang...

Ja, da ist es doch schön erläutert, die Ungenauigkeit beträgt immer 
einen SYSTEM-CLK, da beißt die Maus keinen Faden ab.
Und deshalb, um einen Pegel eindeutig zu erkennen, muß er länger als ein 
SYSTEM-CLK anliegen.


Hast Du nur das Datensignal oder auch den Takt von dem Signal?

Ohne Takt mußt Du mehrfach abtasten oder mit ner PLL den Takt 
restaurieren.
Eine SW-Lösung nur mit AVR ist generell nicht möglich. Da kann Dein Prof 
noch so sehr das Gegenteil behaupten.


Peter

von Hans (Gast)


Lesenswert?

Weil beide Takte nicht 100% syncron laufen. Sagen wir du schaltest das 
ding ein, dann wird die aktuelle Folge z.B. nach 70% der halben 
Impulsdauer abgetastet. Im nächsten Durchlauf genau bei 71% .... 
Irgendwann tastest Du genau auf der Flanke ab. Diese Flanke hat eine 
Rise / Fall-Time. Das heißt, dass Du z.b. genau 8x 2,5V abtastest 
(Zwischen Low und High). Danach bist Du dann bei 101% und alles 
funktioniert wieder... Bis 200% kommt.

von Loo (Gast)


Lesenswert?

ich hab nur das Datensignal. An der Hardware kann ich sowieso nichts 
mache.

bzgl. Anhang:
so wie ich das verstehe ist die schraffierte fläche (SYNC LATCH) 
diejenige, wo der Pegel stabil anliegen sollte. und mit der Steigenden 
Flanke des systemtaktes wird dann der Wert der am ende anlag in der 
schraffierten Fläche übernommen.

Oder versteh ich das falsch?

von Loo (Gast)


Lesenswert?

@Hans
Danke, das ist doch mal ne vernünftige Erklärung.
Dann liegt das wohl an den Flanken des Signals.
Ich hab dummerweise immer aud dem Papier ideal steile Flanken gezeichnet 
und mit überlegt was passiert wenn er an den grenzen der flanke abastet. 
Es kam dabei nie raus, dass nur einsen abgetastet werden.
an reale flanken hab ich gar nicht gedacht, weil das auf den oszi sehr 
ideal aussah als ich gemessen habe.

von Peter D. (peda)


Lesenswert?

Wenn die Signalfrequenz und Deine MC-Frequenz langsam aneinander vorbei 
driften, wirst Du durchaus auch gültige 16Bits einlesen.
Die Frage ist dann bloß, wie kannst Du erkennen, ob die Bits richtig 
sind.
Die Bitfolge wird ja nicht immer nur 01010101 sein
Und in der Praxis wirst Du auch keinen Einfluß auf die Driftfrequenz 
haben.
Sie ändert sich z.B. mit der Temperatur.


Peter

von Loo (Gast)


Lesenswert?

Super. Danke schön für die Hilfe!

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.