Eine Bitte um Hilfe

Ernst

Mitglied
04. Okt. 2009
61
9
8
nähe Regensburg
Sprachen
Zuerst einen netten Gruß an alle. Ich habe mich mit dem I2C:Bus beschäftigt. Zuerst habe ich bei meinem WIN-Avr die Vorlage für den Temperaturfühler LM75 geladen und den Sensor angeschlossen. Die Temperatur wird auf dem Display angezeigt wenn man davon absieht das weder negative Temperaturen noch die Nachkommastelle Angezeigt wird. Ich habe das Programm verbessert so dass 16 statt 8 Bit ausgelesen, umgerechnet und die Temperatur mit Minusvorzeichen und Nachkommastelle korrekt angezeigt werden. Klappt also super. Dann habe ich mir zwei EEProm ST 24C256 BN6 gekauft auf eine Platine montiert, mittels Pins die Adresse verschieden codiert und ein Programm dazu geschrieben. So konnte ich verschiedene Texte für mein 2X16 Display speichern und auch wieder einlesen und korrekt anzeigen. Klappte super. Ich habe mir dann das Kompassmodul https://www.amazon.de/Demarkt-HMC5883L-drei-Achsen-Magnetfeld-elektronischer-Kompass/dp/B06Y2HFN6X
gekauft und versucht es nach der PDF Vorlage anzusprechen. Jedoch ich bekomme keine Daten von Lage des Sensors zurück. Das einzige was ich zurückbekomme ist der letzte Befehl den ich an den Sensor sende. Ich habe in meinem Programm einen freien Port als Ausgang konfiguriert an dem Leds angeschlossen sind. So das immer eine weitere Led leuchtet wenn beispielsweise der Sensor mit seiner Adresse angesprochen wird und sein OK zurück gibt. So bringe ich alles Leds zum Leuchten bis auf die eine wo er die Positionsdaten zurück senden sollte. Da scheint er nicht zu antworten und es erschein am Display nur der letzte Befehl die ich ihm geschickt habe. Mir geht es vorerst nicht darum um Abgleich und so weiter sondern nur das ich überhaupt mal Positionsdaten zurück bekomme. Ich wäre um einen Tipp oder Denkanstoß sehr dankbar.
Gruß Ernst
Hier der Ausschnitt aus dem PDF Dokument nach dem ich den Sensor anspreche



OPERATIONAL EXAMPLES

The HMC5883L has a fairly quick stabilization time from no voltage to stable and ready for data retrieval. The nominal 56 milli-seconds with the factory default single measurement mode means that the six bytes of magnetic data registers (DXRA, DXRB, DZRA, DZRB, DYRA, and DYRB) are filled with a valid first measurement.

To change the measurement mode to continuous measurement mode, after the power-up time send the three bytes:

0x3C 0x02 0x00

This writes the 00 into the second register or mode register to switch from single to continuous measurement mode setting. With the data rate at the factory default of 15Hz updates, a 67 milli-second typical delay should be allowed by the I2C master before querying the HMC5883L data registers for new measurements. To clock out the new data, send:

0x3D, and clock out DXRA, DXRB, DZRA, DZRB, DYRA, and DYRB located in registers 3 through 8. The HMC5883L will automatically re-point back to register 3 for the next 0x3D query. All six data registers must be read properly before new data can be placed in any of these data registers.

Below is an example of a (power-on) initialization process for “continuous-measurement mode”:

1. Write CRA (00) – send 0x3C 0x00 0x70 (8-average, 15 Hz default, normal measurement)

2. Write CRB (01) – send 0x3C 0x01 0xA0 (Gain=5, or any other desired gain)

3. Write Mode (02) – send 0x3C 0x02 0x00 (Continuous-measurement mode)

4. Wait 6 ms or monitor status register or DRDY hardware interrupt pin

5. Loop



Send 0x3D 0x06 (Read all 6 bytes. If gain is changed then this data set is using previous gain)

Convert three 16-bit 2’s compliment hex values to decimal values and assign to X, Z, Y, respectively.

Send 0x3C 0x03 (point to first data register 03)

Wait about 67 ms (if 15 Hz rate) or monitor status register or DRDY hardware interrupt pin

End_loop
 
Hallo @Ernst,

das hört sich erstmal nach einem "Protokollfehler" deinerseits an. Leider hast Du weder Quellcode noch eine Sprache angegeben in der Du programmierst ( oder habe ich es überlesen? ).

Meist haben die Chips ein "ID Register" ( wie dieser auch. 0x10..0x12 )

- An der Adresse "0x10" solltest Du das ASCII 'H' Zeichen auslesen können.
- Die Adresse "0x11" enthält ebenfalls ein ASCII Zeichen, hier sollte eine '4' kommen.
- Letzte Adresse "0x12" eine '3'.

Hast Du das schon probiert? Bevor man irgendwelche AD Werte versucht zu empfangen.

Ansonsten müsste das Kommunikations-Protokoll wie folgt aussehen ( Byteweise! ):

Byte Wert
[0] I2C Slave Adresse
[1] Slave Register Adresse
[2] Slave Register Wert

Und die start bzw. stop Bedingungen müssen beachtet werden, dass sollte jedoch schon klappen ( sonst hättest Du andere Teilnehmer nicht testen können ).
 
Zuletzt bearbeitet:
Grüßt euch

Zuerst möchte ich für die schnelle Antwort danken. Ich schreibe meine Programme in Assembler. Ich glaube auch das es an den Start und Stopp Bedingungen liegt warum es nicht klappt. Ich habe halt einfach das Programm vom LM75 umgeschrieben. Es gibt in diesem Programm Unterprogramme wie Start, Senden, Lesen, Stopp. Ich denke mal das die korrekt sind da ich diese Unterprogramme im Original auf für meine EEProm`s nutze und das klappt auch. Mir geht es darum wie und wann muss ich die Start -und Stoppbefehle senden. Ich habe es so gemacht.

Parameter vom Sensor setzen

Start senden (als Master anmelden)

Adresse senden (0x1E) Sensor Adresse

Schreiben senden (0x3C) schreiben

Daten senden ´ (0x00) Register A auswählen

Daten senden (0x70) 8-Mittelwert, 15 Hz Standard, normale Messung

Stopp

Start (als Master anmelden)

Adresse senden (0x1E) Sensor Adresse

Schreiben senden (0x3C) schreiben

Daten senden ´ (0x01) Register B auswählen

Daten senden ´ (0xA0 )Verstärkung auswählen

Stopp

Start (als Master anmelden)

Adresse senden (0x1E) Sensor Adresse

Schreiben senden (0x3C) schreiben

Daten senden ´ (0x02) Mode Register

Daten senden (0x00) Parameter dauernd messen

Stopp

Anweisungen zum Daten lesen senden

Start senden (als Master anmelden)

Adresse senden (0x1E) Sensor Adresse

Schreiben senden (0x3C) Hier sollte 0x0D stehen bekomme aber dann keine OK Meldung vom Sensor zurück, Ich vermute hier den Start / Stopp Fehler

Daten senden ´ (0x06) alle 6 Bytes lesen

Schreiben senden (0x3C) schreiben

Daten senden ´ (0x03) Zeiger auf erstes Datenregister 03

Daten lesen X MSB Register

Daten lesen X LSB Register

Daten lesen Z MSB Register

Daten lesen Z LSB Register

Daten lesen Y MSB Register

Daten lesen Y LSB Register

Stopp

Schleife zum Programmanfang
 
Assembler ist jetzt nicht so meins.
Da könnten Dir @TommyB oder @LotadaC weiterhelfen.
 
Hallo Ernst,

nach START musst du die I2C Adresse um ein Bit nach links geschoben mit dem Bit 0 für R/W senden.

Du machst das in deinen Beispielen "doppelt".

Du sendest nach START die 7Bit I2C Adresse 0x1E (ohne R/W Bit) und danach entweder die Schreibadresse 0x3C oder die Readadresse 0x3D.
Dies ist so nicht richtig.
Der HMC5883L wird also erst gar nicht adressiert.

Für schreiben machst du zum Beispiel folgendes:

START
0x3C
...
STOP


Dirk :ciao:
 
Grüßt euch
1000 Mal Danke das war der Denkanstoß. Ich habe gedacht ein Bit zu 1E ist dann 1F das habe ich nicht gewusst dass man das Bit hinten dran hängen muss. Ich habe gedacht zuerst die Adresse 1E senden und dann 3D oder 3C fürs Lesen bzw. Schreiben senden. Ich kann es bis zum Wochenende nicht ausprobieren aber ich denke dass es jetzt funktioniert. Nochmals danke.

Gruß Ernst
 
Grüßt euch
leider hat es nicht geklappt. Ich vermute mal das es am Chip liegt. Das der andere Register oder Dialekt spricht. Hier die Aufschrift auf den Chip
D8
5883
7006

Ich habe das Programm schon zig mal geändert und den Chip in aller Denkbarer weise angesprochen bevor ich euch um Hilfe gebeten habe. Leider habe ich immer noch keinen Erfolg damit. Wenn ich ihn mit 3D anspreche kommen nach dem "lesen" nur 3D zurück oder das Programm bleibt stecken.
Falls es jemand interessiert hier der Programmausschnitt fürs Schreiben und fürs Lesen. Die Unterprogramme den Bus als Master ansprechen, starten, schreiben, lesen funktionieren beim Temperatursensor und beim externen EEprom super also glaube ich nicht das es daran liegt.
Hier das Programm fürs Schreiben
rcall twiInitMaster

push r16
rcall twiStart ; TWI starten
ldi r16,0x3c ;select schreiben Register
clr r15 ; kein ACKN
rcall twiWriteByte ; Daten schreiben
ldi r16,0x02;Register 2
clr r15 ; kein ACKN
rcall twiWriteByte ; Daten schreiben
ldi r16,0x00;dauernde Messung
clr r15 ; kein ACKN
rcall twiWriteByte ; Daten schreiben
clr r15 ; kein ACKN
pop r16
rcall twiStopp
ret
Hier das Programm zum lesen

push r15
rcall twiStart ; TWI starten
ldi r16,0x3c ;select schreiben Register
clr r15 ; kein ACKN
rcall twiWriteByte ; Daten schreiben
ldi r16,0x03 ;select schreiben Register
clr r15 ; kein ACKN
rcall twiWriteByte ; Daten schreiben
rcall twiStart ; TWI starten
ldi r16,0x3d ;select schreiben Register
com r15 ; TWEA = acknowledge = TWI-Datenanforderung
rcall twiWriteByte ; Daten schreiben
rcall twiStart
;ldi r16,0x06 ;select schreiben Register
com r15; TWEA = acknowledge = TWI-Datenanforderung
rcall twiWriteByte ; Daten schreiben
clr r15 ; kein ACKN
rcall twiReadByte
mov r17,r16; hier sollten die Daten für Data Output X MSB Register sein
clr r15 ; kein ACKN
rcall twiReadByte
mov r18,r16; hier sollten die Daten für Data Output X LSB Register sein
clr r15 ; kein ACKN
rcall twiReadByte
mov r19,r16; hier sollten die Daten für Data Output Z MSB Register sein
clr r15 ; kein ACKN
rcall twiReadByte
mov r20,r16; hier sollten die Daten für Data Output Z LSB Register sein
clr r15 ; kein ACKN
rcall twiReadByte
mov r21,r16; hier sollten die Daten für Data Output Y MSB Register sein
clr r15 ; kein ACKN
rcall twiReadByte
mov r22,r16; hier sollten die Daten für Data Output Y LSB Register sein
rcall twiStopp
pop r15
ret
 
Zuletzt bearbeitet:
Hi Ernst,

Grüßt euch
leider hat es nicht geklappt. Ich vermute mal das es am Chip liegt. Das der andere Register oder Dialekt spricht. Hier die Aufschrift auf den Chip
D8
5883

schreib dir doch mal nen Programm, das alle I2C-Adressen durchtestet. Also immer in einer Schleife ...

Adresse = 0
-- Schleifenanfang
I2Cstart
I2Cwrite <Adresse>
Wenn Ack vom Baustein kommt, Adresse auf LCD oder Seriell anzeigen
I2Cstop
Adresse +1
-- Schleifenende

Dann kannst du sehen ob der Baustein überhaupt auf irgendwas reagiert.

Das kann man auch machen, wenn man auf nem RasPI die I2C-Hilfsprogramme/Bibliotheken installiert. Dort gibt es auch nen Suchprogramm. Das zeigt dann im Terminal eine Tabelle mit den gefundenen aktiven Adressen an.

Gruß
Dino
 
Hallo Ernst,

stell vielleicht auch nochmal ein Beispielcode in das Forum, wie du auf den Baustein zugreifst, ruhig auch in Assembler.

Dirk :ciao:
 
Grüßt euch
Zuerst ein Danke für eure Hilfe
Ich habe das Programm das Dino mir geraten hat so geschrieben
mainloop: wdr
ldi r31,0
loop:
wdr
push r15
rcall twiStart
mov r16,r31
clr r15
rcall twiWriteByte
mov r28,r31 ;r28 Register für LCD Anzeige
rcall twiStopp
pop r15
rcall Aufbereitung ;LCD Anzeige
inc r31
rjmp loop
Da stoppt das Programm bei 0B00011011 was bedeuten würde das die gefundene Adresse 1B ist. Sehe ich das richtig so?
Gruß Ernst
 
Hallo Ernst,

Da stoppt das Programm bei 0B00011011 was bedeuten würde das die gefundene Adresse 1B ist. Sehe ich das richtig so?
demnach wäre das nach dieser Info (Adressierung) ... https://rn-wissen.de/wiki/index.php/I2C
also 0001 101 und Read .... hmmm ... theoretisch hätte der Chip sich bei 0001 1010 auch melden müssen (das wäre dann Write gewesen). Da das letzte Bit zwischen Read (1) und Write (0) umschaltet, hat ein Baustein eigentlich immer zwei 8Bit-Adressen (aber nur eine 7Bit-Adresse plus angehängtem R/W-Bit).

Gruß
Dino
 
Grüßt euch

Die Adresse ist Schreiben A1 und Lesen B1 auch die Programmregister sind ganz anders. So haben die Ausgaberegister für XL,XH,YL,YH,ZL,ZH die Adressen 0X00 bis 0x05 wobei 0x06 auch ausgelesen werden damit der Chip wieder neue Daten in die Register schreibt. Die Daten für alle Register kann ich jetzt auslesen jetzt muss ich sie nur mit meinem Assembler aufbereiten. Ich schreibe erst heute da ich wieder längere Zeit im Krankenhaus verbringen musste. Ich habe die Zeit genutzt und ein Programm geschrieben womit man elegant die Adressen von einem oder mehreren Slaven am I2C Bus anzeigen kann. Ich schenke es euch wenn ihr es haben möchtet.

Gruß Ernst

Code:
;----------------------------------------------------------------
; Titel :    I2C Bus Slave - Adressenfinder
;----------------------------------------------------------------
; Funktion     : Programm zählt die Adressen von 0 bis 255 hoch
;              : und sucht so die Adresse des I2C Bausteins
;              : Anzeige erfolgt in Dezimalzahlen
;              : LCD Display  2 x 16 an Port B
;     : LCD Display DB4 an Port B0
;    : LCD Display DB5 an Port B1
;    : LCD Display DB6 an Port B2
;    : LCD Display DB7 an Port B3
;    : LCD Display RS  an Port B4
;    : LCD Display E   an Port B5
;    : Taster an Port C0  (für weiter suchen oder neue Suche)
;           : Bus an Port C4 SDA und Port C5 SCl
;----------------------------------------------------------------
; Prozessor : ATmega8
; Takt : 3686400 Hz
; Sprache : Assembler (GNU)
; Datum : 05.03.2020
; Autor : Ernst Preischl
;----------------------------------------------------------------
.include    "avr.h"
.equ    F_CPU,3686400
.equ    TWI_CLOCK,100000 ; Geschwindigkeit des TWI-Busses
;----------------------------------------------------------------
; TWCR - Control-Register-Bits
.equ    _TWINT,0b10000000
.equ    _TWEA,0b01000000
.equ    _TWSTA,0b00100000
.equ    _TWSTO,0b00010000
.equ    _TWWC,0b00001000
.equ    _TWEN,0b00000100
.equ    _TWIE,0b00000001
.equ    Stelle,0x11    ;r17 = Stelle LCD
.equ    Adresse,0x12    ;r18 = Adresse
.equ    Zahl,0x13    ;r19 = Zahl
.equ    ja_nein,0x14    ;r20 = ja/nein
begin:    rjmp    main    ; 1 POWER ON RESET
    reti        ; 2 Int0-Interrupt
    reti        ; 3 Int1-Interrupt
    reti        ; 4 TC2 Compare Match
    reti        ; 5 TC2 Overflow
    reti        ; 6 TC1 Capture
    reti        ; 7 TC1 Compare Match A
    reti        ; 8 TC1 Compare Match B
    reti        ; 9 TC1 Overflow
    reti        ;10 TC0 Overflow
    reti        ;11 SPI, STC Serial Transfer Complete
    reti        ;12 UART Rx Complete
    reti        ;13 UART Data Register Empty
    reti        ;14 UART Tx Complete
    reti        ;15 ADC Conversion Complete
    reti        ;16 EEPROM Ready
    reti        ;17 Analog Comparator
    reti        ;18 TWI (I²C) Serial Interface
    reti        ;19 Store Program Memory Ready
;----------------------------------------------------------------
; Initialisierungen
;----------------------------------------------------------------
main:
;--- Stack Initialisierung ---
    ldi    r16,hi8(RAMEND)
    out    SPH,r16
    ldi    r16,lo8(RAMEND)
    out    SPL,r16
    ldi    r16,0b11111111
    out    DDRB,r16    ;Konfiguration PORT B für LCD
    cbi    DDRC,0    ;Port C0 = IN für Taster
    sbi    PORTC,0    ;Pullup
    rcall    lcdInit
    rcall    lcdClear
    rcall    twiInitMaster
;----------------------------------------------------------------
; Hauptprogramm-Schleife
;----------------------------------------------------------------
mainloop:    wdr        ;Watchdog reset
    rcall    Text_1    ;Text 1 ans Display
    ldi    Zahl,0    ;Zahl 0 laden
    ldi    Stelle,3    ;Stelle 3 Zeile 1 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z1    ;und anzeigen
    ldi    Zahl,0    ;Zahl 0 laden
    ldi    Stelle,11    ;Stelle 11 Zeile 1 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z1    ;und anzeigen
    ldi    Zahl,0    ;Zahl 0 laden
    ldi    Stelle,3    ;Stelle 3 Zeile 2 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z2    ;und anzeigen
    ldi    Adresse,0x00    ;Busadresse 0 laden
loop:    ;Hauptschleife
    mov    Zahl,Adresse    ;Busadresse zu Zahl kopieren
    ldi    Stelle,3    ;Stelle 3 Zeile 1 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z1    ;und anzeigen
    rcall    twiStart    ;TWI starten
    mov    r16,Adresse    ;Adresse ins TWI-Register
    clr    r15    ;kein ACKN
    rcall    twiWriteByte    ;TWI schreiben
    inc    Adresse    ;Adresse um 1 erhöhen
    inc    Adresse    ;nochmal um 1 erhöhen
    wdr        ;Watchdog reset
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    rcall    wait_10ms    ;warten
    cpi    Adresse,254    ;Ende des Scanns?
    brne    loop    ;nein dann zur Hauptschleife
    cpi    ja_nein,0    ;Slave gefunden ja/nein
    brne    nein    ;ja
    rcall    Text_2    ;Text kein Slave gefunden
    rjmp    warte_2    ;zur Warteschleife 2
nein:    rcall    Text_3    ;Text Ende des Scanns
    ldi    ja_nein,0    ;Slave gefunden Register
            ;auf Null setzen
warte_2:    wdr        ;Warteschleife 2
    sbic    PINC,0    ;warte auf Taster
    rjmp    warte_2
    rjmp    mainloop    ;dann zurück zum Start
;----- Unterprogramm Slave gefunden -----
Slave_gefunden:
    ldi    ja_nein,1    ;Slave gefunden Register
    mov    Zahl,Adresse    ;Busadresse zu Zahl kopieren
    ldi    Stelle,11    ;Stelle 11 Zeile 1 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z1    ;und anzeigen
    inc    Zahl    ;erhöhe Zahl um 1
    ldi    Stelle,3    ;Stelle 3 Zeile 2 laden
    rcall    LCD_Aufbereitung    ;für Display aufbereiten
    rcall    Anzeige_Z2    ;und anzeigen
warte_1:    wdr;Warteschleife    1
    sbic    PINC,0    ;warte auf Taster
    rjmp    warte_1
    ret
;----------------------------------------------------------------
;----- Unterprogramm Aufbereitung von Zahlen für LCD Anzeige -----
LCD_Aufbereitung:
    push    r21
    push    r22
    push    r23
    push    r24
    mov    r23,Zahl
    ldi    r21,0
    ldi    r22,0
main1:    cpi    r23,10
    brlo    main2
    subi    r23,10
    inc    r21
    rjmp    main1
main2:    cpi    r21,10
    brlo    main4
    subi    r21,10
    inc    r22
    rjmp    main2
main4:    ldi    r24,0b00110000
    add    r23,r24
    sts    0x70,r23
    add    r21,r24
    sts    0x71,r21
    add    r22,r24
    sts    0x72,r22
    pop    r24
    pop    r23
    pop    r22
    pop    r21
    ret
;----------------------------------------------------------------
;----- Text    Adresse, Read, Write am Display anzeigen ------
Text_1:    push    r16
    rcall    lcdClear    ;Display löschen
    ldi    r16,0b10000000    ;0
    rcall    lcdCmd
    ldi    r16,'A'    ;"A"
    rcall    lcdOut
    ldi    r16,0b10000001    ;1
    rcall    lcdCmd
    ldi    r16,':'    ;":"
    rcall    lcdOut
    ldi    r16,0b10001000    ;2
    rcall    lcdCmd
    ldi    r16,'W'    ;"W"
    rcall    lcdOut
    ldi    r16,0b10001001    ;2
    rcall    lcdCmd
    ldi    r16,':'    ;":"
    rcall    lcdOut
    ldi    r16,0b11000000    ;3
    rcall    lcdCmd
    ldi    r16,'R'    ;"R"
    rcall    lcdOut
    ldi    r16,0b11000001    ;4
    rcall    lcdCmd
    ldi    r16,':'    ;":"
    rcall    lcdOut
    ldi    r16,0b11001111    ;5
    rcall    lcdCmd
    ldi    r16,'>'    ;">"
    rcall    lcdOut
    pop    r16
    ret
;----------------------------------------------------------------
;----- Text Error kein Slave gefunden am Display anzeigen ------
Text_2:    push    r16
    rcall    lcdClear    ;Display löschen
    ldi    r16,0b10000000    ;0
    rcall    lcdCmd
    ldi    r16,'E'    ;"E"
    rcall    lcdOut
    ldi    r16,0b10000001    ;1
    rcall    lcdCmd
    ldi    r16,'r'    ;"r"
    rcall    lcdOut
    ldi    r16,0b10000010    ;2
    rcall    lcdCmd
    ldi    r16,'r'    ;"r"
    rcall    lcdOut
    ldi    r16,0b10000011    ;3
    rcall    lcdCmd
    ldi    r16,'o'    ;"o"
    rcall    lcdOut
    ldi    r16,0b10000100    ;4
    rcall    lcdCmd
    ldi    r16,'r'    ;"r"
    rcall    lcdOut
    ldi    r16,0b10000101    ;5
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b10000110    ;6
    rcall    lcdCmd
    ldi    r16,'k'    ;"k"
    rcall    lcdOut
    ldi    r16,0b10000111    ;7
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b10001000    ;8
    rcall    lcdCmd
    ldi    r16,'i'    ;"i"
    rcall    lcdOut
    ldi    r16,0b10001001    ;9
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b10001010    ;10
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b10001011    ;11
    rcall    lcdCmd
    ldi    r16,'S'    ;"S"
    rcall    lcdOut
    ldi    r16,0b10001100    ;12
    rcall    lcdCmd
    ldi    r16,'l'    ;"l"
    rcall    lcdOut
    ldi    r16,0b10001101    ;13
    rcall    lcdCmd
    ldi    r16,'a'    ;"a"
    rcall    lcdOut
    ldi    r16,0b10001110    ;14
    rcall    lcdCmd
    ldi    r16,'v'    ;"v"
    rcall    lcdOut
    ldi    r16,0b10001111    ;15
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b11000000    ;0
    rcall    lcdCmd
    ldi    r16,'g'    ;"g"
    rcall    lcdOut
    ldi    r16,0b11000001    ;1
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b11000010    ;2
    rcall    lcdCmd
    ldi    r16,'f'    ;"f"
    rcall    lcdOut
    ldi    r16,0b11000011    ;3
    rcall    lcdCmd
    ldi    r16,'u'    ;"u"
    rcall    lcdOut
    ldi    r16,0b11000100    ;4
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b11000101    ;5
    rcall    lcdCmd
    ldi    r16,'d'    ;"d"
    rcall    lcdOut
    ldi    r16,0b11000110    ;6
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b11000111    ;7
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b11001000    ;8
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001001    ;9
    rcall    lcdCmd
    ldi    r16,'!'    ;"!"
    rcall    lcdOut
    ldi    r16,0b11001010    ;10
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001011    ;11
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001100    ;12
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001101    ;13
    rcall    lcdCmd
    ldi    r16,' '    ;":"
    rcall    lcdOut
    ldi    r16,0b11001110    ;14
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001111    ;15
    rcall    lcdCmd
    ldi    r16,'>'    ;">"
    rcall    lcdOut
    pop    r16
    ret
;----------------------------------------------------------------
;----- Text    Ende    des Scanns ------
Text_3:    push    r16
    rcall    lcdClear    ;Display löschen
    ldi    r16,0b10000000    ;0
    rcall    lcdCmd
    ldi    r16,'E'    ;"E"
    rcall    lcdOut
    ldi    r16,0b10000001    ;1
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b10000010    ;2
    rcall    lcdCmd
    ldi    r16,'d'    ;"d"
    rcall    lcdOut
    ldi    r16,0b10000011    ;3
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b10000100    ;4
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b10000101    ;5
    rcall    lcdCmd
    ldi    r16,'d'    ;"d"
    rcall    lcdOut
    ldi    r16,0b10000110    ;6
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b10000111    ;7
    rcall    lcdCmd
    ldi    r16,'s'    ;"s"
    rcall    lcdOut
    ldi    r16,0b10001000    ;8
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b10001001    ;9
    rcall    lcdCmd
    ldi    r16,'S'    ;"S"
    rcall    lcdOut
    ldi    r16,0b10001010    ;10
    rcall    lcdCmd
    ldi    r16,'c'    ;"c"
    rcall    lcdOut
    ldi    r16,0b10001011    ;11
    rcall    lcdCmd
    ldi    r16,'a'    ;"a"
    rcall    lcdOut
    ldi    r16,0b10001100    ;12
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b10001101    ;13
    rcall    lcdCmd
    ldi    r16,'n'    ;"n"
    rcall    lcdOut
    ldi    r16,0b10001110    ;14
    rcall    lcdCmd
    ldi    r16,'s'    ;"s"
    rcall    lcdOut
    ldi    r16,0b10001111    ;15
    rcall    lcdCmd
    ldi    r16,'!'    ;"!"
    rcall    lcdOut
    ldi    r16,0b11000000    ;0
    rcall    lcdCmd
    ldi    r16,'N'    ;"N"
    rcall    lcdOut
    ldi    r16,0b11000001    ;1
    rcall    lcdCmd
    ldi    r16,'e'    ;"e"
    rcall    lcdOut
    ldi    r16,0b11000010    ;2
    rcall    lcdCmd
    ldi    r16,'u'    ;"u"
    rcall    lcdOut
    ldi    r16,0b11000011    ;3
    rcall    lcdCmd
    ldi    r16,'s'    ;"s"
    rcall    lcdOut
    ldi    r16,0b11000100    ;4
    rcall    lcdCmd
    ldi    r16,'t'    ;"t"
    rcall    lcdOut
    ldi    r16,0b11000101    ;5
    rcall    lcdCmd
    ldi    r16,'a'    ;"a"
    rcall    lcdOut
    ldi    r16,0b11000110    ;6
    rcall    lcdCmd
    ldi    r16,'r'    ;"r"
    rcall    lcdOut
    ldi    r16,0b11000111    ;7
    rcall    lcdCmd
    ldi    r16,'t'    ;"t"
    rcall    lcdOut
    ldi    r16,0b11001000    ;8
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001001    ;9
    rcall    lcdCmd
    ldi    r16,'?'    ;"?"
    rcall    lcdOut
    ldi    r16,0b11001010    ;10
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001011    ;11
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001100    ;12
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001101    ;13
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001110    ;14
    rcall    lcdCmd
    ldi    r16,' '    ;" "
    rcall    lcdOut
    ldi    r16,0b11001111    ;15
    rcall    lcdCmd
    ldi    r16,'>'    ;">"
    rcall    lcdOut
    pop    r16
    ret
;----- LCD Anzeige Zeile 1------
Anzeige_Z1:    push    r16
    ldi    r16,0b10000000    ;Register Zeile 1
    add    r16,r17
    rcall    lcdCmd
    lds    r16,0x72    ;Ziffer    1
    rcall    lcdOut
    lds    r16,0x71    ;Ziffer 2
    rcall    lcdOut
    lds    r16,0x70    ;Ziffer 3
    rcall    lcdOut
    pop    r16
    ret
;----- LCD Anzeige Zeile 2------
Anzeige_Z2:    push    r16
    ldi    r16,0b11000000    ;Register Zeile 2
    add    r16,r17
    rcall    lcdCmd
    lds    r16,0x72    ;Ziffer 1
    rcall    lcdOut
    lds    r16,0x71    ;Ziffer 2
    rcall    lcdOut
    lds    r16,0x70    ;Ziffer 3
    rcall    lcdOut
    pop    r16
    ret
;----------------------------------------------------------------
;----- Display inialisieren -----
myWait_ms:
    push    r16
    ldi    r16,1
myWait_ms_3:
    push    r16
    ldi    r16,5
myWait_ms_2:
    push    r16
    ldi    r16,255
myWait_ms_1:
    dec    r16
    brne    myWait_ms_1
    pop    r16
    dec    r16
    brne    myWait_ms_2
    pop    r16
    dec    r16
    brne    myWait_ms_3
    pop    r16
    dec    r16
    brne    myWait_ms
    ret
;--------------------------------------------------------------------
lcdOut:    push    r16
    push    r17
    push    r18
    ldi    r18,0b00010000
    mov    r17,r16    ;"Sicherungskopie" für
; die Übertragung des 2.Nibbles
    swap    r16    ;Vertauschen
    andi    r16,0b00001111    ;oberes Nibble auf Null setzen
    or    r16,r18    ;entspricht 0b00010000
    out    PORTB,r16    ;ausgeben
    rcall    lcdEnable    ;Enable-Routine aufrufen
; 2. Nibble, kein swap da es schon
; an der richtigen stelle ist
    andi    r17,0b00001111    ;obere Hälfte auf Null setzen
    or    r17,r18    ;entspricht 0b00010000
    out    PORTB,r17    ;ausgeben
    rcall    lcdEnable    ;Enable-Routine aufrufen
    rcall    lcdWait    ;Delay-Routine aufrufen
    pop    r18
    pop    r17
    pop    r16
    ret
;--------------------------------------------------------------------
; Warte-Routine für 5 ms
; die Routine wartet inclusive Aufruf 5,031 ms
;--------------------------------------------------------------------
lcdWait:    ldi    r16,20
    rcall    myWait_ms
    ret
;--------------------------------------------------------------------
lcdCmd:    push    r16
    push    r17
    push    r18
    mov    r17,r16    ;"Sicherungskopie" für
; die Übertragung des 2.Nibbles
    swap    r16    ;Vertauschen
    andi    r16,0b00001111    ;oberes Nibble auf Null setzen
    out    PORTB,r16    ;ausgeben
    rcall    lcdEnable    ;Enable-Routine aufrufen
; 2. Nibble, kein swap da es schon
; an der richtigen stelle ist
    andi    r17,0b00001111    ;obere Hälfte auf Null setzen
    out    PORTB,r17    ;ausgeben
    rcall    lcdEnable    ;Enable-Routine aufrufen
    rcall    lcdWait    ;Delay-Routine aufrufen
    pop    r18
    pop    r17
    pop    r16
    ret        ;zurück zum Hauptprogramm
;--------------------------------------------------------------------
lcdClear:    ldi    r16,0b00000001    ;Display löschen
    rcall    lcdCmd
    rcall    lcdWait
    ret
;---------------------------------------------------------------------
lcdEnable:    sbi    PORTB,5    ;Enable high
    nop        ;kurz warten
    nop
    nop
    cbi    PORTB,5    ;Enable wieder low
    ret
;----------------------------------------------------------------------
lcdHome:    ldi    r16,0b00000010    ;Cursor Anfang Zeile1
    rcall    lcdCmd
    rcall    lcdWait
    ret
;----------------------------------------------------------------
lcdLine1:    ldi    r16,0b10000000    ;DRAM auf Adresse 0x00
    rcall    lcdCmd
    rcall    lcdWait
    ret
;----------------------------------------------------------------
lcdLine2:    ldi    r16,0b11000000    ;DRAM auf Adresse 0x00
    rcall    lcdCmd
    rcall    lcdWait
    ret
;----------------------------------------------------------------
lcdInit:    cbi    PORTB,4    ; LDC RS = Low
    ldi    r18,20
powerUp:    rcall    lcdWait    ;warte bis PowerUp
    dec    r18
    brne    powerUp    ;Power-Up Wartezyklus min 30 ms
; sende Resetsequenz kompatibel zu HD44780 Industriestandard
    ldi    r16,0b00000011    ;Reset-Sequenz Teil 1
    out    PORTB,r16
    rcall    lcdEnable    ;Enable-Impuls
    rcall    lcdWait
    ldi    r16,0b00000011    ;Reset-Sequenz Teil 2
    out    PORTB,r16
    rcall    lcdEnable    ;Enable-Impuls
    rcall    lcdWait
    ldi    r18,100    ;Wartezyklus bei RESET LCD min 100 µs
resetLCD:    nop
    nop
    nop
    dec    r18
    brne    resetLCD
    ldi    r16,0b00000011    ;Reset-Sequenz Teil 3
    out    PORTB,r16
    rcall    lcdEnable    ;Enable-Impuls
    rcall    lcdWait
    ldi    r16,0b00000010    ;4 Bit Modus aktivieren
    out    PORTB,r16
    rcall    lcdEnable    ;Enable-Impuls
    rcall    lcdWait
    ldi    r16,0b00101000
    rcall    lcdCmd    ;Function Set 4 Bit, 2 Zeilen, 5x7
    ldi    r16,0b00001100
    rcall    lcdCmd
    ldi    r16,0b00000100
    rcall    lcdCmd    ;Entry Mode Set, increase+shifted
    ret
;----------------------------------------------------------------
; twiInitMaster (ohne Interrupt)
; gestattet die Benutzung von TWI und setzt die Master-Clock-Rate
;----------------------------------------------------------------
twiInitMaster:
    push    r16
    ldi    r16,((F_CPU/TWI_CLOCK)-16)*2    ; Clock
    out    TWBR,r16    ;TWI-Status-Register (Vorteiler)
    ldi    r16,0
    out    TWSR,r16    ;Enable
    ldi    r16,_TWINT|_TWEN
    out    TWCR,r16
    pop    r16
    ret
;----------------------------------------------------------------
; Start TWI
;----------------------------------------------------------------
twiStart:
    push    r16
    in    r16,TWCR
    andi    r16,_TWEN|_TWIE    ;nur Beibehalten von Enable und InterruptJ/N
    ori    r16,_TWINT|_TWSTA
    out    TWCR,r16
twiStartWait1:
    in    r16,TWCR
    sbrs    r16,7    ;TWINT
    rjmp    twiStartWait1
    pop    r16
    ret
;----------------------------------------------------------------
; Stopp TWI
;----------------------------------------------------------------
twiStopp:
    push    r16
    in    r16,TWCR
    andi    r16,_TWEN|_TWIE    ;nur Beibehalten von Enable und InterruptJ/N
    ori    r16,_TWINT|_TWSTO
    out    TWCR,r16
    pop    r16
    ret
;----------------------------------------------------------------
; Write Byte per TWI (ohne Interrupt)
; PE: r16 = Data
;     r15.0 = 1 -> Acknowledge (=TWEA) setzten für Datenanforderung
;----------------------------------------------------------------
twiWriteByte:
    push    r16
    out    TWDR,r16    ;Daten bereitlegen
    in    r16,TWCR
    andi    r16,_TWEN|_TWIE    ;nur Beibehalten von Enable und InterruptJ/N
    ori    r16,_TWINT
    sbrc    r15,0
    ori    r16,_TWEA    ;evt. TWEA setzen, für Datenanforderung
    out    TWCR,r16    ;senden
twiWriteByteWait2:
    in    r16,TWCR
    push    r16
    in    r16,TWSR
    cpi    r16,24    ;feststellen der Slaveadresse
    brne    weiter
    rcall    Slave_gefunden    ;zum Unterprog Slave Adressen
weiter:    pop    r16
    sbrs    r16,7    ;Twint
    rjmp    twiWriteByteWait2
    pop    r16
    ret
;----------------------------------------------------------------
; Read Byte per TWI (ohne Interrupt)
; PE: r15.0 = 1 -> Acknowledge (=TWEA) setzten für Datenanforderung
; PA: r16 = Data
;----------------------------------------------------------------
twiReadByte:
    in    r16,TWCR
    andi    r16,_TWEN|_TWIE
    ori    r16,_TWINT
    sbrc    r15,0
    ori    r16,_TWEA    ;evt. TWEA setzen, für Datenanforderung
    out    TWCR,r16
twiReadByteWait2:
    in    r16,TWCR
    sbrs    r16,7    ;TWINT
    rjmp    twiReadByteWait2
    in    r16,TWDR
    ret
;----------------------------------------------------------------
wait_10ms:
    push    r16
    ldi    r16,10
    rcall    myWait_ms
    pop    r16
    ret
;----------------------------------------------------------------
 
  • Like
Reaktionen: Dirk
Die Adresse ist Schreiben A1 und Lesen B1
Das ist unplausibel, in beiden Fällen ist das LSB=1 (das Low-Nibble ist 0001), was gemäß I²C 'ne "Leseadresse" darstellt. (Der Master wechselt nach dem ACK des Slave-Receivers vom Master-Transmitter in den Master-Receiver Mode, der Slave soll folglich Slave-Transmitter werden...)

Laut Datenblatt (sowohl des HMC5883 als auch des HMC5883L) ist die 7-Bit Adresse die 0011110=0x1E.
Zum Schreiben 'ne Null dran ergibt als Schreibadresse die 00111100=0x3C
Zum Lesen 'ne Eins dran ergibt als Leseadresse die 00111101=0x3D

Nebenbei:
bei den 7-Bit-Adressen ist nur der Raum 0x08..0x77 erlaubt; alle anderen Adressen sind reserviert.
Die Adressen die mit 111_10xx beginnen, stehen für 10-Bit-Adressierung. Genauer in zwei Bytes, die beide vom Slave zu ACKen sind:
1|1|1|1|0|A9|A8|R/W - A7|A6|A5|A4|A3|A2|A1|A0
 
Zuletzt bearbeitet:

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)