- LiFePO4 Speicher Test    Werbung      
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 34

Thema: SRF02. Wie ohne Timer Messwert-Abfrage steuern

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Zitat Zitat von oberallgeier Beitrag anzeigen
    Tja. Wenn ich dieses Detail nur kapieren würde.

    Im Internet hatte ich folgende Anleitung gefunden:
    Code:
    Busy Test geht so: 
    1. Start senden 
    2. Adresse + W senden 
    3. ACK lesen 
    4. if ACK gehe zu 7. 
    5. Stop senden 
    6. gehe zu 1. 
    7. Stop senden 
    Ende
    Soo schwer ist I2C nicht. Ich benutze dazu keine Libraries, die "paar" Zeilen mach ich selber (dann sind auch Fehler im Code meine eigenen).

    Ich versuch mal eine Erklärung:
    Für jedes Byte werden 9 Bit übertragen. Wenn der Master schreibt, schickt er die ersten 8 Bit (die Daten) und der Slave quitiert beim 9. Takt mit ACK, bzw. quitiert nicht also NAK.

    Wenn der Master liest, taktet er 8 Bit ein (der Master gibt immer den Takt vor) und liefert mit dem 9. Takt entweder ACK oder NAK.

    Dann kann der Master auf dem Bus noch eine Startkondition oder eine Stopkondition anlegen. Das sind feste Zustände. Und als letztes: treibt der Master den Bus nicht und sind SCL und SDA high, ist der Bus idle.

    Die passenden Timingdiagramme gibt es zuhauf in den diversen Datenblättern von I2C Chips oder hier. Das ist eigentlich schon alles über den Datentransfer auf dem I2C Bus.

    Und jetzt zu dem Ablauf von oben:

    Busy Test geht so:
    1. Start senden

    Eigentlich sollte man zuerst prüfen, ob der Bus idle ist, also SDA und SCL == 1. Wenn ja, eine Startkondition erzeugen. Ist häufig einfach ein Bit im Controler setzen.
    2. Adresse + W senden
    Das erste Byte nach dem Start muß das Adressbyte sein, oberste 7 Bit die I2C-Adresse des Slave, unterste Bit das R/W bit. Das wird typisch ins Datenregister des Chips geschrieben, der erzeugt dann die erforderlichen 9 Takte und liefert das ACK bzw. NAK in einem Bit zurück. Bei einem NAK muß die Übertragung mit Stop abgebrochen werden
    3. ACK lesen
    4. if ACK gehe zu 7.
    5. Stop senden

    Das ist hier passiert
    6. gehe zu 1.
    Slave not ready, weiter probieren. Es könnte aber auch bedeuten, Slave garnicht da, hat sich ausgelötet , Adresse ist falsch etc
    7. Stop senden
    Das müßte man nicht machen, der Slave ist da und bereit, man könnte jetzt die Registeradresse schreiben und dann erst Stop anlegen.

    Ein "I2C read" ist hier nicht vorgekommen, daher halte ich die Verwendung einer Funktion mit "read" im Namen für falsch (ich kenne die Library nicht). Ich vermute aber mal so ins Blaue: die Funktion i2c_start() liefert als Returnwert den Status des ACK-Bits.

    Ich hoffe, das hilft etwas weiter.

    @Sternthaler
    In deiner while(1)-Schleife ist KEIN wait enthalten.
    In dem Beispiel ist ein 'Wait' mit Bascom als "Waitms 1" angegeben.
    Ich bin nicht sicher, aber ein "Dauerfeuer" auf dem Bus ist nicht erlaubt.
    Ein "Dauerfeuer" wie du es nennst, ist selbstverständlich erlaubt. Man muß sich nur an die Setup und Holdzeiten der Chips halten und das sind ganz wenige µs eher Nanosekunden. So schnell kann dein Programm garnicht laufen. Und Chips, die eine lange Leitung haben, quitieren nicht (was dann ein NAK ist) solange sie nicht fertig sind.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  2. #2
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Zitat Zitat von oberallgeier Beitrag anzeigen
    ## Timer1 = 2
    lobyte = 6

    Das Ergebnis bedeutet, dass ich a) mehr als zwischen 100 µs und 150 µs fürs abarbeiten gebraucht habe und dass b) das gelesene Byte die ominöse 6 ist. Der Fall a) würde bedeuten, dass die zum Lesen vom SRF02 benötigten 75 ms (MILLI !) nicht erreicht wurden. In < 150 µs läuft der Schall ganz grob 5 cm, der Sensor hat aber rund 2 m bis zum Echo . . .
    Hallo oberallgeier,
    nochmals ich.

    Ich rechne mal etwas anders als du.
    Wenn der Schall 300 Meter pro Sekunde schafft, dann sind das 300 * 100cm / 1000ms * 75ms-Messdauer = 2250 cm Weg.

    Unser Schall muss hin und zurück laufen. Somit vom SRF02 zum Hinderniss die Hälfte: 1125 cm Weg.
    Die Reichweite vom Sensor wird mit 600 cm angegeben und entspricht somit ca. der Hälfte 'meiner' Rechnung.

    Wenn also der Piepston mit einer Dauer von NULL erzeugt würde, könnte der Sensor in der Zeit die doppelte Entfernung schaffen.
    Ich gehe also davon aus, dass auch das Piepen selbst schon Zeit benötigt
    Evenuell wird auch zwei mal 'gepiept' um eine Mittelwertmessung zu machen.

    cu Sternthaler

    - - - Aktualisiert - - -

    Zitat Zitat von Klebwax Beitrag anzeigen
    Ein "Dauerfeuer" wie du es nennst, ist selbstverständlich erlaubt. Man muß sich nur an die Setup und Holdzeiten der Chips halten und das sind ganz wenige µs eher Nanosekunden. So schnell kann dein Programm garnicht laufen. Und Chips, die eine lange Leitung haben, quitieren nicht (was dann ein NAK ist) solange sie nicht fertig sind.
    Hallo Klebwax,

    jepp, du hast Recht mit deinen Zeitangaben.
    Ich hatte im Hinterkopf, dass im dicken AVR-Handbuch so eine Zeitangabe zwischen STOP und nächstem START angegeben ist.

    Nun wiedergefunden im Kapitel "Electrical Characteristics" und Unterkapitel "Two-wire Serial Interface Characteristics" aus einer Atmel-Doku zum ATmega48A bis 328P:

    Bus free time between a STOP and START condition
    fSCL < 100kHz 4.7 – μs
    fSCL > 100kHz 1.3 – μs


    oberallgeier ist beim I2C mit 400 kHz unterwegs und somit sind 1.3 μs nun nicht wirklich die Welt. Aber trotzdem schaffen seine 20 MHz dann schon 26 1-Takt Befehle!
    Und nun könnte man mal schauen, was zwischen i2c_stop() und dem nächsten i2c_start() an Maschinenbefehlen steht. (In der Loop gibt es das 2 mal.)

    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.735
    Erstmal vielen Dank Klebwax und Sternthaler für eure Geduld und Ausdauer.
    Soo schwer ist I2C nicht. Ich benutze dazu keine Libraries, die "paar" Zeilen mach ich selber ...
    Klar, das ist der richtige Ansatz. Bisher hatte ich die Anleitungen dazu in der Dokumentation von Fleury undoder von Atmel schon nach den ersten Zeilen wegen massiven Nichtverstehens weggelegt. Sorry. Das hatte mir schon vor vielen Monaten Schwierigkeiten gemacht - damals konnte ich nie schnellere I2C-Taktraten als 100 kHz störungsfrei fahren :-/ Hier bin ich mittlerweile mit so ner Art full speed (ok ok, da gibts natürlich Bremser vom Slave) störungsfrei *lichtblick*

    Grundlagen: Dokumentation zum mega1284 : 8272D–AVR–05/12 und die verwendete Bibliothek von PFleury : i2cmaster.zip

    Euer Entgegenkommen nutze ich mal noch mehr aus und versuche mal langsam mein Nicht-Verständnis abzubauen. Es fängt ja schon mit der von mir verwendeten Bibliothek an (Peter Fleurys I2C Master library).

    Code:
    Erklärung in der Dokumentation zur Bibliothek (siehe obigen Link "... Master lib..") :
    unsigned char i2c_start     (      unsigned char      addr      )      
    
    Issues a start condition and sends address and transfer direction.
    
    Parameters:
            addr     address and transfer direction of I2C device
    
    Return values:
            0     device accessible
            1     failed to access device 
    
    Hier die Startsequenz, stimmt im Wesentlichen mit der Dokumentation zum mega1284 überein.
    /*************************************************************************    
      Issues a start condition and sends address and transfer direction.
      return 0 = device accessible, 1= failed to access device
    *************************************************************************/
    unsigned char i2c_start(unsigned char address)
    {
        uint8_t   twst;
    
        // send START condition
        TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    
        // wait until transmission completed
        while(!(TWCR & (1<<TWINT)));
    
        // check value of TWI Status Register. Mask prescaler bits.
        twst = TW_STATUS & 0xF8;
        if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
    
        // send device address
        TWDR = address;
        TWCR = (1<<TWINT) | (1<<TWEN);
    
        // wail until transmission completed and ACK/NACK has been received
        while(!(TWCR & (1<<TWINT)));
    
        // check value of TWI Status Register. Mask prescaler bits.
        twst = TW_STATUS & 0xF8;
        if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
    
        return 0;
    
    }/* i2c_start */
    
    /*************************************************************************
    Hier fehlt >für mich< schon mal der Wert für TW_STATUS. In der Atmeldokumentation steht dazu TWSR z.B. auf Seite 220 bei Check value of TWI Status Register :

    Code:
    if ((TWSR & 0xF8) != START)
    ERROR();
    und pfleury schreibt dazu
    Code:
        // check value of TWI Status Register. Mask prescaler bits
        twst = TW_STATUS & 0xF8;
    In myfile.lls finde ich dazu:
    Code:
        // check value of TWI Status Register. Mask prescaler bits.
        twst = TW_STATUS & 0xF8;
         25c:    80 91 b9 00     lds    r24, 0x00B9
         260:    88 7f           andi    r24, 0xF8    ; 248
        if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
         262:    88 30           cpi    r24, 0x08    ; 8
         264:    21 f0           breq    .+8          ; 0x26e <i2c_start+0x22>
         266:    80 31           cpi    r24, 0x10    ; 16
         268:    11 f0           breq    .+4          ; 0x26e <i2c_start+0x22>
         26a:    81 e0           ldi    r24, 0x01    ; 1
         26c:    08 95           ret
    und weiter oben:
    Code:
    void i2c_init(void)
    {
      /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
      
      TWSR = 0;                         /* no prescaler */
         240:    10 92 b9 00     sts    0x00B9, r1
      TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
         244:    8c e0           ldi    r24, 0x0C    ; 12
         246:    80 93 b8 00     sts    0x00B8, r24
    
    }/* i2c_init */
         24a:    08 95           ret
    Und da setzts bei mir aus - ob das TWIStatusregister TWSR richtig angegeben ist. Und .. ich finde in den Quellen kein define für das TWSR . . .

    Einfach wäre es jetzt im fleury-code das TWI_TW_STATUS durch TWSR zu ersetzen. Aber es wäre eben experimentelle Softwareentwicklung :-/

    Danke im Voraus!

    Nachtrag:
    in der m1284def.inc steht bei "... TWI ..." nur:
    Code:
    ; TWSR - TWI Status Register
    .equ    TWPS0    = 0    ; TWI Prescaler
    .equ    TWPS1    = 1    ; TWI Prescaler
    .equ    TWS3    = 3    ; TWI Status
    .equ    TWS4    = 4    ; TWI Status
    .equ    TWS5    = 5    ; TWI Status
    .equ    TWS6    = 6    ; TWI Status
    .equ    TWS7    = 7    ; TWI Status
    Geändert von oberallgeier (30.09.2014 um 10:53 Uhr) Grund: Auszug aus der m1284def.inc zitiert
    Ciao sagt der JoeamBerg

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.735
    Meine Fehler sind ja noch schlimmer - im R N Wiki steht ein Beispielprogramm für den SRF02 MIT der Sequenz Warteaufmessung (in Bascom) die wohl genau das tut, was ich eigentlich suche:
    Code:
    '------------- Hilfsfunktionen für SRF02 ----------
    Function Srf02_firmware(byval Slaveid As Byte) As Byte
      Local Firmware As Byte
      Local Slaveid_read As Byte
      slaveid_read = Slaveid + 1
      I2cstart
      I2cwbyte Slaveid
      I2cwbyte 0 'Leseregister festlegen
      I2cstop
      I2cstart
      I2cwbyte Slaveid_read
      I2crbyte Firmware , Nack
      I2cstop
      Srf02_firmware = Firmware
    End Function
    
    Function Srf02_entfernung(byval Slaveid As Byte) As Integer
      Local Lob As Byte
      Local Hib As Byte
      Local Firmware As Byte
      Local Temp As Byte
      Local Slaveid_read As Byte
    
      slaveid_read = Slaveid + 1
    
      'Messvorgang in starten
      I2cstart
      I2cwbyte Slaveid
      I2cwbyte 0
      I2cwbyte 81 'in Zentimetern messen
      I2cstop
    
      Warteaufmessung:
        Waitms 1
        Firmware = Srf02_firmware(slaveid)
      If Firmware = 255 Then Goto Warteaufmessung
    
      I2cstart
      I2cwbyte Slaveid
      I2cwbyte 2 'Leseregister festlegen
      I2cstop
      I2cstart
      I2cwbyte Slaveid_read
      I2crbyte Hib , Ack
      I2crbyte Lob , Nack
      I2cstop
      Srf02_entfernung = Makeint(lob , Hib)
     End Function
    End
    Ciao sagt der JoeamBerg

  5. #5
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    Ich mache mit PICs rum und kenne mich daher mit AVR nicht so aus. Ich hab mir daher das Datenblatt von Atmel mal angesehen. Dafür hat Atmel weder einen Preis für Didaktik noch für Chipdesign verdient. Jetzt kann ich verstehen, weswegen viele I2C für kompliziert halten.

    Aber in deinem geposteten Code findet sich das wieder, was ich oben geschrieben habe. In i2c_start() wird alles nötige gemacht.

    also:
    Code:
    if(i2c_start(Adresse und Write) == 0) {
            Chip ist fertig mit der Messung und bereit zum Lesen
    	i2c_write(Registeradresse)
    	i2c_stop()
    	if(i2c_start(Adresse und Read) != 0) {
    		eben war der Chip doch noch bereit, was soll das jetzt? Selbstzerstörung einleiten??
    	}
    	ErsteByte = i2c_readAck()
    	ZweiteByte = i2c_readAck()
            .  .  .  .
    	LetzteByte = i2c_readNak()
    	i2c_stop()
    } else {
    	Chip noch nicht bereit, mach erstmal was anderes und versuchs später noch einmal
    }
    So sollte es gehen.

    Und zu deinem Problem mit TW_STATUS: wenn es nicht definiert wäre, würde der Compiler maulen. In dem meisten IDEs kann man sich irgendwie die Macroexpansion anzeigen lassen, da findet man dann auch wo das steht. Aber man kann da natürlich auch TWSR schreiben, das ist kein Experiment sondern aus dem Datenblatt. TW_STATUS hat sich auch nur jemand ausgedacht (weil es sich schöner liest?).

    etwas OT:
    Das ganze ist halt ein muchtiges Design. Das eigentlich Statuswort steht in den 5 oberen Bits von TWSR, kann man so machen, ist halt die Hardware. Aber in der Status-Codeliste immer die unteren Bits mitzuschleppen ist Krampf.

    Eigentlich müßte man schreiben:

    TwiStatus = TWSR >> 3

    Und dann kann man mit if oder case die Auswertung auf TwiStatus machen.

    Aber trotzdem schaffen seine 20 MHz dann schon 26 1-Takt Befehle!
    Da Start und Stop in Hardware erzeugt werden und im Code darauf gewartet wird, das sich der Status ändert, spielt das keine Rolle.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.735
    Ich mache mit PICs rum ... Datenblatt von Atmel ... weder einen Preis für Didaktik noch für Chipdesign verdient. Jetzt kann ich verstehen, weswegen viele I2C für kompliziert halten ...
    Seit einigen Wochen denke ich, dass PICs vielleicht die bessere Alternative sind: mein Program mer, der erste, der mir wirklich sehr gut gefällt, hat nen PIC. Der SRF02, der ja ziemlich gut funktioniert, hat auch nen PIC.

    Ok, ich habe jetzt mal rumbastelt am Quellcode und dies hier
    Code:
    //      30. Sept 2014, 14:ff
    //      Hier der Code von oben, mit Modifikationen (siehe Klebwax)
    
      cli(); tmr1  = 0; sei();      // Timer 1 starten
      i2c_start (Sadd + I2C_WRITE); // Starte Slave lesen
      i2c_write ( 0x00 );           // write address = dieses Byte soll gelesen werden
            i2c_stop();             //
    
      for ( ; ; )
      {                             //
        i2c_start (Sadd + I2C_READ);  // Slave bereit zum Lesen?
        lobyte  = i2c_readNak();      // Byte lesen... ACK
            i2c_stop();             //
        if ( lobyte > 200 ) break;
        uputs0 ("\r\tlbt "); uputs0u ( lobyte );
        .....
    in allerlei Variationen ausgekostet. Fazit: dieses Byte nimmt im Verlauf der Messung ansteigende Werte an bis die Messung (vermutlich) fertig ist, danach wird die Versionsnummer - aktuell 6 - gelesen.

    WENN ich z.B. bei >200 abbreche, dann fange ich schon mal viele Messungen ab, der Timer hat dann auch Werte, die zur Laufzeit "hin und zurück" passen.

    WENN ich bei 6 abbreche, dann hat üblicherweise die Messung nicht wirklich angefangen, dann läuft der Timer bis so etwa 2 bis 4 mal (ein Timerschritt sind 50µs). Die Variante "Abbruch bei 6 - Neustart lesen - Abbruch bei 6" funktioniert dann eher. Offensichtlich läuft dieses Hochtickern von Null bis zum Endwert und da kommt man eben an der Sechs schon beim Hochtickern vorbei. Die Versionsnummer ist 6.

    WENN ich bei 255 abbreche - abbrechen möchte - dann läuft der Controller sofort ins Koma. Irgendwie ominös, diesen Wert hatte ich nie gesehen, allenfalls etwas bei 240 und knapp drüber.

    Die Versuche leiden natürlich durch Zeitprobleme. Wenn ich zu schnell abfrage dann gibst Fehlfunktionen aber ich hoffe, dass ich diese Geschichten, die meist reproduzierbar waren, ordentlich interpretiert habe.

    Jedenfalls weiß ich jetzt, dass ich nicht die genannten 65 ms warten muss. Eine Messung geht teilweise deutlich schneller und passt gut in meine sonstigen, teils noch geplanten Aktivitäten, zumal ich zwei Ultraschallsensoren alternierend abfrage.
    Ciao sagt der JoeamBerg

  7. #7
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    @oberallgeier
    Du mußt den Returnwert von "i2c_start (Sadd + I2C_WRITE)" auswerten. So wie ich das in meinem Pseudocode geschrieben habe

    if(i2c_start(Adresse und Write) == 0) {
    .....
    Code:
    Erklärung in der Dokumentation zur Bibliothek (siehe obigen Link "... Master lib..") :
    unsigned char i2c_start     (      unsigned char      addr      )      
    
    Issues a start condition and sends address and transfer direction.
    
    Parameters:
            addr     address and transfer direction of I2C device
    
    Return values:
            0     device accessible
            1     failed to access device
    1 heißt, das Device ist nicht ansprechbar, hat nicht mit ACK geantwortet.

    Wer schreibt eigentlich den Code, den du da so postest, z.B. den Bascom Code. Ich sehe an keiner Stelle, daß ACK bzw NAK ausgewertet wird. Da wird überall blind in den Bus hineingerufen, ob ein Device nun antwortet oder gar nicht da ist. Das wird dann auch noch als Beispielcode veröffentlicht.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  8. #8
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.735
    ... Du mußt den Returnwert von "i2c_start (Sadd + I2C_WRITE)" auswerten ... if(i2c_start(Adresse und Write) == 0) { ...
    Sorry, ja, danke. Zu Beginn dieser Litanei, den ich nicht zitiert hatte, hab ich es ja noch richtig:
    Code:
    //      Messung starten auf Sensor Sadd
    // - - - - - - - - - - - - - - -
      if (!(i2c_start (Sadd + I2C_WRITE)))  // Slave bereit zum schreiben?
      {                                     //   dann Werte schreiben
        i2cdmy  =  i2c_write (  00 );       // Buffer Startadresse setzen     
        i2cdmy  =  i2c_write ( 0x51 );      // Startbefehl SRF02
                   i2c_stop();              // Zugriff beenden
      }                                     //
      else                  // Weiter mit if (!(i2c_start( Sadd + I2C_WRITE )))
      {                                     //
        uputs0("\r\t## SRF_rdat\r");
        wms (   10);
        return 9901;                        // Return mit Fehlercode
      }                     // Ende if (!(i2c_start( Sadd + I2C_WRITE )))
    Und danach - hat das dauernde Ändern zu Schlamperei geführt. Hast ja Recht.

    ... Wer schreibt eigentlich den Code, den du da so postest, z.B. den Bascom Code ...
    Bascom sind Beispiele aus dem RN Wi ki, das kann ich nicht. Die C-Sequenzen sind von mir - sicher mehr schlecht als recht :-/ . Die I²C-Bibliothek ist von PFleury.
    Ciao sagt der JoeamBerg

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo zusammen,

    natürlich weitere Unterstützung (leider auch Fragen) von mir.


    @oberallgeier

    Die Defines für die TWI-Schnittstelle sind angegeben in twi.h im Verzeichnis ...\GCC-COMPILER\... \avr\include\util\

    #define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3) )

    #define TW_STATUS (TWSR & TW_STATUS_MASK)

    Und die Form der hier benutzten Definition passt dann natürlich auch zu den 'Gegenstücken' um in einer case()-Anweisung die case-Sprungstellen zu finden.
    Die 'Gegenstücke' sind also sinnvollerweise auch in der Datei twi.h zu finden.
    Beispielsweise mit:
    #define TW_MT_SLA_ACK 0x18

    Somit ist es sehr wohl relevant, ob man nun die vorhandenen Defines nutzt oder "TwiStatus = TWSR >> 3".

    switch (TW_STATUS) {
    case TW_MT_SLA_ACK: xxx
    wird funktionieren.

    Aber
    TwiStatus = TWSR >> 3;
    switch (TwiStatus) {
    case TW_MT_SLA_ACK: xxx
    wird nicht mehr funktionieren, da nun die Bits mit >> 'versetzt' zu den 'Gegenstück'-Define stehen.

    Genauso wie es schon wichtig ist, dass man NICHT das Register TWSR in seinem switch() benutzt, da dann ja immer noch die letzten beiden Bits TWPS0 und TWPS1 zum Einstellen vom Prescaler enthalten sind, und dann auch nicht mehr zu den 'Gegenstücken' in der case-Orgie passen werden.


    Dein letzter Beitrag deutet ja darauf hin, dass während der Messung dieses 'merkwürdige' Versionsregister 0 eben nicht das macht was in der Doku steht.
    Nicht gut.



    @Klebwax

    Tut mir leid, jetzt kommen eher Fragen

    Und was passiert tatsächlich mit folgenden beiden C-Codezeilen?

    Erzeuge STOP mit sofort folgendem START in der TWI-Hardware:

    TWCR = (1<<TWSTO)|(1<<TWINT) | (1<<TWEN)|(1<<TWIE);
    TWCR = (1<<TWSTA) |(1<<TWINT) | (1<<TWEN)|(1<<TWIE);


    Der Compiler macht daraus:
    4d6: 85 e9 ldi r24, 0x95 ; 149
    4d8: 80 93 bc 00 sts 0x00BC, r24 <<== Register für TWI-Hardware im mega168 und anderen AVRs.

    4dc: 85 ea ldi r24, 0xA5 ; 165
    4de: 80 93 bc 00 sts 0x00BC, r24


    Hier liegen wir garantiert unter den 1.3 us und nun stellen sich mir folgenden Fragen:
    Was macht die Hardware tatsächlich, wenn sie STOP'en und sofort wieder START'en soll?
    Wird dann der Softwareteil beim START'en verzögert? Kann ich mir beim besten Willen nicht vorstellen.
    OK, nach dem START wird es etwas dauern, bis im TWSR das Bit TWINT wieder gesetzt wird. Klar, das macht die Hardware.

    Wenn ich die TWI-Hardware benutze, dann sollte ich natürlich nicht dein angegebenes "... und im Code darauf gewartet wird. ..." dahingehend wörtlich nehmen, dass ich nun eine Schleife im Code bauen soll, die zwischen STOP und START prüft, "... das sich der Status ändert ..."?

    Kannst du deine Erklärung genauer formulieren, bzw. mir eine Erklärung geben, die ich verstehe?


    Da die TWI-Hardware, nach einem durch die Software angegebenem STOP-Kommando an das Register TWCR, sich nicht mehr per Interrupt meldet, da nämlich kein Status-Wert für diese Aktion definiert ist im TWSR-Register (ODER habe ich diese Info noch nicht gefunden!), kann ich somit den nächsten START-Aufruf tatsächlich nur ohne Interrupt-Kontrolle erzeugen.
    Also auch im Extremfall wie oben angegeben.


    Im Handbuch finde ich folgendes: (mega48 bis 328 )

    Im Kapitel "Overview of the TWI Module" Unterpunkt "Bus Interface Unit":
    "When in Transmitter mode, the value of the received (N)ACK bit can be determined by the value in the TWSR."
    Also hier noch keine Angabe, was im TWSR nach einem STOP steht.

    Im Kapitel "Using the TWI" ist das Bild "Interfacing the Application to the TWI in a Typical Transmission" angegeben, welches die Aktionen von Software und Hardware sehr schön im (typischen) Zusammenspiel zeigt.
    Hinter dem STOP wird hier nichts mehr angegeben.
    Hast du hier eine Info, ob, und wie, der STOP-Zustand auf dem BUS im TWSR 'zu sehen' ist?

    Und das dazu wohl wichtigste Kapitel:
    "Overview of the TWI Module" Unterpunkt "Control Unit" ist zu finden, wann das Bit TWINT im TWSR gesetzt wird um anzuzeigen, das die Hardware fertig ist.
    • After the TWI has transmitted a START/REPEATED START condition.
    • After the TWI has transmitted SLA+R/W.
    • After the TWI has transmitted an address byte.
    • After the TWI has lost arbitration.
    • After the TWI has been addressed by own slave address or general call.
    • After the TWI has received a data byte.
    • After a STOP or REPEATED START has been received while still addressed as a Slave.
    • When a bus error has occurred due to an illegal START or STOP condition.
    Dort ist KEINE ANGABE vorhanden, das ein STOP das Bit setzt.
    Aus meiner Sicht ist somit nicht zu prüfen, wann das STOP 'fertig' ist. --> Alles eben beim ATmega und nicht in einem PIC.


    Gruß aus dem frühen neuen Tag
    Sternthaler


    Nachtrag:
    Vielleicht doch ne' Lösung vorhanden?

    In "Transmission Modes" Unterkapitel "Miscellaneous States" steht natürlich noch etwas zu diesem "illegal START or STOP condition"
    Table 22-6. Miscellaneous States

    0x00 Bus error due to an illegal START or STOP condition
    No TWDR action 0 1 1 X
    Only the internal hardware is affected, no STOP condition is sent on the bus. In all cases, the bus is released and TWSTO is cleared.
    Geändert von Sternthaler (01.10.2014 um 00:34 Uhr) Grund: 'illegal condition' aus dem Handbuch hinzugefügt.
    Lieber Asuro programieren als arbeiten gehen.

  10. #10
    Erfahrener Benutzer Roboter-Spezialist Avatar von schorsch_76
    Registriert seit
    25.03.2012
    Ort
    Kurz vor Neuschwanstein
    Alter
    49
    Beiträge
    456
    Hier
    TWCR = (1<<TWSTO)|(1<<TWINT) | (1<<TWEN)|(1<<TWIE);
    TWCR = (1<<TWSTA) |(1<<TWINT) | (1<<TWEN)|(1<<TWIE);

    muss man eigentlich warten bis das STO wieder zurück esetzt wurde (siehe Tabelle in DS).

    Seite 229 Atmega328 Doku: Table 21-2. Status codes for Master Transmitter Mode
    bzw. Table 21-3 für Master Receive.

    Man kann auch STO und STA gleichzeitig setzen. Siehe die genannten Tabellen.

Seite 1 von 2 12 LetzteLetzte

Ähnliche Themen

  1. [ERLEDIGT] Probleme mit IF-Abfrage / Timer
    Von sammler im Forum C - Programmierung (GCC u.a.)
    Antworten: 11
    Letzter Beitrag: 25.04.2011, 12:41
  2. SRF02 über RS232 Beispielcode ohne Funktion?
    Von TobiasBlome im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 2
    Letzter Beitrag: 10.05.2009, 15:21
  3. problem mit button-abfrage im timer (c#)
    Von Roboman93 im Forum Open Source Software Projekte
    Antworten: 4
    Letzter Beitrag: 29.12.2008, 18:40
  4. SRF02 Messwert in Millimeter ermitteln
    Von Stiffer im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 1
    Letzter Beitrag: 29.03.2008, 13:00
  5. Messwert Diagramm erstellen... aber wie?
    Von raptor_79 im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 15.11.2007, 09:30

Berechtigungen

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

    Werbung      fchao-Sinus-Wechselrichter AliExpress