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
volatileuint8_tresult[16]={0};
2
3
voiddatenLesen(){
4
//Hier wird pro Takt das ganze PINC in jeweils ein Register gespeichert und anschliessend
Um dann die eingelesenen Bits von PC5 auf einem Display auszugeben
benutze ich diese Funktion.
1
volatileuint8_tmaskierbyte=0b00100000;//Daten kommen am PC5
2
volatileuint8_tpin5=0;
3
4
voiddatenAusgeben(){
5
for(inti=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
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 ;)
>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
voiddatenAusgeben(){
2
for(uint8_ti=0;i<=7;i++){
3
setDisplayCursorTo(i+1);
4
5
if(PINC&(1<<PC5))writeCharToDisplay('1');
6
elsewriteCharToDisplay('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.
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
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???
>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?
@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
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.
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
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?
>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;)
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...
>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;)
>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.
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.
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
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.
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?
@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.
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