hallo,
in die wo wird der wert des sensors in var "wert "gespeichert" ?
Druckbare Version
hallo,
in die wo wird der wert des sensors in var "wert "gespeichert" ?
Hallo an alle,
hier mal ein Programmschnippsel für die Neugierigen, die wissen wollen wie es geht: (Und es geht gut!)
Um z.B. das Status-Register 14 (Hex) auszulesen macht man folgendes:Code:/*----------------------------------------------------------------------------
Defines: Adresse vom BMA020-3D-Beschleunigungssensor
*/
#define I2C_BMA_W 0x70
#define I2C_BMA_R 0x71
int16_t x, y, z;
uint8_t ret;
/*
Lesen von 6 Registern ab Register 0x02. X, Y, Z-Koordinate
*/
ret = StartI2C (I2C_BMA_W);
ret = WriteI2C (0x02);
StopI2C ();
ret = StartI2C (I2C_BMA_R);
ret = ReadI2C (ACK); x = (int16_t)ret;
ret = ReadI2C (ACK); x = x | ((int16_t)ret << 8); x /= 64;
ret = ReadI2C (ACK); y = (int16_t)ret;
ret = ReadI2C (ACK); y = y | ((int16_t)ret << 8); y /= 64;
ret = ReadI2C (ACK); z = (int16_t)ret;
ret = ReadI2C (NAK); z = z | ((int16_t)ret << 8); z /= 64;
StopI2C ();
Code:/*----------------------------------------------------------------------------
Defines: Adresse vom BMA020-3D-Beschleunigungssensor
*/
#define I2C_BMA_W 0x70
#define I2C_BMA_R 0x71
/*
Lesen des Status-Registers 0x14 : reserviert:7:5 range:4:3 bandwidth:2:0
*/
uint8_t ret, r14;
uint8_t range;
ret = StartI2C (I2C_BMA_W);
ret = WriteI2C (0x14);
StopI2C ();
ret = StartI2C (I2C_BMA_R);
r14 = ReadI2C (NAK);
StopI2C ();
range = (r14 & 0b00011000) >> 3;
Und bei mir betrug die Lieferzeit nur ca. 10 Tage. Jippie ;-)
Gruß
Sternthaler
[edit 11.10.2010]
Auf Wunsch eine kleine Erklärung für die Berechnung der x-, y-, z-Werte.
Für X steht im oberen Code-Block folgendes:
Zeile 1) ret = ReadI2C (ACK); x = (int16_t)ret;
Zeile 2) ret = ReadI2C (ACK); x = x | ((int16_t)ret << 8 ); x /= 64;
In Zeile 1) wird beim ersten ReadI2C der Wert vom Register 0x02 aus dem Chip gelesen. Darin sind nur die beiden obersten Bit relevant für das X-Ergebnis. Es sind die beiden untersten Bits vom gesamten 10-Bit-Messwert.
Trotzdem wird diese Byte nun als 16-Bitwert in der Variablen x gespeichert.
In Zeile 2) wird mit dem nächsten ReadI2C das Register 0x03 aus dem Chip gelesen. (Die Adresse wird automatisch vom Chip hochgezählt.)
Dahinter wird nun das in Zeile 1) gelesene BIT-Muster mit |-Zeichen und dem in Zeile 2) gelesenen und mit dem <<8 um 8 BIT nach links geschobenem Registerwert aus 0x03 'verbunden'.
=> 0000 0000 ??-- ----: Die 2 Bits aus Zeile 1) in der 16-Bit-Variablen x
Bit-ODER-Verknüpft (|-Zeichen) mit dem um 8 Bit nach links geschobenem Wert aus Zeile 2)
=> ???? ???? 0000 0000: Die oberen 8 Bit vom Messwert. Ergibt:
----------------------------
=> ???? ???? ??-- ----
Die ? sind also nun die 10 Bit Messergebnis
Die - sind Bits, die auch gelesen wurden, aber hier nicht interessieren.
Die 0 sind Bits, die wir bewusst gesetzt hatten.
Jetzt noch in Zeile 2) mit dem x /= 64 diese Ergebnis einfach um 6 Bit nach rechts schieben. (Man kann auch schreiben x = x / 64;)
Man hätte auch x = ( x | ((int16_t)ret << 8 ) ) >> 6; schreiben können. Das macht der Compiler sowiso daraus.
Also ist das Ergebnis nun:
=> 0000 00?? ???? ????
Und damit haben wir die 10 Bit X-Messwert 'greifbar'.
ACHTUNG: Das höchste ?-Bit ist ein Vorzeichen.
Die Zählweise für den Betrag des Wertes kann man am besten in der Doku nachlesen.
Datenblatt: BMA020
Die Register sind auf Seite 9 beschreiben.
Die Zählweise vom Ergebnis ist auf Seite 21.
Viel Spaß beim Lesen wünscht
Sternthaler
@wtp
Hallo, 3 Dinge sind mir aufgefallen in deinem Programm.
Aber erst mal muss ich gleich sagen, dass ich noch nie mit diesem Basic was gemacht habe und, dass ich die I2C-Schnittstelle hier zum ersten mal benutze. Allerdings in C und es funktioniert bei mir.
Nun zu deinem Programm.
1) Nach dem I2C-Init setzt du noch einen Parameter mit config. Das würde ich tauschen.
2) Vor dem schreiben der Adresse 71 (Leseaufforderung) hast du ein I2C-Start. Ich habe vor dem Start noch einen Stop-Befehl. Eventuell hilft das schon.
3) Du liest Register 02 aus. Das sind nur die beiden untersten Bits von X-Beschleunigungswert. Versuche mal Register 03 zu lesen. Oder las das setzen vom Shadow_dis-Bit und lese dann Register 02 und sofort auch Register 03 und nutze nur 03.
Viel Erfolg
Gruß Sternthaler
Was kann man denn mit so ein teil tolles machen? ^^
Geschwindigkeit? Zurückgelegte strecke?
LG Raz
Hallo,
hat jemand schon Erfahrungen mit diesem Gyro gemacht?
Mich Interessiert vorallem die Bascom kompabilität, die tauglichkeit für ausbalancierte Fluggeräte (Tri-Quadrocoper), und die zuverlässigkeit.
Kann jemand zu einem der Punkte schon etwas sagen?
Es grüßt,
Basteltisch
- Lesen - ;-)
...hat nix mit Gyro zu tun !
Falls es am Datenblatt mangelt - das hab ich noch ;)
Ich hab vor ca. einem Jahr bei Bosch Sensortec angerufen und da wurde mir gesagt, daß der BMA020 nicht mehr hergestellt wird.
Moin Leute,
ich versuche auch Daten aus dem Sensor mit einem ATMega644 zu lesen (via SPI). Leider gibt mein Display für die 8 höchsten Bits der z-Beschleunigung eine 0 aus.
Ich hab das Programm gut kommentiert, sollte leicht verständlich sein.
Sieht jemand von Euch einen Fehler darin? Meines Erachtens habe ich alles beachtet.
Code:#include <avr/io.h>
#include <util/delay.h>
#include "m50530.h"
#include <stdlib.h>
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define PIN_SPI PINB
#define DD_BMA020_CS PB4
#define DD_MOSI PB5
#define DD_MISO PB6
#define DD_SCK PB7
#define P_BMA020_CS PB4
#define P_MOSI PB5
#define P_MISO PB6
#define P_SCK PB7
#define acc_z 7
#define read 7
void SPI_MasterInit(void)
{
// Set MOSI and SCK output, all others input
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);
// BMA020 ChipSelect is output (low active)
DDR_SPI |= (1<<DD_BMA020_CS);
// Deselect BMA020
PORT_SPI |= (1<<P_BMA020_CS);
// Enable SPI, Master, set clock rate fck/16, SPI Mode 3
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPOL)|(1<<CPHA);
}
void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
char getZ(void)
{
// Select BMA020
PORT_SPI &=~ (1<<P_BMA020_CS);
// Send command: Read z_acceleration
SPI_MasterTransmit((1<<read)|(acc_z));
// Send dummy byte
SPI_MasterTransmit(0);
// Deselect BMA020
PORT_SPI |= (1<<P_BMA020_CS);
// Return z acceleration
return SPDR;
}
int main(void)
{
uint16_t z=0;
char string[20];
// Wait 2 ms for the BMA020
_delay_ms(2);
// Initialize LCD and SPI
LCDInit();
SPI_MasterInit();
while(1)
{
// Read z-axis via SPI
z=getZ();
// Convert z To String
itoa(z, string, 10);
// Print z on LCD
LCDWrite(string);
// Set CoursorPosition to [0,0]
LCDSetCursorPos(0,0);
}
return 0;
}
Vielen Dank schonmal und Grüße aus Hamburch
Hallo,
falls es noch für jemanden von Interesse ist: ich habe die I2C-Kommunikation mit dem Sensormodul mal in BASCOM implementiert. Hier ist ein Beispielcode:
Ich habe auf meiner Homepage noch ein paar zusätzliche Informationen zu dem Programm hinterlegt. Hier kann man nachlesen, wenn man mag: http://www.mtahlers.de/index.php?opt...d=32&Itemid=69Code:' kleines beispielprogramm zum auslesen des bma020
' malte ahlers 2010
' weitere infos auf malteahlers.de
'
'
' compiler steuerung
$regfile = "m8def.dat"
$crystal = 1000000
$framesize = 64
$swstack = 64
$hwstack = 64
$baud = 9600
$lib "i2c_twi.lbx"
'
' hardware konfigurieren
' - taster
Config Pinb.6 = Input
Portb.6 = 1
Config Pinb.7 = Input
Portb.7 = 1
Config Pind.5 = Input
Portd.5 = 1
Taster1 Alias Pinb.6
Taster2 Alias Pinb.7
Taster3 Alias Pind.5
' - leds
Config Portd.7 = Output
Config Portd.6 = Output
Config Portb.0 = Output
Led_gl Alias Portd.7
Led_rt Alias Portd.6
Led_gr Alias Portb.0
' - i2c
Config Scl = Portc.5
Config Sda = Portc.4
'
' variablen dimensionieren
Dim V(6) As Byte
Dim Ax As Integer At V(1) Overlay
Dim Ay As Integer At V(3) Overlay
Dim Az As Integer At V(5) Overlay
Dim Acc_cntr As Byte
Dim I As Byte
Dim Acc_range As Byte
Dim D2g As Single
Dim S As Single
'
' konstanten
Const Acc_w = &H70
Const Acc_r = &H71
'
' subs
Declare Sub Set_acc_range(byval Range As Byte)
'
' hauptprogramm
Print "acc test!"
Wait 1
'
I2cinit
'
Call Set_acc_range(0)
' messbereich:
' Set_acc_range(0) -> +/- 2g (default)
' Set_acc_range(1) -> +/- 4g
' Set_acc_range(2) -> +/- 8g
'
Do
I2cstart
'
' sensor adressieren
I2cwbyte Acc_w
'
' acc datenregister adressieren
I2cwbyte &H02
'
I2cstop
'
I2cstart
'
' daten lesen
I2cwbyte Acc_r
'
For I = 1 To 5
I2crbyte V(i) , Ack
Next I
I2crbyte V(6) , Nack
'
I2cstop
'
' format konvertieren
Ax = Ax / 64
Ay = Ay / 64
Az = Az / 64
'
' in beschleunigungen umrechnen & ausgeben
S = Ax * D2g
Print "a(x)= " ; S ;
S = Ay * D2g
Print " a(y)= " ; S ;
S = Az * D2g
Print " a(z)= " ; S
'
Toggle Led_rt
Waitms 10
'
Loop
'
End
'
Sub Set_acc_range(byval Range As Byte)
I2cstart
'
' sensor adressieren
I2cwbyte Acc_w
'
' kontrollregister adressieren
I2cwbyte &H14
'
I2cstop
'
I2cstart
' kontrollregister lesen
I2cwbyte Acc_r
I2crbyte Acc_cntr , Nack
'
I2cstop
'
' kontrollregister manipulieren
Acc_cntr.3 = Range.0
Acc_cntr.4 = Range.1
'
I2cstart
'
' kontrollregister zurückschreiben
I2cwbyte Acc_w
I2cwbyte &H14
I2cwbyte Acc_cntr
'
I2cstop
'
' umrechnungsfaktor neu berechnen
D2g = 2 ^ Range
D2g = D2g * 2
D2g = D2g / 512
'
End Sub
Gruß
Malte
hallo malthy,
hallo Sternthaler,
Danke für die Code-Beispiele.
Der Basic-Code sieht aus meiner Sicht sehr gut aus und ist gut dokumentiert. Einzig in der Leseschleife wird bei V() ein kleines i verwandt, aber da ist Basic vielleicht gnädig ?
Beim C-Code wäre mir ein wenig Doku hilfreich.
Auch wäre in der ASURO-Umgebung interessant, wie man die Sensordaten
auf dem LCD-Display, das ja auch an I2C hängt, ausgeben kann.
SCL könnte bleiben (MY_I2C_SCL --> PC3/Pin26) aber SDA müsste man wohl umswitchen von PC2/PIN25 für LCD auf z.B. PC4/Pin27 für BMA020.
Werd aber wohl mit dem C-Code testen, da ich von BASIC wenig Ahnung habe.
Gruss mausi_mick