- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 8 von 8

Thema: Hardware-I2C klappt nicht

  1. #1
    Murus
    Gast

    Hardware-I2C klappt nicht

    Anzeige

    Praxistest und DIY Projekte
    Hallihallo zusammen,

    ich möchte bei einem Mega8 das hardwareseitige I2C-Interface benutzen.
    Momentan läuft die Sache mit dem Software-I2C von Bascom. Dies möchte ich ändern und stattdessen den Code umschreiben, damit das AVR interne Modul verwendet wird.
    Angesprochen wird ein Temperatursensor (DS1631Z)

    Leider funktioniert die Hardware-Version nicht und ich weiss nicht wieso, hier die Codes:

    Auszug aus dem funktionierenden Code:

    Code:
    ' I2C initialisieren:
    Config Scl = Portc.5                                        'Is serial clock SCL
    Config Sda = Portc.4
    Const Schreiben = &B10010000       ' Schreibadresse                      
    Const Lesen = &B10010001             ' Leseadresse
    .
    .
    .
    ' Thermometer soll Temperatur messen:
    I2cstart
    I2cwbyte Schreiben
    I2cwbyte &H51           ' Befehl fürs Temperaturmessen schicken
    I2cstop
    
    Waitms 30
    
    ' Thermometer soll Temperatur an den AVR schicken:
    I2cstart
    I2cwbyte Schreiben
    I2cwbyte &HAA         'Temperaturausgabe-Befehl schicken
    I2cstart
    I2cwbyte Lesen
    I2crbyte Twidaten1 , Ack
    I2crbyte Twidaten2 , Nack
    I2cstop
    Dieser Code funktioniert wunderbar, die beiden Bytes Twidaten1 und Twidaten2 enthalten dann die Temperatur des Thermometers. Die Routine zum Ansprechen des Temperatursensors stimmt auch, das klappt also.

    Dieses Vorgehen möchte ich nun mit der Hardware-Lösung machen. Hier das momentane, leider nicht funktionale Listing:

    Code:
    'Das I2C-Interface initialisieren:
    Twsr = &B00000000                                           ' Prescaler = 1
    Twbr = 10                                                   ' Frequenz des TWi:  10,4kHz
    .
    .
    .
     'Befehl zum Messen ausgeben:
        Twcr = &B10100100                                       ' Start erzeugen
         Gosub Twiloopsub                                       ' Warten bis fertig
    
        Twdr = &B10010000                                       ' Slave Adresse senden
        Twcr = &B10000100                                       ' Aktion auslösen
        Gosub Twiloopsub                                        ' Warten bis fertig
    
        Twdr = &B1010001                                        ' Befehl zum Messen senden
        Twcr = &B10000100                                       ' Aktion auslösen
         Gosub Twiloopsub                                       ' Warten bis fertig
    
        Twcr = &B10010100                                       ' Stop
    
        Waitms 30
    
       'Temperaturwert einlesen:
    
         Twcr = &B10100100                                      ' Start erzeugen
         Gosub Twiloopsub                                       ' Warten bis fertig
    
        Twdr = &B10010000                                       ' Slave Adresse senden
        Twcr = &B10000100                                       ' Aktion auslösen
        Gosub Twiloopsub                                        ' Warten bis fertig
    
        Twdr = &B10101010                                       ' Befehl senden
        Twcr = &B10000100                                       ' Aktion auslösen
        Gosub Twiloopsub                                        ' Warten bis fertig
    
        Twcr = &B10100100                                       ' Erneut Start erzeugen
        Gosub Twiloopsub                                        ' Warten bis fertig
    
        Twdr = &B10010001                                       ' Slave Adresse senden (lesen)
        Twcr = &B10000100                                       ' Aktion auslösen
        Gosub Twiloopsub                                        ' Warten bis fertig
    
        Twcr = &B11000100                                       ' Ack erzeugen
        Gosub Twiloopsub
        Twidaten1 = Twdr
    
        Twcr = &B10000100                                       ' Nack erzeugen
        Gosub Twiloopsub
        Twidaten2 = Twdr
    
        Twcr = &B10010100                                       ' Stop
    
        ' Twidaten1/2 enthalten den Temperaturwert.
    
    Twiloopsub:
    Do : Loop Until Twcr.twint = 1    ' Dann ist TWI-Aktion beendet. 
    
    Return
    Diese beiden Listings sollten genau das Gleiche machen, dem Sensor sagen, er soll messen und dann den Wert abrufen.
    Nur klappt das mit der zweiten Variante gar nicht.
    Twidaten1 enthält immer den Wert 196 und Twidaten2 den Wert 0. Eine Kommunikation zum Sensor findet also nicht statt.

    Sieht jemand gerade eine Lösung für dieses Problem?

    Herzlichen Gruss und vielen Dank

    Mario

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo,

    wenn du von Soft-I2C auf Hardware umstellen möchstest, und schon einen Code hast der läuft, geht das am einfachsten in dem man die I2C-TWI-Lib einbindet:
    Diese Zeile irgendwo am Anfang des Programms:
    Code:
    $lib "i2c_twi.lbx"
    Schon wird die Hardware verwendet, und man kann die gewohnten Bascom-Befehle für I2C verwenden.

    Was man dann aber noch angeben muss, ist die Geschwindigkeit, und damit die Register initialisiert werden:
    Code:
    Config Twi = 400000
    ' auch am Anfang irgendwo
    Man muss ja nicht immer alles neu erfinden

  3. #3
    Murus
    Gast
    Hmmm... eigentlich hab ich gedacht, ich lese halt mal das DB und strick mir so was zusammen. Möchte von diesen Bascom-Highlevel-Befehlen etwas loskommen.
    Deshalb wäre es super, direkt die AVR-Register zu konfigurieren... Es kommt mir mehr auf den Lerninhalt darauf an, als auf die Funktion.

    Deshalb wäre es super, wenn das auch noch funktionieren würde. Ich mache mal ein anderes Programm, welches die Statuscodes des AVRs noch auswertet, dann seh ich mal, wo es klemmt.
    Der Hardware-Code sollte doch stimmen, oder? Oder vergesse ich etwas? Die Subroutine hab ich gemacht, um Speicher zu sparen. Sie sollte auch angesprungen werden, habe swstack, hwstack und framesize auf 128 gesetzt.
    Achja: der AVR läuft intern mit 1MHz, die I2C-Frequenz ist 10,4kHz.

    Herzlichen Gruss
    Mario

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Schau mal ins Wiki, erst bei TWI dann auch die Seite TWI-Praxis,
    da hab ich mal was vorbereitet
    Für Slave und Master.

    Speichersparen würde ich erst anfangen wenns läuft, dann kann man an den verschiedenen Stellen zum optimieren anfangen.

  5. #5
    Murus
    Gast
    Ok, hab mal im TWI-Praxis rumgewühlt.

    Morgen werde ich mal diesen Code ausprobieren:

    Code:
    $regfile = "m8def.dat"
    $crystal = 1000000
    $baud = 1200
    $swstack = 128
    $hwstack = 128
    $framesize = 128
    
    
    'Nun eine Temperatur messen:
    
    Twcr = &B10100100   ' Start erzeugen
    Gosub Twiloopsub    ' Warten bis Start erzeugt
    
    If Status = &H08 Or Status = &H10 Then       ' falls start gesendet
       Twdr = &B10010000       ' Slave Adresse senden  (w)
       Twcr = &B10000100       ' Aktion auslösen
       Gosub Twiloopsub ' Warten bis fertig
    
       If Status = &H18 Or Status = &H40 Then       ' falls ack empfangen
       Twdr = &B1010001 ' Befehl zum Messen senden
       Twcr = &B10000100       ' Aktion auslösen
       Gosub Twiloopsub ' Warten bis fertig
    
          If Status = &H28 Then
          Twcr = &B10010100       ' Stop
          ' warten bis stop-flag gelöscht:
          Do
          Loop Until Twcr.twsto = 0
    
          Else
          Print "byte nicht gesendet"
          Print Status
    
          End If
    
    
       Else
       Print "kein addressack"
       Print Status
    
       End if
    
    Else
    Print "Startfehler"
    Print Status
    
    End If
    
    ' nun auslesen:
    Twcr = &B10100100   ' Start erzeugen
    Gosub Twiloopsub    ' Warten bis fertig
    
    If Status = &H08 Or Status = &H10 Then
    Twdr = &B10010000   ' Slave Adresse senden (w)
    Twcr = &B10000100   ' Aktion auslösen
    Gosub Twiloopsub    ' Warten bis fertig
    
        If Status = &H18 Then       ' falls ack vom slave
        Twdr = &B10101010       ' Befehl senden
        Twcr = &B10000100       ' Aktion auslösen
        Gosub Twiloopsub       ' Warten bis fertig
    
          If Status = &H28 Then       ' falls ack vom slave
          Twcr = &B10100100       ' Erneut Start erzeugen
          Gosub Twiloopsub       ' Warten bis fertig
    
             If Status = &H08 Or Status = &H10 Then       ' falls 2.start gesendet
             Twdr = &B10010001       ' Slave Adresse senden (lesen)
             Twcr = &B10000100       ' Aktion auslösen
             Gosub Twiloopsub       ' Warten bis fertig
    
                If Status = &H40 Then       ' falls slave addr. gelesen raus
                Twcr = &B11000100       ' Ack erzeugen
                Gosub Twiloopsub       ' warten bis empfangen
    
                   If Status = &H58 Or Status = &H50 Then       ' dann auslesen
                   Twidaten1 = Twdr
                   Else
                   Print "nichts empfangen 1"
                   Print Status
                   End If
    
                Twcr = &B10000100       ' Nack erzeugen
                Gosub Twiloopsub
    
                   If Status = &H58 Or Status = &H50 Then
                   Twidaten2 = Twdr
                   Else
                   Print "nichts empfangen 2"
                   Print Status
                   End If
    
                Twcr = &B10010100       ' Stop
    
    
    
    
                Else
                Print "kein lese-slave"
                Print Status
                End If
    
             Else
             Print "kein 2.Start raus"
             Print Status
             End If
    
          Else
          Print "kein command gesendet"
          Print Status
          End If
    
       Else
       Print "kein slaveschreib"
       Print Status
       End If
    
    Else
    Print "kein Start"
    Print Status
    End If
    
        ' Twidaten1/2 enthalten den Temperaturwert.
    Print Twidaten1
    Print Twidaten2
    
    Twiloopsub:
    Do : Loop Until Twcr.twint = 1
    Status = Twsr And &HF8
    Return
    Mal schauen, was sich da so tut...

  6. #6
    Murus
    Gast
    Huch, jetzt steh ich aber ganz auf dem Schlauch.

    Hab jetzt den obigen Code mit der Statusauswertung getestet. (Habe zusätzlich alle Statusinformationen per UART ausgeben lassen)

    Gemäss den Statusbytes funktioniert alles prächtig. Die Kommunikation mit dem Thermometer läuft haargenau nach dem Protokoll ab, genau so, wie es sein muss, die Statusbytes stimmen immer völlig überein.

    Nur enthalten die beiden Bytes Twidaten1/2 falsche Informationen... Twidaten1 hat immer den Wert 196 und Twidaten2 hat den Wert 0, obwohl die Kommunikation zum Thermometer funktioniert.

    Jetzt kommt natürlich der Verdacht auf, dass das twdr nicht korrekt in die Bascom-Variable übernommen wird... twidaten1/2 sind beide als Byte deklariert...
    Zur Erinnerung: die Bascom-Software Routine funktioniert. Da werden alle Werte korrekt übernommen und angezeigt. Gemäss Statusbyte-Auswertung funktioniert auch meine Kommunikation, nur enthalten die beiden Bytes falsche Daten (Twidaten1 und Twidaten2)...

    Was kann das sein?

    Hier noch die Status Bytes der Kommunikation mit dem Temperatursensor. Zuerst wird der Befehl geschickt, eine Messung zu starten. Danach soll das Thermometer den Wert ausgeben (2 Bytes):

    H8 - Start gesendet
    H18 - Slaveadresse für schreiben gesendet, Ack empfangen
    H28 - Datenbyte gesendet, Ack empfangen (Befehl für Temperaturmessung)

    Nun die Temperatur auslesen:
    H8 - Start gesendet
    H18 - Slaveadresse für Schreiben gesendet, Ack empfangen
    H28 - Datenbyte gesendet, Ack empfangen (Befehl zum Temperatur ausgeben)
    H10 - Wiederholter Start gesendet (muss so sein)
    H40 - Slaveadresse für Lesen gesendet, Ack empfangen
    H50 - Datenbyte empfangen, Ack empfangen (Temperaturbyte 1 vom Thermometer, AVR muss Ack ausgeben)
    H58 - Datenbyte empfangen, NAck empfangen (Temperaturbyte 2 vom Thermometer, AVR muss NACK ausgeben)

    Von daher scheint es ja zu funktionieren... nur enthalten die beiden Temperaturbytes Käse...

    What to do?

    Gruss
    Mario

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Wenn er 196 zurückliefert hat er noch nix gemessen, scheint als klappt das starten der Messung nicht, dann kommt immer -60°C raus !
    Das kommt aber auch raus, wenn man beim ersten mal zu schnell ausliest, man muss dem DS1631 etwas Zeit lassen damit er messen kann, bis zu 750ms bei max. Auflösung (laut DB) !

    Wie oft hintereinander hast Du gemessen, lass mal solange die Temperatur auslesen bis ein anderer Wert kommt ?!

    Schreib auch mal das 8. Bit in der Zeile "Befehl zum Messen senden" dazu, oder gibs auch Hexadezimal an (&H51), nicht das Bascom das anders umrechnet

  8. #8
    Murus
    Gast
    Achjaa.. stimmt... der Sensor braucht ja seine 750ms... heieiei... voll vergessen...

    *ausprobier*

    Jaaa... es geht Das fehlende 8. Bit ist ein Tippfehler, im Code passts.

    Suupi, vielen Dank für den Hinweis!!

    Herzlichen Gruss und Danke

    Mario

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress