mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Abfrage Taster durch USI vom Slave mit zwei AVR


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo
In einer kleinen Schaltung verwende ich einen Atmega 128 als Master. 
Dabei sind die Pins PC5 und PC6 mit LEDs beschaltet.
Als Slave benutze ich einen Attiny2313. Bei ihm ist der Pin PD0 mit 
einem Taster belegt. Zur Kontrolle erfogt ein schalten einer LED an PD5.
Das senden von Daten vom Master zum Slave klappt ohne Probleme.
Aber vom Slave zum Master erfogt keine Anzeige.
Im Slave verwende ich das:
if (PIND & (1<<PIND0))           // Taster T2 PD0
      {                    // Wenn T1 gedrückt...
      byte3=40;              // setze byte3 auf 40
      PORTD |=(1<<PIND3);          // LED 4 D5 aus  
      }
    else
      {
      PORTD &=~(1<<PIND3);        // LED 4 D5 ein
      byte4=30;              // setze byte4 auf 30
      }
    txbuffer[0]=byte3;            // byte10 in den Sendepuffer auf [0]
    txbuffer[1]=byte4;
Vom Master erfolgt die Abfrage ob Taster gedrückt wird damit:
void s_read1()                // lese Slave1
    {
      i2c_start(slave_adresse);        // Start Bus schreiben
      i2c_write(0x00);          
      i2c_rep_start(slave_adresse);        // starte Slave lesen
      byte3=i2c_readAck();          // 2. Byte lesen und in "gelesen" ablegen
      byte4=i2c_readNak();          // letztes Byte lesen, darum kein ACK
      i2c_stop();                // Zugriff beenden  
    }
und damit die Auswertung und Anzeige:
s_read1();    
      
        if (byte4 == 30)        
          {                  // Wenn Wert 30 gelesen wurde...
            PORTC &= ~( (1<<PINC5));    // schalte Port A6  
        PORTC |=(1<<PINC6);        // wenn nicht lösche Port A6  
          }
        else
          {  
          PORTC |=(1<<PINC5);        // wenn nicht lösche Port A6
        PORTC &= ~( (1<<PINC6));    // schalte Port A6  
          }
Als Slave Adresse benutze ich 50, Ein- und Ausgäne sind frei gegeben bzw 
eingestellt.
Es erfogt keine Auswertung des Tasters auf dem Slave und damit keine 
Anzeige bzw. keine Umschaltung.
Leider kann ich meinen Fehler nicht finden.
LG Peer

Autor: Rufus Τ. F. (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> if (PIND & (1<<PIND0))           // Taster T2 PD0
>       {                    // Wenn T1 gedrückt...
>       byte3=40;              // setze byte3 auf 40

Hast Du Dir mal Deine Kommentare angesehen?

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vergiss bitte die Kommentare. Die stimmen gar nicht und muss sie noch 
mal überarbeiten

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand helfen?

Autor: Max D. (max_d)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du einen logic-analyzer? (für i2c tut ein 10€ saleae-klon mit 
pulseview)

Außerdem: ganzen Code anhängen. uc.net bietet die Option mehrere Dateien 
anzuhängen (auch sourcen).

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> Leider kann ich meinen Fehler nicht finden.

Dann gehe systematisch bei der Fehlersuche vor.
Laß den Slave konstante Daten senden und gib sie vom Master über die 
UART oder auf ein LCD aus.
Und gibt erstmal aus, ob den Master überhaupt den Slave adressiert.
Immer schön Schritt für Schritt debuggen.

Aus dem Zusammenhang herausgerissene Schnipselchen mit falschen 
Kommentaren kannst Du Dir sparen. Wer soll damit was anfangen können?
Wenn Du Code postest, dann so vollständig, daß er compiliert und keine 
Warnungen wirft.
Wenn Du Warnungen nicht deuten kannst, dann poste sie vollständig und 
exakt (C&P).

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok - die Kommentare sind falsch. Die werde ich erst mal rausstreichen. 
Der Master erkennt den Slave ganz korrekt. Habe zu Anfang auch eine 
Abfrage drin die mir Anzeig ob der Slave auf dieser Adresse exestiert. 
Ausgabe erfolgt auf einem LCD. Beim kompilieren werden keinerlei 
Fehlermeldungen angezeigt. Der Code für den Master und den Slave kann 
korrekt übertragen werden. Die Steuerung vom Master zum Slave geht ohne 
Probleme.
Der Fehler liegt in der übertragung vom Slave zum Master.

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der komplette Code vom Slave:
#define F_CPU 16000000UL
#include <stdlib.h>                
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "usiTwiSlave.h"

#define slave_adresse 0x52            // Adresse Slave

uint8_t  byte1, byte2, byte3, byte4;
uint16_t buffer;

int main(void) 
  {
  cli();                    
  usiTwiSlaveInit(slave_adresse);        
  sei();          
  
  DDRD=0b00111000;                    
  
  PORTD|=0b00111000;            

  
  while(1) 
    {    
    byte1 = rxbuffer[0];          
    byte2 = rxbuffer[1];
  ///////////////////////////////////////////////////////////////////////  
    if (byte1==43)              
      {                  
      PORTD &=~(1<<PIND5);        
      PORTD |=(1<<PIND4);          
      }
    if (byte1==42)              
      {                    // wenn dann ...
      PORTD &=~(1<<PIND4);        
      PORTD |=(1<<PIND5);          
      }
  //////////////////////////////////////////////////////////////////////  
    if (PIND & (1<<PIND0))           
      {                    
      byte3=40;              
      PORTD |=(1<<PIND3);          
      }
    else
      {
      PORTD &=~(1<<PIND3);        
      byte4=30;            
      }
    txbuffer[0]=byte3;            
    txbuffer[1]=byte4;
    }                      // end.while
    }                      // end.main
Zu dem anderen Teil komme ich erst heute abend. Werde das mit dem LCD 
machen.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> Der komplette Code vom Slave:

Dann kann es ja nicht funktionieren, es fehlt der I2C-Code.

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> #include "usiTwiSlave.h"

Peer schrieb:
> usiTwiSlaveInit(slave_adresse);

In diesen beiden Sachen steckt der I2C Bus. Im ori ist es von Jtronk

Autor: Max B. (citgo)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Also ich suche mir die Sachen jetzt nicht im Netz zusammen.

Du sagst erst Slave hat die Adresse 50 und im Code steht 52!?

Ich weiß auch nicht was txbuffer[] macht.

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> In diesen beiden Sachen steckt der I2C Bus.

Wenn Du den vollständigen Code von Master und Slave nicht zeigen willst, 
dann sag das doch gleich.

Autor: Peer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Das ist der vollständige Code vom Slave

Peer schrieb:
> #include "usiTwiSlave.h"

kann gern auch diese Datei einstellen.
Master kommt ebenfalls noch

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt, die Adresse ist 52

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der komplette Code vom Master
/* I2C-Master-Routinen von Peter Fleury verwenden siehe: http://homepage.hispeed.ch/peterfleury/avr-software.html#libs */
/*  Abgestimmt auf meine Hardware P30, D2, P52, NT2, 2xP20
    Bedienung: 
  Slave - Port B Anzeige welche LED, T2 Umschaltung der Sende byte, L2 und L4 Anzeige der Sende byte
  Master - T1 und T3 sende byte zum Slave, T2 hole byte vom Slave, Anzeige am Port A    */  
    
    #include <stdbool.h>
    #include <avr/pgmspace.h>
    #include "main.h"
    #include <util/delay.h>
    #include "i2clcd.h"
    #include "i2cmaster.h"
    #include "avr/io.h"
    #include "util/delay.h"
    #include "avr/interrupt.h"
    
    #define slave_adresse 0x52        // Slave Adresse schreiben
    #define slave_adresse_r 0x53        // Slave Adresse lesen
    
    uint8_t ret;                     // Kontrollvariable ob Slave vorhanden
    uint8_t byte1, byte2;              // Daten zum Senden vom Master zu Slave
    uint8_t byte3, byte4;
    uint8_t byte10;              // Daten zum holen vom Slave zu Master
///////////////////////////////////////////////////////////////////////////////////////////////////
  void startanzeige()              // Titelbild
    {
    lcd_command(LCD_CLEAR);              // Leere Display
    _delay_ms(2);                  // Warte 2ms
    lcd_printlc(1,2,"USI Bus M-Prg1");       // Zeile 1
    lcd_printlc(2,2,"Verbindung von");    // Zeile 2
    lcd_printlc(3,2,"Prz ueber I2C ");    // Zeile 3
    lcd_printlc(4,2,"(by P.)");    // Zeile 4
    _delay_ms(3000);                 // Warte 5000ms
    }
///////////////////////////////////////////////////////////////////////////////////////////////////
  void slavetest()              // Abfrage Slave, Fehlermeldung und Anzeige
    {                      // Abfarge ob Slave vorhanden ist
    ret = i2c_start(slave_adresse);      // Start i2C mit Adresse Slave
    i2c_write(0x00);            // Sende Daten
    i2c_stop();                // I2C Stop
    if (ret == 0)              // Bus ok - 0, kein Bus 1
      {                           // Anzeige Slave ok
      lcd_command(LCD_CLEAR);        // Leere Display
      _delay_ms(2);                // Warte 2ms
      lcd_printlc(2,4,"Slave ist ");    // Ausgabe Text
      lcd_printlc(3,5,"OK !!!!!");    // Slave OK
      _delay_ms(2000);              // Warte 2s
      }
    else                  // Fehlermeldung
      {                                // Anzeige Slave nicht ok
      lcd_command(LCD_CLEAR);        // Leere Display
      _delay_ms(2);                // Warte 2ms
      lcd_printlc(2,5,"Slave ist");    // Ausgabe Schrift
      lcd_printlc(3,5,"Nicht OK");    // Slave Nicht O
      _delay_ms(1000);              // Warte 2s
      }
    } 
/////////////////////////////////////////////////////////////////////////////////////////////////////  
  void s_write1 (void)            // schreibe Daten 1 von Master zu Slave
    {
    i2c_start(slave_adresse);        // Slave ist bereit zum Schreiben
    i2c_write(0x00);                        // Buffer Startadresse setzen
    i2c_write(42);                          // Drei Bytes schreiben...
    i2c_stop();                             // Zugriff beenden  
     }
//////////////////////////////////////////////////////////////////////////////////////////  
  void s_write2 (void)            // schreibe Daten 2 von Master zu Slave
    {
      i2c_start(slave_adresse);        // Slave ist bereit zum Schreiben
    i2c_write(0x00);                        // Buffer Startadresse setzen
    i2c_write(43);                          // Drei Bytes schreiben...
    i2c_stop();                             // Zugriff beenden
    } 
/////////////////////////////////////////////////////////////////////////////////////////////////
  void s_read1()                // lese Slave1
    {
      i2c_start(slave_adresse);        // Start Bus schreiben
      i2c_write(0x00);          
      i2c_rep_start(slave_adresse);        // starte Slave lesen
      byte3=i2c_readAck();          // 2. Byte lesen und in "gelesen" ablegen
      byte4=i2c_readNak();          // letztes Byte lesen, darum kein ACK
      i2c_stop();                // Zugriff beenden  
    }
//////////////////////////////////////////////////////////////////////////   
  int main(void)
    {
    cli();                             // Interrupts deaktiviert
    i2c_init();                        // Starte I2C Bus
    lcd_init();                        // Starte I2CLCD    
    // Display Befehle
    lcd_command(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGOFF);
    lcd_light(0);              // Licht an
    startanzeige();
    lcd_command(LCD_CLEAR);            // Leere Display
    _delay_ms(2);                  // Warte 2ms
    slavetest();
    _delay_ms(2);
    
    DDRC=0b01100000;    //Taster    // setzt Port C auf Ausgang, PC5 und PC6
    //DDRA=0b11111111;      //LED    // setzt Port A auf Ausgang, PC5 und PC6
      
    PORTC|=0b01001111;    //Taster    // Deaktiviere Ports C5-6 (LEDs aus)
    //PORTA|=0b11111111;    //LED      // Deaktiviere Pins A0-7 (LEDs aus)
    
    while(1)
      {
        // ========>> AUF GELESENE DATEN REAGIEREN
      s_read1();    
      
        if (byte4 == 30)        
          {                  // Wenn Wert 30 gelesen wurde...
            PORTC &= ~( (1<<PINC5));    // schalte Port A6  
        PORTC |=(1<<PINC6);        // wenn nicht lösche Port A6  
          }
        else
          {  
          PORTC |=(1<<PINC5);        // wenn nicht lösche Port A6
        PORTC &= ~( (1<<PINC6));    // schalte Port A6  
          }
  ///////////////////////////////////////////////////////////////////////////////////////////////    
        // ========>> TASTENEINGABEN
        if (!(PINC & (1<<PINC2)) )      // Taster T1
          {                  // Wenn T1 gedrückt...
          PORTA &=~(1<<PINA1);      // LED 2 A1 ein
          s_write1();            // Schreib 1 Funktion aufrufen
          }
        else
          {
            PORTA |=(1<<PINA1);        // sonst LED 2 A1 aus
          }
        // ========>> TASTENEINGABEN
        if (!(PINC & (1<<PINC4)) )      // Taster T 3
          {                  // Wenn T1 gedrückt...
          PORTA &=~(1<<PINA2);      // LED 3 A2 ein
          s_write2();            // Schreib 2 Funktion aufrufen
          }
        else
          {
          PORTA |=(1<<PINA2);        // sonst LED 3 aus
          }
  
        }
        }
Habe den Code so weit möglich aufgeräumt. Bitte die Kommentare 
vorsichtig betrachten, sind noch Fehler drin.

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Werte zum Quarz und Adresse des Displays befinden sich in der main.h

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte jemand sich die Sache ansehen und mit helfen?

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> Könnte jemand sich die Sache ansehen

So jetzt üben wir das nochmal.
Mache 2 Verzeichnisse, eins mit dem kompletten Mastercode und eins mit 
dem kompletten Slavecode. Und dann zippe es und poste es als Anhang.

Hast Du es denn schonmal mal mit systematischer Fehlersuche probiert?
D.h. konstante Daten an Master senden, mit UART ausgeben, konstante 
Daten an Slave senden, mit UART ausgeben.

: Bearbeitet durch User
Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter
hatte es wie geschrieben mit einer Ausgabe zur Kontrolle auf dem Display 
gemacht. Werte die vom Master gesendet werden kann ich anzeigen. Werte 
die vom Master gelesen werden sollen kommen nicht auf das LCD.
Hatte dazu konstante Werte genommen.
Mit dem zippen habe ich das wohl falsch verstanden. Einige haben es 
gezippt und andere haben sich beschwert wer es den entzippen soll. Da 
gehen die Meinungen etwas auseinander.
Mache mich ans zip.

Autor: Peer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe alle Datein jeweils für Master und Slave als zip reingestellt. Es 
sind alle Datein dabei. Die Kommentare sind nicht überarbeitet und 
teilweise falsch

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir einer helfen?

Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat jemand eine Idee?

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gehe systematisch vor. Reduziere das Programm auf weniger Baustellen.

Besorge Dir einen PCF8574, und eine Hand voll LEDs mit 1kΩ 
Vorwiderständen. Und besorge Dir einen Logic Analyzer (z.B. diese 
billigen (8ch 25MHz Dinger von Amazon).

Jetzt hängst du an den I²C Bus und an die 8 Ausgänge des PCF8574 jeweils 
eine LED:
AVR                                        PCF8574

            +---[===]---------o 5V
            |
            +---[===]---|<|---o 5V
            |
SCL o-------+------------------------------o SCL

SDA o-------+------------------------------o SDA
            |
            +---[===]---|<|---o 5V           P0 o---[===]---|<|---o 5V
            |                                P1 o---[===]---|<|---o 5V
            +---[===]---------o 5V           P2 o---[===]---|<|---o 5V
                                             P3 o---[===]---|<|---o 5V
                                             P4 o---[===]---|<|---o 5V
                                             P5 o---[===]---|<|---o 5V
                                             P6 o---[===]---|<|---o 5V
                                             P7 o---[===]---|<|---o 5V

Jetzt versuchst du nur die LEDs am Ausgang des PCF8574 leuchten zu 
lassen. Sonst nichts. Kein zweiter µC, kein LCD Display, keine Taster. 
Wenn das klappt, programmiere ein Lauflicht.

Damit prüfst du deinen I²C Master.
Analysiere die I²C Kommunikation mit Hilfe der beiden Leuchtdioden und 
dem Logic Analysator. Berichte, was dabei heraus kam.

Als nächsten Schritt ersetzt du den PCF8574 durch deinen Slave µC und 
programmierst ihn so, dass er ebenfalls einfach nur das empfangene Byte 
mit den LEDs anzeigt. Alles sonstigen Schnickschnack lässt du erstmal 
weg.

Analysiere erneut die I²C Kommunikation mit Hilfe der beiden 
Leuchtdioden und dem Logic Analysator. Berichte, was dabei heraus kam.

Dann sehen wir weiter.

: Bearbeitet durch User
Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefanus
das mit 8574 geht alles. Verwende auch noch ca. 20 andere Bausteine am 
Bus. Auch die Widerstände sind drin.
Beim Start des Atmega erfolgt eine Abfrage ob ein Slave mit der 
eingestellte Adresse vorhanden ist. Ist er nicht dran erfolgt auf dem 
display eine Anzeige das der Slave nicht ok ist und das Programm stopt. 
Ist der Slave dran und die Adresse korrekt erfolgt die Anzeige das der 
Bus ok ist.
Auf dem Master habe ich mehrere Taster. Wenn ich diese betätige erfolgt 
das wechsel seitige schalten von 2 LEDs auf dem Slave. Damit erfolgt 
eine korrekte übertragung der Daten vom Master zum Slave. Habe 
zusätzlich noch ein paar LEDs am Master zu laufen die mir das zur 
Kontrolle anzeigen.
Es geht um die Abfrage des Slaves durch den Masters und die Anzeige 
dazu.
LG Peer

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann würde ich jetzt als Nächstes die Kommunikation zum Slave mit dem 
Logic-Analyzer untersuchen.

Sendet der Master, was er soll?
Antwortet der Slave, wie er soll?

Kannst du serielle Debug Meldungen ausgeben, um die Inhalte von 
Variablen (z.B. byte3 und byte4) zu kontrollieren?

: Bearbeitet durch User
Autor: Peer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Master sendet in Abhängigkeit der gedrückten Taster zwei 
unterschiedliche Werte. Die Betätigung der Tasten und die zu senden 
bytes lasse ich mir anzeigen. Da der Slave auf die Sicherheitsabfrage 
reagiert und Antwortet erfolgt ein Kommunikation vom Master zum Slave 
und Antwort. Alles wie er soll.
Die Abfrage vom Master zum Slave und die Antwort des Slave kommen nicht.
Als Slave Adresse habe ich 50 (52) eingestellt. Das ist doch die 
Schreibadresse. Muss ich beim Ati 2313 auch eine Leseadresse angeben 
oder einstellen?

Stefanus F. schrieb:
> Kannst du serielle Debug Meldungen ausgeben, um die Inhalte von
> Variablen (z.B. byte3 und byte4) zu kontrollieren?

Es soll der Zustand einer LED ausgelesen werden, leuchtet oder nicht.
Versuche gerade das zu machen. Welche Werte kommen oder gelesen werden, 
ob überhaupt gelesen wird.

Autor: Stefanus F. (stefanus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal: Analysiere die Kommunikation mit einem Logic Analyzer und 
schaue in deine Variablen rein.

Deine wiederholte Bitte, die Problemursache zu erraten, bringt nichts 
gutes.

Zur Adresse: I²C Device haben eine Adresse. Es gibt nicht eine 
Schreib-Adresse und eine Lese-Adresse. Es gibt nur eine Adresse mit 7 
bits. Nach der Adresse wird das r/w Bit übertragen, welches aber nicht 
Bestandteil der Adresse ist.

: Bearbeitet durch User
Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peer schrieb:
> Die Abfrage vom Master zum Slave und die Antwort des Slave kommen nicht.

Was heißt "kommen nicht"?
Irgendwas liest der Master und genau das gib aufs LCD oder die UART aus.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.