hallo, versuche diesen accelerometer in betrieb zu nehmen. doch ich stehe beim spi interface an. wenn ich WHO_AM_I per USART an den PC schicke bekomme ich immer 0xFF, sollte ja aber 0x3A geben. Erstaunlicherweise tut es das, wenn ich den software teil für den Slave select pin weglasse, d.h dass ich SS weder auf low noch auf high ziehe. irgendwie komisch. was meint ihr? #include "avr/io.h" #include <util/delay.h> //#include <avr/interrupt.h> #define ON 0 #define OFF 1 #define TOGGLE 2 #define FOSC 8000000 // Clock Speed #define BAUD 19200 #define MYUBRR FOSC/16/BAUD-1 ////////////////// SPI //////////////////// void SPI_MasterInit(void){ /* Set MOSI, SCK and SS output, all others input */ DDRB = (1<<PB2)|(1<<PB3)|(1<<PB5); PORTB |= (1<<PB2); /* Enable SPI, Master, set clock rate fck/16, SCK high in idle, sampling at rising edge */ SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPOL); } unsigned char SPI_MasterTransmit(unsigned char cData){ PORTB &= ~(1<<PB2); /* Start transmission */ SPDR = cData; /* Wait for transmission complete */ while(!(SPSR & (1<<SPIF))); PORTB |= (1<<PB2); return SPDR; } unsigned char SPI_MasterReceive(void){ /* Wait for reception complete */ while(!(SPSR & (1<<SPIF))); /* Return data register */ return SPDR; } ///////////////ACCELEROMETER ////////////// void AccelerometerInit(void){ writeRegister(0x20,0x47); //Power on device, enable all axis, and turn off self test - CTRL_REG1 } unsigned char readRegister(unsigned char registerName){ registerName |= 0x80; // set D7 to 1 for read mode SPI_MasterTransmit(registerName); return SPI_MasterTransmit(0x00); //send dummy byte } void writeRegister(unsigned char registerName, unsigned char registerValue){ registerName &= 0x7F; //Clear D7 to 0 for write mode SPI_MasterTransmit(registerName); SPI_MasterTransmit(registerValue); } //////////////// USART /////////////////// void USART_Init( unsigned int ubrr){ /* Set baud rate */ UBRRH = (unsigned char)(ubrr>>8); UBRRL = (unsigned char)ubrr; /* Enable receiver and transmitter, enable interrupt */ UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE); /* Set frame format: 8data, 1stop bit */ UCSRC = (1<<URSEL)|(3<<UCSZ0); } void USART_Transmit( unsigned char data ){ /* Wait for empty transmit buffer */ while ( !( UCSRA & (1<<UDRE)) ); /* Put data into buffer, sends the data */ UDR = data; } void USART_Transmit_String( unsigned char *string ){ while (*string){ USART_Transmit(*string); string++; } } unsigned char USART_Receive( void ){ /* Wait for data to be received */ while ( !(UCSRA & (1<<RXC)) ); /* Get and return received data from buffer */ return UDR; } /*ISR(USART_RXC_vect){ USART_Transmit(UDR); }*/ //////////////// LED /////////////////// void LedInit(void){ DDRC |= (1<<PC5); } void setLed(unsigned char state){ switch (state) { case 0: PORTC &= ~(1<<5); break; case 1: PORTC |= 1<<5; break; default: if (PORTC & 1<<5) PORTC &= ~(1<<5); else PORTC |= 1<<5; } } void blinkLed(unsigned int nrBlinks){ unsigned int counter; volatile unsigned int i; //muss volatile sein, sonst optimiert compiler for schleife weg for(counter=0;2*nrBlinks>counter;counter++){ setLed(TOGGLE); for(i=0;i<60000;i++); } } //////////////// BUTTON /////////////////// void ButtonInit(void){ DDRD &= ~(1<<PD2); } int getButtonStatus(void){ if (!(PIND & (1<<PD2))) { _delay_ms(50); _delay_ms(50); if (PIND & (1<<PD2)){ _delay_ms(50); _delay_ms(50); return 1; } } return 0; } //////////////// MAIN /////////////////// int main(void) { //sei(); LedInit(); ButtonInit(); USART_Init(MYUBRR); SPI_MasterInit(); //AccelerometerInit(); // has to be placed after SPI_MasterInit() writeRegister(0x20,135); setLed(ON); //_delay_ms(50); USART_Transmit(readRegister(0x0F)); //WHO_AM_I //USART_Transmit(readRegister(0x29)); //blinkLed(5); //while(1){ //if(getButtonStatus()) /* -> noch per Intterrupt steuerbar machen!*/ /* setLed(TOGGLE); if(USART_Receive()=='s') setLed(TOGGLE); } */ while(1); return 0; }
das ganze funktioniert wenn ich, d.h ich bekomme 0x3A zurück wenn ich folgende Sachen auskommentiere: PORTB |= (1<<PB2); in SPI_MasterInit PORTB &= ~(1<<PB2); und PORTB |= (1<<PB2); in SPI_MasterTransmit writeRegister(0x20,135); in main() sobald ich writeRegister(0x20,135); wieder hinsetze oder etwas mit dem PORTB machen will, dann gibt es mir immer 0x00 oder 0xFF. irgendwie komisch das ganze. SPI auf aut dem ATmega8 ist doch so konfiguriert, dass ich SS per software auf low oder high ziehen muss!
ach ja das teil arebitet mit 1.8-3.6 oder so was. ich verwende aber TTL levels, sollte eigetnlcih schon gehen oder?
Lustigerweise will ich die nächsten Tage/Wochen selber mit dem LIS3LV02DL per SPI Interface etwas experimentieren. Habe vor ein paar Tagen mein neues Controller Board fertig gebaut und den winzigen Sensor auf eine Adapterplatine gelötet um ihn besser anschließen zu können. Ich kann dir deshalb leider noch nichts zu deinem Problem sagen. Aber grundsätzlich solltest du den Sensor nicht direkt mit 5V TTL Pegeln betreiben, da er ja nur bis maximal 3,6V spezifiziert ist. Mein Controller (LPC936) arbeitet mit 3,3V, weshalb ich diesbezüglich keine Bedenken habe bei mir. Grundsätzlich kann es zwar sein, daß der Sensor mit 5V Pegeln funktioniert, aber damit betreibst du ihn außerhalb der Spezifikationen. Hast du ein brauchbares Digitalspeicher-Oszi zur Verfügung? Falls ja, dann schau dir mal das Verhalten zwischen SS, CLK und MiSO an, vielleicht siehst du dann ja schon eine eventuelle Ursache. Zum lesen musst du ja immer genau 2 Bytes schicken, wodrauf der Sensor ein Byte parallel zum 2. Byte zurück schickt. Genau das machst du auch in readRegister(unsigned char registerName). Aber in deinem Code ist mir die Methode SPI_MasterReceive(void) etwas schleierhaft. Denn diese wartet auf ein empfangenes Byte per SPI, was aber nie passieren kann, ohne vorher einen Transfer zum Sensor zu initiieren. :) An Adresse 0x20 den Wert 135 schreiben halte ich dem Datenblatt zufolge schon für richtig. Zum testen würde ich aber mal 128 rein schreiben, wodurch die 3 Axen erst mal deaktiviert bleiben, der Sensor ansich aber aktiv bleibt. Sobald ich mit meinen experimenten angefangen habe kann ich ja mal meine Erfahrungen schreiben. Ich wäre auch an daran interessiert, falls du neue Ergebnisse zu deinem Problem herausbekommst. Ciao, Rainer
hallo rainer, danke für dein interesse. ich werde dich selbstverständlich auf dem laufenden halten. SPI_MasterReceive ist mittlerweilen überflüssig. Wenn du SPI_MasterTransmit anschaust, siehst du dass ich das Empfangen auch gleich in diese Funktion gepackt habe. Oszi habe ich leider keines, muss wahrscheinlich mal was organisieren. sind ja aber leider nicht ganz günstig... software fehler hast du keine festgestellt,oder?
Software Fehler zu finden ist etwas schwer, wenn man den Code nur anschaut und ihn nicht debuggen kann. Da ich eine andere Architektur als du programmiere, habe ich auch keine Entwicklungstools für AVR auf meinem Rechner. Ich habe den Code eigentlich nur mal so überflogen, wobei mir das vorher genannte aufgefallen ist. Ich finde vor allem die Bitmanipulationen bei AVR Controllern immer so "aufwendig" und unlesbar geschrieben, weshalb ich mir diese nicht angeschaut habe. Bei meiner Architektur gibt es direkt Befehle zur Bitmanipulation. Aber das ist ein anderes Thema. ;) Ich persönlich bin auch kein Fan von zu kompakt geschriebenem Code, weil er dadurch nur unleserlich wird. Vor allem solche Konstrukte wie USART_Transmit(readRegister(0x0F)) würde ich nicht in einer Zeile machen, sondern lieber nacheinander in zwei Zeilen. Die heutigen Compiler optimieren den Code sowieso, weshalb das keinen großen Unterschied macht. Aber das ist natürlich auch nur Geschmackssache. :) Ich werde vielleicht heute noch dazu kommen erste Tests mit dem Sensor zu unternehmen. Ansonsten sollte ich spätestens am Wochenende dazu kommen. Ciao, Rainer
Also ich habe mittlerweile mal selber ein kleines Programm geschrieben, welches das WHO_AM_I Register ausliest. Leider bin ich noch nicht dazu gekommen, dieses mit dem Sensor zu testen. Dabei ist mir nur eine Sache aufgefallen, die in deinem Programm nicht ganz richtig ist. Ich habe sie Anfangs in meinem Programm auch übersehen gehabt. In dem SPI Protokoll ist angegeben, daß die Adresse aus 1+1+6 Bits besteht. Dabei ist das MSB R/W, dann kommt M/S und dann eine 6 Bit lange Adresse. Die Adressen stehen ja im Datenblatt drin, wobei WHO_AM_I 0x0F ist. Aber da das Register ausgelesen und nicht beschrieben werden soll, muss das Bit R/W eine 1 sein. Dadurch verändert sich das Byte, welches du als Adresse senden musst von 0x0F auf 0x8F ab. Denn mit 0x0F als Adresse würde man ja versuchen an diese Adresse ein Byte zu schreiben und nicht lesen. Ich habe dafür die Adresse in der Routine zum Senden einfach mit 0x80 verodert, wodurch das MSB gesetzt wird. Ich hoffe ich komme morge dazu mein Programm mit dem Sensor zusammen zu testen. Bin ja schon recht gespannt auf die Ergebnisse. :) Ciao, Rainer
Hallo Rainer, Wenn du nochmals meine Funktion readRegister anschaust, dann wirst du sehen, dass ich das ganze auch "verodert" (set D7 to 1 for read mode) habe. Hier nochmals die Funktion. Ich komme im Moment einfach nicht weiter, brauche unbedingt mal ein Oszi. unsigned char readRegister(unsigned char registerName){ registerName |= 0x80; // set D7 to 1 for read mode SPI_MasterTransmit(registerName); return SPI_MasterTransmit(0x00); //send dummy byte }
Ok, du hast natürlich Recht. Da habe ich deinen Code nicht genau genug durchgelesen gehabt. :) Ich werde morgen mal meinen Code testen und eventuell auch mein Oszi dranhängen, falls er nicht wie erwartet funktionieren sollte, was ich natürlich nicht hoffe. Ciao, Rainer
So ich habe heute mal den ersten Test mit dem Sensor gemacht. Ich habe ebenfalls nur das WHO_AM_I Register ausgelesen, was bei mir ohne Probleme funktioniert hat. Ich habe zum Test aber erst mal nur eine sehr niedrige Taktrate benutzt, da ich das dann schön auf meinem Oszi mitverfolgen kann. Ich habe aber kein Register vorher beschrieben, auch nicht CTRL_REG1. Der Sensor sollte sich deshalb noch im Powerdown Modus befinden. Ich habe die Bilder vom Oszi auf meiner Seite online, da man hier leider nur eine Datei an die Nachricht anhängen kann. Du kannst die Bilder unter http://quakeman.homelinux.net/LIS3LV02DL/ einsehen. Bild1: Timing zwischen CS und MOSI, Adressbyte(0x8F) und Dummybyte(0) Bild2: Timing zwischen CLK und MOSI, Adressbyte(0x8F) und Dummybyte(0) Bild3: Timing zwischen CLK und MOSI, nur Adressbyte(0x8F) im Detail Bild4: Timing zwischen SS und MISO, WHO_AM_I(0x3A) im 2. Byte Bild5: Timing zwischen SS und MISO, nur 2. Byte mit WHO_AM_I(0x3A) im Detail Ich werde jetzt mein Programm mal dahingehend erweitern, daß ich den Sensor aus dem powerdown Modus aufwachen lassen und versuche die Werte der verschiedenen Achsen auszulesen. Ich werde weiterhin berichten, wie das Ganze verläuft. :) Ciao, Rainer
hey, habe es jetzt auch endlich geschafft. das ding läuft und habe auch schon werte ausgelesen. zum einen habe ich die CS leitung vergessen gehabt zu setzen und zum andern muss man (1<<CPHA) machen, damit das funktioniert. geht aber so nicht aus dem Datenblatt hervor, oder?! werde das prog bei gegebener zeit hier posten.
CPHA und CPOL werden nicht erwähnt, weil diese Begriffe eigentlich nur bei Microcontrollern vorkommen und nicht bei der Peripherie. Dort steht aber drin, daß idle CLK high ist und bei steigender Flanke übernommen werden soll. Das entspricht CPHA=1 und CPOL=1, wenn man die vier möglichen Modes berücksichtigt. Ich ging eigentlich davon aus, daß du das schon richtig gehabt hättest, weshalb ich auf diesen Fehler gar nicht gekommen bin. ;) Ich habe heute mal ein kleines Programm geschrieben, mit wlechem ich per RS232 jedes einzelne Register des Sensors beschreiben oder auslesen kann im Ascii Mode. Sequentielles lesen mehrerer Bytes hintereinander habe ich mit dem M/S Bit realisiert. Ebenso habe ich einen Testmode eingebaut in welchem ich alle 6 Achsenregister (High/Low) kontinuierlich hintereinander ausgebe. So kann ich in dem Terminalprogramm schön sehen was passiert, wenn ich den Sensor bewege. :) Ciao, Rainer
hey rainer, wie siehts aus so? habe mittlerweilen ein java programm geschrieben, das mir per rs232 die beschleunigungswerte ausliest. jetzt will ich es noch grafisch darstellen. braucht aber noch ne weile. was hast du überhaupt für einen mikrocontroller? was soll es denn geben wenn dein projekt fertig ist?
Ich benutze einen P89LPC936 von Philips (8051er Architektur). Also mein Programm im Controller funktioniert mittlerweile völlig problemlos und gibt mir im Modus "fortlaufend" alle drei Achsen kontinuierlich als ASCII-Hex Zahlen aus. Ein Freund ist gerade dabei ein kleines Programm zu schreiben, um diese Daten graphisch anzuzeigen. Wenn das alles soweit funktioniert wollen wir den Sensor in eine selbst gebaute LED-Stirnlampe integrieren, um die Luxeon LED's, je nach Kopfbewegung/-neigung zu dimmen oder umzuschalten. Sobald man den Kopf senkt wird auf die rote weitläufige LED umgeschaltet, weil man dann meistens lokal sich etwas anschauen will. Und rote LEDs ziehen Mücken nicht so sehr an. Wenn man geradeaus schaut wird auf die stärker fokusierte weiße LED umgeschaltet mit der man besser in die Ferne leuchten kann. Bei definierten Kopfbewegungen sollen die LEDs dann auch noch heller oder dunkler gedimmt werden können per PWM. Diese Idee ist uns bei etlichen Nachtcaches (Geocaching) gekommen, wenn wir immer mit den Taschenlampen herumhantieren mussten. Auf das integrieren der Beschleunigungssensoren kamen wir eher zufällig, als ich die Beschreibung eines neuen Handys mit integrierten Beschleunigungssensoren gelesen hatte. ;) Ciao, Rainer
Tönt interessant, da musst du aber dann wahrscheinlich noch einen groben Tiefpass dimensionieren, da du ja beim Gehen ja immer noch andere Beschleunigungen hast als nur der g-Vektor.
Wir haben mittlerweile ein kleines Testprogramm, welches die drei Achsen graphisch am PC anzeigt und die Werte in "g" umgerechnet daneben. Ich habe auch mit den diversen Einstellungen des Sensors etwas herumexperimentiert, wobei die Fülle der Möglichkeiten ja schon recht groß ist. Aber vor allem der eingebaute Hochpass Filter ist sehr interessant, weil dieser die Erdbeschleunigung aus den Werten rausrechnet nach kurzer Zeit. Dadurch kann man dann anstatt absoulter Werte relative Werte vom Sensor abfragen. Es ist schon ziemlich interessant, was man so alles machen kann mit dem Sensor. :) Ciao, Rainer
hallo rainer, habe jetzt mal ein Java GUI erstellt. im Anhang findest du ein bild davon.
Na ganz so schön und aufwendig ist unsere Anwendung nicht. Um ehrlich zu sein ist sie eigentlich mickrig dagegen. :) Mein Bekannter hat das Programm in C# geschrieben, was mir persönlich nicht so recht gefällt, da ich eigentlich nur Java am PC programmiere. Würde es dir etwas ausmachen, mir deine Java Version zukommen zu lassen? Denn an Dieser könnte ich auch selber noch herumschrauben im Gegensatz zu der C# Version. Ich bin mehr der Programmierer für die reine Funktionalität und habe mit GUIs deshalb nicht wirklich viel am Hut. Ciao, Rainer
ja klar, ich kann sie dir gut mal schicken. nur ganmz fertig ist sie noch nicht. wird wahrscheinlich noch eine woche oder so dauern. willst du sie schon jetzt mal oder erst später. wo soll ich die das zeugs hinschicken?
Also ich habe es nicht eilig, komme selber nur hin und wieder dazu weiterzumachen an meiner Hard-/Software. Deshalb eilt es nicht, wenn du an deiner Software noch weiter schrauben willst. Du kannst mir ja einfach irgend wann mal eine Version an Quakeman1@gmx.net schicken, wenn du magst. :) Ich habe mir mal eine kleine LCD Routine eingebaut, wodurch ich mir die Werte etwas portabler anzeigen lassen kann, wenn ich z.B. mal unterwegs bin. Aber eine andere Frage hätte ich noch, und zwar wie du den Sensor "verarbeitet" hast? Deine Version ist ja im QFN28 Gehäuse, welches auch nicht besser ist als meiner im LGA16 Gehäuse. Ich hatte wirklich kämpfen müssen um dieses Gehäuse von Hand auf eine Adapter Platine zu bekommen. Da das LGA Gehäuse vor allem keine seitlichen Anschlüsse mehr besitzt musste ich den Sensor über Kopf festkleben und per Drähtchen jeden Pin auf die Platine löten. An solchen Tagen wünschte ich mir einen Reflow Ofen. Vielleicht hast du ja diesbezüglich eine bessere Möglichkeit gefunden gehabt. Ich habe mal ein Foto meiner Adapterplatine mit angehängt. Ciao, Rainer
ich habe mir einfach das breakoutboard bei sparkfun.com besorgt :-) an der software werde ich noch ein wenig basteln und dir dann mal schicken, vielleicht kannst du sie ja dann brauchen. mit welcher methode ätzst du?
Ich benutze die gute alte belichten->entwickeln->ätzen Methode. Damit erreiche ich mittlerweile recht gute Ergebnisse. Das neue Verfahren per aufbügeln halte ich für sehr unausgereift. Habe diesbezüglich sehr viele Misserfolgsmeldungen gelesen, weshalb ich doch beim Altbewährten bleibe. In hoffentlich nicht allzuferner Zukunft sollte meine 3D CNC Fräse auch fertig werden, an der ich schon seit letztem Jahr baue. In erster Linie baue ich mir die um Platinen dann zu fräsen anstatt zu ätzen da ich dann weniger Sauerrei habe und nicht immer dabei sein muß. :) Mit $43.95 ist das Board aber auch nicht unbedingt günstig. Über welchen Distributor und zu welchem Preis hast du es denn bezogen in Deutschland? Ich habe meine LIS3LV02DL über einen Bekannten als Samples bekommen. Dafür musste ich mir eben die Arbeit machen ein Adapterboard selber zu basteln. Noch ne Frage zu deinem Programm. Ich habe von nem Bekannten diesen Link zu einem vergleichbaren Programm bekommen gehabt: http://www.skippari.net/projects/wp-content/uploads/accel_test.png Wenn ich das richtig sehe, gibt es wohl fertige GUI Elemente in Java die man dafür benutzen kann. Ich vermute mal, du verwendest ebenfalls solche GUI Bausteine für deine GUI. Kannst du mir mal ein paar Pakete nennen, in welchen man solche schönen GUI Elemente findet? Ich habe nämlich schon das eine oder andere mal eine kleine GUI für etwas schreiben wollen in Java, hatte aber nie so schöne Anzeigen gefunden gehabt. Und selber die Anzeigen per Grafikbibliothek zusammenbasteln wollte ich dann doch nicht. ;) Ciao, Rainer
habe das board direkt bei sparkfun zu diesem preis dort gekauft. lieferkosten sind da nicht unbedingt teurer als sonst irgendwo. genau, verwende natürlich solche vorgefertigte gui elemente. andernfalls kommt man nie zum ziel... habe sie von http://www.jfree.org/jfreechart/ die charts sind zwar gratis, den developer guide musst du dir aber dazu kaufen oder als torrent runterladen ;-)
Ich war eben mal auf der jfree Seite und die haben ja haufenweise schöne Grafikbausteine in deren Paket drin. Und die Beispiele samt Javadoc reichen mir völlig aus. Brauche da keinen weiteren developer guide. Dafür arbeite ich schon lange genug mit Java. :) Ich denke ich werde damit mal etwas herumspielen müssen. Ciao, Rainer
Wohl zu früh gefreut. Wie es aussieht gibt es auf der Homepage überhaupt keine Beispiele sondern nur in diesem blöden Developer Guide. Naja, das wird das Ganze dann natürlich etwas schwieriger machen, aber das wird schon irgendwie klappen. :)
Also den Developer Guide habe ich gefunden, aber leider nicht den Java Quellcode zu den vielen Beispielen. Vielleicht kannst du mir die Java Dateien an quakeman1@gmx.net mal schicken. :)
hallo, was willst du genau? ich habe auch nur die library und den developer guide.
Achso, ok dann hat es sich erübrigt. Ich dachte, du hättest die Java Quellcode Dateien zu den Beispielen, die man alle sich auf der Homepage anschauen kann. Die sollten angeblich bei dem Developer Guide dabei sein. Ich habe aber nur das PDF von dem Developer Guide gefunden. :)
Hi I have try you code, it does not work for me. So i want to ask you what MCU you are using? Atmega 16 or something. Thanks
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.