Hallo AVR-Gemeinde...
ich habe mir vor kurzem einen Bosch BMA020 Beschleunigungsmesser
zugelegt und hab diesen auch schon mit I2C ansprechen können.
Das Problem an dem ich jetzt scheiter ist das Verarbeiten des
Zweierkomplements.
Laut Datenblatt (s. Anhang) gibt der Sensor die Daten der drei Achsen in
je zwei Registern aus. Für Achse X Register 0x02 für das niederwertige
Byte, von dem nur Bit 6 und 7 benötigt werden, und Register 0x03 von dem
das Gesamte Byte benutzt wird(für die anderen Achsen ensprechend andere
Register)
Soweit so gut...damit ich jetzt mit den Daten was anfangen kann, muss
ich die beiden Bytes zusammenfügen und zwar nach meinem Verständnis in
eine 16bit Integer Variable, da der Sensor ja 10bit ausgibt.
Nach mehrfachem googeln bin ich der Meinung das man so machen kann:
gX = (data[2]<<2 | data[1]);
Wobei data[1] das niederwertige und data[2] das höherwertige Byte ist.
Um zu kontrollieren ob überhaupt was passiert, wandel ich den wert mit
my_itoa um und gebe diesen auf dem LCD aus.
Jetzt meine Fragen bei denenen ich nicht weiter komme bzw. mir unsicher
bin:
1. Kann man Zweierkomplemente so zusammenfügen??Und wenn ja, sind die
Schiebewerte richtig??
2. Hab ich das richtig Verstanden, das der Sensor beim Auslesen, die
Registeradresse automatisch erhöht??
3. Wie müsste ich die Integer Variable umrechnen, damit irgendwann G im
Display steht??
Achso noch ein paar Infos:
- Prozessor ist Atmega32
- I2C von Peter Fleury
- Programieren mit AVR Studio
- Kommentierte main.c im Anhang.
Ich möchte keinen Fertigen Code haben, sondern stubser in die richtige
Richtung um das ganze zu verstehen.
Gruß und vielen Dank vorweg
Nils
danke für die schnelle antwort, also muss ich das so verstehen,
da ich das data[2] byte zwei stellen nach links schiebe,damit ich platz
für die beiden anderen bits mache, und data[1] sechs stellen nach rechts
schiebe, damit ich die restlichen 6 "rausschmeisse"??
und wozu ist das (int) vor dem data[2] gut??
gruß nils
du hast eine temporäre 16bit variable mit dem cast (int), verODERst das
mit MSB, schiebst es um 2 nach links, damit die unteren 2 frei sind und
verODERst das mit LSB, sechs nach rechts, damit die an die ersten 2
stellen kommen
dummerweise wirst du somit aber keine signed variable erhalten
das vorzeichenbit ist ja immer das most significant bit, also das ganz
linke.
Es genügt nicht das MSB von deinem wert um 6 nach links zu shiften, so
würde das 2er Komplement nicht funktionieren
ok das hab ich soweit verstanden...aber was muss ich dafür nun tun,
damit ich eine signed variable bekommen und ich auch negative Werte
herausbekomme und dann die in Beschleunigung umwandeln kann??
auf die Frage hab ich gewartet ^^
nu denn, du hast ja 10 bit auflösung.
da du den Acc nicht anders konfiguriert hast, geh ich ma von einem Range
+-2g aus.
Demzufolge stellen ein diskreter Wert etwa 3,9mg dar.
Wenn du auf die unteren 2 Bit verzichten, also mit einer Auflösung von
11,7mg leben kannst, schmeiß LSB weg und schieb das MSB direkt in eine
signed 8bit varibale und werd glücklich.
Andernfalls könnte man es so machen wie bisher, also das verODERn und
bitshiften der 2 Werte mit der int variable, das obere bit von MSB
maskieren..müsste demzufolge an der Stelle 9 sein (wenn man 0 mitzählt),
und anhand dessen ne kurze bedienung ob der "restliche" 9bit wert nun
positiv oder negativ ist (...für die weniger schlauen: *(-1) wenn
gesetzt)
gruß
die auflösung ist mir erstmal egal...soll erstmal laufen.
also ich hab jetzt data[2] also das MSB(LSB muss ausgelesen werden)
folgendermaßen:
gX = data[2];
zugewiesen.wobei gX ein signed char ist. dementsprechend sollte ich ja
werte von -127 bis +127 bekommen, richtig??
Wo ich jetzt noch ein problem mir hab, ist die ausgabe auf dem LCD.
ich wandel mit
void my_itoa(int32_t zahl, char* string)
die ich hier im forum gefunden habe den wert in einen string um und gebe
diesen dann aus.
aber da gX ja ein char ist und my itoa ja ein int32_t gibts da bestimmt
wieder ein problem oder??
sollte eigentlich kein Problem sein. Der Compiler könnte höchstens eine
Warning ausgeben, dass der übergabeparameter von einem anderen typ ist,
aber entweder machst du dann im funktionsaufruf einen typecast, also
"my_itoa((int32_t)gX,string);" oder du deklarierst gX direkt schon als
int32_t, was allerdings 3 verschenkte Bytes wären.
soo ich habe mir jetzt mal die z - achse betrachtet und die ausgeben
lassen.
die werte machen sogar sinn, da der wert umgerechnet bei 1G liegt, nur
ich bekomme keine negativen werte, wenn ich den chip umdrehe, ist der
wert identisch, allerdings müsste er ja negativ sein...hat das wieder
was mit dem msb und der auswertung zu tun??
Nils B. schrieb:> soo ich habe mir jetzt mal die z - achse betrachtet und die ausgeben> lassen.>> die werte machen sogar sinn, da der wert umgerechnet bei 1G liegt, nur> ich bekomme keine negativen werte, wenn ich den chip umdrehe, ist der> wert identisch, allerdings müsste er ja negativ sein...hat das wieder> was mit dem msb und der auswertung zu tun??
lass dir das ganze binär ausgeben, also auf Bitebene.
Dazu die original Registerinhalte auf Bitebene. Der Vergleich sollte für
dich Licht in die Sache bringen.
(Irgendwann musst du ja mal lernen, wie man Bits aus mehreren Registern
zusammensetzt)
Eigentlich nicht viel anders als das für die x-Achse, ich habe nur mal
den Wert aus Register 0x06 genommen und den auf dem Display dargestellt.
Was schon mal besser ist, dass es keine Werte mehr von 0...255 gibt,
sondern max. bis 120, mehr G kann ich nicht erzeugen :). und wenn ich
nach
Registerwert x 2 / 127 umstelle, kommt das mit dem Wert 60 den ich aus
dem Register bekomme auch hin mit 1G, nur mit dem Vorzeichen hapert das
noch.
void my_itoa(int32_t zahl, char *string) {
uint8_t i;
string[11]='\0'; // String Terminator
if( zahl < 0 ) { // ist die Zahl negativ?
string[0] = '-';
zahl = -zahl;
}
else string[0] = ' '; // Zahl ist positiv
for(i=10; i>=1; i--) {
string[i]=(zahl % 10) +'0'; // Modulo rechnen, dann den
ASCII-Code von '0' addieren
zahl /= 10;
}
}
void lcd_numout(char *string, uint8_t start, uint8_t komma, uint8_t
frac) {
uint8_t i; // Zähler
uint8_t flag=0; // Merker für führende Nullen
// Vorzeichen ausgeben
if (string[0]=='-') lcd_data('-'); //else lcd_data(' ');
// Vorkommastellen ohne führende Nullen ausgeben
for(i=start; i<komma; i++) {
if (flag==1 || string[i]!='0') {
lcd_data(string[i]);
flag = 1;
}
else lcd_data(' '); // Leerzeichen
}
lcd_data(','); // Komma ausgeben
// Nachkommastellen ausgeben
for(; i<(komma+frac-1); i++) lcd_data(string[i]);
}
Dazu noch die Funktion die alles auf dem LCD ausgibt. Beide aus dem
Forum hier kopiert. Bei Analogen Werten die ich einlese und ausgeb is
alles super.
Es gibt dir die gelesenen Registerwerte, den Int der sich aus der
Zusammensetzung ergibt und dessen Wert in Dezimal aus. Ich hab zwar die
Hardware nicht da, aber im Simulator haben die simulierten Werte gut
ausgesehen.
Falls du keine lcd_puts hast, hier ist eine
So hier mal das akutell Program für Achse Z.
Auf dem Display wird ,0060 bzw. ein entsprechender Wert je nach Lage.
Für die anderen Achsen funktioniert das genau so.
Vielen Dank für die geduldige Hilfe!!!!
nuja, da ich keinen BMA020 hier habe, kann ich das so direkt jetz nich
ausprobieren ;)
es wird ein komma gleich schon mit ausgegeben? aber eigentlich hat der
wert doch keine nachkommastellen nor?
Hallo Karl Heinz,
ich hab dein Programm mal Probiert und hab jetzt folgendes auf dem
LCD(musste es ein bischen zurechtrücken, da ich nur 20 Zeichen habe)
0x00 0x7f 0x01FC 508
gruß Nils
So...nachdem ich das Program von Karl Heinz Probiert habe, hab ich
wieder die dynamischen Werte aus dem Chip genommen, und siehe da es gibt
negative und positive Zahlen :)
das einzige was mich noch wundert, das die Werte im negativen Bereich
bis -20 gehen und im positiven bis 265. obwohl ich den chip nur halte
und nicht aktiv beschleunige.
Nils B. schrieb:> So...nachdem ich das Program von Karl Heinz Probiert habe, hab ich> wieder die dynamischen Werte aus dem Chip genommen, und siehe da es gibt> negative und positive Zahlen :)
Ach. Ich hab vergessen meine Hardgecodeten Werte ruaszuwerfen, mit denen
ich die Umrechnung kontrolliert habe :-)
>> das einzige was mich noch wundert, das die Werte im negativen Bereich> bis -20 gehen und im positiven bis 265. obwohl ich den chip nur halte> und nicht aktiv beschleunige.
Na ja.
Sieh dir die Register an, die vom Chip ausgelesen wurden. Dann weisst
du, ob die Werte schon vom Chip so kommen, oder ob zwischendruch was
passiert.
Genau aus dem Grund lasse ich mir ja die Urwerte, so wie ich sie das
erste mal in die Finger kriege ausgeben: Damit ich weiß, ob ich bei mir
einen Fehler habe, oder ob mein Programm grundsätzlich stimmt und die
ausgelesenen Werte falsch sind.
Du hast ein LCD! Benutze es um dir alle für die Fehlersuche relevanten
Faktoren ausgeben zu lassen.
Ich werd da gleich mal gucken.
Eine Frage hab ich noch, was meinst du mit
"Achtung: Alle Register sind gegenüber dem Datenblatt um 1 verschoben!"
und wieso hast du das gemacht??
Wenn der Fehler im Wertebereich noch da ist?? Dann tippe ich darauf, das
der Chip die absolute Beschleunigung anzeigt. Da geht die normale
Gravitation mit ein.
Nils B. schrieb:> Ich werd da gleich mal gucken.>> Eine Frage hab ich noch, was meinst du mit>> "Achtung: Alle Register sind gegenüber dem Datenblatt um 1 verschoben!">> und wieso hast du das gemacht??
Das hab nicht ich gemacht. Das hast du so gemacht.
Laut Datenblatt stehen die für dich interessanten Werte in den
Chip-Registern 0x02 und 0x03. Durch die Art und Weise, wie du dein
Auslesen organisiert hast, landet das IC-Register 0x02 bei dir in
data[1] und das IC-Register 0x03 in data[2]. Und weil ich da
drübergestolpert bin, hab ich mir da einen Kommentar dazugemacht. Denn
wenn wer eine for Schleife macht
for( i = 1; i <= .....
die anstelle von mit 0 mit 1 anfängt und anstelle von < ein <=
beinhaltet, dann klingeln bei mir die Alarmglocken und ich seh mir
genauer an, was da gemacht wurde.
> das einzige was mich noch wundert, das die Werte im negativen Bereich> bis -20 gehen und im positiven bis 265. obwohl ich den chip nur halte> und nicht aktiv beschleunige.
ich hab das mysterium um den Wertebereich gelöst...ist mir ja schon fast
peinlich die Auflösung zu geben...das Display war zu Ende,dadurch ist
die dritte Stelle durch das "-" nach Hinten weg :D
Jetzt gehts von -200 -> +265
Den rest bekomme ich auch in den griff...hoffe ich...
Aber erstmal vielen Dank für die Hilfe und den Code!!!
Gruß Nils
Ich habe gerade das Datenblatt überflogen. Da finde ich aber nix von
Kompensation der Schwerkraft! Macht das Teil beim Einschalten eine
Kompensation aufgrund der momentanen Ruhelage?
Es gab die Sache hier wohl schonmal bei einem AD-Chip.