I2C Bus mit dem Attiny 841

achim S.

Mitglied
16. Jan. 2010
704
13
18
Berlin Biesdorf
Sprachen
  1. ANSI C
Hallo
versuche den Attiny 841 über den I2C Bus anzusprechen. Als Master verwende ich den ATmega 1284p. Das Progamm auf dem Master funktioniert ohne Probleme. Kann vom Master aus den Slave ansprechen und bekomme ein ACK zurück. Damit wird der Master erkannt und quittiert. Leider versteh ich die Eingabe nicht korrekt.
Das Programm:


CodeBox C
void I2C_init(void)
  {
    TWSA = I2C_SLAVE_ADDRESS;                    // TWI Adressregister
    TWSD = 0xFF;                                // Datenregister
    TWSCRA = (1<<TWEN)|(1<<TWSHE)|(1<<TWASIE)|(1<<TWSIE)|(1<<TWDIE);            
    // Register A, TWEN-Schnittstelle Aktivieren, TWSHE-Haltezeit aktivieren, TWASIE-Adressenunterbrechung aktivieren, 
    // TWSIE-Stop Unterbrechung aktivieren, TWDIE-Datenunterbrechung aktivieren 
    TWSCRB = (1<<TWAA)|(1<<TWCMD1)|(0<<TWCMD0);    // Register B, TWI Bestätigungsaktion, TWI Befehl
    sei();            // Interrups einschalten
  }

ISR( TWI_SLAVE_vect )
  {
    uint8_t status = TWSSRA & 0xC0;            // Register A
    if (status & I2C_DATA_INTERRUPT)
    // Daten wurden vom Master empfangen oder werden angefordert
      {
        if (TWSSRA & (1 << TWDIR))                    // Master fordert Daten vom Slave an
          {
            if(tx_buf_index >= sizeof(tx_buf))
              {
                tx_buf_index=0;
              }
            TWSD = tx_buf[tx_buf_index];
            tx_buf_index++;
            TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
          }
        else             // Master sendet Daten zum Slave
          {
            TWSCRB |= (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
            command = TWSD;
          }
      }
    else if (status & I2C_ADDRESS_STOP_MATCH)
      {
        if (TWSSRA & I2C_BUS_COLLISION)
          {
            TWSCRB = (uint8_t) (1<<TWCMD1);
          }
        else
          {
            if (TWSSRA & (1<<TWAS))
              {
                // ACK
                TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
              }
            else
              {
                // Stop Condition
                TWSCRB = (uint8_t) (1<<TWCMD1);
              }
          }
      }
  }


int main(void)
  {
    //ADC_init();
    I2C_init();
    //Timer0_init;
    while(1)
      {
        if(command != 0x00)
        {
            switch(command)
            {
                case 0x01:
                // Test Daten
                tx_buf[0] = 0x01;
                tx_buf[1] = 0x02;
                tx_buf[2] = 0x03;
                tx_buf[3] = 0x04;
                tx_buf_index = 0;
                break;
            }
            command = 0x00;
        }

Vielleicht kann mir jemand dabei helfen es zu verstehen.
achim
 
Hallo achim S.

Hallo
Damit wird der Master erkannt und quittiert. Leider versteh ich die Eingabe nicht korrekt.

Vielleicht kann mir jemand dabei helfen es zu verstehen.
achim

Leider sind Deine Angaben etwas .... unspezifisch - was meinst Du mit "versteh ich die Eingabe nicht korrekt."??
Welche Eingabe?
Warum postest Du nicht den gesamten Code sondern nur Codeschnipsel?

mfg

Hero_123
 
Das ist der Rest zu, Programm.


CodeBox C
#include "main.h"            // Angabe CPU 16MHz
#include <avr/interrupt.h>  // dient zur Behandlung der Interrupts
#include <avr/io.h>         // Integer-Definitionen

#define I2C_SLAVE_ADDRESS       0x52    // Slave Adresse
#define I2C_DATA_INTERRUPT      0x80
#define I2C_BUS_COLLISION       0x08
#define I2C_ADDRESS_STOP_MATCH  0x40

volatile uint8_t command;
volatile uint8_t tx_buf[4];
volatile uint8_t tx_buf_index = 0;

// Funktionsprototypen
//void ADC_init(void);
void I2C_init(void);
//void Timer0_init(void);

mehr habe ich nicht dazu.
void ADC und void Timer gibt es noch nicht. Es sind Testdaten angegeben, die vom Master ausgelesen werden. Die Eingabe der Daten erfolgt im Register TWSD. Doch wie kommen die Daten in das Register bzw. die übergabe der Daten?
Da der Slave vom Master erkannt wird und mit ACK antwortet müssen die Daten vom Master ausgelesen werden. Erfolgt das ganauso wie bei anderen Slaves?
achim
 
Die Abfrage des Slave und Anzeige auf einem Display durch den Master erfogt damit:


CodeBox C
void s_read()                                // lesen Slave
      {
        i2c_start(slave_adresse);                // Start Bus schreiben
        i2c_write(0x00);                    
        i2c_rep_start(slave_adresse+1);            // starte Slave lesen
        byte1=i2c_readAck();                    // Byte lesen und in "gelesen" ablegen
        byte2=i2c_readNak();                    // letztes Byte lesen, darum kein ACK
        i2c_stop();                                // Zugriff beenden    
        
        lcd_printlc(3,3,"byte 1:");                // Anzeige byte 1
        itoa(byte1, Buffer, 10 );                // umrechnung
        lcd_printlc(3,12,Buffer);                // Anzeige
        lcd_printlc(4,3,"byte 2:");                // Anzeige byte 2
        itoa(byte2, Buffer, 10 );                // umrechnung
        lcd_printlc(4,12,Buffer);                // Anzeige
      }
 
Hallo achim S.

Deine Codeschnipseln ... naja - die sind ja sehr aussagekräftig. Haste das irgendwo ... ^C ^V??

Die Eingabe der Daten erfolgt im Register TWSD. Doch wie kommen die Daten in das Register bzw. die übergabe der Daten?
Da der Slave vom Master erkannt wird und mit ACK antwortet müssen die Daten vom Master ausgelesen werden. Erfolgt das ganauso wie bei anderen Slaves?
achim

Du hast doch die globalen Variablen und die werden sowohl in der main als auch in der ISR verwendet, um TWSD zu lesen bzw zu beschreiben (siehe Deinen Codeschnipsel #1 und Codeschnipsel #3).

mfg

Hero_123


Tante Edith: Hast Du Dein Problem nicht auch schon in https://www.mikrocontroller.net/topic/476038#5882056 als Peer (Gast) geschildert??
 
Zuletzt bearbeitet:
Hallo Hero_123
Das mit den Codeschnipseln kann ich leider nicht ändern. Nach der wenigen Literatur und Beispielen im Netz gibt es keinerlei Datein die dazu eingebunden werden müssen. Es spielt sich alles in der main ab. Dabei übernimmt die ISR alles. Es werden Daten und Einstellungen direkt in die Register geschrieben. Habe das Datenblatt des Herstellers gelesen und (vielleicht) verstanden. Das ori des Programm stammt aus AVRFREACK und wahrscheinlich für den Attiny441 geschrieben. Es gibt noch die Einbindung des ADC dazu. Habe ca. 5 verschidene Sachen im Netz gefunden. Teilweise auch Versuche dazu. Eigentlich nichts konkretes. Da der Attiny 841 anders ist als anderen Attinay kann ich keinerlei Beispiele von anderen ICs dazu nehmen. Jedenfalls habe ich meinen gesamten Code reingestellt. In der main dazu steht noch drin das die CPU 16MHz hat. Beim Atmega und dem angeschlosssenen LCD bekomme ich immer 0x00 angezeigt. Es stimmt etwas nicht mit dem Auslesen der Daten oder der übertragung. Laut Programm müsste tex_buf [0-3] die Werte 0x00 bix 0x03 haben. Kommen aber nicht an. Keine Erklärung warum nicht.
achim
P.S. Da einige Leute im Netz statt ehrlicher Hilfe lieber über Anfänger herziehen und beschimpfen ziehe ich verschiedene Namen als Gast vor.
 
Hallo achim S.
P.S. Da einige Leute im Netz statt ehrlicher Hilfe lieber über Anfänger herziehen und beschimpfen ziehe ich verschiedene Namen als Gast vor.

Derartige Foren kannste vergessen :angry:; ich denke aber, dass Du auch als Gast dann keine vernünftige Antwort erhalten wirst.
Ich habe keinen ATTiny841 und kann Dir somit nur bedingt helfen ...

mfg

Hero_123
 
Eigentlich bin ich geteilter Meinung dazu. Teilweise habe ich sehr grosse Hilfe aus dem Netz bekommen, teilweise auch nur Beschimpfung. Es gibt verschiedene Sachen und Stufen sich über andere Menschen auszulassen. Wenn jemand ohne Grund sich über andere erhebt und mit Wissen um sich wirft ist er das was er sagt. In der heutugen Zeit kann kein Mensch ohne den anderen Leben. Ein Arzt braucht die Putzfrau und den Müllman genau wie umgekehrt.
Möchte keinen persönlich angreiffen, aber das sie so meine Erfahrungen.
achim
 
:offtopic:

Es ist erbärmlich, wenn ein "Spezialist" anderen Hilfesuchenden mehr als überheblich verdeutlicht, dass sie keine Ahnung haben und er ein Forum dazu missbraucht, seinen Frust (auf was auch immer) loszuwerden, indem er Andere beschimpft.
Wenn er nicht helfen will - ist ja ok, ist sein gutes Recht - niemand muss einem Anderen helfen, so er nicht willens dazu ist.
Aber dem Anderen die eigene "Überlegenheit" spüren zu lassen - das ist ....

mfg

Hero_123

Aber das löst wohl nicht Dein Problem ;)
 
Danke für deine Worte.
Kann dir aber mitteilen das ich was gefunden habe. Die Übertragung von Daten vom Slave zum Master auf Anforderung geht schon. Muss noch vom Master zum Slave in den Griff bekommen. Damit rückt der Attiny 841 in greifbahre Nähe um Funktionen mit dem i2C Bus zu machen.
achim
 
Da der Attiny 841 anders ist als anderen Attinay kann ich keinerlei Beispiele von anderen ICs dazu nehmen.
Deine "anderen" ATtinies - wenn Du damit die klassischen SPI-programmierbaren meinst - besitzen meist gar kein I²C/TWI. Einige besitzen 'n USI, welches mit etwas zusätzlichem Softwareaufwand als TWI-Slave, und mit noch mehr Softwareaufwand (Clock) als TWI-Master verwenden läßt.
Als Ausnahme gibt es einen klassischen Tiny (48/88 ??), der 'n echtes Hardware-TWI (wie die klassischen Megas) besitzt
"Andere" ATtinies wären aber auch die X0- und X1-Core Tinies (UPDI-programmierbar), die eine neues TWI (ähnlich den XMegas) haben. Die können dann quasi nativ Master und Slave.

Dein ATtiny241/441/841 besitzt als klassischer SPI-Tiny Komponenten, die an die der TPI-Tinies erinnern - vielleicht solltest Du diese bei Deiner Code-Schnipsel-Suche miteinbeziehen. Also den ATtiny20 und den ATtiny40...
(Der 1634 hatte AFAIR gar kein TWI...)
Dieses TWI-Modul ist allerdings Slave-only - der Tiny441/841 besitzt zwar nebenbei noch zwei UARTs und ein SPI, aber nichts, was sich irgendwie als Master-TWI verwenden läßt. Master-TWI wäre hier also als reine Softwarelösung zu implementieren...

So...
Zum C-Code kann ich wenig/nichts sagen - in einen PAP könnte ich mich vielleicht reindenken, wenn ich die nötige Zeit hätte (insbesondere um auch die Datenblätter (insbesondere das des Tiny448/841) durchzugehen.)
Sorry
 
Danke für die Info
Der Attiny 841 ist mit seinem I2C Slave wirklich sehr anders. Wenn du dir ersten Code anschaust, sind da Sachen drin die ich so gar nicht kenne. Er hat wahrscheinlich bei den Bastlern noch wenig Einzug gehalten. Hatte sehr viel Mühe was passen des zu finden. Ohne Beispiel ist man ganz schön verlassen. Egal, der erste Code läuft, Sicherheitsabfrage und Daten vom Slave auslesen zum Master gehen. Den Rest noch und gut ist. Dann kann ich bei der Hardware weiter machen. Der 841 lohnt sich richtig als kleiner Slave. Dachte dabei an einen kleinen Wandler um ADC zu machen oder Encoder oder einen Joystick oder einen Entfernungsmesser mit SR04 oder als Wandler zu Servo oder Schrittmotor. Es gibt viel Sachen dazu. Kannte so was bisher nur mit einem PIC als StartUP. Da kann man viel Konkurrenz machen. Einige Platinen sind schon fertig. Wenn Software läuft kommt es als Tut für alle. Ist vielleicht auch was für Dirk.
achim
 
Wenn du dir ersten Code anschaust, sind da Sachen drin die ich so gar nicht kenne.
C-Code selbst ist 'ne Sache, die ich nicht kenne;)
Der 841 lohnt sich richtig als kleiner Slave.
Der hat'n recht interessanten ADC (differentiell mit aufschaltbarem Verstärker, drei unterschiedliche interne Referenzen; außerdem zwei ACs und acht PWM-Beine, die in gewissem Maße flexibel auf die drei Timer gemultiplext werden können. Zwei der Timer verfügen über Input Capture Units. Die beiden UARTs und der SPI könnten auch interessant sein.
Also wie Du gesagt hast: als Sensor-/Aktor-/Kommunikationsbaustein in irgendeinem komplexeren Netz einsetzbar...
 
Das Datenblatt scheinst du gründlich gelesen zu haben. Da habe ich mal eine Fage (oder mehr) dazu. Beabsichtige verschiedene Version damit aufzubauen. Die Lage der Anschlüsse zu den anderen Modulen soll immer gleich bleiben, so mit 5V, 12V, SCL, SDA und GND. dazu kommt dann noch ISP. Ein paar Beine bleiben übrig. Welches Pin nehme ich füe was am besten?
- Pins mit Taster, LEDs und Poti für ADC
- zusätzlicher Wannenstecker zum Anschluss eines Modules z.B. Servo oder Schrittmotor und vielleicht PWM
- Anschluss Entfernungsmessung mit SR04 mit Timer
- Anschluss Encoder
- Anschluss Joystick
Alle Teile sollen separat am Bus laufen können bzw. auch ohne Master.
Möchte nicht die gleichen Fehler machen wie bei den anderen Teilen.
achim
 
Hmm...
Bei kleinen Controllern mit vielen Hardware-Modulen sind die Beine natürlich "überladen". Du kannst zwar einige Funktionen auf alternative Beine umlegen, aber eben nicht alle. Alle Module des Controllers wirst Du also nicht gleichzeitig nutzen können.
Du hast Dich zum Beispiel auf TWI festgelegt - entsprechend sind die default-SPI-Beine nicht nutzbar. Wenn also neben TWI auch SPI genutzt werden sollen, müssen es da die alternativen Beine sein.
Für die PWM-Ausgabe stehen acht Beine bereit, die in gewissem Maße flexibel auf die Timer geschaltet werden können - hervorzuheben sind aber zei Beine, die extra-hihg-sink-fähig wären.
Wenn das alles genutzt werden soll, sind aber bereits alle der drei mölichen UART-Transmitter-Beine belegt.
Ok, so'ne eirelegende Wollmilchsau hast Du nicht gefordert...

SDA und SCL sind festgelegt (A6 und A4).
Für Taster und (einfache) LEDs brauchst Du keine speziellen Beine.
Für den Ultraschall-Entfernungssensor bietet sich möglicherweise der InputCapturePin eines der beiden 16bit-Timer an - ansonsten wären alle Beine PCINTs.
Bei den Drehencodern kommts darauf an, wie die arbeiten und prellen - meine PECS???? haben z.B bei jedem Rastpunkt dieselben Pegel auf beiden Leitungen. Ich muß also nur eine Leitung überwachen, und nach einer erkannten Flanke prüfen, ob das andereBein denselben Pegel hat (also vorrauseilte) oder noch nicht (also folgen wird).
Die Entprellung erfolgt nach dem Dino'schen-Schiebetrick, erfordert also nur 'ne geeignete Zeitbasis durch irgendeinen Timer (der nebenbei PWM oder sonstwas generieren kann).
Vom Joystick hab ich grad gar keine Vorstellung. Einfach nur vier Taster, oder zwei Potis, oder irgendwas digitales, oder wie?
Für ADC-Messungen wären zumindest einige Beine interessant, die auch differentiell arbeiten können - hatte ich hier nicht mal irgendwo 'n entsprechendes Bild/Grafik hochgeladen, welche Eingänge wie gegeneinander messen können?

Ich habe üblicherweise eher irgend'ne konkrete Aufgabe, die der Controller lösen können soll (da sind dann bereits einige ungeeignet, andere nicht vorhanden usw...)
Aus der/den Aufgabe/n heraus sind dann ggf diverse Beine bereits festgelegt - bei Funktionen, die keine speziellen Beine benötigen, werden dann möglichst Beine gewählt, die keine Spezialfunktionen (oder zumindest weniger rare) blockieren. Ggf spielt dann auch das einfachere Routing 'ne Rolle.

Bei Deinem, eher variabel einsetzbaren Modul würde ich die Sensoren/Aktoren also eher flexibel auf die Beine stecken wollen, eben je nach konkreter Zusammenstellung...
 
Alle Funktionen sollen nicht auf einem Modul vereinigt werden. Sollen ca 5 werden. Anzahl ist aber nach oben offen. Jedes Modul soll nur eine konkrete Aufgabe haben.
Joystick besteht aus zwei Potis mit ja ca. 10 kOhm. Bei meinen anderen Modulen habe ich ein Bein auf 5V das andere auf GND und das 3. messe ich. Muss nur die Richtung beachten. Zusätzlich ein Taster als Quitt noch. Als Software verwende ich sehr gern die Dateien von Peter. Sind mit entprellung und verschiedenen Versionen vorhanden.
Bleiben noch einige zur Anzeige mit LED oder Taster. Verwende bei diesem Attiny nur LEDs mit 2mA. Kann am Wannenstecker eine Testplatine mit 8 LEDs anschliessen. Habe aber nur 6 Pins als Ausgang frei.
Konkrete Frage: Welche Pins für ADC bei Joystick und welcher bei Entfernungsmessung mit SR04 - Timer?
achim
 
Sorry vergessen zu schreiben:
Habe jetzt lesen und schreiben zwischen Master und Slave im Griff. Damit kann die Anwendung losgehen.
Hat jemand eine Idee was noch alles drauf kann als separates I2C Bus Teil?
Achim
 
Habe noch eine Idee dazu. Möchte ein Servo mit dem SR04 kombinieren. Damit kann man "Radar" aufbauen. Hatte sowas schon mal beim Nibo 2. Damit konnte man einen bestimmten Winkel abtasten und das Ergebnis wurde auf einem Display als Radarbild angezeigt. Wenn ich das richtig sehe brauche dazu 2 Timer, bloss welche sind am besten dafür?
achim
 
Hmm...
Also grundsätzlich(!) sollte das auch mit einem Timer gehen - wenn die nötigen und gewünschten Zeiten passen.
Ich gehe mal davon aus, daß der Tiny(241/441/841) mit seinen internen 8MHz getaktet wird. Ein Takt dauert also 125ns.

Zum Servo:
Meiner Erinnerung nach erfolgt alle 20ms ein High-Signal, dessen Länge den Servowinkel festlegt. 950µs entspricht Minimum, 2050µs entspricht Maximum.
Das ist also nichts anderes als PWM, wobei nur etwa ein zehntel der möglichen Zeit genutzt wird. Warum? Weil dort andere Servokanäle auf das Signal gemultiplext werden.
Wir benötigen also 'ne 20ms-PWM-Periode, drinnen aber 'ne möglichst hohe Auflösung. Also wäre ein 16bitter zu wählen.
Mit Prescaler=1 wären also 65536*125ns=8,192ms erreichbar -> zu wenig.
Mit Prescaler=8 würde der Timer mit 8*125ns=1µs ticken, hätte also 'ne Reichweite von 65,536ms. Paßt, leider Verschenken wir Auflösung. 'N Prescaler von 4 wär ideal - gibts aber nicht)
Für 20ms(=20000µs) braucht der Timer jetzt logischerweise 20000 Schritte - man müßte ihn also bei Compare=19999 überlaufen lassen. (Begrenzung Vorzugsweise mit Compare Kanal A, das Input Capture Unit soll frei bleiben).
Zur Ansteuerung des Servos wid also Kanal B verwendet - quasi die oben genannten 950..2050 ins OCRnB schreiben - nur eben immer eins weniger (also 949..2049). Somit kann das Servo also 2049-949+1 = 1101 Positionen anfahren (wenn das Servo selbst das kann).
Einmal konfiguriert läuft der Timer als im Dauerbetrieb mit 1µs-Schritten und Überläufen alle 20ms im Hintergrund. Die De-/Aktivierung der eigentlichen PWM-Ausgabe sowie die Manipulation des Stellwerts (OCRnB) kann jederzeit irgendwo erfolgen.

Zum US-Sensor:
Der hat'n digitalen Signalausgang, die High-Zeit entspricht der Dauer, die der Schall braucht. Unsere zeitliche Auflösung wäre 1µs, da müßte man unter Berücksichtigung der Schallgeschwindigkeit (und des doppelten Weges wegen Reflektion) mal ausrechnen, welche Wegauflösung das wäre, und ob das reicht. Ansonsten müßte man den 2ten 16Bitter nehmen, mit Prescaler=1 (also der achtfachen Auflösung)

Wenn der Sensor getriggert wird, brüllt er irgendwann los und setzt gleichzeitig seinen Ausgang high - hört er sein Echo, setzt er seinen ausgang wieder low.
Wir verwenden also den Input Capture Interrupt (erstmal auf steigende Flanke)- triggert der, steht der Zeitpunkt des eigentlichen Anstiegs im Input Capture Register. Wir stellen in der ISR also auf fallende Flanke um, lesen das ICR aus. Beim nächsten IRQ, also der fallenden Flanke steht der End-Zeitpunkt im ICR.
Maximalwert des Sensors wären wohl 200ms - der Timer kann also mehrfach überlaufen.
Diese Überläufe müssen sowiso berücksichtigt werden - also im Interrupt des OCRnA (der ja die 20ms festlegt). Dort brauchst Du also einen Überlaufszähler.
Mit den gezählten Überlaufen und den beiden ICR-Werten kann also µs-genau die Schall-Laufzeit bestimmt werden.

Idee soweit klar?
 

Ü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)