Hallo zusammen, ich habe ein Programm für folgenden Beschleunigungssensor geschrieben, http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/APPLICATION_NOTE/CD00229883.pdf welches Sensordaten einfach nur per UART ausgibt. Dieses Programm wollte ich jetzt mit einem anderen Sensor laufen lassen http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00250937.pdf und erhalte falsche Sensorwerte. Obwohl der Sensor auf dem Tisch liegt, gibt er nicht das erwartete 1g auf der z-Achse aus und außerdem ändern sich die Werte ständig. Eigentlich kann das nicht sein, da die Sensorposition sich auch nicht ändert. Ich habe für den neuen Sensor einfach nur die Register etwas umgeschrieben, da sie sich etwas vom Aufbau unterscheiden. Grundsätzlich müsste es doch richtig sein das Status Register zu pollen um zu sehen ob neue Daten vorhanden sind. Danach pollen ob Daten überschrieben wurden und dann eben die Output Register einfach auslesen. Wär echt klasse, wenn mir das jemand bestätigen würde oder mir einen Fehler in meinem Modell aufzeigt.
Also, wenn er nur so auf dem Tisch liegt, wird er ja also auch nicht bewegt. Da sollte man für alle Achsen 0,0 messen.
doug schrieb: > Obwohl der Sensor auf dem Tisch liegt, gibt er nicht das erwartete 1g > auf der z-Achse aus und außerdem ändern sich die Werte ständig. > Eigentlich kann das nicht sein, da die Sensorposition sich auch nicht > ändert. Entweder du hast einen Programmfehler. Oder aber: Willkommen in der wunderbaren Welt der Realität, in der Sensoren schon auch mal rauschen und so manches scheinbar ganz einfache Prinzip der physikalischen Theorie für die Praxis unbrauchbar machen.
Mr Tannnoy schrieb: > Also, wenn er nur so auf dem Tisch liegt, wird er ja also auch nicht > bewegt. Da sollte man für alle Achsen 0,0 messen. Nö. in allen Achsen 0 misst man nur im freien Fall.
0,0 G im freien Fall??? Ich tippe da eher auf 1G. Schau mal in ein Physikbuch... 1G=9,81m/s² Beschleunigung bedeutet die Geschwindigkeit ändern!
Mr Tannnoy schrieb: > 0,0 G im freien Fall??? > > Ich tippe da eher auf 1G. > > Schau mal in ein Physikbuch... Genau. Schau da mal rein. > Beschleunigung bedeutet die Geschwindigkeit ändern! Aber du kannst sie mit dem Sensor nicht messen. PS: Der Sonsor misst nicht wirklich die Beschleunigung direkt. Das geht nämlich ohne externen Bezugspunkt nicht. Was er misst, ist die Kraft, die auf ihn (genauer: einen Teil von ihm) wirkt. Und im freien Fall ist er in sich kräftefrei. Erst wenn er auf dem Tisch liegt, kann er wieder die Kraft feststellen, die die Tischplatte auf ihn ausübt um ihn am Fallen zu hindern.
Mr Tannnoy schrieb: > Also, wenn er nur so auf dem Tisch liegt, wird er ja also auch nicht > bewegt. Da sollte man für alle Achsen 0,0 messen. nö. Gibt ja auch die Erdbeschleunigung.
In Ruhelage auf dem Tisch misst er x=0g y=0g z=1g. Das steht auch so im Datenblatt. Mit dieser Erkenntnis ist aber mein Problem nicht gelöst. Die Sache mit dem möglichen Rauschen werd ich mir mal näher ansehn.
doug schrieb: > In Ruhelage auf dem Tisch misst er x=0g y=0g z=1g. > Das steht auch so im Datenblatt. Logisch. Geht auch mit einem reinen Beschleunigungssensor nicht anders. Woher soll der denn auch wissen, wo 'unten' ist. > > Mit dieser Erkenntnis ist aber mein Problem nicht gelöst. > Die Sache mit dem möglichen Rauschen werd ich mir mal näher ansehn. Fangen wir mal so an. In welcher Größenordnung bewegen sich denn deine Werte? Dann kann man schon mal abschätzen, ob es sich um Messrauschen handelt, oder ob eine Programmfehler wahrscheinlicher ist. Exakt 0.0/0.0/1.0 wirst du nicht kriegen. Aber wenn die Werte +-2.0 rumspringen, dann ist das auch kein Rauschen mehr.
Die Werte liegen zwischen 0 und ca. 2,5g. Es ist heftig, dass sie immer variieren.
doug schrieb: > Die Werte liegen zwischen 0 und ca. 2,5g. Ist zuviel für Rauschen. Da hast du noch irgendwo einen Programmfehler
Es ist halt so, dass das Programm mit dem LIS331DL welcher nur +-8g, 400Hz, 8bit Datenregister hat funktioniert. Der neue Sensor kann +-24g, 1kHz, High + Low Byte als Datenregister, also 16bit. Das sind eigentlich nur die Unterschiede und deshalb versteh ich nicht, warum es auf dem Alten, aber nicht auf dem neuen läuft.
Hallo, Was häufig falsch gemacht wird, ist die Reihenfolge der Bytes, wenn der Messwert größer als 8bit ist. Das Rauschen im letzten Bit wird dann schnell zu einem heftigen Signalwackeln. Beste Grüße, Tom
Tom schrieb: > Hallo, > Was häufig falsch gemacht wird, ist die Reihenfolge der Bytes, wenn der > Messwert größer als 8bit ist. Das Rauschen im letzten Bit wird dann > schnell zu einem heftigen Signalwackeln. Habe auch schon beide Bytes gedreht. Macht leider keinen Unterschied. Ich schaue mir das Low und High Byte über ein Terminalprogramm an. Auffällig ist aber, dass alle Sensorwerte durch 8 teilbar sind, also Vielfache von 8 sind. Das find ich ziemlich seltsam.
doug schrieb: > Habe auch schon beide Bytes gedreht. Macht leider keinen Unterschied. dann stimmt aber auf jeden Fall etwas nicht, wenn sich da nichts ändert.
Peter II schrieb: > doug schrieb: >> Habe auch schon beide Bytes gedreht. Macht leider keinen Unterschied. > > dann stimmt aber auf jeden Fall etwas nicht, wenn sich da nichts ändert. Ne Idee?
Michael H. schrieb: > ja. > der fehler liegt im code. Hi Michael, hier mal das Programm. Kann den Fehler einfach nicht finden.
doug schrieb: > Kann den Fehler einfach nicht finden. Wir auch nicht, weil wir weder deine Hardware haben, noch dein Programm und vor allem nicht die Messwerte sehen. Wie wäre es wenn du dir etwas mehr Mühe gibst und vieleicht mal das komplette compilierbare Programm anhängst, und mal eine Tabelle von echten Messwerten hier reinstellst.
Du musst folgendes beachten. Der ST hat nur ein 16 Bit output und nicht Auflösung. In dem 16 Bit Wert steht nur ein 12 Bit wert im zweierkomplement um 4 Bits nach links geshiftet drin. Du musst also sowas machen wie
1 | int16_t acc_x; |
2 | |
3 | ...
|
4 | acc_x = SPI_MasterRead(OUTZ_H)<<8; |
5 | acc_x |= (SPI_MasterRead(OUTZ_L))&0xFF; |
6 | |
7 | acc_x >>= 4; //um 4 Bits nach rechts |
Dann hast du den realen Wert, den du dann noch entsprechend deiner "Range" skalieren musst.
doug schrieb: > Danach pollen ob Daten überschrieben wurden und dann eben die Output > Register einfach auslesen. Welchen Sinn soll das eigentlich haben? In Deinem Programm wartest du dann und sorgst so dafür, dass noch mehr Werte überschrieben werden. Normal ists sch**egal wenn ein Wert verloren geht, das müsste schon ein heftiger Ruck (oder langsamme Abfragefrequenz) sein wenn 2 aufeinanderfolgende Werte deutlich voneinander abweichen. Stephan
Sorry Udo, kein Problem. Hier ist das komplette Programm mit den Messwerten. Habe die Messwerte mit HTerm dargestellt.
Man sieht also high Byte und low byte immer im Wechsel, beginnend mit high byte. Das high byte hat einen Offset von 4.
Dann shift das doch mal so wie ich es gesagt habe... und spar dir erstmal das abziehen des Offsets (wie kommt du überhaupt auf -3 von HighByte)? Den Offset verwende ich um eine minimale Schräglage auszugleichen, also wenn dann nur im Low-Byte. "-3" im Highbyte entspricht ja schon 9,2g im +-24g bereich. Willst du die Erdbeschleunigung abziehen? Wenn du die Lage damit bestimmen willst dann würde ich das nicht machen, und dann würde ich auch nicht den "großen" Messbereich nehmen. Was genau willst du denn mit den Beschleunigungswerten machen?
doug schrieb: > Das high byte hat einen Offset von 4. Genau das ist dein Fehler, du hast keinen Offset von 3 oder 4 nur im High Byte. Wie Timmo gesagt hat, alle Werte der Low Bytes sind durch 16 teilbar, das weist genau darauf hin, daß die 4 LSB Bits des Messwerts im high Nibble des Low Bytes stecken. Also mal so addieren und shiften wie Timmo gesagt hat, und schon stimmen die Werte und du siehst nur noch normales Rauschen. Wenn du dir solche Werte binär oder Hexadezimal aufschreibst oder printest dann siehst du sowas deutlich schneller.
Danke euch beiden. Hatte dummerweise angenommen, dass es sich um 16bit Zweierkomplement Daten handelt.
doug schrieb: > Danke euch beiden. > Hatte dummerweise angenommen, dass es sich um 16bit Zweierkomplement > Daten handelt. Ist ja auch ein 16 Bit Wert im Zweierkomplement nur repräsentiert das nur den 12 Bit Wert, wie ja auch im Datenblatt auf Seite 9 in der Tabelle steht. ST aligned das halt immer ganz links um damit das Vorzeichen im int16 passt. Bei Freescale muss man z.B. oftmals das 12. Bit zur Vorzeichenerkennung verwenden und dann selbst den Rest mit "1" auffüllen. Oder man shiftet es erst 4 nach links und dann wieder beide Bytes um 4 nach rechts. Hat beides vor und Nachteile. Bei manchen Sensoren kann man das auch selbst bestimmen ob nun rechts oder links ausgerichtet. Am besten ist es natürlich wenn die Auflösung gleich 16 Bit ist und nicht nur 12 oder 14 Bit, aber das kostet dann halt wieder Geld (z.B Invensense MPU6050) ST verzichtet oftmals halt gerne darauf das nochmals etwas zu verdeutlichen (bzw. wenn findest man das nur in Appnotes und nicht im Datenblatt)
Timmo H. schrieb: > ST verzichtet oftmals halt gerne darauf das nochmals etwas zu > verdeutlichen (bzw. wenn findest man das nur in Appnotes und nicht im > Datenblatt) Bin leider darauf reingefallen. Leider konnte ich zum LIS331HH keine Application note finden.
Ja Appnotes gibts nicht für alles. Wenn man öfter mit ST arbeitet dann kennt man irgendwann die Fallstricke.
Ist doch oft bei A/D Wandlern genauso. Damit musst du nicht shiften wenn dich nur ein 8 Bit Wert interessiert, dann kannst du einfach die unteren Bits weglassen.
Ja stimmt. Das ist auch wohl der Hintergedanke beim left align. Man braucht dann nur halt 3 Bytes auslesen (für alle Achsen) anstatt 6 welche dann geshiftet werden müssten um dann wieder nur 8 Bit zu nutzen. Dann hat man auch auch gleich das Rauschen weg wenn man die untersten 4 Bit nicht benutzt :D
Jetzt wollte ich mal die sleep to wake Funktion ausprobieren und wundere mich darüber warum am INT1 oder auch INT2 pin ich keinen Auschlag erhalte, wenn ich den Sensor anrege. Hab hier die Scope Bilder. Auf dem einen Bild sieht man den INT1pin Rauschen wenn ich den Sensor ohne sleep Mode configuriere. Das Rauschen ist mir egal, da ich ja das Signal nicht weiterverwende, in diesem Fall. Wenn ich jetzt den Sensor im sleep Mode aktiviere sehe ich, dass das Rauschen annähernd verschwindet. Leider erhalte ich aber keinen Auschlag, wenn ich den Sensor anrege. Der Sensor befindet sich im sleep mode, aber der INT1pin ändert sich nicht bei Anregung des Sensors. Hier ist der Code. Hat jemand ne Idee?
Hat sich schon erledigt. Der Sensor bei 24g ist erheblich träger als mein alter Sensor mit 8g und deshalb hatte ich mehr Emfpindlichkeit erwartet. Es funktioniert jetzt. Bei stärkerer Anregung.
Habe jetzt versucht 3 Sensoren hintereinander zum laufen zu bringen und versteh nicht, warum es nicht geht. Eigentlich müsste es........ Es ist so, dass die Daten nur langsam rauskommen, was daran liegt, dass Daten überschrieben werden. D.h. Er landet jeden Durchlauf in der if( status_reg & 0x40) und dort steht dann in der delay, die mir anzeigt, dass Daten überschrieben werden. Bin ziemlich verzweifelt weil es nicht klappt. Wäre echt super wenn sich das einer von Euch nochmal anschauen würde. Super verzweifelt.
Kurzfassung: Die Sensoren werden 1,2,3,1,2,3... ausgelesen. Dummerweise kommt es jedesmal (bei jedem Auslesen) zu einem overwrite der Daten und ich kann es mir nicht erklären. ------------------------------------------------------------------------ - Mit meinem 1 Sensor-Programm kann ich problemlos ca. 1000Werte/Sekunde auslesen und es kommt nie zu einem overwrite im STATUS_REG. Der einzige Unterschied bei meinem neuen Programm zum alten ist, dass ich jetzt 3 CS mache anstatt nur einen und jedesmal eine if-Abfrage mache, um zu sehen, um welchen Sensor es sich handelt. Diese Erneuerungen können doch nicht soviel Zeit fressen um einen Overwrite zu verursachen. Kann mir bitte jemand weiterhelfen?
doug schrieb: > D.h. Er landet jeden Durchlauf in der if( status_reg & 0x40) und dort > steht dann in der delay, die mir anzeigt, dass Daten überschrieben > werden. Dann lass die Wartezeit halt weg! Oder für was soll die gut sein, ausser das Zeitverhalten zu verhunzen und die Diagnose zu erschweren?
Stephan schrieb: > Dann lass die Wartezeit halt weg! > Oder für was soll die gut sein, ausser das Zeitverhalten zu verhunzen > und die Diagnose zu erschweren? Eigentlich soll es mir die Diagnose erleichtern. Ich habe das Programm länger laufen lassen und am Terminal Programm gesehn, dass jeder Wert 1000ms verzögert rauskommt. Das bedeutet ich habe jeden Durchgang einen overwrite. Ohne die delay-Zeit könnte ich doch niemals den overwrite erkennen. Das wäre mit einem Oszi vielleicht möglich,aber viel zu aufwendig. So ist es doch angenehmer. Durch das Auskommentieren der delay-Zeit erhalte ich jetzt ca 5600Werte/sec von 3 Sensoren. D.h. ca. 1867Werte/sec von einem Sensor aber eben immer nur mit overwrite, was uns ja die delay, auch wenn sie jetzt auskommentiert ist gezeigt hat. Ich muss die Ursache für den overwrite finden.
doug schrieb: > Durch das Auskommentieren der delay-Zeit erhalte ich jetzt ca > 5600Werte/sec von 3 Sensoren. Da ist doch schon der Hinweis... 5600 16-Bit-Werte / s nehme ich an. Diw Werte kommen viel zu schnell für 3x1kHz und auuffällig nahe an dem was über den UART bei 115.2kBaud maximal geht. > Deine Statusabfrage ist unwirksam. Wenn da einmal Bit 4 gesetzt ist wird nie mehr abgefragt. Und wenn da Bit 7 auch gesetzt war ... > abgefragten Statuswert zurücksetzen Außerdem 5600 * 1/s 2 (8+2) = 112kBaud und dein Programm wartet solange bis der UART wieder frei ist. Bleiben am Ende 22k Takte/Sekunde oder knapp 40 Takte pro Schleifendurchlauf übrig: Während das 1. Byte gesendet wird steht das Programm quasi. Während das 2. Byte gesendet wird läuft die Haupschleife weiter, SPI wird abgefragt und dann steht das Programm wieder weil das 2. Byte aus dem vorherigen Durchgang noch nicht fertig gesendet wurde. Die 40 Takte gehen für 2* Funktionsaufruf UART_send und 2* Nachladen innerhalb von UART_send drauf. Für sowas nimmt man Interrupts und nen Sendepuffer. Momentan läuft dein Programm noch schön gleichmäßig, vom UART eingetaktet. Sobald du aber noch alle paar Durchläufe Mittelwerte oder ähnliches ausgeben willst werden die Zeitscheiben ungleichmäßig. Außerdem #2 Hast du wirklich 8MHz CPU-Frequenz? Da dürfte bei 115.2kBaud ziemlicher Datenmüll ankommen. Stephan
Karl Heinz Buchegger schrieb: > Logisch. Geht auch mit einem reinen Beschleunigungssensor nicht anders. > Woher soll der denn auch wissen, wo 'unten' ist. 'Unten' ist natürlich auf der Seite, wo der Tisch. Sonst läge der Sensor schließlich nicht auf dem Tisch.
Stephan schrieb: > Diw Werte kommen viel zu schnell für 3x1kHz und auuffällig nahe an dem > was über den UART bei 115.2kBaud maximal geht. >> Deine Statusabfrage ist unwirksam. Wenn da einmal Bit 4 gesetzt ist wird nie > mehr abgefragt. Und wenn da Bit 7 auch gesetzt war ... >> abgefragten Statuswert zurücksetzen > Für sowas nimmt man Interrupts und nen Sendepuffer. Habe jetzt eine FIFO gepufferte ISR(USART_UDRE_vect), lösche meine status_reg Variable am Ende der UART Übertragung, sprich am Ende der while(1). Habe ich Dich mit dem status_reg so richtig verstanden? Leider tritt immer noch das selbe Problem auf mit der Verzögerung. Laut ATMEL lohnen sich bei SPI nur Interrupts, ab einem SPI Clock-Teiler von 64, gegenüber Polling. Ich verstehe nicht, wieso sogar schon beim allerersten Schleifendurchlauf der overrun bzw. overwrite auftritt.
Habe jetzt mit dem sleep-Mode des Mikrocontrollers rumgespielt und es tritt das selbe Phänomen auf. Wenn er aufwacht werden die Daten auch verzögert ausgegeben. Die Fehlerquelle muss also die gleiche sein. Aber welche bloß?
Der einzige Unterschied der jetzt entstanden ist, ist das die Werte falsch sind. In Ruhelage bekomme ich jetzt den Wert 255dec für Lowbyte. Es muss doch ein Zusammenhang bestehen.
doug schrieb: > Habe jetzt eine FIFO gepufferte ISR(USART_UDRE_vect), lösche meine > status_reg Variable am Ende der UART Übertragung, sprich am Ende der > while(1). > > Habe ich Dich mit dem status_reg so richtig verstanden? > > Leider tritt immer noch das selbe Problem auf mit der Verzögerung. Ähem. Das ist ja ne do-while-Schleife. Kannst dir das Rücksetzen am Ende sparen (hab Mist erzäht). doug schrieb: > Laut ATMEL lohnen sich bei SPI nur Interrupts, ab einem SPI Clock-Teiler > von 64, gegenüber Polling. Die brauchen hier jedenfalls kaum Zeit. doug schrieb: > Ich verstehe nicht, wieso sogar schon beim allerersten > Schleifendurchlauf der overrun bzw. overwrite auftritt. Klär lieber mal warum "new data" scheinbar ohne Funktion ist (die zu hohe Ausleserate). Evtl. weil du ZYXDA abprüfst, X und Y aktiv sind aber nie ausgelesen werden. Außerdem die Sache mit der CPU-Frequenz und der Baudrate. 115.2kBaud@8MHz geht eigentlich nicht. Stephan
Michael H. schrieb: > doug schrieb: >> Ich muss die Ursache für den overwrite finden. > warum? frag dich das doch mal... Da ich ein annähernd 100% funktionierendes Messsytem haben möchte. Ich hatte mit 3 ähnlichen Sensoren bei annähernd gleichem Quellcode (Sensor Register etwas anders angeordnet) keine Probleme mit overwrite. Hatte das STATUS_REG genauso abgefragt. Deshalb interessiere ich mich dafür. Das ist für mich der Beweis, dass es geht, bzw. gehen kann. Es sei denn diese Methode sei bei 16bit Daten nicht möglich. Mein vorheriger Sensor hatte nur 8bit Output Daten. Stephan schrieb: > Klär lieber mal warum "new data" scheinbar ohne Funktion ist (die zu > hohe Ausleserate). > Evtl. weil du ZYXDA abprüfst, X und Y aktiv sind aber nie ausgelesen > werden. > > Außerdem die Sache mit der CPU-Frequenz und der Baudrate. > 115.2kBaud@8MHz geht eigentlich nicht. > > Stephan Die X und Y-Achse waren immer disabled. Hatte versehentlich ZYXDA geprüft anstatt ZDA. Habe dies geändert aber immer noch keine Veränderung zu sehen. Ausserdem habe ich jetzt F_CPU auf 7,3728MHz abgeändert. Die UART Werte sind immer noch die gleichen in Ruhelage. Sie liegen leicht unter 1g z-Achse durch Rauschen, genauso wie vorher. Muss dazu sagen, dass ich den internen RC-Oszillator verwende, da egal bei welcher externen Quarz Fuse Einstellung es immer Probleme mit den UART Werten gab.
Stephan schrieb: > Klär lieber mal warum "new data" scheinbar ohne Funktion ist (die zu > hohe Ausleserate). Habe jetzt noch ausprobiert, ob sich durch ein langsameres Auslesen etwas verändert. Leider ohne Erfolg.
> internen RC-Oszillator und > Ausserdem habe ich jetzt F_CPU auf 7,3728MHz abgeändert. Du scheinst gar nicht zu wissen was du machst ! Grundlagen lernen ! Bei internem RC geht UART eh nicht. Aber bei SPI sollte es keine probleme geben da Takt mitgeliefert wird.
Uwe schrieb: >> internen RC-Oszillator > und >> Ausserdem habe ich jetzt F_CPU auf 7,3728MHz abgeändert. > Du scheinst gar nicht zu wissen was du machst ! > Grundlagen lernen ! > > Bei internem RC geht UART eh nicht. > Aber bei SPI sollte es keine probleme geben da Takt mitgeliefert wird. Moment. Programmiere erst seit 5 Monaten. Kannst du das bitte genauer erklären was du meinst? Wieso geht UART bei Internem RC-Oszillator eh nicht?
doug schrieb: > Wieso geht UART bei Internem RC-Oszillator eh nicht? Zu ungenau, bzw. zu große Temperaturabhängigkeit / Drift. Außerdem passt die Frequenz nicht sonderlich gut. Damit kommt häufig nur Datenmüll raus. Idealerweise nimmt man für schnelle Übertragungen (115.2kBaud ist schnell) Baudratenquarze. z.B. 7,3728MHz. "Gerade" Frequenzen (wie 1-2-4-8MHz) funktionieren nur für niedrige Übertragungsraten. Hier kannst mal ausrechnen: http://www.gjlay.de/helferlein/avr-uart-rechner.html Toleranz sollte unter 1% liegen. Stephan
doug schrieb: > Wieso geht UART bei Internem RC-Oszillator eh nicht? AVR Checkliste für UART: http://www.mikrocontroller.net/articles/AVR_Checkliste#UART.2FUSART
Stephan schrieb: > doug schrieb: >> Wieso geht UART bei Internem RC-Oszillator eh nicht? > > Zu ungenau, bzw. zu große Temperaturabhängigkeit / Drift. Außerdem passt > die Frequenz nicht sonderlich gut. > Damit kommt häufig nur Datenmüll raus. > > Idealerweise nimmt man für schnelle Übertragungen (115.2kBaud ist > schnell) Baudratenquarze. z.B. 7,3728MHz. "Gerade" Frequenzen (wie > 1-2-4-8MHz) funktionieren nur für niedrige Übertragungsraten. > Hier kannst mal ausrechnen: > http://www.gjlay.de/helferlein/avr-uart-rechner.html > Toleranz sollte unter 1% liegen. > > Stephan Heisst das man kann keinen 8MHz Quarz mit #define 7372800UL verwenden? Wirklich nur den Quarz(wert) passend?
Hi >Heisst das man kann keinen 8MHz Quarz mit #define 7372800UL verwenden? >Wirklich nur den Quarz(wert) passend? Nein. Ja. MfG Spess
doug schrieb: > Heisst das man kann keinen 8MHz Quarz mit #define 7372800UL verwenden? > Wirklich nur den Quarz(wert) passend? Genau richtig. Der Wert wird in Makros verwendet um z.B. Timer-Einstellungen, Teiler für UART, etc. auszurechnen. Wenn Du den falschen Wert reinschreibst werden die Einstellungen falsch gewählt. Und nein. Die Angabe stellt nicht den internen Oszillator oder einen externen Quarz auf die Frequenz ein. Da hat genau die in der Hardware festgelegte Frequenz zu stehen. Stephan
doug schrieb: > Ausserdem habe ich jetzt F_CPU auf 7,3728MHz abgeändert. > ... > Muss dazu sagen, dass ich den internen RC-Oszillator verwende, Und du glaubst nur weil du eine Definition in deinem Programm abänderst ändert sich der Takt mit dem dein µC getaktet wird? Les mal hier das Tutorial bzgl Takterzeugung durch und schau dir mal ein Datenblatt genau an.
Habe schon öfter gesehn, dass Leute z.B. #define F_CPU 16000000UL zu beginn des Codes schreiben. Heisst das, dass man ganzzahlige Vielfache verwenden kann? Welchen Sinn macht das?
Oder sagt man damit dem Compiler einfach nur, dass man einen 16MHz Quarz verwendet, also nix mit Teilern oder Vielfachen?
Hi >Habe schon öfter gesehn, dass Leute z.B. >#define F_CPU 16000000UL zu beginn des Codes schreiben. >Heisst das, dass man ganzzahlige Vielfache verwenden kann? >Welchen Sinn macht das? Nein. Die verwenden mit Sicherheit einen 16MHz-Quarz. MfG Spess
doug Wenn du mit dem Auto mit 130 km/h auf der Autobahn fährst, kannst du natürlich die Skala deines Tachos umzeichnen, so dass die Zahl bei der Nadel 185 lautet. Du kannst das machen, ja. Ändert aber nichts daran, dass deine Auto trotzdem immer noch mit 130 fährt. Und wenn du Zeitberechnungen mit den am Tacho angezeigten 185 machst, dann wird da eben nicht das richtige rauskommen. Um 160 Kilometer zurückzulegen errechnest du mit den 185 zwar 51 Minuten, brauchen wirst du aber trotzdem 1 Stunde 23 Minuten. Selbst wenn auf deinem Tacho 185 angezeigt wird. So einfach ist das. F_CPU ist die Information für den Compiler, wie schnell der µC getaktet wird. Und diese Information sollte tunlichst mit der Realität übereinstimmen. Weil sonst darauf basierende Berechnungen einfach nicht stimmen werden.
Karl Heinz Buchegger schrieb: > doug > > Wenn du mit dem Auto mit 130 km/h auf der Autobahn fährst, kannst du > natürlich die Skala deines Tachos umzeichnen, so dass die Zahl bei der > Nadel 185 lautet. > Du kannst das machen, ja. Ändert aber nichts daran, dass deine Auto > trotzdem immer noch mit 130 fährt. Und wenn du Zeitberechnungen mit den > am Tacho angezeigten 185 machst, dann wird da eben nicht das richtige > rauskommen. Um 160 Kilometer zurückzulegen errechnest du mit den 185 > zwar 51 Minuten, brauchen wirst du aber trotzdem 1 Stunde 23 Minuten. > Selbst wenn auf deinem Tacho 185 angezeigt wird. > > So einfach ist das. > F_CPU ist die Information für den Compiler, wie schnell der µC getaktet > wird. Und diese Information sollte tunlichst mit der Realität > übereinstimmen. Weil sonst darauf basierende Berechnungen einfach nicht > stimmen werden. Alles klar.
Es war zwar wichtig, aber wir sind ganz schön vom Thema abgekommen. Aktueller Stand: Alle Hinweise befolgt, Problem leider noch nicht gelöst. doug schrieb: > Ich verstehe nicht, wieso sogar schon beim allerersten > Schleifendurchlauf der overrun bzw. overwrite auftritt.
Hab grad einen anderen Fehler entdeckt. Mein High Byte hat immer den Wert 0x00, egal wie ich meinen Sensor anrege. Hier der Codeausschnitt um den es geht: outZ_high = SPI_MasterRead(OUTZ_H, i); outZ_low = SPI_MasterRead(OUTZ_L, i); outZ = outZ_high<<8; outZ |= outZ_low & 0xFF; outZ >>= 4; //UART zuerst high byte, dann low byte senden UART_send(outZ & 0xFF00); UART_send( outZ & 0x00FF); Das müsste doch eigentlich richtig sein....
doug schrieb: > //UART zuerst high byte, dann low byte senden > UART_send(outZ & 0xFF00); > > UART_send( outZ & 0x00FF); > > > Das müsste doch eigentlich richtig sein.... Nein. "outZ" ist bei Dir doch eine 16-Bit-Variable (besteht also aus 2 Byte). Vor dem Senden musst Du "outZ" in zwei 8-Bit-Werte zerlegen. Eine einfache Maskierung einer 16-Bit-Varialble mit einer 16-Bit-Maske reicht hierfür nicht.
Guck dir mal deine chip_Select und chip_UnSelect funktionen genauer an, und überleg, ob die tatsächlich das machen, was die machen sollten (evtl. PORTC auf UART ausgeben lassen).
Ziegenpeter schrieb: > Guck dir mal deine chip_Select und chip_UnSelect funktionen genauer an, > und überleg, ob die tatsächlich das machen, was die machen sollten > (evtl. PORTC auf UART ausgeben lassen). Habe es vorsichtshalber nochmal durchgesteppt mit dem debugger. Das CS funktioniert einwandfrei.
doug schrieb: > > //UART zuerst high byte, dann low byte senden > UART_send(outZ & 0xFF00); > > UART_send( outZ & 0x00FF); > > > Das müsste doch eigentlich richtig sein.... Tu dir selbst einen Gefallen und schreib dir für derartige Standard-Aufgaben kleine Hilfsfunktionen.
1 | void UART_int( uint16_t value ) |
2 | {
|
3 | UART_send( value >> 8 ); |
4 | UART_send( value ); |
5 | }
|
Hat doch keinen Sinn, quer übers Programm verstreut immer wieder die gleichen Fehler zu machen, nur weil man zu stolz ist, sich ein für alle mal ein paar kleine Helfer zuzulegen, die man ganz einfach an den bewussten Stellen benutzen kann ohne jedesmal wieder neu überlegen zu müssen. In der Zeit, in der du die beiden falschen Zeilen an bewusster Aufrufstelle eingebaut hast, hast du auch schon besagte Funktion geschrieben. Nur das du besagte Funktion in nächster Zeit noch ein paar zig-mal brauchen können wirst. Ausgabefunktionen für alle möglichen Datentypen auf allen möglichen verschiedenen Ausgabegeräten braucht man immer wieder mal. Und sei es nur, weil man zu Debugzwecken sich irgendwelche Werte ansehen will.
J.-u. G. schrieb: > Nein. "outZ" ist bei Dir doch eine 16-Bit-Variable (besteht also aus 2 > Byte). Vor dem Senden musst Du "outZ" in zwei 8-Bit-Werte zerlegen. Eine > einfache Maskierung einer 16-Bit-Varialble mit einer 16-Bit-Maske reicht > hierfür nicht. Mist. Habe ich voll übersehn. Grad abgeändert. Funktioniert. Karl Heinz Buchegger schrieb: > doug schrieb: > >> >> //UART zuerst high byte, dann low byte senden >> UART_send(outZ & 0xFF00); >> >> UART_send( outZ & 0x00FF); >> >> >> Das müsste doch eigentlich richtig sein.... > > Tu dir selbst einen Gefallen und schreib dir für derartige > Standard-Aufgaben kleine Hilfsfunktionen. > void UART_int( uint16_t value ) > { > UART_send( value >> 8 ); > UART_send( value ); > } > > Hat doch keinen Sinn, quer übers Programm verstreut immer wieder die > gleichen Fehler zu machen, nur weil man zu stolz ist, sich ein für alle > mal ein paar kleine Helfer zuzulegen, die man ganz einfach an den > bewussten Stellen benutzen kann ohne jedesmal wieder neu überlegen zu > müssen. In der Zeit, in der du die beiden falschen Zeilen an bewusster > Aufrufstelle eingebaut hast, hast du auch schon besagte Funktion > geschrieben. Nur das du besagte Funktion in nächster Zeit noch ein paar > zig-mal brauchen können wirst. Ausgabefunktionen für alle möglichen > Datentypen auf allen möglichen verschiedenen Ausgabegeräten braucht man > immer wieder mal. Und sei es nur, weil man zu Debugzwecken sich > irgendwelche Werte ansehen will. Macht Sinn. Bin gar nicht auf die Idee gekommen eine Funktion zu schreiben.
doug schrieb: > Stephan schrieb: > >> Dann lass die Wartezeit halt weg! >> Oder für was soll die gut sein, ausser das Zeitverhalten zu verhunzen >> und die Diagnose zu erschweren? > > Eigentlich soll es mir die Diagnose erleichtern. Wenn du dir dir Diagnose erleichtern willst, dann gib einfach die Werte aus, die du bekommst. Zb. das Status-Register! Dazu hast du ja jetzt eine UART aktiviert, damit du dir Dinge ausgeben kannst! Und du solltest darüber nachdenken, dir die Dinge im Klartext ausgeben zu lassen und nicht als Hex-Bytes. Wenn du sowieso dein Programm mit _delay_ms spickst, dann kannst du genausogut diese Zeit auch nutzen lassen, um dir die Werte vernünftig lesbar ausgeben zu lassen. > Das bedeutet ich habe jeden Durchgang einen overwrite. Und du denkst ernsthaft, das wird besser, wenn du den µC zwischendurch möglichst lange warten lässt, so dass der Sensor beim nächsten mal schon wieder melden muss, dass er Daten produziert hat, die keiner abgeholt hat, weil der µC ja in der Zwischenzeit Däumchen drehen musste? > Ohne die delay-Zeit könnte ich doch niemals den overwrite erkennen. :-) Du hast eine UART! Wenn du was wissen willst, dann lass es dir hinschreiben! (Oder schalte eine LED ein, oder sonstirgendwas anderes schnelles, wenn die UART Ausgabe zu lange dauert.) Dein konkretes Problem ist, das der erste Overwrite durch die Wartezeit den nächsten Overwrite triggert. Das kann natürlich bei einer UART Ausgabe auch passieren. Das ist die Krux beim Debuggen - durch Debuggen verändert sich das Zeitverhalten des Programms.
1 | void UART_send(uint8_t data) |
2 | {
|
3 | while(!(UCSR0A & (1<<UDRE0))); //warten bis abgeschlossen |
4 | UDR0 = data; // senden |
5 | }
|
6 | |
7 | void UART_string(const char* txt) |
8 | {
|
9 | while( *txt ) |
10 | UART_send( *txt++ ); |
11 | }
|
12 | |
13 | void UART_int(uint16_t value) |
14 | {
|
15 | char buff[6]; |
16 | utoa( value, buff, 16 ); |
17 | UART_string( buff ); |
18 | }
|
19 | |
20 | void UART_byte(uint8_t value) |
21 | {
|
22 | char buff[4]; |
23 | utoa( value, buff, 16 ); |
24 | UART_String( buff ); |
25 | }
|
26 | |
27 | void UART_dbg_byte( const char* label, uint8_t value ) |
28 | {
|
29 | UART_string( label ); |
30 | UART_string( ": 0x" ); |
31 | UART_byte( value ); |
32 | UART_string( "\n" ); |
33 | }
|
34 | |
35 | void UART_dbg_int( const char* label, uint16_t value ) |
36 | {
|
37 | UART_string( label ); |
38 | UART_string( ": 0x" ); |
39 | UART_int( value ); |
40 | UART_string( "\n" ); |
41 | }
|
42 | |
43 | void main(void) |
44 | {
|
45 | uint8_t status_reg = 0; |
46 | uint8_t outZ_low = 0; |
47 | uint8_t outZ_high = 0; |
48 | uint16_t outZ = 0; |
49 | |
50 | DDRC = (1<<DDC1); // PC1 als CS |
51 | |
52 | SPI_MasterInit(); //SPI init |
53 | |
54 | UART_init(); //UART Init |
55 | |
56 | sei(); //enable global interrupt |
57 | |
58 | //9.1 Startup sequence
|
59 | SPI_MasterWrite(CTRL_REG1, 0x3C); //enable device, normal mode, z-axis enable |
60 | |
61 | SPI_MasterWrite(CTRL_REG2, 0x00); |
62 | |
63 | SPI_MasterWrite(CTRL_REG4, 0x30); //full scale +-24g, data LSB@lower adress |
64 | |
65 | |
66 | while(1) |
67 | {
|
68 | //1. and 2.
|
69 | do //warten solange keine neuen Daten |
70 | {
|
71 | status_reg = SPI_MasterRead(STATUS_REG); |
72 | }while( !(status_reg & 0x08) ) ; |
73 | |
74 | |
75 | UART_dbg_byte( "Stat", status_reg ); |
76 | |
77 | //6. high und low byte auslesen
|
78 | outZ_high = SPI_MasterRead(OUTZ_H); |
79 | outZ_low = SPI_MasterRead(OUTZ_L); |
80 | |
81 | outZ = outZ_high << 8 + outZ_low; |
82 | |
83 | UART_dbg_int( "Z", outZ ); |
84 | }
|
85 | }
|
Habe deinen Rat befolgt und jetzt festgestellt, dass ich 12 overruns/sec hab. Das ist sehr viel und ich versteh einfach nicht vorher das kommt. Das Status_Reg zeigt mir dann immer 0xCC. D.h. Overrun Z-Achse und new Data available Z-Achse.
doug schrieb: > Habe deinen Rat befolgt und jetzt festgestellt, dass ich 12 overruns/sec > hab. Na ja. was sagt denn ein Overrun aus? Ein Overrun besagt, dass das Programm die Werte nicht schnell genug abgeholt hat (siehe Datenblatt). Ein neuer Messwert wurde vom Sensor produziert und in die Abhol-Register geschrieben, noch ehe der vorher gemessene Wert ausgelesen wurde. Mit einer UART, die ja vergleichsweise langsam ist, ist das auch nicht weiter verwunderlich. Das kann schon sein. Der Sensor produziert nun mal schneller als der µC die Werte per SPI holen und per UART auf dein Terminal bringen kann. Du hast wahrscheinlich an einen Werte-Overflow gedacht. Aber das ist nicht die Bedeutung dieser Bits.
Karl Heinz Buchegger schrieb: > doug schrieb: >> Habe deinen Rat befolgt und jetzt festgestellt, dass ich 12 overruns/sec >> hab. > > Na ja. was sagt denn ein Overrun aus? > > Ein Overrun besagt, dass das Programm die Werte nicht schnell genug > abgeholt hat (siehe Datenblatt). Ein neuer Messwert wurde vom Sensor > produziert und in die Abhol-Register geschrieben, noch ehe der vorher > gemessene Wert ausgelesen wurde. > > Mit einer UART, die ja vergleichsweise langsam ist, ist das auch nicht > weiter verwunderlich. Das kann schon sein. Vielleicht ist auch meine Pufferung schlecht? Ich lade mal meinen aktuellen Code hoch.
doug schrieb: > Vielleicht ist auch meine Pufferung schlecht? da hilft dir auch ein Puffer nichts. Wenn eine Maschine alle 50 Sekunden ein Bauteil produziert und der Maschinenbetreuer alle 60 Sekunden 1 Bauteil von der Maschine fortbringt, dann werden sich die Bauteile irgendwann bei der Maschine stapeln. Egal wie groß die Kiste ist, in die die Maschine die Bauteile reinwirft. Brauchst du zum Bearbeiten einer Akte 1 Stunde und legt dir dein Chef alle 30 Minuten einen neuen Akt auf den Schreibtisch, dann wird dein Schreibtisch irgendwann überquellen. Können durch einen Tunnel in der Stunde 500 Autos fahren, kommen aber pro Stunde 800 AUtos zum Tunnel, dann hast du Stau. Und wenn die 800 Autos Stunde für Stunde nicht weniger werden, dann wird der Stau wachsen und wachsen und wachsen. Das ganz hat nichts mit Puffer oder dergleichen zu tun, sondern damit, dass ein Mechanismus insgesamt zu langsam ist um das Aufkommen zu bewältigen. µC sind zwar schnell, aber zaubern können sie auch nicht. Irgendwann ist jede FIFO voll, wenn ständig mehr reingeht als rausgenommen wird. Im Endeffekt wirst du ja die UART nicht mehr haben, d.h. da fällt eine enorme Verzögerung der Hauptschleife sowieso weg.
doug schrieb: > Vielleicht ist auch meine Pufferung schlecht? woah, NEIN. das gibts doch nicht mehr langsam... schau doch mal ins datenblatt von deinem sensor und schau, wie schnell der daten in sein register anliefert. und dann schaust du, wie lang deine uart-übertragung dauert. kleiner vorkauen als karl-heinz kann mans doch gar nicht mehr...
> Im Endeffekt wirst du ja die UART nicht mehr haben, d.h. da fällt eine > enorme Verzögerung der Hauptschleife sowieso weg. Also: Jetzt einfach mal nicht ins Hemd machen und damit leben, dass du nicht jeden einzelnen Messwert mitkriegst, sondern auch mal ein paar fehlen werden.
Danke, habe jetzt durch eine kleinere SPI Geschwindigkeit eine geringere Fehlerquote.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.