Forum: Mikrocontroller und Digitale Elektronik i2c Slave Problem


von Alex (Gast)


Lesenswert?

Hallo,

ich habe einen Sensor mit dem I2C Bus, den ich abfragen möchte.
Hier ist mein Beispielprogramm:
1
$regfile = "M8def.dat"       
2
$crystal = 16000000                                        
3
$hwstack = 32                                               
4
$swstack = 10                                               '
5
$framesize = 40                                            
6
$baud = 9600
7
8
9
Dim Lesen1 As Byte
10
11
12
'SDA und SCL definieren
13
Config Sda = Portc.4
14
Config Scl = Portc.5
15
16
I2cinit
17
18
19
I2cstart
20
I2cwbyte &H54h
21
I2cwbyte &HB6
22
I2crbyte Lesen1 , Nack                                  
23
I2cstop
24
25
Print Err
26
27
28
Print "gelesen: "
29
Print Lesen1
30
31
32
End

Die Ausgabe sieht immer so aus:
----------------
1
gelesen:
255
----------------

Datenblatt des Sensors:
www.captured-dreams.de/temp/TSEV01C_Application_Note_0_6.pdf


Hat jemand eine Idee, was ich falsch mache? Ich vermute bei der 
Adressierung ist etwas falsch.

Danke!

von John S. (linux_80)


Lesenswert?


von ingo (Gast)


Lesenswert?

guten abend gemeinde.

ich habe eine frage bezüglich dem beschreiben von registern.
über meinen mikrocontroller möchte ich werte aus meinem sensor über I2c 
auslesen.
das ganze ist ein beschleunigungssensor von bosch (SMB380) und der 
controller ist der Atmega1281.lese ich nicht veränderbare register 
aus,passt das alles.ich nutze die I2c-ansteuerung von Peter Fleury.

mein problem ist,dass mir ziemlich schwankende beschleunigungswerte 
ausgibt,obwohl dieser eigentlich fest montiert ist.die werte schwanken 
so in einer spanne von ca. 30dezimal.

meine vermutung ist,dass ich aus versehen bei der einstellung des 
registers für den messbereich (register 0x14) etwas falsch gemacht 
habe.in diesem register sind die obersten 3 bit (bit 7:5) für wichtige 
kalibrierungen nötig und dürfen nicht beschrieben werden.

leider habe ich dies wahrscheinlich mit meinem quellcode

i2c_init();       // Bus initialisieren
i2c_write(0x14);  // Register auswählen
i2c_write(0x06);  // Daten reinschreiben
i2c_stop();       // Busverbindung beenden

getan.

im user manual steht:
"Bits 4,6 and 7 of register address 0x14 do contain critical sensor 
individual calibration data which must not be changed or deleted by any 
means.
In order to properly modify address 0x14 for range and(or bandwidth 
selection using bits 0,1,2,3 and 4, it is highly recommended to read-out 
the complete byte,perform bit-slicing and write back the complete byte 
unchanged bits 5,6 and7.Otherwise the reported acceleration data may 
show incorrect results."

meine frage ist nun ganz einfach:

wie stelle ich das an was in dem 2.absatz des auszuges aus dem user 
manual steht????also nur einzelne bits ändern und die bits 5,6 und 7 
nicht "anfassen"!

im forum bei der sensorkommunikation über spi standen so befehle wie:

bit_setzen(data,(1<<5)); -> ist das bei i2c ähnlich?

bin über jede hilfe dankbar!!!

von ingo (Gast)


Lesenswert?

guten morgen.
kann mir hier niemand zu oben genannten problem einen tipp geben?

von Justus S. (jussa)


Lesenswert?

reg = ausgelesenes Einstellungsregister


reg2write = reg & 0b11100000;
reg2write = reg | 0b000XXXXX;

mit XXXXX die gewünschten Einstellungen

gibt wahrscheinlich auch noch bessere Möglichkeiten...

von ingo (Gast)


Lesenswert?

danke erstmal für die antwort.

ich habe mir das so gedacht:

uint8_t aendern;
{
startI2c(0x70);                writeI2c(0x14);
rep_startI2c(0x71);
aendern = readAckI2c();
aendern &=~((1<<4)|(1<<2)|(1<<1)); // meine vorzunehmenden Einstellungen
writeI2c(aendern);
stopI2c();
}

mir stellt sich jetzt nur die Frage ob ich nach dem Auslesen des 
Registers und Ändern gleich einen write-Befehl anschließen kann,oder 
erst noch stop-Befehl und dann nochmal von vorn: start usw.??

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Fokussieren wir mal diesen Design-Hinweis:
1
which must not be changed or deleted
und
1
it is highly recommended to read-out
2
the complete byte,perform bit-slicing and write back the complete byte
Damit dürftest du mit deiner Aktion
1
i2c_init();       // Bus initialisieren
2
i2c_write(0x14);  // Register auswählen
3
i2c_write(0x06);  // Daten reinschreiben
4
i2c_stop();       // Busverbindung beenden
Genau das gemacht haben was niemals hätte passieren dürfen:
du hast auf die oberen bits einfach Nullen geschrieben.
Besser wäre es entsprechend dem Datenblatt, erst das Register zu lesen, 
diesen Wert zu ändern, und dann wieder zurückzuschreiben.
1
uint8_t r14:
2
3
i2c_init();       // Bus initialisieren
4
i2c_write(0x14);  // Register auswählen
5
r14 = i2c_read();   // Daten auslesen -- wie auch immer diese funktion
6
i2c_stop();       // Busverbindung beenden
7
8
r14 &= 0xE0; // obere Bits behalten
9
r14 |= 0x06; // Daten dazu
10
11
i2c_init();       // Bus initialisieren
12
i2c_write(0x14);  // Register auswählen
13
i2c_write(r14);   // Daten reinschreiben
14
i2c_stop();       // Busverbindung beenden

Allerdings sind die schwankenden Werte doch eigenartig...
Lies doch mal das Versionsregister 0x01 (al_version und ml_version) aus.
Bekommst du dort richtige und stabile Werte?

BTW:
>... habe.in ...
>... ist,dass ...
Mach doch bitte nach Satzzeichen ein Leerzeichen, das erhöht die 
Lesbarkeit (mal abgesehen von der Groß- u. Kleinschreibung) ungemein.

EDIT:
> nach dem Auslesen des Registers und Ändern gleich
> einen write-Befehl anschließen kann
Probiers mal mit einem Repeated-Sart...
Ist dein i2c_init() das selbe wie ein i2c_start()?
1
/*************************************************************************
2
 Initialization of the I2C bus interface. Need to be called only once
3
*************************************************************************/
4
void i2c_init(void)
5
:
6
:
7
8
/*************************************************************************
9
  Issues a start condition and sends address and transfer direction.
10
  return 0 = device accessible, 1= failed to access device
11
*************************************************************************/
12
unsigned char i2c_start(unsigned char address)
13
:

von Justus S. (jussa)


Lesenswert?

ingo wrote:
> danke erstmal für die antwort.

> aendern &=~((1<<4)|(1<<2)|(1<<1)); // meine vorzunehmenden Einstellungen

uns was ist mit den Bits 0 und 3? oder weisst du, dass die vorher 
richtig waren?

von ingo (Gast)


Lesenswert?

@Lothar Miller:

Vielen Dank für die ausführliche Antwort! :)

>Ist dein i2c_init() das selbe wie ein i2c_start()?
Nein, in meiner init wird nur das Register TWBR auf den entsprechenden 
Wert gesetzt, sonst nichts weiter. Die i2c_start() ist halt die aus der 
lib von Peter Fleury.

>Lies doch mal das Versionsregister 0x01 (al_version und ml_version) aus.
>Bekommst du dort richtige und stabile Werte?

Ja hab ich gemacht und nicht nur diese Register. Außer den 
Achsenregistern sind meine Werte 100% zuverlässig/genau.
Das liegt aber sicher auch daran, dass die nichts mit 
Einstellungsregistern zu tun haben.

Ich denke mit dem Code den du mir gepostet hast werde ich es versuchen. 
Das repeated_start lasse ich erstmal weg.

Justus Skorps wrote:
>uns was ist mit den Bits 0 und 3? oder weisst du, dass die vorher
>richtig waren?

Naja, dass Register hat einen default-Wert. Da steht das die Bist 0 und 
3 beide "0" sind. Ändern will ich die ja nicht.

von ingo (Gast)


Lesenswert?

Also langsam verzeifle ich. :(

Hab nun auf ein 2.Modul einen neuen SMB380 draufgelötet und das Programm 
draufgeflasht wie Lothar Miller das vorgeschlagen hat (so hatte ich mir 
das auch überlegt).
Trotzdem driften die dezimalen Werte auseinander,was eigentlich nicht 
sein sollte.
Hab echt keine Ahnung mehr woran das liegen kann. Zum Test hab ich 
nochmal voreingestellte Register ausgelesen, d.h. Register 0x12 und 0x13 
und die Werte die erwartet werden (162 und 13) kommen immer nach dem 
Sensorauslesen raus.
Die Achsendaten werden vom Sensor periodisch mit 3KHz erneuert. Aber 
durch das Bit "shadow_dis" wird verhindert, dass MSB und LSB von 
unteschiedlichen Samples kommen können.
Ich weiss nicht so recht,ob es evtl an den "new_data *flags" liegen 
kann,aber eigentlich signalisieren diese nur,ob die Achsendaten 
ausgelesen wurden.

"...new data*flags... can be used to detect if acceleration values have 
already been read out."

von ingo (Gast)


Lesenswert?

Niemand noch eine Idee?

von Tommy T. (tommy776)


Lesenswert?

Hallo!

Wenn ich folgenden Ablauf auf dem I2c-Bus habe, müsste ich doch im 
I/O-Fenster des AVR-Studio im TWSR-Register am Ende auch die Statuse 
0x50 bzw. 0x58 sehen oder?

initI2c();
startI2c(0x70);
writeI2c(0x02);
rep_startI2c(0x71);
inclination = readAckI2c();
inclination1 = readNakI2c();
stopI2c();

Nach dem Status 0x40 steht nach dem Einlesen der Werte 0xF8!
Ich habe die Library von Peter Fleury.

von Tommy T. (tommy776)


Lesenswert?

ist das normal,dass nach einem STOP-Befehl das Statusregister irgendwann 
0xF8 anzeigt bevor eine neuerliche START-Bedingung gesendet wird?

Ich versuche hier mit der lib von Peter Fleury ein EEPROM-Register eines 
Sensors zu beschreiben. Um überhaupt Zugriff auf das Register zu 
bekommen, muss ich vorher noch in einem anderen Register ein Bit auf "1" 
setzen um überhaupt Zugriff auf dem EEPROM zu haben.

initI2c();
startI2c(0x70);
writeI2c(0x0A);         // Registeradresse wo Bit4 auf 1 soll
writeI2c(0x10);         // beschreibe Bit4 mit 1
erlauben = readAckI2c();
stopI2c();

startI2c(0x70);
writeI2c(0x14);        // Image von EEPROM-Register
rep_startI2c(0x71);
aendern = readAckI2c();
stopI2c();

aendern &=0xE0;
aendern |= 0x01;

startI2c(0x70);
writeI2c(0x34);        // EEPROM-Register;nur schreiben
writeI2c(aendern);
stopI2c();

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
Noch kein Account? Hier anmelden.