Forum: Mikrocontroller und Digitale Elektronik ADC Messung mit dem Attiny 841


von Heiner (Gast)


Lesenswert?

Hallo
Beim Attiny 841 steht im Register ADCL und ADCH das Ergebnis der ADC 
Wandlung. In diesem Code erfolgt die Rückgabe des Ergenisses.
1
uint16_t ADC_Read()                  // ADC Einzelmessung
2
  {
3
  ADMUXA |=(1<<MUX1);          // Register ADMUXA
4
  // MUX - Auswahl welcher Eingang - 00011 - ADC3
5
  ADCSRA |= (1<<ADSC);                    // Register ADCSRA
6
  // ADSC - Start Konvertierung "single conversion"
7
  while (ADCSRA & (1<<ADSC) )
8
    {                        // auf Abschluss der Konvertierung warten
9
    }
10
  return ADCW;                            // ADC auslesen und zurückgeben
11
  }
Leider konnte ich verstehen was ADCW ist. Nach Angabe kann ich 10 Bit 
oder 8 Bit zurückgeben.
Wie kann ich das einstellen?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Für 8 Bit kann man das Alignment in ADCL/ADCH entsprechend einstellen 
und braucht dann nur eines der Register auslesen.

von weiter weg (Gast)


Lesenswert?

Heiner schrieb:
> Leider konnte ich verstehen was ADCW ist.

Ich nehme an du hast es nicht verstanden.

Aber ein Blick ins Datenblatt (16.13.3) lässt die Vermutung
aufkommen dass es sich um eine Kombination von ADCL und ADCH
handelt.

Das bestätigt dann auch ein Blick in die Datei iotn841.h

von weiter weg (Gast)


Lesenswert?

Ben B. schrieb:
> Für 8 Bit kann man das Alignment in ADCL/ADCH entsprechend einstellen

Siehe 16.13.5 im Datenblatt.

ADCSRB – ADC Control and Status Register B

von Heiner (Gast)


Lesenswert?

Wenn ich das in 16.13.5 richtig verstanden habe besteht ADCW bei 10 Bit 
aus ADCH und ADCL. Wenn ich nur 8 Bit brauche wird in Register ADCSRB 
das Bit ADLAR auf 1 gsetzt.
Habe ich das richtig verstanden?

von weiter weg (Gast)


Lesenswert?

Heiner schrieb:
> Wenn ich nur 8 Bit brauche wird in Register ADCSRB
> das Bit ADLAR auf 1 gsetzt.

Ja, und nur ADCH auslesen (8 bittig!)... da die unteren 2 Bit
nicht zu auswerten sind.

Warum willst du nur 8 Bit?

von Heiner (Gast)


Lesenswert?

Um es einmal zu verstehen und arbeite an einer übertragung mit I2C. 
Wollte mir nicht gleich die 10 Bit antun.
Kannst du mir ein paar Tips geben wenn ich 10 Bit per I2C übertragen 
will?

von Einer K. (Gast)


Lesenswert?

Heiner schrieb:
> Kannst du mir ein paar Tips geben wenn ich 10 Bit per I2C übertragen
> will?

Klar:
Sende 16Bit

von weiter weg (Gast)


Lesenswert?

Heiner schrieb:
> Kannst du mir ein paar Tips geben wenn ich 10 Bit per I2C übertragen
> will?

Man überträgt einfach zweimal 8 Bit (ein 10 Bit ADC Wert wird
in einer 16 Bit Variable gespeichert, siehe Return-Wert ADCW)
da du 10 bit über I2C nicht einfach übertragen kannst.

von Heiner (Gast)


Lesenswert?

Da liegt auch das Problem. Eine 16 Bit übertragung mit I2C habe ich noch 
nie gemacht. Kennst du ein Beispiel dazu?

von weiter weg (Gast)


Lesenswert?

Heiner schrieb:
> Eine 16 Bit übertragung mit I2C habe ich noch nie gemacht.

Dann zeig mal deine 8 Bit Übertragung.

von Heiner (Gast)


Lesenswert?

Habe bisher die übertragung der Tastenzustände am Attiny 841 vom Slave 
zum Master und zurück hinbekommen. Paralle habe ich den Komparator und 
ADC am ATI 841 geschafft. Da der Ati 841 beim Bus sehr anders ist, kann 
ich meine bisherigen Programm mit dem Atmega 128 nicht nutzen. Da werde 
ich wohl erst einiges machen müssen.

von Einer K. (Gast)


Lesenswert?

Heiner schrieb:
> Eine 16 Bit übertragung mit I2C habe ich noch
> nie gemacht.

Wer es verstanden hat 1 Byte zu senden, kann auch ein zweites 
übertragen.
Und wenn das nichts wird, dann liegen die Probleme ganz woanders.

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Habe bisher die übertragung der Tastenzustände am Attiny 841 vom Slave
> zum Master und zurück hinbekommen. Paralle habe ich den Komparator und
> ADC am ATI 841 geschafft. Da der Ati 841 beim Bus sehr anders ist, kann
> ich meine bisherigen Programm mit dem Atmega 128 nicht nutzen.

Nicht der Bus ist anders, nur die Hardware. Und deren Funktionsprinzip 
ist sehr ähnlich, wenn man mal gedanklich auf Slave beschränkt und die 
Smart-Features des 441/841-TWI-Slave aussen vor läßt, also nicht 
aktiviert.

Unter diesen Randbedingungen kann man gut geschriebenen Slave-Code für 
die normale Mega-TWI-Einheit praktisch ohne jegliche strukturelle 
Änderungen für den TWI-Slave der 441/841 übernehmen. Man muß nur etliche 
symbolische Konstanten singemäß anpassen.

Setzt natürlich voraus, dass man den Sinn verstanden hat, was bei selbst 
geschriebenem Code vorausgesetzt werden kann. Nur bei C&P-Code muss man 
erst verstehen lernen, was der eigentlich tut...

von Stefan F. (Gast)


Lesenswert?

Ich glaube der Heiner verarscht uns.

von weiter weg (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich glaube der Heiner verarscht uns.

Daher wollte ich auch erst mal sehen was er selbst gemacht hat.

weiter weg schrieb:
> Dann zeig mal deine 8 Bit Übertragung.

Aber die ganzen übereifrigen, unausgelasteten Technik-Freaks haben
solch massive Scheuklappen dass sie das nicht erkennen können.

von Heiner (Gast)


Lesenswert?

Ich möchte euch auf keinen Fall verarschen. Um den Attiny 841 zu 
verstehen gehe ich jeden Anwendungsfall nach Datenblatt durch. Dazu 
übersetze ich mir den Inhalt, lese die Register genau und vergleiche es 
mit den Programmen die ich bisher habe. Hatte euch ja schon öfters um 
Rat gefragt und viele Infos dazu bekommen.
Mein Code für den Attiny841 als Slave zum I2C Bus:
1
void I2C_init(void)
2
  {
3
  TWSA = I2C_SLAVE_ADDRESS;          // TWI Adressregister
4
  TWSD = 0xFF;                // Datenregister
5
  TWSCRA = (1<<TWEN)|(1<<TWSHE)|(1<<TWASIE)|(1<<TWSIE)|(1<<TWDIE);      
6
  // Register A, TWEN-Schnittstelle Aktivieren, TWSHE-Haltezeit aktivieren, TWASIE-Adressenunterbrechung aktivieren, 
7
  // TWSIE-Stop Unterbrechung aktivieren, TWDIE-Datenunterbrechung aktivieren 
8
    TWSCRB = (1<<TWAA)|(1<<TWCMD1)|(0<<TWCMD0);  // Register B, TWI Bestätigungsaktion, TWI Befehl
9
  sei();      // Interrups einschalten
10
  }
Und ISR dazu:
1
ISR( TWI_SLAVE_vect )
2
  {
3
    uint8_t status = TWSSRA & 0xC0;      // Register A
4
  if (status & I2C_DATA_INTERRUPT)
5
  // Daten wurden vom Master empfangen oder werden angefordert
6
    {
7
      if (TWSSRA & (1 << TWDIR))          // Master fordert Daten vom Slave an
8
      {
9
      TWSD = tx_buff;
10
      TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
11
      }
12
    else       // Master sendet Daten zum Slave
13
      {
14
      TWSCRB |= (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
15
      command = TWSD;
16
      }
17
    }
18
  else if (status & I2C_ADDRESS_STOP_MATCH)
19
    {
20
    if (TWSSRA & I2C_BUS_COLLISION)
21
      {
22
      TWSCRB = (uint8_t) (1<<TWCMD1);
23
      }
24
    else
25
      {
26
      if (TWSSRA & (1<<TWAS))
27
        {
28
        // ACK
29
        TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
30
        }
31
      else
32
        {
33
        // Stop Condition
34
        TWSCRB = (uint8_t) (1<<TWCMD1);
35
        }
36
      }
37
    }
38
  }
Damit kann ich bereits Daten zum Master übertragen.
Sicher geht es besser.
Heiner

von Heiner (Gast)


Lesenswert?

Sorry vergessen zu sagen, senden und empfang klappt damit.

von Heiner (Gast)


Lesenswert?

Noch mal zur ADC.

Heiner schrieb:
> Wenn ich das in 16.13.5 richtig verstanden habe besteht ADCW bei 10 Bit
> aus ADCH und ADCL. Wenn ich nur 8 Bit brauche wird in Register ADCSRB
> das Bit ADLAR auf 1 gsetzt.
> Habe ich das richtig verstanden?

Habe jetzt ADCSRB |=(1<<ADLAR) auf 1 gesetzt. Habe dann die Spannung 
zwischen 0 und 5V verändert. Klappt aber nicht damit nur 8 Bit zu 
nutzen.
Mit welchem Bit kann ich von 10 Bit auf 8 Bit umschalten?

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Habe jetzt ADCSRB |=(1<<ADLAR) auf 1 gesetzt. Habe dann die Spannung
> zwischen 0 und 5V verändert. Klappt aber nicht damit nur 8 Bit zu
> nutzen.

Doch das klappt schon. Wenn man verstanden hat, was da passiert.

> Mit welchem Bit kann ich von 10 Bit auf 8 Bit umschalten?

Garnicht. Wenn du nur 8 Bit des Ergebnisses haben willst, benutzt du 
auch einfach nur acht Bit davon.

ADLAR dient nur dazu, die relevanten 8Bit der Wandlungsergebnisses in 
einem 8Bit-Register bereitzustellen und erspart so, zwei Register 
auszulesen und das Ergebnis erst passend zu hinschieben zu müssen.

Sprich: statt ADCW (2x 8 Bit) liest du nur ADCH aus. Da stehen deine 8 
Bit schon vollkommen passend drinne. Die zwei wegzuwerfenden Bits stehen 
in ADCL. Da du sie sowieso wegwerfen willst, brauchst du es erst 
garnicht auslesen.

von weiter weg (Gast)


Lesenswert?

Heiner schrieb:
> Klappt aber nicht damit nur 8 Bit zu nutzen.
> Mit welchem Bit kann ich von 10 Bit auf 8 Bit umschalten?

Ich habe es dir doch beschrieben wie es funktioniert.
Was bitte ist an meinem Satz nicht zu verstehen?
Du schaffst es nicht deine Lesefunktion so abzuändern damit
es wie von mir beschrieben arbeitet?

weiter weg schrieb:
> Ja, und nur ADCH auslesen (8 bittig!)... da die unteren 2 Bit
> nicht zu auswerten sind.

Wenn du das nicht willst/kannst dann unterstelle ich dir Trollerei
oder vollständige Überforderung. Im zweiten Fall empfehle ich dir
ein anderes Hobby wie z.B. Wandern oder Stricken/Häkeln.

von Noch weiter weg (Gast)


Lesenswert?

weiter weg schrieb:
> Im zweiten Fall empfehle ich dir
> ein anderes Hobby wie z.B. Wandern oder Stricken/Häkeln.

Mach Dich einfach weg. Ganz weit weg. Mach Dich RAUS!!

von Heiner (Gast)


Lesenswert?

Warun wird hier einem sofort ein Troll zu sein untergeschoben?
Die Fragen die ich stelle sind von grossen Intresse für mich.
Ist das der Umgang von euch sogenannten Fachleuten mit Anfänger oder 
macht ihr nur Stimmung oder blöde Anmache.
Zurüchk zum Thema.
Habe es jetzt so hinbekommen.
1
ADCSRB |=(1<<ADLAR);        // bei 8 Bit links
2
  while (ADCSRA & (1<<ADSC))
3
    {                  // auf Abschluss der Konvertierung warten
4
    }
5
  //return ADCW;            // ADC auslesen und zurückgeben bei 16 Bit
6
  return ADCH;            // 8 Bit mit ADLAR=1
Damit läuft 8 Bit und ich kann mit den Auskommentierten Zeilen auf 16 
Bit umstellen.
Bleibt noch das Problem mit der übertragung von 16 Bit mit dem Bus.

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Bleibt noch das Problem mit der übertragung von 16 Bit mit dem Bus.

Du meinst, es bleibt das Problem, dass dir da noch niemand eine fertige 
Lösung geliefert hat, richtig?

Wie wäre es mal mit tatsächlich selber programmieren? Alles Nötige an 
Hinweisen hast du im Laufe dieses Threads bereits bekommen.

Mehr geht nicht, das wäre Auftragsarbeit, dafür musst du mit Kohle rüber 
kommen.

von mitleser (Gast)


Lesenswert?

Heiner schrieb:
> Bleibt noch das Problem mit der übertragung von 16 Bit mit dem Bus.

Das wirkt wirklich äusserst dümmlich oder trollig. Bleibt keine
andere Schlussfolgerung.

Hier hattest du bereits den Hinweis:

Arduino Fanboy D. schrieb:
> Wer es verstanden hat 1 Byte zu senden, kann auch ein zweites
> übertragen.

von Heiner (Gast)


Lesenswert?

Nicht schon wieder das mit dem Troll. Versuche einfach es zu verstehen.
Hatte weiter oben bereits den Code für den Attiny 841 und den I2C bus 
angegeben. Da er anders ist z.B. als bei einem Slave (kein Prozessor) 
mit 16 Bit sieht die übertragung anders aus. Leider habe ich im Netz 
keine Info dazu gefunden.Vielleicht gehen ein paar Brocken zu meinem 
Verständnis.

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> mit 16 Bit sieht die übertragung anders aus.

Nur ganz unwesentlich.

> Leider habe ich im Netz
> keine Info dazu gefunden.Vielleicht gehen ein paar Brocken zu meinem
> Verständnis.

Mein Gott. Verstehe einfach, wie I2C funktioniert und benutze es. Das 
hat doch rein garnix mit der AVR8-Architektur im Allgemeinen oder dem 
TWI-Slave der ATiny441/841 im Besonderen zu schaffen.

Man muss einfach nur verstehen, wie der Bus funktioniert und den 
vorhandenen Code entsprechend nutzen. Wenn man ein Byte korrekt senden 
kann, zwei aber nicht, beweist das genau eine Sache: Man benutzt Code, 
den man nicht verstanden hat. Und die einzige logische Erklärung dafür 
ist:

Weil man wohl einfach zu FAUL war, zu lernen, wie der Bus 
funktioniert...

von mitleser (Gast)


Lesenswert?

c-hater schrieb:
> Weil man wohl einfach zu FAUL war, zu lernen, wie der Bus
> funktioniert...

Ein Troll hat immer noch ein "gutes" Argument in der Hinterhand.

von Veit D. (devil-elec)


Lesenswert?

Hallo Heiner,

ich sehe 2 Möglichkeiten

a) du zeigst uns wie du derzeit ein Byte sendest und empfängst
b) du nimmst die Arduino IDE, installierst zusätzlich das Package von 
SpenceKonde https://github.com/SpenceKonde/ATTinyCore und nutzt die 
fertige Lib von den Arduino Leuten bzw. die angpasste von Spencekonde an 
den ATtiny

von Einer K. (Gast)


Lesenswert?

Heiner schrieb:
> Hatte weiter oben bereits den Code für den Attiny 841 und den I2C bus
> angegeben.

Das hast du nicht!
Die Initialisierung, ja.
Die ISR auch.

Aber die (read/Write) API zur Software hast du geheim gehalten.

Also:
Nur ein untestbares Fragment gezeigt.
Exakt den Bereich, an dem es hakt, geheim gehalten.

von Heiner (Gast)


Lesenswert?

Habe nichts geheim gehalten. Noch mal das komplette Programm. Mehr habe 
ich dazu nicht und es geht damit.
1
#include "main.h"            // CPU 16MHz
2
#include <avr/interrupt.h>        // dient zur Behandlung der Interrupts
3
#include <avr/io.h>            // Integer-Definitionen
4
5
#define I2C_SLAVE_ADDRESS       0x52  // Slave Adresse 0x52
6
#define I2C_DATA_INTERRUPT      0x80  // 0x80
7
#define I2C_BUS_COLLISION       0x08  // 0x08
8
#define I2C_ADDRESS_STOP_MATCH  0x40  // 0x40
9
10
volatile uint8_t command;
11
volatile uint8_t tx_buf[2];  // 4
12
volatile uint8_t tx_buff = 11;  // 4
13
volatile uint8_t tx_buf_index = 0;
14
15
// Funktionsprototypen
16
void I2C_init(void);
17
18
void I2C_init(void)
19
  {
20
  TWSA = I2C_SLAVE_ADDRESS;          // TWI Adressregister
21
  TWSD = 0xFF;                // Datenregister
22
  TWSCRA = (1<<TWEN)|(1<<TWSHE)|(1<<TWASIE)|(1<<TWSIE)|(1<<TWDIE);      
23
  // Register A, TWEN-Schnittstelle Aktivieren, TWSHE-Haltezeit aktivieren, TWASIE-Adressenunterbrechung aktivieren, 
24
  // TWSIE-Stop Unterbrechung aktivieren, TWDIE-Datenunterbrechung aktivieren 
25
    TWSCRB = (1<<TWAA)|(1<<TWCMD1)|(0<<TWCMD0);  // Register B, TWI Bestätigungsaktion, TWI Befehl
26
  sei();      // Interrups einschalten
27
  }
28
29
ISR( TWI_SLAVE_vect )
30
  {
31
    uint8_t status = TWSSRA & 0xC0;      // Register A
32
  if (status & I2C_DATA_INTERRUPT)
33
  // Daten wurden vom Master empfangen oder werden angefordert
34
    {
35
      if (TWSSRA & (1 << TWDIR))          // Master fordert Daten vom Slave an
36
      {
37
      TWSD = tx_buff;
38
      TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
39
      }
40
    else       // Master sendet Daten zum Slave
41
      {
42
      TWSCRB |= (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
43
      command = TWSD;
44
      }
45
    }
46
  else if (status & I2C_ADDRESS_STOP_MATCH)
47
    {
48
    if (TWSSRA & I2C_BUS_COLLISION)
49
      {
50
      TWSCRB = (uint8_t) (1<<TWCMD1);
51
      }
52
    else
53
      {
54
      if (TWSSRA & (1<<TWAS))
55
        {
56
        // ACK
57
        TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
58
        }
59
      else
60
        {
61
        // Stop Condition
62
        TWSCRB = (uint8_t) (1<<TWCMD1);
63
        }
64
      }
65
    }
66
  }
67
68
int main(void)
69
  {  
70
  DDRA=0b00000011;      // Port A auf Ausgang schalten
71
  PORTA=0b00000011;      // Port A auf aus 
72
  DDRB=0b00000011;      // Port A auf Ausgang schalten
73
  PORTB=0b00000011;      // Port A auf aus  
74
  I2C_init();
75
  while(1)
76
    {
77
    if (command != 42)       // Taster T2 PD0
78
     {              // Wenn T1 gedrückt...
79
       PORTA &=~(1<<PINA1);    // LED 2 ein  
80
     }
81
     else
82
    {              // wenn nicht
83
       PORTA |=(1<<PINA1);    // LED 2 ein ??
84
    }  
85
     if (command != 43)       // Taster T2 PD0
86
    {              // Wenn T1 gedrückt...
87
      PORTA &=~(1<<PINA0);    // LED 2 ein
88
    }
89
     else
90
    {              // wenn nicht  
91
      PORTA |=(1<<PINA0);    // LED 2 ein ??
92
    }   
93
    
94
    {
95
    
96
      {
97
            
98
    // ========>> TASTENEINGABEN T3
99
    if (!(PINA & (1<<PINA7)) )  // Taster T 3
100
      {              // Wenn T3 gedrückt...
101
      tx_buff = 5;  // 4
102
      }
103
    
104
    // ========>> TASTENEINGABEN T2
105
    if (!(PINB & (1<<PINB2)) )  // Taster T 3
106
      {              // Wenn T3 gedrückt...
107
      tx_buff = 3;  // 4
108
      }    
109
      }
110
    }
111
   
112
    }
113
  }
Das einzige was fehlt ist die main. Da steht nur drin das CPU 10MHz 
sind.
LG Heiner

von Heiner (Gast)


Lesenswert?

Soll 16MHz sein

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Im Moment sendest du genau ein Byte aus 'tx_buff'.  Eine Ansatz wäre, 
aus tx_buff ein Array aus 2 Byte zu machen und dann tx_buff[0] und 
tx_buff[1] hintereinander zu senden.
In deiner ADC Routine könnte zum füllen dann stehen
1
tx_buff[0] = ADCH;
2
tx_buff[1] = ADCL;

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Danke für die Info

Matthias S. schrieb:
> In deiner ADC Routine könnte zum füllen dann stehen
> tx_buff[0] = ADCH;
> tx_buff[1] = ADCL;

Bei 16 Bit verwende ich ADCW und das besteht aus ADCH und ADCL.
Wenn ich nur 8 Bit verwende, nutze ich ADCH und ADLAR=1.
Dann brauche ich im Master nur aus denn 2 x 8 Bit wieder 16 Bit machen.
Das gefällt mir.

Heiner schrieb:
> if (TWSSRA & (1 << TWDIR))          // Master fordert Daten vom Slave an
>       {
>       TWSD = tx_buff;
>       TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
>       }

Meinst du diese Stelle?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Heiner schrieb:
> Meinst du diese Stelle?

J, sicher. Ist ja die Stelle, wo die Daten gesendet werden.

von Heiner (Gast)


Lesenswert?

Das Programm des Slave beim I2C Bus bzw. ISR empfinde ich als relativ 
gross und kompliziert. Da ich noch nicht beim Bus angekommen bin, ergibt 
sich eine Frage für mich.
Gibt es ein weniger Aufwändiges Programm für den Slave beim Attiny 441?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

I2C erfordert mehr Aufwand. Derzeit schreibst du das zu sendende Byte 
direkt in das Senderegister. Du weißt es kann nur ein Daten Byte geben, 
deswegen ist alles andere "egal". Für mehr als 1 Daten Byte benötigt man 
ein Protokoll. Ansonsten weiß man nicht ob ein Byte das Erste oder das 
Zweite oder welches überhaupt ist, wenn man hintereinander senden würde. 
Schau dir einmal die App Note AVR311 und AVR315 von Atmel an. Die 
Register passt du auf deinen ATtiny an.
https://www.microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en591794
https://www.microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en591792

Am Ende hast du eine Sende- und Empfangsfunktion.

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Habe mir die Stellen angesehen. Bin dazu geteilter Meinung. Habe z.B. 
Angaben wie asm und nop gefunden. Dachte eigentlich das sowas lange raus 
ist.

von Hannes (Gast)


Lesenswert?

Donnerwetter!

Du bist wirklich ein Crack!
Weißt Du, wofür “nop” oder “Sam” benötigt wird? Ich bezweifle das, und 
mit “Copy & Paste” kommst du nicht weit

SCNR

Hannes

von Hannes (Gast)


Lesenswert?

Mist!

Muss natürlich “asm” heißen nicht “Sam” - sche** Autokorrektur

von Halterloser (Gast)


Lesenswert?

Hannes schrieb:
> Mist!
>
> Muss natürlich “asm” heißen nicht “Sam” - sche** Autokorrektur

Ja, die Autokorrektur macht schöne Sachen. Mir hat sie mal ein Auto von 
MAN auf Scania korrigiert. Da konnte ich dann 2 Tonnen mehr laden.

von Rainer V. (a_zip)


Lesenswert?

Auch wenn ich noch nicht restlos davon überzeugt bin, dass wir hier 
nicht über den Tisch gezogen werden, zeigt sich doch ganz deutlich, wie 
heute Programmiert wird! Entsetzlich :-)
Gruß Rainer

von Veit D. (devil-elec)


Lesenswert?

Heiner schrieb:
> Habe mir die Stellen angesehen. Bin dazu geteilter Meinung. Habe z.B.
> Angaben wie asm und nop gefunden. Dachte eigentlich das sowas lange raus
> ist.

Hallo,

du meinst das?
1
asm("nop");

nop bedeutet eine einzige Taktverzögerung in der Arbeitung. asm bedeutet 
das nop inline gemacht wird, also wirklich real einen Takt Pause 
erzeugt. Im Kontext betrachtet mit den Kommentaren steht das in dem Code 
Bsp. nur als Platzhalter für irgendwelchen weiteren Code.

nop ist auch heute noch praktisch wenn man es sinnvoll einsetzt. Bspw. 
redet dein µC mit einem Device welches mittels meinetwegen SPI 
angesprochen wird. Jetzt ist dein Bus samt deiner Code Abarbeitung 
schneller wie das Device mit gewissen Wartezeiten zwischen seinen 
Kommandos/Daten. Allerdings sind die Wartezeiten auch nicht so lang, 
dass es sich lohnt kurz andere Dinge zu erledigen. Vorrausgesetzt Du 
möchtest das Device so schnell wie möglich fertig behandelt haben. Du 
benötigst bspw. 100ns Wartezeit wofür es sich nicht lohnt erst aus einer 
Funktion rauszuspringen und dann wieder reinzuspringen. Das benötigt 
deutlich mehr Takte als was es bringt. Hier kannste bspw. 2x nop 
einbauen. CPU Takt 20MHz -> 1x nop 50ns. Wenn das Device nicht 
zeitkritisch ist muss man es nicht machen und kann zwischendurch anderes 
erledigen.

Oft sieht man folgendes define.
1
#define NOP __asm__ __volatile__ ("nop\n\t")

Wofür \n\t hinter nop dienen soll kann ich nicht erklären.
new line und Tabulator? Wer kann den Grund dafür zusammen mit nop 
erklären?

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Veit D. schrieb:
> Wofür \n\t hinter nop dienen soll kann ich nicht erklären.
> new line und Tabulator? Wer kann den Grund dafür zusammen mit nop
> erklären?

Wenn man sich den ASM Zwischencode anzeigen lässt, steht das schön 
untereinander, statt in einer Zeile gequetscht

von Stefan F. (Gast)


Lesenswert?

Veit D. schrieb:
> Wofür \n\t hinter nop dienen soll kann ich nicht erklären.

Zeilenumbruch und Tabulator.
In Assembler muss hinter jedem Befehl ein Zeilenumbruch kommen und die 
Befehle sind üblicherweise mit Tabulator ein gerückt. Das spielt erst 
eine Rolle, wenn du mehrere asm befehle hintereinander schreibst und 
dann den Quelltext als Assembler-Listing ausgibt. Der sieht dann schöner 
aus.

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

Danke euch. Also Syntaxvorschrift. Im disassamblierten Code kann ich das 
nicht herauslesen. Da finde ich nur
1
#define NOP __asm__ __volatile__ ("nop\n\t")
2
  NOP; 
3
 280:  00 00         nop
4
  asm("nop\n\t");
5
 282:  00 00         nop

Original:
1
void setup (void)
2
{
3
  #define NOP __asm__ __volatile__ ("nop\n\t")
4
  NOP; 
5
  asm("nop\n\t");
6
}
7
8
void loop (void)
9
{ }

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Veit D. schrieb:
> Im disassamblierten Code kann ich das
> nicht herauslesen. Da finde ich nur
Da lassen sich die \n und \t auch nicht mehr finden.

Der C Compiler baut ASM Zwischencode(auf Wunsch), da siehst du es.
Der C++ Compiler tut das nicht.

von Veit D. (devil-elec)


Lesenswert?

Aha, Danke.

von Heiner (Gast)


Lesenswert?

Du scheinst es nicht zu glauben. Ich will keinen ärgern, über den Tisch 
ziehen oder ähnliches damit machen. Mein Ziel ist es einfach den Attiny 
441 (841) zu verstehen und anzuwenden. Mir gefällt einfach die 
Baugrösse, klein relativ wenige Pins und viele Anwendungen. Leider 
scheint meine Freude an dem IC nur von wenigen geteilt zu werden. Man 
findet im Netz wenige Beispiel dazu. Ja es stimmt, verwende teilweise 
vorhandenen Code aus dem Netz. Das sind dann aber Sachen um die Funktion 
zu verstehen oder einfach mal anschauen wie es andere machen. Wenn ich 
dann das Datenblatt dazunehme komme ich mit den Funktione weit aus 
besser klar. Da die Anwendung aber auf mein Brett bezogen sind, muss ich 
alles umbauen oder halt neu machen.
Soweit ist das klar. Sehen wir mal was es so für den I2C Bus gibt. Ein 
Programm geht ja, ist aber wahrscheinlich einfacher möglich.
LG Heiner

von Stefan F. (Gast)


Lesenswert?

Mit Arduino wärst du längst fertig.

von Hannes (Gast)


Lesenswert?

@Stefan

Das wage ich zu bezweifeln. Auch wenn Arduino Libraries bietet, mit 
denen man Funktionen “zusammenklimpern” kann, muss man dennoch wissen, 
wie es geht 😉.

Außerdem hat Veit D. schon mit den links brauchbare Hinweise gegeben- 
wenn man aber nicht versteht sie anzuwenden…

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Mit Arduino wärst du längst fertig.

Das ist schon möglich.
Kann ich den die ganzen Sachen verwenden wenn ich nicht mit einem 
Arduino arbeite?
Habe bisher alles in C gemacht ohne die ganzen Sachen von Arduino.
Alle notwendigen Sachen für den I2C Bus beim Attiny 841 sollen im 
Datenblatt stehen. Mag sein, leider schwer für mich zu verstehen. Habe 
angefangen die Register anzuschauen und wenn möglich zu verstehen. Ist 
leider für mich sehr schwer. Kann mir jemand dabei helfen es zu 
verstehen?

von Heiner (Gast)


Lesenswert?

Gibt es einen Attiny oder anderen IC der die gleiche I2C Schnitstelle 
wie der Attiny 441/841 verwendet?

von Hannes (Gast)


Lesenswert?

Hallo Heiner

Ich dachte, Du hättest den I2C Bus vom Attiny 841 schon funktionsfähig 
bzw. schon Daten per I2C ausgetauscht?

von Hannes (Gast)


Lesenswert?

Hallo Heiner

Ist Dein Problem der I2C des Attiny 841 oder die ADC Messung (lt 
Betreff)?

von Heiner (Gast)


Lesenswert?

Die ADC mit 8 und 16 Bit geht ohne Probleme.
Möchte jetzt einfach weitermachen und den ADC Wert auf einem Display mit 
dem Bus darstellen. Dazu möchte ich einen Atmega 128 als Master 
verwenden und ein Display ansteuern. Die Ansteuerung mit dem Atmega 
funktioniert bereits korrekt.
Soll ich lieber etwas neues aufmachen?

von Heiner (Gast)


Lesenswert?

Hannes schrieb:
> Ich dachte, Du hättest den I2C Bus vom Attiny 841 schon funktionsfähig
> bzw. schon Daten per I2C ausgetauscht?

Ja das stimmt, habe bereits Daten ausgetauscht. Leider ist das Programmm 
für den Slave etwas gross geraten. Deshalb mein Versuch es etwas kleiner 
und damit übersichtliches zu machen. Habe das Datenblatt dazu genommen, 
komme leider nur sehr schwer damit zurecht. Das funktionierende Beispiel 
für den slave kann ich kaum nachvollziehen.

von Hannes (Gast)


Lesenswert?

Hallo Heiner

Habe ich das korrekt verstanden:
Du willst mit dem Attiny 841 per ADC Werte einlesen (8 Bit), diese per 
I2C an den Atmega 128 schicken und die Werte per Display (das direkt 
ohne I2C am Atmega 128 angeschlossen ist) anzeigen.
Stimmt meine Zusammenfassung?

von Hannes (Gast)


Lesenswert?

Wobei der Attiny 841 der I2C Slave ist und der Atmega 128 der I2C Master 
ist - korrekt

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Kann ich den die ganzen Sachen verwenden wenn ich nicht mit einem
> Arduino arbeite?

Ja schon, weitgehend. Voraussetzung ist, dass Arduino diesen 
Mikrocontroller unterstützt. Offenbar gibt es für den ATtiny841 ein 
passendes Plugin (Core).

> Alle notwendigen Sachen für den I2C Bus beim Attiny 841 sollen im
> Datenblatt stehen. Mag sein, leider schwer für mich zu verstehen.

Ja das ist so. Die I²C Schnittstelle ist komplizierter als die meisten 
anderen, weil sie nicht nur einfach nur Daten rein/raus schiebt sondern 
ein komplettes Protokoll implementiert.

In Arduino ist der Teil bereits fertig. Diesen Anzuwenden ist fast so 
einfach, wie printf().

> Kann mir jemand dabei helfen es zu verstehen?

Fange mal mit eine Beschreibung des Protokolls an:
https://howtomechatronics.com/tutorials/arduino/how-i2c-communication-works-and-how-to-use-it-with-arduino/

Erstmal musst du verstehen, welche Signale der Bus in welcher 
Reihenfolge überträgt und welche Zustände es gibt. Denn diese spiegeln 
sich in den Registern wieder.

Lies auch die I²C Spezifikation, das Dokument ist uralt aber sehr gut:
https://www.nxp.com/docs/en/user-guide/UM10204.pdf

von Heiner (Gast)


Lesenswert?

Hannes schrieb:
> Du willst mit dem Attiny 841 per ADC Werte einlesen (8 Bit), diese per
> I2C an den Atmega 128 schicken und die Werte per Display (das direkt
> ohne I2C am Atmega 128 angeschlossen ist) anzeigen.

Stimmt nicht ganz. Der Attiny 841 soll per I2C an den Atmega 128 
angeschlossen werden. Auch das Display wird per I2C angeschlossen z.B. 
mit PCF8574. Verwende teilweise verschiedene Displays. Das Display und 
Verbindung mit verschiedenen Slaves funktioniert korrekt.

Stefan ⛄ F. schrieb:
> Ja das ist so. Die I²C Schnittstelle ist komplizierter als die meisten
> anderen, weil sie nicht nur einfach nur Daten rein/raus schiebt sondern
> ein komplettes Protokoll implementiert.

Da gebe ich dir sofort Recht.
Mit diesem Protokoll gibt es den Attiny 441/841. Gibt es da noch andere 
Typen mit dem gleichen Protokoll.
LG Heiner

von Einer K. (Gast)


Lesenswert?

Heiner schrieb:
> Mit diesem Protokoll gibt es den Attiny 441/841. Gibt es da noch andere
> Typen mit dem gleichen Protokoll.
Die Frage verstehe ich nicht

I2C ist ein Protokoll!
Das Protokoll besteht aus einer Hardware Vereinbarung und einem 
logischen Regelwerk.

Ich sage mal: ALLE µC können I2C.
Ein paar Tinys bieten dafür den USI Block
Andere Mega, nutzen spezialisierte TWI Einheiten.
Und per Software geht auch immer, wenn sonst nix geht.

Also:
Protokolle hat man nicht, sondern man implementiert sie.

Ist klar geworden, wo der Fehler in der Frage liegt?

von Heiner (Gast)


Lesenswert?

Vom Hersteller dieser Attiny werden noch andere Typen produziert. Gibt 
es andere Typen die die gleiche Hardware haben? Bei denen man auch mit 
der gleichen Software arbeiten kann?
Beispiel:
Es gibt Attiny die haben kein I2C. Da kann man per Software etwas 
machen.
Es gibt Attiny die haben I2C Bus ohne eigenes Protokoll.
Gibt es andere Attinys die das gleiche Protokoll verwenden?
Kurz gesagt, gibt es noch andere Typen deren Software auf dem Attiny 441 
anwenden oder vergleichen kann?

von Cyblord -. (cyblord)


Lesenswert?

Also ich habe den Tiny841 in einigen Projekten im Einsatz. Der tut was 
er soll, ohne große Überraschungen. Keine Ahnung warum jetzt 
ausgerechnet dieser Controller hier das Problem sein soll. Der TE ist 
das Problem. Mit dem Wissenstand wird JEDER Controller zum Problem. 
Daher kann ich leider auch nicht wirklich On-Topic antworten. Das wäre 
alles müßig und vergebens.

: Bearbeitet durch User
von Hannes (Gast)


Lesenswert?

Hallo Heiner

Hast Du hier schon mal geschaut 
Beitrag "ATtiny841 I2C Slave Beispiel"

von Hannes (Gast)


Lesenswert?

Hallo Cyblord

Schön wenn es bei Dir funktioniert 👍.

Wenn Du aber nicht helfen willst, kannst Du Dir den Beitrag sparen

SCNR

von Heiner (Gast)


Lesenswert?

Verwende selber diesen Controller in einigen Anwendungen. Da ich ein 
Anfänger bin erarbeite ich mir die Anwendungen. Schaue dazu ins 
Datenblatt und gehe die verschiedenen Möglichkeiten durch. Weiter oben 
habe ich nach ADC gefragt. Das funktioniert jetzt ohne Probleme. Kann es 
Anwenden und Nutzen. Bin dan zur nächsten Stufe gegangen und das ist für 
mich I2C, die übertragung der Daten vom Slave zum Master und Anzeige auf 
einem Display. Bei anderen Controller habe ich das relativ einfach 
hinbekommen. Leider ist das Beispiel für einen funktionierenden Slave 
sehr gross und für mich in einigen Sachen nicht verständlich. Deshalb 
einfach die Frage nach Hilfe dabei.

von Heiner (Gast)


Lesenswert?

Hannes schrieb:
> Hast Du hier schon mal geschaut
> Beitrag "ATtiny841 I2C Slave Beispiel"

Ja, diesen Beitrag kenne ich. Er ist auch Grundlage für meinen Slave. 
Mein Programm funktioniert damit, noch ein paar Anpassungen und es geht.
Was ich daran nicht verstehe ist die ISR. Die ist doch so gross.
Geht das nicht auch kleiner?

von Hannes (Gast)


Lesenswert?

Wenn’s funktioniert ist es doch 👍

Kleiner machen geht immer, ob’s DANN noch funktioniert 🤔

Warum willst Du die ISR denn kleiner haben?

von Heiner (Gast)


Lesenswert?

Hallo Hannes
Es geht haupsächlich darum es zu verstehen.
Habe jetzt im Netz gesucht und noch einiges gefunden.
Einfache Frage dazu:
Warum braucht der Attiny 441
- void Timer0_init(void)
- ISR(TIMER0_COMPA_vect)
- ISR(TWI_SLAVE_vect)

Da ich den Attiny 441(841) in verschiedenen Schaltungen verwenden 
möchte, kann es dazu führen 16 Bit oder 8 Bit oder mehrfache 8 Bit (z.B. 
2 oder 4 x ADC) oder (schnelle) Schalterstelleungen zu übertragen. Das 
nutze ich z.B. um eine Tasterentprellung zu machen. Dadurch kann man 
Tasten verschieden nutzen. Oder einen Enkoder als universeller Eingabe 
zu verwenden oder ein Joystick.
Teilweise sind Teile da von schon lauffähig, andere warten noch auf das 
Programm.
LG Heiner

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Mit diesem Protokoll gibt es den Attiny 441/841. Gibt es da noch andere
> Typen mit dem gleichen Protokoll.

Alle Mikrocontroller mit I²C (bzw. TWI), also eigentlich fast alle außer 
ein paar wenige Ausnahmen die nur USI haben. Die sind noch schwieriger 
zu programmieren.

Heiner schrieb:
> Vom Hersteller dieser Attiny werden noch andere Typen produziert. Gibt
> es andere Typen die die gleiche Hardware haben? Bei denen man auch mit
> der gleichen Software arbeiten kann?

Was soll denn diese Frage? Andere Typen mit gleicher hardware wirst du 
genau so wenig programmieren können. Bleibe mal lieber auf dem Weg zur 
Problemlösung.

von Hannes (Gast)


Lesenswert?

@Stefan

+1 😉

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ehrlich gesagt verstehe ich dein Problem, Heiner, so langsam auch nicht 
mehr. Wenn du es bei anderen Controllern hinbekommen hast, woran 
scheitert es dann beim ATtiny? Das kam noch nie zur Sprache. Schau mal 
ob du damit was anfangen kannst.
http://www.peterfleury.epizy.com/avr-software.html#libs
Es ist auch keine Schande sich die Arduino Quellen anzuschauen oder gar 
zu nutzen. Im Grunde brauchst du dir nur die Quellen von Spencekonde 
anschauen. 
https://github.com/SpenceKonde/ATTinyCore/tree/master/avr/libraries/Wire
Jetzt bist du dran.

von Lass gehn, Elfriede! (Gast)


Lesenswert?

Es scheitert daran, daß manche AVR
- Kein I²C interface haben
- andere kein USI Interface besitzen
- wieder andere keins von Beiden und mittels Software selbst eines 
gebastelt werden muss

- Unverständliche Software mit unverständlichen Bibliotheken aus aller 
Herren Länder verwurstelt werden muß.

-> Schmeiß den Dreck aus dem Konntrolle und installiere Bascom. Damit 
geht es am Einfachsten und es gibt jeweils ein Beispielprogramm in der 
Hilfe.

von Heiner (Gast)


Lesenswert?

Veit D. schrieb:
> Schau mal
> ob du damit was anfangen kannst.
> http://www.peterfleury.epizy.com/avr-software.html#libs

Die Datein und Programme von Peter verwende ich bereits. Besonders für 
I2C und das Display. Seine Programme sind auch Grundlage bei anderen 
Sachen von mir.
Leider ist der Attiny 441 mit seinem I2C Bus anders als die anderen. 
Nach Quellen im Netz haben die es total anders gemacht. Mit den anderen 
Programmen die auf den slaves laufen geht es nicht. Teilweise sind die 
Register anders.
Da muss ich mich weiter durchkämpfen.
LG Heiner

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Was soll denn diese Frage? Andere Typen mit gleicher hardware wirst du
> genau so wenig programmieren können. Bleibe mal lieber auf dem Weg zur
> Problemlösung.

Habe gehofft einen anderen IC zu finden mit der gleichen Hardware, wo es 
vielleicht besser passende Software.

von Egonwalter M. (heiner1234)


Lesenswert?

Heiner schrieb:
> Stefan ⛄ F. schrieb:
>> Was soll denn diese Frage? Andere Typen mit gleicher hardware wirst du
>> genau so wenig programmieren können. Bleibe mal lieber auf dem Weg zur
>> Problemlösung.
>
> Habe gehofft einen anderen IC zu finden mit der gleichen Hardware, wo es
> vielleicht besser passende Software.

Naja, wenn's die gleiche Hardware ist, wird's wohl auch die gleiche 
Software sein ...
Denke, es wäre zielführend, wenn Du mal ALLE (!) Deine bislang für 
dieses Projekt erstellten Sourcen hier zur Verfügung stellen würdest; 
vielleicht könnte man dann besser Hilfe geben.

Und wenn Du GENAU erklärst, was Deine Zielsetzung ist - z.B "mit dem 
ATiny 841 ADC Werte (8Bit) einlesen, mittels I2C an den Master 
(ATMega128) übertragen und diese Werte mittels I2C an ein LCD schicken 
zwecks Anzeige der 8-Bit ADC Werte" - eine klar umrissene 
Aufgabenstellung...

mfg

von Heiner (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Und wenn Du GENAU erklärst, was Deine Zielsetzung ist - z.B "mit dem
> ATiny 841 ADC Werte (8Bit) einlesen, mittels I2C an den Master
> (ATMega128) übertragen und diese Werte mittels I2C an ein LCD schicken
> zwecks Anzeige der 8-Bit ADC Werte" - eine klar umrissene
> Aufgabenstellung...

Du hast es bereits gesagt. Genauso will ich es machen. Die gesamte 
vorhanden Software steht bereits oben drin. ADC funktioniert dank eurer 
Hilfe. Jetzt bleibt noch die Werte zum Master zuschicken und dann 
anzuzeigen

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Heiner

Ich versteh's nicht - Du hast doch Dein Programm von 
Beitrag "Re: ATtiny841 I2C Slave Beispiel"

- dieses Programm soll doch funktionieren, speziell nach den 
Zeit-Anpassungen beim Master

- Was funktioniert denn bei Deinem Programm nicht?

- Beim o.a. Programm sind ja DEBUG Ausgaben, damit man feststellen kann, 
was und wo's klemmt...

- eigentlich müsstest Du doch das o.a. Programm problemlos übernehmen 
können, da es für den Attiny 841 ist und einen Sendebuffer von 4 Bytes 
beim Slave (Attiny 841) hat ...

mfg

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Ja das stimmt genau. Das Programm funktioniert korrekt. Was ich noch 
machen muss, die Anpassung an 8 oder 16 Bit und die passende übertragung 
dazu.
Was mich bei diesem Programm verunsicht ist die Grösse. Dadurch ist es 
für mich sehr unübersichtlich und kompliziert. Programme bei anderen 
slaves sind übersichtlicher und damit besser zu verstehen.
Deshalb auch die Frage dazu, geht es nicht kürzer bzw. einfacher.

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Heiner

Grundgütiger!

Wenn die Übertragung und die Anpassung an 8 bzw 16 Bit noch nicht 
gemacht ist, funktioniert Dein Programm noch NICHT - ganz klar!

Und das Programm kürzer machen - geht bestimmt, dann musst Du es aber 
auch mal zeigen, meine Glaskugel ist derzeit in Reparatur 🤷‍♂️.

Das Stück SW, das Du oben reingestellt hast ist gelinde gesagt …

Zeig was Du hast, sonst kann man Dir nicht helfen 🤷‍♂️

Eine schwammige Aussage wie “kann man das Programm nicht kleiner oder 
kürzer machen” ist Unsinn

Mit freundlichen Grüßen

von weiter weg (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Hallo Heiner

Beim grundgütigen Egonwalter sollte man sich erst mal seinen
ureigensten Thread reinziehen bevor man darüber urteilt ob
er hier kompetente Hilfestellung geben kann oder nicht.

Beitrag "Arduino UNO USART Daten fehlen"

von Cyblord -. (cyblord)


Lesenswert?

Hier fehlt es einfach an Programmiererfahrung und Wissen. Es gibt an 
sich gar kein Problem. Und per default ist das ADC Ergebnis sowieso 
schon am LSB ausgerichtet. Die Makros machen den Rest. D.h. man liest 
einfach ADCW und hat den 16 Bit Wert. Wer unbedingt den 8 Bit Wert will, 
setzt das entsprechende Bit für die Umschaltung der Ausrichtung und kann 
dann einfach ADCL lesen.
Das ist alles lächerlich einfach. Wer sich damit so überfordert fühlt 
der soll einfach mal einen Gang zurückschalten und nochmal zur 
blinkenden LED zurückgehen.

Und vor allem: I2C Slave an den AVRs, nein an allen Controller, würde 
ich vermeiden. Vor allem für so unsichere Anfänger. Einfach nicht 
machen.

: Bearbeitet durch User
von Egonwalter M. (heiner1234)


Lesenswert?

@ weiter weg

Und was hat der von Dir zitierte Beitrag mit Heiner’s Problem zu tun?

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Was mich bei diesem Programm verunsicht ist die Grösse. Dadurch ist es
> für mich sehr unübersichtlich und kompliziert. Programme bei anderen
> slaves sind übersichtlicher und damit besser zu verstehen.

Wohl kaum. Das Programm ist (noch nicht einmal ganz) komplex genug, um 
das Protokoll abbilden zu können. Es gibt nunmal für einen I2C-slave so 
und so viele mögliche Stati und wenn man einen vollwertigen Slave 
implementieren will, muss man die halt auch alle unterstützen, also im 
Programm behandeln.

Einsparungen können sich nur dann ergeben, wenn man auf Teile der 
Möglichkeiten des Protokolls verzichtet, z.B. halt auf die Möglichkeit, 
mehr als ein Payload-Byte pro Transaktion zwischen Master und Slave zu 
bewegen. Und/oder gar auf die Möglichkeit, überhaupt Payload in eine der 
beiden Richtungen zu transferieren. Am allermeisten spart man 
allerdings, wenn man überhaupt keinen Transport von Payload vorsieht. 
Und du wirst lachen: selbst dafür gibt es denkbare Anwendungen.

Dein Problem ist offensichtlich: du kennst das I2C-Protokoll nicht und 
scheinst auch nicht gewillt zu sein, zu lernen, wie es funktioniert. 
Dann hat man NATÜRLICH erhebliche Probleme, zu verstehen, wie ein 
Programm funktioniert, welches dieses Protokoll implementiert. 
Insbesondere dann, wenn es das Protokoll vollständig implementiert, denn 
dann erreicht es naturgemäß den größten Umfang.

von Heiner (Gast)


Lesenswert?

Könnte es seindas es hier Unterschiede im Protokoll gibt. Man kann ja 
Daten von einem Slave lesen, z.B. PCF8574 oder einem Attiny oder halt 
einen anderen Prozessor. Beim PCF8574 ist die Sache ja relativ einfach, 
ist Hardware mässig alles vorhanden. Die Software kommt in den Master. 
Der Master liest die Daten aus dem Slave aus oder schreibt neue rein. 
Weiter oben steht ein Hinweis auf das Protokoll. Das habe ich 
durchgelesen, ist unterteilt in verschiedene Bereiche, wie Adresse, 
Register und Daten.
Bei dem Attiny ist das was anderes für mich. Es gibt fertige 
Bibliotheken dazu, da wurde jtronic genannt. Die kenne ich, sind aber 
nur für bestimmte Typen brauchbar. Das passt alles nicht zum Attiny841. 
Vergessen wir mal den Umfang. Bin dabei zu lesen. Da werde ich nichts 
dran änder und alles so lassen wie es ist.
LG Heiner

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Könnte es seindas es hier Unterschiede im Protokoll gibt.

Nein, das I2C-Protokoll ist immer das gleiche. Aber man kann es auf 
unterschiedliche Art nutzen. Das ist dann ein übergeordnetes Protokoll. 
Es entsteht ein Protokollstack.

Ganz genau dieselbe Soße wie z.B. im Netzwerkbereich. Da gibt es MAC, 
darauf setzt z.B. IP auf, darauf wiederum z.B. TCP, darauf wiederum z.B. 
HTTP usw. usf.

In deinem Anwendungsfall ist es halt einfach so, dass du das 
übergeordnete Protokoll komplett frei definieren kannst, da du sowohl 
master als auch slave selber implementierst.
Es gibt keinen verpflichtenden Standard dafür. Das einzige, was es 
sicherstellen muss, ist die standardgerechte Nutzung des I2C-Protokolls, 
was es als Transport-Protokoll benutzt.
Im µC-Bereich verschmelzen aber diese beiden Layer aus Effizienzgründen 
oft, d.h.: man implementiert auf dem I2C-Layer nur das, was man für das 
übergeordnete Protokoll tatsächlich benötigt.

> PCF8574

Wenn du einen Slave bauen willst, der mit dem Anwendungsprotokoll dieses 
Teils kompatibel ist, dann musst du das halt einfach tun. Nur ist es 
wohl nicht sonderlich sinnvoll. 8Bit-digital-IO (konfigurierbar) vs. 
16bit-analog-out (nicht konfigurierbar)? Nur ein Idiot würde versuchen, 
das kompatibel zu machen. Passt einfach nicht.

Vergiß' die Wichsvorlagen, lerne Denken.

von Rainer V. (a_zip)


Lesenswert?

Heiner schrieb:
> Da liegt auch das Problem. Eine 16 Bit übertragung mit I2C habe ich noch
> nie gemacht. Kennst du ein Beispiel dazu?

So weit waren wir am 12.06....und für mich ist der TO seitdem keinen 
Schritt weiter gekommen. Sorry...glaube kaum, dass das noch was wird.
Gruß Rainer

von Egonwalter M. (heiner1234)


Lesenswert?

Heiner hat 'nen neuen Thread bezgl I2C aufgemacht - wäre schön gewesen, 
er hätte es auch hier kundgetan ...

siehe:

Beitrag "I2C Bus mit dem Attiny 841"

SCNR

: Bearbeitet durch User
Beitrag #6731431 wurde von einem Moderator gelöscht.
von Heimer (Gast)


Lesenswert?

Sorry und Danke für deine Hilfe

von c-hater (Gast)


Lesenswert?

Rainer V. schrieb:

> So weit waren wir am 12.06....und für mich ist der TO seitdem keinen
> Schritt weiter gekommen. Sorry...glaube kaum, dass das noch was wird.

Sehe ich auch so. Es sei denn, irgendwer erbarmt sich und liefert eine 
fertige Wichsvorlage.

So, wie's aussieht, ist genau das, was der TO erreichen will. Er selber 
ist offensichtlich unfähig, auch nur die Konzepte zu verstehen. Und 
lernen mag er wohl auch nicht.

von Heiner (Gast)


Lesenswert?

Staube über deinen Pessimismus. Es kommt so richtig negativ rüber.
Zu deiner Info. Das Programm funktioniert ohne Probleme. Kann es als 8 
bit oder 10 Bit nutzen. Kann verschiedene Werte angeben. Habe 
verschiedne Stufen drin. Habe das Programm für mich vollkommen 
auskommentiert mit den Angaben im Datenblatt versehen. Die Einstellungen 
die DB angegeben werden sind soweit klar. Teste noch Einstellungen mit 
der Verstärkung, Differenzeingang und anderes. Da bin ich aber auch der 
Hardware dran. Ansonsten habe ich angefangen die Werte per I2C am Bus zu 
übertragen und Anzuzeigen.
Nach Anfang sieht das nicht mehr aus.

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> und liefert eine
> fertige Wichsvorlage.

Auch das ist schon geschehen!
Veith sprach mehrfach vom "Spencer Arduino Core für Tinys"
https://github.com/SpenceKonde/ATTinyCore

OK, das ist C++ (zu einem großen Teil), aber das winzige Detail fällt 
hier wohl nicht ins Gewicht.

Beitrag #6731881 wurde von einem Moderator gelöscht.
von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Staube über deinen Pessimismus. Es kommt so richtig negativ rüber.

Entspricht meinem Gefühl beim Schreiben. Das WAR sehr negativ.

> Zu deiner Info. Das Programm funktioniert ohne Probleme.

Wenn das so ist: Warum sind deine beiden Threads noch nicht mit "Lösung 
gefunden" und "Lösung sieht soundso aus" beendet?

Das wäre ja die logische Konsequenz, wenn stimmt, was du hier 
behauptest...

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Heiner

Wenn Dein Programm bezüglich ADC funktioniert-prima 👍.

Dann markiere DIESEN Thread als “erledigt”, damit keiner mehr meint, er 
müsste seinen “Senf” dazugeben - und Du ersparst Dir Beleidigungen wie 
von “c-hater” (schon sein Pseudonym ist Hinweis auf seine Einstellung 
und seine vulgäre Sprache 🤮)

von Heiner (Gast)


Lesenswert?

Das würde ich sehr gern machen, doch wo stelle ich das ein?

von Rainer V. (a_zip)


Lesenswert?

Egonwalter M. schrieb:
> und Du ersparst Dir Beleidigungen wie
> von “c-hater” (schon sein Pseudonym ist Hinweis auf seine Einstellung
> und seine vulgäre Sprache 🤮)

Bullshit...c-hater drückt oftmals genau das aus, was manchmal einfach 
ist! Nämlich unerträgliche Blödheit. Da schlägt man auch schon mal über 
die Strenge, besonders wenn sich Blödheit, Unkenntnis und Arroganz 
paaren. Geht mir oft auch so, auch wenn ich nicht immer einer Meinung 
mit anderen bin... auch wenn es so scheint. An den TO speziell: du 
scheinst zu den Leuten zu gehören, die extrem unflexibel und 
schwerfällig bei der Horizonterweiterung agieren. Zudem gehörst du auch 
offensichtlich zu den Leuten, die sich einfach umdrehen und weggehen, 
wenn sie nicht das hören, was sie hören wollen. Das ist auch im 
richtigen Leben richtig Sch...man macht keinen neuen Thread auf, nur 
weil man im alten zu hören bekommt, dass das Problem mangels 
Sachverstand nicht zu lösen sein wird. Aber was rede ich, ist ja alles 
nicht neu und wird auch nicht das letzte mal sein...also auf in den 
Biergarten :-)
Gruß Rainer

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Rainer V.

Fühlst Du Dich nun besser?

SCNR

von Heiner (Gast)


Lesenswert?

Zum ADC hatte ich gesagt es funktioniert und da der Titel nicht das 
aussagt was ich wissen möchte, kommt ein anderer Thread.
Warum müssen alle so agressiv sein. Ich Frage weil ich es nicht weis. Es 
kommen Hinweise, mal kleine oder mal grosse dazu. Ich will es nicht 
geschenkt haben, aber ein Hinweise oder Infos über was falsches sind 
sehr Hilfreich.
Leider bleibt mir der Inhalt der Datenblätter teilweise, auch mit 
übersetzung, sehr verschlossen.
Ein paar freundliche Worte oder ein kleiner Anstoss wirken Wunder und 
ist alle mal besser als seine Wut über das Wissen der anderen 
auszudrücken.
Geh ruhig Biertrinke und beruhige dich. Geniesse das schöne Wetter und 
lass uns gemeinsam anstossen.

von Rainer V. (a_zip)


Lesenswert?

Ich akzeptiere dein Friede-Freude...aber es ist halt relativ sinnlos! 
Auch wenn du es nicht so empfinden wirst, ist hier zuallererst 
Sachlichkeit gefordert. Und die wird durch angekündigte Unwissenheit 
nicht einfach weggewischt. Hier meldet sich jeder zweite mit dem 
Hinweis, dass er erstens überhaupt keine Ahnung hat und zweitens auch 
gerade nicht weiß - also quasi ratlos ist - wie er überhaupt mehr Infos 
zu seinem "Wißbegehren" (genau das ist es und genau das ist in dieser 
Allgemeinheit in einem Fachforum eben fehl am Platz!) bekommen kann. Und 
genau diese Haltung provoziert oft nach wenigen Einträgen halt Unwillen. 
Wenn ich was zu Lebensfragen im allgemeinen Sinn wissen will, dann frage 
ich bei "Wer weiß was" und wenn ich mich berufen fühle, darauf zu 
Antworten, dann tu ich das dort. Aber hier ist kein "Wer weiß was" und 
das soll auch so bleiben!!
Gruß Rainer

von Einer K. (Gast)


Lesenswert?

Heiner schrieb:
> aber ein Hinweise oder Infos über was falsches sind
> sehr Hilfreich.

Hmm ....
Ich würde richtige Hinweise als hilfreicher erachten, als falsche, oder 
Hinweise auf falsches.

Heiner schrieb:
> Leider bleibt mir der Inhalt der Datenblätter teilweise, auch mit
> übersetzung, sehr verschlossen.
Das ist natürlich eine schwierige Situation.
Welche "wir" auch nicht ändern können.

Denn es gilt ja der Grundsatz:
> Selber lesen, macht selber schlau.

Beitrag #6732109 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> OK, das ist C++ (zu einem großen Teil), aber das winzige Detail fällt
> hier wohl nicht ins Gewicht.

Er will sich ja "nicht verzetteln" und lieber "bei C bleiben".

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Er will sich ja "nicht verzetteln" und lieber "bei C bleiben".

Das ist so ziemlich die einzige vernünftige Entscheidung, die er 
getroffen hat. Das muss man ihm zu Gute halten.

C ist schon schwierig genug, aber C++ ist ein absoluter Moloch, den 
selbst die Schöpfer und Entwickler der Sprache kaum noch im vollen 
Umfang überblicken.

Bezüglich der normalen Programmierer ist es aber ziemlich dieselbe Soße, 
kaum einer beherrscht die selbst gewählte Sprache wirklich im vollen 
Umfang. Übrigens auch du nicht und auch der Fanboy nicht.

von Rainer V. (a_zip)


Lesenswert?

Wenn es nicht so banal wäre, würde ich schon verzetteln beim TO für 
relativ unmöglich halten! Er kann sich gar nicht Verzetteln, weil er 
überhaupt nur einen einzigen großen Zettel hat! Ein eindeutiges Zeichen 
für vernünftiges Verhalten ist, seine Probleme verstehen zu können!!! 
Hat mal irgendwer gesagt (Monty Python war es sicher nicht)
Rainer

von Stefan F. (Gast)


Lesenswert?

c-hater schrieb:
> C ist schon schwierig genug, aber C++ ist ein absoluter Moloch, den
> selbst die Schöpfer und Entwickler der Sprache kaum noch im vollen
> Umfang überblicken.
>
> Bezüglich der normalen Programmierer ist es aber ziemlich dieselbe Soße,
> kaum einer beherrscht die selbst gewählte Sprache wirklich im vollen
> Umfang. Übrigens auch du nicht und auch der Fanboy nicht.

Da muss ich dir ausnahmsweise mal zustimmen.

Ergänzend: Es ist OK und praktikabel, eine Programmiersprache nur 
teilweise zu verwenden. Problematisch wird das erst, wenn man auf 
fremden Code stößt, den man deswegen nicht versteht.

Das vollständige Verstehen von beliebigem fremden Code ist allerdings 
eher etwas für die alten Hasen mit viel Berufserfahrung. C++ macht es da 
einem besonders schwer, dicht gefolgt von Java. Diese voll zu 
durchblicken sollte man nicht von Anfängern erwarten, das wäre gemein.

Es hat schon seinen guten Grund, warum immer wieder Programmiersprachen 
erdacht werden, die einfach und dennoch ausreichend seien sollen. Wir 
werden in 30 Jahren sehen, ob das jemandem mit Erfolg gelungen ist. 
Vielversprechende Ansätze sind zu sehen, z.B.: Python und Go. Die sind 
aber noch zu jung, um sie final zu bewerten, finde ich.

Assembler glänzt mit Einfachheit und der Gewissheit, dass man damit 
wirklich ohne Einschränkung alles machen kann - irgendwie. Doch der 
Sprache fehlt es am Mitteln zur übersichtlichen Gestaltung großer 
Programme, der Unterstützung von Teamarbeit und statische Code-Analysen 
zur Vermeidung von Fehlern.

Mit Assembler programmieren ist, als ob ich dich mit Spitzhacke, Schwert 
und Feuerzeug bewaffnet vor einen Berg stelle und dir sage: Baue mir ein 
Hotel - du hast 10 Monate Zeit.

Ist das machbar: Zweifellos! Will das jemand so machen? 
Unwahrscheinlich, es sei denn derjenige nennt sich c-hater.

von Egonwalter M. (heiner1234)


Lesenswert?

c-hater schrieb:
> Stefan ⛄ F. schrieb:
>
>> Er will sich ja "nicht verzetteln" und lieber "bei C bleiben".

> Bezüglich der normalen Programmierer ist es aber ziemlich dieselbe Soße,
> kaum einer beherrscht die selbst gewählte Sprache wirklich im vollen
> Umfang. Übrigens auch du nicht und auch der Fanboy nicht.

Nur jemand mit übersteigertem Selbstbewusstsein wird für sich in 
Anspruch nehmen (wollen), dass er die selbst gewählte Sprache wirklich 
in vollem Umfang beherrscht.

von Stefan F. (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Nur jemand mit übersteigertem Selbstbewusstsein wird für sich in
> Anspruch nehmen (wollen), dass er die selbst gewählte Sprache wirklich
> in vollem Umfang beherrscht.

Oder jemand, der nur die primitivste Sprache akzeptiert, weil er sie 
tatsächlich vollständig beherrschen kann.

Meinen Pelikan Füller kann ich vollständig beherrschen, aber ich kann 
damit keine Enzyklopädie in angemessener Zeit und Qualität erstellen.

von Einer K. (Gast)


Lesenswert?

c-hater schrieb:
> Stefan ⛄ F. schrieb:
>
>> Er will sich ja "nicht verzetteln" und lieber "bei C bleiben".
>
> Das ist so ziemlich die einzige vernünftige Entscheidung, die er
> getroffen hat. Das muss man ihm zu Gute halten.
>
> C ist schon schwierig genug, aber C++ ist ein absoluter Moloch, den
> selbst die Schöpfer und Entwickler der Sprache kaum noch im vollen
> Umfang überblicken.
>
> Bezüglich der normalen Programmierer ist es aber ziemlich dieselbe Soße,
> kaum einer beherrscht die selbst gewählte Sprache wirklich im vollen
> Umfang. Übrigens auch du nicht und auch der Fanboy nicht.

Da ist er wieder der c-hater, und noch mehr C++ Hasser....

Meine Ansage lautet:
Wenn zur Wahl steht C oder C++ zu lernen, dann ist ganz klar C++ zu 
bevorzugen.


Von den Gründen möchte ich hier mal nur 2 aufführen.

- Pointer vs. Referenzen.
Man kann viel mehr Mist mit Pointern bauen, als mit Referenzen.

- Array Index Überschreitungen
Ein Tipp oder logischer Fehler, bei der Indexberechnung in for 
Schleifen, führt ganz fix ins Versagen.
Der RangeBasedForLoop vermeidet dieses.

Diesen Zugewinn in den Wind zu schlagen, nur weil an anderer Stelle 
evtl. eine Überforderung auftreten könnte ist dumm.

Damit ist die Entscheidung des TO dumm, weil ohne Fachkenntnis getroffen 
und die Zustimmung des c-hassers sicherlich aus dem gleichen Grund 
genauso dumm.

Dem TO, kann ich verzeihen da er es nicht besser weiß.
Aber der C-hater, der könnte es wissen, aber er hat wenn er C++ hört, 
sofort so viel Schaum vorm Mund, dass es ihn blind macht.

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Diesen Zugewinn in den Wind zu schlagen, nur weil an anderer Stelle
> evtl. eine Überforderung auftreten könnte ist dumm.

Das ist nur dumm, wenn man davon ausgeht, irgendwann mal Fehler zu 
machen. Der c-hater weiß aber, dass er so etwas nicht nötig hat, weil er 
keine Fehler macht. Zumindest scheint er das zu glauben. Wir kennen ja 
seine entsprechenden Vorträge.

von Egonwalter M. (heiner1234)


Lesenswert?

Arduino Fanboy D. schrieb:


> Meine Ansage lautet:
> Wenn zur Wahl steht C oder C++ zu lernen, dann ist ganz klar C++ zu
> bevorzugen.
> >
> Von den Gründen möchte ich hier mal nur 2 aufführen.
>
> - Pointer vs. Referenzen.
> Man kann viel mehr Mist mit Pointern bauen, als mit Referenzen.
>
> - Array Index Überschreitungen
> Ein Tipp oder logischer Fehler, bei der Indexberechnung in for
> Schleifen, führt ganz fix ins Versagen.
> Der RangeBasedForLoop vermeidet dieses.
>
> Diesen Zugewinn in den Wind zu schlagen, nur weil an anderer Stelle
> evtl. eine Überforderung auftreten könnte ist dumm.
>
> Damit ist die Entscheidung des TO dumm, weil ohne Fachkenntnis getroffen
> und die Zustimmung des c-hassers sicherlich aus dem gleichen Grund
> genauso dumm.
>
> Dem TO, kann ich verzeihen da er es nicht besser weiß.
> Aber der C-hater, der könnte es wissen, aber er hat wenn er C++ hört,
> sofort so viel Schaum vorm Mund, dass es ihn blind macht.

Das ist eine etwas ... arrogante ... Sichtweise, jemandes Entscheidung 
als "dumm" zu bezeichnen, nur weil er sich für C und nicht C++ 
entschieden hat.
Ich kann auch kein C++, verwahre mich aber schärfstens dagegen, dass 
irgendjemand meine Entscheidung als "dumm" bezeichnet.

Noch herrscht das Recht auf freie Entscheidung, und die ist zu 
respektieren.

von Gib 8, was Du sagst (Gast)


Lesenswert?

Egonwalter M. schrieb:


> Ich kann auch kein C++, verwahre mich aber schärfstens dagegen, dass
> irgendjemand meine Entscheidung als "dumm" bezeichnet.
>
> Noch herrscht das Recht auf freie Entscheidung, und die ist zu
> respektieren.

Aber doch nicht hier! Schreibe hier mal beiläufig, daß Du z.B. mit 
Bascom alle Deine Aufgaben erledigst. Binnen 5 Minuten liegst Du als 
blank genagtes Skelett da.

Der Mensch beginnt hier erst mit der Benutzung von C.

von Helmut L. (helmi1)


Lesenswert?

Stefan ⛄ F. schrieb:
> Mit Assembler programmieren ist, als ob ich dich mit Spitzhacke, Schwert
> und Feuerzeug bewaffnet vor einen Berg stelle und dir sage: Baue mir ein
> Hotel - du hast 10 Monate Zeit.

Oder man ist so schlau und baut sich damit erstmal bessere Werkzeuge...

von Einer K. (Gast)


Lesenswert?

Punkt 1:
Egonwalter M. schrieb:
> Noch herrscht das Recht auf freie Entscheidung, und die ist zu
> respektieren.

Da hast du wahr!
Natürlich darfst du eigene Entscheidungen treffen!
Wie könnte ich dir das verwehren?

Allerdings darf ich auch eine Meinung dazu haben, wie "schlau" diese 
Entscheidung ist.

Und jetzt zu Punkt 2:
Natürlich darfst du dich auch so weit mit deinen Entscheidungen 
identifiziere, so dass eine Kritik an dieser Entscheidung, also eine 
Wertung dieser Entscheidung, dich beleidigt.
Das wäre allerdings schade, wenn du das konsequent so hältst....

Noch mal, ganz klar:
Es liegt nicht in meinem Interesse dich zu beleidigen.
Deine Entscheidung hatte ich eher für falsch, als richtig.

von Egonwalter M. (heiner1234)


Lesenswert?

Hallo Arduino Fanboy

Kritik an meinen Entscheidungen sind ok, solange sie konstruktiv ist und 
nicht destruktiv; dann ist sie willkommen, da sie einen Denkanstoß 
liefert

Und natürlich darf jeder eine Meinung darüber haben, ob meine 
Entscheidung klug war oder nicht

Ich denke, mit dieser Sichtweise sind wir beide gleicher Meinung 😉👍

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Wie versprochen der ganze Code zur ADC Messung am Attiny 841. Habe die 
Variante drin mit 8 Bit und 10 Bit. Die Anzeige erfolgt durch 3 x LED. 
Beim drehen des Poti werden die LEDs nach einander eingeschaltet. Beim 
zurückdrehen gehen sie wieder aus.
1
#define F_CPU 16000000UL              // Angabe der Frequenz, wichtig für die Zeit
2
#include <util/delay.h>                // Einbindung Datei Pause
3
#include <avr/io.h>                  // Einbindung Datei Ausgänge
4
#include <avr/interrupt.h>
5
6
void init_ADC()
7
  {
8
  ADMUXB &=~((1<<REFS2)|(1<<REFS1)|(1<<REFS0));  // Register ADMUXB
9
  // REF-Auswahl Referenzspannung, auf Vcc(5V)
10
  ADCSRA |=((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));  // Register ADCSRA
11
  // ADPS - Teilungsfaktor 16MHz/128=125kHz
12
  ADCSRA |= (1<<ADEN);              // ADC aktivieren
13
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung "single conversion"
14
  while (ADCSRA & (1<<ADSC))
15
    {                        // auf Abschluss der Konvertierung warten
16
    }
17
  }
18
19
uint16_t ADC_Read()            // ADC Einzelmessung
20
  {
21
  ADMUXA |=(1<<MUX1);          // Register ADMUXA
22
  // MUX - Auswahl welcher Eingang - 000010 - ADC2
23
  ADCSRA |= (1<<ADSC);              // Register ADCSRA
24
  // ADSC - Start Konvertierung "single conversion"
25
  ADCSRB |=(1<<ADLAR);        // bei 8 Bit links
26
  while (ADCSRA & (1<<ADSC))
27
    {                  // auf Abschluss der Konvertierung warten
28
    }
29
  //return ADCW;            // ADC auslesen und zurückgeben bei 10 Bit ohne Adlar
30
  return ADCH;            // ADC auslesen und mit 8 Bit zurück mit ADLAR=1
31
  }
32
33
int main(void)
34
  {
35
  DDRA=0b00101001;          // Port A auf Ausgang schalten
36
  PORTA=0b00101001;          // Port A auf aus
37
  uint8_t adcval;            // 16 Bit mit ADCW
38
  init_ADC();
39
  while(1)
40
      {
41
    adcval = ADC_Read();
42
    if(adcval>=58)           // bei 8 Bit und 10 Bit
43
      {
44
      
45
      PORTA &=~(1<<PINA5);    // LED2 ein
46
      }
47
    else
48
      {
49
      PORTA |=(1<<PINA5);      // aus
50
      }
51
    if(adcval>128)           // bei 8 Bit, bei 10 Bit 600
52
      {
53
      PORTA &=~(1<<PINA0);    // LED3 ein
54
      }
55
    else
56
      {
57
      PORTA |=(1<<PINA0);      // aus
58
      }
59
    if(adcval>228)           // bei 8 Bit, bei 10 Bit 950
60
      {
61
      PORTA &=~(1<<PINA3);    // LED4 ein
62
      }
63
    else
64
      {
65
      PORTA |=(1<<PINA3);      // aus
66
      }  
67
    }    // while
68
  }      // main
Die 10 Bit habe ich auskommentieret. Programm läuft ohne Probleme bei 
mir.
Wünsche viel Spass damit. Danke an Alle und entschuldigung für die 
vielen blöden Fragen.
LG Heiner

von Egonwalter M. (heiner1234)


Lesenswert?

Sollte man eine ADC Messung nicht mehrmals nacheinander machen und die 
erste Messung verwerfen 🤔

So wird’s jedenfalls vorgeschlagen im Netz (mache es selbst ebenso)

Naja 🤷‍♂️

von Heiner (Gast)


Lesenswert?

Ja das stimmt. In dem DB steckt aber noch mehr. Das ist mein erstes 
Programm dazu. Erweiterungen jederzeit möglich. Besonders bei der 
eigentlichen Messung und übertragung. Da werde ich noch einiges machen 
dazu.

von Egonwalter M. (heiner1234)


Lesenswert?

Heiner schrieb:
> Ja das stimmt. In dem DB steckt aber noch mehr. Das ist mein
> erstes
> Programm dazu. Erweiterungen jederzeit möglich. Besonders bei der
> eigentlichen Messung und übertragung. Da werde ich noch einiges machen
> dazu.

Wenn Du es weißt, warum machst Du es dann nicht (mehrmals den ADC Wert 
einlesen und den ersten verwerfen) in Deinem hier vorgestellten 
Programm?

Und was hat das DB damit zu tun?

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Im DB stehen die Register drin und die Anwendung dazu. Fange immer mit 
einem leichten Programm an und nehme dann in dem nächsten Programm 
weitere Sachen dazu. Lieber erst ein kleines und leichtes Programm zum 
laufen bekommen als gleich mit dem schwersten anfangen.

Egonwalter M. schrieb:
> Wenn Du es weißt, warum machst Du es dann nicht (mehrmals den ADC Wert
> einlesen und den ersten verwerfen) in Deinem hier vorgestellten
> Programm?

Das habe ich in einem Versuch bereits drin. Da in dem ersten Programm 
die Auswertung nur durch das ein- und ausschalten von LEDs erfolgt ist 
das noch nicht notwendig.

von Egonwalter M. (heiner1234)


Lesenswert?

Heiner schrieb:

> Egonwalter M. schrieb:
>> Wenn Du es weißt, warum machst Du es dann nicht (mehrmals den ADC Wert
>> einlesen und den ersten verwerfen) in Deinem hier vorgestellten
>> Programm?
>
> Das habe ich in einem Versuch bereits drin. Da in dem ersten Programm
> die Auswertung nur durch das ein- und ausschalten von LEDs erfolgt ist
> das noch nicht notwendig.

Wenn Dein Programm hier als Vorlage dienen soll, sollte es auch korrekt 
sein (mit mehrfachem Einlesen) damit eventuelle User nicht unliebsame 
Überraschungen erleben, wenn sie es denn nehmen und für ihre Zwecke 
verwenden.

Du möchtest ja auch nicht ein halb gares Programm nehmen, oder?

Wie auch immer - einmal einlesen ist Murks

von Rainer V. (a_zip)


Lesenswert?

Egonwalter M. schrieb:
> Sollte man eine ADC Messung nicht mehrmals nacheinander machen und die
> erste Messung verwerfen 🤔

Das ist kein Vorschlag (aus dem Netz...) das steht in den diversen 
Applikationen! Scheint etwas mit Einschwingverhalten zu tun haben...mit 
was auch sonst...aber machen muß man es!!
Gruß Rainer

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> DDRA=0b00101001;          // Port A auf Ausgang schalten
> PORTA=0b00101001;         // Port A auf aus

> uint8_t adcval;           // 16 Bit mit ADCW

> if(adcval>=58)            // bei 8 Bit und 10 Bit

Die Kommentare stiften mehr Verwirrung als zu helfen.

Arbeite nochmal an der Positionierung der Klammern. Ich empfehle, Tabs 
durch 4 Leerzeichen zu ersetzen, das kannst du in deinem Editor bestimmt 
einstellen.

> PORTA &=~(1<<PINA5);    // LED2 ein

Dies würde ich in eine Funktion verschieben, die LED2_ein() heißt. 
Dadurch wird der Code besser lesbar. Und keine Sorge, er wird dadurch 
nicht größer oder langsamer.

Egonwalter M. schrieb:
> Sollte man eine ADC Messung nicht mehrmals nacheinander machen und die
> erste Messung verwerfen

Nur wenn die Quelle zu hochohmig ist und man mehr als 8 Bit nutzen will. 
Das macht man nicht für den ADC, sondern um Zeit für die äußere 
Schaltung zu gewinnen.

von Stefan F. (Gast)


Lesenswert?

Rainer V. schrieb:
> Das ist kein Vorschlag (aus dem Netz...) das steht in den diversen
> Applikationen!

Wo denn?

Hier schonmal nicht:
http://ww1.microchip.com/downloads/en/Appnotes/AN2538-ADC-of-megaAVR-in-SingleEnded-Mode-00002538A.pdf
http://ww1.microchip.com/downloads/en/AppNotes/00002535A.pdf

von Egonwalter M. (heiner1234)


Lesenswert?

Stefan ⛄ F. schrieb:

>
> Egonwalter M. schrieb:
>> Sollte man eine ADC Messung nicht mehrmals nacheinander machen und die
>> erste Messung verwerfen
>
> Nur wenn die Quelle zu hochohmig ist und man mehr als 8 Bit nutzen will.
> Das macht man nicht für den ADC, sondern um Zeit für die äußere
> Schaltung zu gewinnen.

Generell sollte man den ersten gelesenen Wert des ADC verwerfen, egal ob 
8 Bit oder 10 Bit, es sei denn, man will sich seltsame Effekte 
einhandeln - und wer will das?

von Heiner (Gast)


Lesenswert?

Hatte es so verstanden:
Da die erste Wandlung nicht korrekt, sollte man sie verwerfen. Bei ( Bit 
streiten sich die Leute. Manche sagen: ist auf jeden Fall besser und die 
letzten Stellen wackeln nicht so stark. Andere sagen: Bei 8 Bit ist es 
nicht unbedingt notwendig.
In diesem Programm ist es relativ egal da das Auslesen mehrfach erfolgt 
und die Anzeige mit LEDs erfolgt. Dabei ist keine grosse Genauigkeit 
gefordert.

Stefan ⛄ F. schrieb:
> Die Kommentare stiften mehr Verwirrung als zu helfen.
>
> Arbeite nochmal an der Positionierung der Klammern. Ich empfehle, Tabs
> durch 4 Leerzeichen zu ersetzen, das kannst du in deinem Editor bestimmt
> einstellen.
>
>> PORTA &=~(1<<PINA5);    // LED2 ein

Danke für den Hinweis. Diese Kommentare sind eigentlich nur für mich, 
das ich nicht vergesse die richtigen Stellen zu ändern.
Verwende auch Funktionen, doch bei diesem Programm geht es erst mal um 
das Verständnis. Werde es aber auf jeden Fall machen.
LG Heiner

von Egonwalter M. (heiner1234)


Lesenswert?

Heiner schrieb:
> Hatte es so verstanden:
> Da die erste Wandlung nicht korrekt, sollte man sie verwerfen. Bei ( Bit
> streiten sich die Leute. Manche sagen: ist auf jeden Fall besser und die
> letzten Stellen wackeln nicht so stark. Andere sagen: Bei 8 Bit ist es
> nicht unbedingt notwendig.
> In diesem Programm ist es relativ egal da das Auslesen mehrfach erfolgt
> und die Anzeige mit LEDs erfolgt. Dabei ist keine grosse Genauigkeit
> gefordert.
>

Wenn ich weiß, dass es nicht korrekt ist und es trotzdem ignoriere …
Damit bin ich raus

Außerdem erfolgt das Auslesen nicht MEHRMALS, sondern EINMAL pro 
Durchlauf Deiner while-Schleife, Kollege

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Da die erste Wandlung nicht korrekt, sollte man sie verwerfen.

Im Datenblatt steht genau drin, wie viele Takte der ADC zur 
Initialisierung benötigt und wann sich das Umschalten des Multiplexers 
auswirkt. Wenn man diese Takte abwartet, dann misst der ADC von Anfang 
an korrekt.

Warten kann man auf unterschiedliche Art - auch indem man den ADC 
Messungen macht und verwirft. Aber das macht man, um Zeit zu schinden, 
nicht um irgend etwas einschwingen zu lassen. Der ADC muss sich nicht 
einschwingen.

von Einer K. (Gast)


Lesenswert?

Egonwalter M. schrieb:
> Wenn ich weiß, dass es nicht korrekt ist und es trotzdem ignoriere …

Stimmt!
Man kann auch Wartezeiten, ohne Sinn und Verstand, einstreuen und wenn 
das dann kritisiert wird, sauer von dannen ziehen.

von Rainer V. (a_zip)


Lesenswert?

Stefan ⛄ F. schrieb:
> Wo denn?

Sorry, finde natürlich jetzt nichts...aber ich habe mir das für die 
AVR's grundsätzlich als Merker weggeschrieben...und das habe ich mir 
sicher so nicht ausgedacht. Die anderen Beispiele, die hier genannt 
wurden, fallen auch eher in "falsche Beschaltung" und passen daher auch 
nicht zu meinen Gedanken.
Gruß Rainer

von Einer K. (Gast)


Lesenswert?

Rainer V. schrieb:
> ..und das habe ich mir
> sicher so nicht ausgedacht.
Aber offensichtlich nicht verstanden!
Und darum falsch gemerkt und den Irrtum weiter verbreitet.

Die Umschaltung der Referenz, z.B. von Vcc zu Intern, benötigt Zeit.
Je größer der Kondensator an ARef, desto länger.

Auch ein (zu) hoher ADC Takt, klarer, zu kurze S&H Umladezeit, zu hohe 
Eingangsimpedanz können eine zweite Messung nötig machen.
Aber das ist nicht in Stein gemeißelt und hier sehe ich auch keine 
Anzeichen dafür.

Auch Multiplexerumschaltungen im FreeRunningMode erfordern das Verwerfen 
von Werten.
Aber das ist wieder ein anderes Thema....

Du siehst....
Verallgemeinern gilt nicht.

von Rainer V. (a_zip)


Lesenswert?

Arduino Fanboy D. schrieb:
> und den Irrtum weiter verbreitet.

Mea culpa...

von c-hater (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:

> Die Umschaltung der Referenz, z.B. von Vcc zu Intern, benötigt Zeit.
> Je größer der Kondensator an ARef, desto länger.

Richtig.

> Auch ein (zu) hoher ADC Takt, klarer, zu kurze S&H Umladezeit, zu hohe
> Eingangsimpedanz können eine zweite Messung nötig machen.

Ebenfalls richtig.

> Auch Multiplexerumschaltungen im FreeRunningMode erfordern das Verwerfen
> von Werten.

Das ist falsch. Das ist höchstens dann zutreffend, wenn man das 
Zeitverhalten seines Codes nicht im Griff hat.

von Stefan F. (Gast)


Lesenswert?

Das Umschalten des Multiplexers wirkt sich auf die nächste Messung aus, 
nicht auf die gerade laufende Messung. Das ist des Pudels Kern, so steht 
das auch im Datenblatt.

Für die Art, wie der TO hier den ADC nutzt, ist dieses Detail 
irrelevant.

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Das Umschalten des Multiplexers wirkt sich auf die nächste Messung aus,
> nicht auf die gerade laufende Messung. Das ist des Pudels Kern, so steht
> das auch im Datenblatt.

So ist es, aber trotzdem nur die halbe Wahrheit.

Im FreeRunning-Mode gibt es nämlich die Möglichkeit für Quirks, wenn man 
den Multiplexer in der ADC-ISR umschaltet. Da kann es nämlich passieren, 
dass die neue Multiplexer-Konfiguration noch für den gerade laufenden 
(durch FreeRun automatisch gestarteten) ADC-Zyklus wirksam wird, nämlich 
dann, wenn die ISR wenig Overhead hat und auch gerade nicht durch eine 
konkurrierende ISR verzögert wurde.

OK: Bei in C geschriebenen ISRs ist es relativ unwahrscheinlich, dass 
das passiert, aber eben nicht unmöglich. In Asm hingegen ist das ein 
absolut relevantes Thema, welches man natürlich entsprechend 
berücksichtigen muss.

Und übrigens, ohne Quirks: Die Multiplexer-Konfiguration, wird im 
nächsten Zyklus gültig, d.h.: das daraus resultierende Ergebnis ist erst 
das ÜBERNÄCHSTE.

von Rainer V. (a_zip)


Lesenswert?

Wie auch immer, seine AD-Wandlungen im Auge zu behalten, ist nie 
verkehrt! Und in den seltensten Fällen wird man genau auf diese, erste 
Wandlung angewiesen sein...also...

von Egonwalter M. (heiner1234)


Lesenswert?

Rainer V. schrieb:
> Wie auch immer, seine AD-Wandlungen im Auge zu behalten, ist nie
> verkehrt! Und in den seltensten Fällen wird man genau auf diese, erste
> Wandlung angewiesen sein...also...

😉👍

von Einer K. (Gast)


Lesenswert?

Rainer V. schrieb:
> ...

Egonwalter M. schrieb:
> ...

Alles klar...
Bestenfalls 30%  verstanden.
Im Grundsatz widerlegt worden, aber miteinander, wie bei einem Sieg 
abklatschen.

Wow...
Soviel Chuzpe hätte ich nicht!
Meinen Glückwunsch.

von Rainer V. (a_zip)


Lesenswert?

Das ist eben der Unterschied :-)

von Egonwalter M. (heiner1234)


Lesenswert?

Arduino Fanboy D. schrieb:

Fühlst Du Dich nun besser?

von Peter D. (peda)


Lesenswert?

c-hater schrieb:
> Im FreeRunning-Mode gibt es nämlich die Möglichkeit für Quirks, wenn man
> den Multiplexer in der ADC-ISR umschaltet.

Ja, der FreeRunning-Mode ist häßlich. Daher benutze ich ihn nur, wenn 
nur ein Eingang eingelesen werden muß.
Bei Prescaler 128 muß man sonst 128 CPU-Zyklen warten, bis der MUX 
umgeschaltet werden darf.

von Einer K. (Gast)


Lesenswert?

Peter D. schrieb:
> Daher benutze ich ihn nur, wenn
> nur ein Eingang eingelesen werden muß.

Naja...
Auch eine Möglichkeit des Ausblendens.

Peter D. schrieb:
> Bei Prescaler 128 muß man sonst 128 CPU-Zyklen warten, bis der MUX
> umgeschaltet werden darf.

Die Alternative ist, wenn man nicht weiß, in welchen ADC Takt man ihn 
erwischt hat, ist das verwerfen des ersten Ergebnisses nach der 
Umschaltung. Und wenn auch andere ISR im Spiel sind KANN man das nicht 
wissen.

Wozu der c-hater dann sagt:
c-hater schrieb:
> Das ist falsch.

von Peter D. (peda)


Lesenswert?

Arduino Fanboy D. schrieb:
> Die Alternative ist, wenn man nicht weiß, in welchen ADC Takt man ihn
> erwischt hat, ist das verwerfen des ersten Ergebnisses nach der
> Umschaltung.

Das kostet ja noch viel mehr Zeit.
Warum nicht einfach in der ISR den MUX umschalten und dann die neue 
Messung starten?
Wie gesagt, der FreeRunning-Mode ist nicht gut durchdacht.

von Helmut L. (helmi1)


Lesenswert?

Peter D. schrieb:
> Wie gesagt, der FreeRunning-Mode ist nicht gut durchdacht.

Das wird wohl beim Design des ADC sich einfach so ergeben haben.

von Take a Walk on the wild Side (Gast)


Lesenswert?

Helmut L. schrieb:
> Peter D. schrieb:
>> Wie gesagt, der FreeRunning-Mode ist nicht gut durchdacht.
>
> Das wird wohl beim Design des ADC sich einfach so ergeben haben.

Das mußte eben schnellgehen. Heißt ja: Free running und nicht
"Langsam einlesing"

von Helmut L. (helmi1)


Lesenswert?

Oder wie IBM immer zu sagen pflegte: "It's not a bug, it's a feature"

von c-hater (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:

> Die Alternative ist, wenn man nicht weiß, in welchen ADC Takt man ihn
> erwischt hat, ist das verwerfen des ersten Ergebnisses nach der
> Umschaltung. Und wenn auch andere ISR im Spiel sind KANN man das nicht
> wissen.

Doch, natürlich kann man das wissen. Wenn man halt das Laufzeitverhalten 
seiner Anwendung vollständig im Griff hat. Dann kann man für JEDE 
einzelne ISR EXAKT vorhersehen, wie hoch die Latenz mindestens und 
höchstens ausfallen wird.

Und dann hat man noch die Wahl zwischen zwei Varianten. Wenn es nur 
wenige konkurrierende ISRs gibt und/oder man die Zeit ihrer exklusiven 
Ausführung kurz genug halten kann, dann kann man den ADC regulär und 
zuverlässig im "Quirks-Bereich" nutzen. Bis jetzt habe ich das noch in 
jeder Anwendung geschafft, in der sich FreeRunning anbot.

Und falls das mal nicht möglich sein sollte, hat man immer noch die 
Möglichkeit, die ADC-ISR so zu gestalten, dass die Wartezeit für den 
Fall der Minimal-Latenz keine verlorene Zeit ist, sondern sinnvoll 
genutzt werden kann.

> Wozu der c-hater dann sagt:
> c-hater schrieb:
>> Das ist falsch.

Ist es halt auch wirklich. In meiner Welt der berechenbaren 
Laufzeiten...

von Bernd (Gast)


Lesenswert?

c-hater schrieb:
> Wenn man halt das Laufzeitverhalten
> seiner Anwendung vollständig im Griff hat.
Ah ja. Ein NOP hinzugefügt oder weggenommen und das Kartenhaus bricht 
zusammen...

> Dann kann man für JEDE
> einzelne ISR EXAKT vorhersehen, wie hoch die Latenz mindestens und
> höchstens ausfallen wird.
Schön. Und wenn Du eine Kleinigkeit am Code änderst, fängt die 
Rechnerei, ob alles noch passt von vorne an.
Kann man machen.

Oder man programmiert robust und defensiv...

von c-hater (Gast)


Lesenswert?

Bernd schrieb:

> Ah ja. Ein NOP hinzugefügt oder weggenommen und das Kartenhaus bricht
> zusammen...

Nun, in gut geplante Kartenhauser braucht man halt nichts mehr 
hinzufügen oder wegnehmen. Die stehen ewig.

> Oder man programmiert robust und defensiv...

Das Vorgehen für diese Variante hatte ich doch ebenfalls beschrieben. Da 
geht es dann nur noch darum, in der ADC-ISR genug Rechenzeit sinnvoll zu 
benutzen, statt sinnlos zu verwarten. Das ist dann endgültig eine 
wirklich einfache Aufgabe, der vielleicht sogar Leute wie du gewachsen 
sein könnten...

von Heiner (Gast)


Lesenswert?

Hallo
Habe zu der ADC Messung am Attiny 841 die Mittelwertbildund dazu 
genommen:
1
uint16_t ADC_lesen1()            // ADC Einzelmessung
2
  {
3
  ADMUXA |=(1<<MUX1);          // Register ADMUXA
4
  // MUX - Auswahl welcher Eingang - 000010 - ADC2
5
  ADCSRA |= (1<<ADSC);              // Register ADCSRA
6
  // ADSC - Start Konvertierung "single conversion"
7
  ADCSRB |=(1<<ADLAR);        // bei 8 Bit links
8
  while (ADCSRA & (1<<ADSC))
9
  {                  // auf Abschluss der Konvertierung warten
10
  }
11
  //return ADCW;            // ADC auslesen und zurückgeben bei 10 Bit ohne Adlar
12
  return ADCH;            // ADC auslesen und mit 8 Bit zurück mit ADLAR=1
13
  }
14
  
15
uint16_t ADC_lesen_avg(uint8_t anzahlmessung)
16
  {  
17
  uint16_t summemessung=0;
18
  for (uint8_t i = 0; i < anzahlmessung; ++i )  
19
    {
20
      summemessung += ADC_lesen1();  
21
    }
22
  return ( summemessung/anzahlmessung );    // Durchschnitt errechnen und zurück
23
  }
Den Aufruf und übertragung zum Master über den I2C Bus erfolgt damit:
1
int main(void)
2
  {
3
  init_I2C();  
4
  init_ADC();
5
  while(1)
6
    { 
7
    //wert1= ADC_lesen1();  
8
    wert1= ADC_lesen_avg(5);
9
    if(command != 0x00)
10
      {
11
      switch(command)
12
        {
13
        case 0x01:
14
        // Test Daten
15
        tx_buf[0] = wert1;
16
        tx_buf[1] = 2;
17
        tx_buf[2] = 3;
18
        tx_buf[3] = 14;
19
        tx_buf_index = 0;
20
        break;
21
        }
22
      command = 0x00;
23
      }
24
    }
25
  }
Bei einem Aufruf des Mittelwertes mit wert1= ADC_lesen_avg(5); werden 
für alle 4 tex_buf unterschiedliche Werte angezeigt. Bei jeder änderung 
des wert1 ändert sich auch tx_buf 1,2,3. Wenn ich nur mit wert1= 
ADC_lesen1(); den ADC Wert übertrage stimmen die Werte. Leider ist mir 
nicht klar warum das so ist.
LG Heiner

von Stefan F. (Gast)


Lesenswert?

Wo wird denn sonst noch absichtlich oder unabsichtlich auf tx_buf 
zugegriffen? Du musst schon den gesamten Quelltext zeigen.

von Heiner (Gast)


Lesenswert?

Kein Problem
1
#define F_CPU 16000000UL        // Angabe der Frequenz, wichtig für die Zeit
2
#include <util/delay.h>          // Einbindung Datei Pause
3
#include <avr/io.h>            // Einbindung Datei Ausgänge
4
#include <stdio.h>
5
#include <avr/interrupt.h>
6
7
#define I2C_SLAVE_ADDRESS       0x52
8
#define I2C_DATA_INTERRUPT      0x80
9
#define I2C_BUS_COLLISION       0x08
10
#define I2C_ADDRESS_STOP_MATCH  0x40
11
12
volatile uint8_t command;
13
volatile uint8_t tx_buf[4];
14
volatile uint8_t tx_buf_index = 0;
15
volatile uint8_t wert1;
16
//volatile uint16_t sum;
17
18
void init_I2C()
19
  {
20
  TWSA = I2C_SLAVE_ADDRESS;  // Slave Adresse
21
  TWSD = 0xFF;
22
  TWSCRA = (1 << TWEN)       // Zwei-Draht-Schnittstelle aktivieren
23
  | (1 << TWSHE)        // TWI SDA Haltezeit aktivieren
24
  | (1 << TWASIE)       // TWI-Adresse/Stop-Unterbrechung aktivieren
25
  | (1 << TWSIE)        // TWI Stop Interrupt Enable aktivieren
26
  | (1 << TWDIE);       // TWI Datenunterbrechung aktivieren
27
  sei();
28
  }
29
30
ISR( TWI_SLAVE_vect )
31
  {
32
  uint8_t status = TWSSRA & 0xC0;
33
  if (status & I2C_DATA_INTERRUPT)  // Daten wurden vom Master empfangen oder werden angefordert
34
    {
35
    if (TWSSRA & (1 << TWDIR))    // Master fordert Daten vom Slave an
36
      {
37
      if(tx_buf_index >= sizeof(tx_buf))
38
        {
39
        tx_buf_index=0;
40
        }
41
      TWSD = tx_buf[tx_buf_index];// Daten in Sendepuffer
42
      tx_buf_index++;
43
      TWSCRB = ((1<<TWCMD1)|(1<<TWCMD0));
44
      }
45
    else       // Master sendet Daten zum Slave
46
      {
47
      TWSCRB |= ((1<<TWCMD1)|(1<<TWCMD0));
48
      command = TWSD;
49
      }
50
    }
51
  else if (status & I2C_ADDRESS_STOP_MATCH)
52
    {
53
    if (TWSSRA & I2C_BUS_COLLISION)
54
      {
55
      TWSCRB = (1<<TWCMD1);
56
      }
57
    else
58
      {
59
      if (TWSSRA & (1<<TWAS))
60
        {      // ACK
61
        TWSCRB =  ((1<<TWCMD1)|(1<<TWCMD0));
62
        }
63
      else
64
        {      // Stop Condition
65
        TWSCRB = (1<<TWCMD1);
66
        }
67
      }
68
    }
69
  }
70
71
void init_ADC()
72
  {
73
  ADMUXB &=~((1<<REFS2)|(1<<REFS1)|(1<<REFS0));  // Register ADMUXB
74
  // REF-Auswahl Referenzspannung, auf Vcc(5V)
75
  ADCSRA |=((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));  // Register ADCSRA
76
  // ADPS - Teilungsfaktor 16MHz/128=125kHz
77
  ADCSRA |= (1<<ADEN);              // ADC aktivieren
78
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung "single conversion"
79
  while (ADCSRA & (1<<ADSC))
80
    {                        // auf Abschluss der Konvertierung warten
81
    }
82
  }
83
84
uint16_t ADC_lesen1()            // ADC Einzelmessung
85
  {
86
  ADMUXA |=(1<<MUX1);          // Register ADMUXA
87
  // MUX - Auswahl welcher Eingang - 000010 - ADC2
88
  ADCSRA |= (1<<ADSC);              // Register ADCSRA
89
  // ADSC - Start Konvertierung "single conversion"
90
  ADCSRB |=(1<<ADLAR);        // bei 8 Bit links
91
  while (ADCSRA & (1<<ADSC))
92
  {                  // auf Abschluss der Konvertierung warten
93
  }
94
  //return ADCW;            // ADC auslesen und zurückgeben bei 10 Bit ohne Adlar
95
  return ADCH;            // ADC auslesen und mit 8 Bit zurück mit ADLAR=1
96
  }
97
  
98
uint16_t ADC_lesen_avg(uint8_t anzahlmessung)
99
  {  
100
  uint16_t summemessung=0;
101
  for (uint8_t i = 0; i < anzahlmessung; ++i )  
102
    {
103
      summemessung += ADC_lesen1();  
104
    }
105
  return ( summemessung/anzahlmessung );    // Durchschnitt errechnen und zurück
106
  }
107
  
108
int main(void)
109
  {
110
  init_I2C();  
111
  init_ADC();
112
  while(1)
113
    { 
114
    //wert1= ADC_lesen1();  
115
    wert1= ADC_lesen_avg(5);
116
    if(command != 0x00)
117
      {
118
      switch(command)
119
        {
120
        case 0x01:
121
        // Test Daten
122
        tx_buf[0] = wert1;
123
        tx_buf[1] = 2;
124
        tx_buf[2] = 3;
125
        tx_buf[3] = 14;
126
        tx_buf_index = 0;
127
        break;
128
        }
129
      command = 0x00;
130
      }
131
    }
132
  }
Auf die tx_buf 1,2,3 wird nur an dieser Stelle zugegriffen. Wenn ich das 
gleiche mit wert1=ADC_lesen1(); mache ändern sich die Werte nicht.
Habe noch die ganzen Kommentare drin.

von Helmut L. (helmi1)


Lesenswert?

tx_buf  ist auch gross genug dimensioniert?

von Stefan F. (Gast)


Lesenswert?

Ich sehe da auf Anhieb keinen Fehler.

Eine Frage um das Problem einzukreisen:
Bist du sicher dass sich tx_buf[1] bis [3] verändern oder schließt du 
das aus den Daten, die dein Mikrocontroller auf dem I²C Bus sendet?

Und noch eine: Wird der Stack-Pointer richtig initialisiert? 
Kontrolliere mal dessen Wert.

von Heiner (Gast)


Lesenswert?

ist mit
volatile uint8_t tx_buf[4];
angegeben, da ich nur 8 Bit per Bus übertrage.
Mir ist noch was anderes aufgefallen. Wenn ich schreibe
1
wert1= ADC_lesen1();  
2
    //wert1= ADC_lesen_avg(5);
3
    if(command != 0x00)
4
      {
5
      switch(command)
6
        {
7
        case 0x01:
8
        // Test Daten
9
        tx_buf[0] = 12;
10
        tx_buf[1] = 2;
11
        tx_buf[2] = 3;
12
        tx_buf[3] = 14;
13
        tx_buf_index = 0;
14
        break;
15
        }
16
      command = 0x00;
17
      }
werden genau diese 4 Werte übertragen.
Schreibe ich aber
{c]
 {
    //wert1= ADC_lesen1();
    wert1= ADC_lesen_avg(5);
    if(command != 0x00)
      {
      switch(command)
        {
        case 0x01:
        // Test Daten
        tx_buf[0] = 12;
        tx_buf[1] = 2;
        tx_buf[2] = 3;
        tx_buf[3] = 14;
        tx_buf_index = 0;
        break;
        }
      command = 0x00;
      }
    }
[/c]
bekomme ich bei jeder Abfrage unterschiedliche Werte.
Wieso? Die Werte für tx_buf[..] sind doch immer gleich.

von Stefan F. (Gast)


Lesenswert?

Ich glaube ich hab es:

Wenn der Master Daten anfordert, antwortest die ISR immer sofort mit den 
4 Bytes des Buffers, auf die tx_buf_index zeigt.

Während dessen läuft vielleicht gerade deine langsame 5-fache ADC 
Messung. Dann merkst du dass ein Kommando empfangen wurde und dann setzt 
du tx_buf_index index einfach auf 0 ohne zu berücksichtigen, in welchem 
Status sich die I²C Übertragung gerade befindet.

Es könnte sein, dass tx_buf_index gerade den Wert 1 oder 2 oder 3 hat 
und du setzt es dann einfach "unerlaubt" auf 0 zurück. Als nächstest 
sendet die ISR du dann erneut tx_buf[0] an den Master anstatt das 
richtige Byte das eigentlich an der Reihe gewesen wäre.

Das ist eine klassische Race Condition, Willkommen in der Welt der 
Nebenläufigkeit. Dir fehlt eine Synchronisation der beiden parallelen 
Vorgänge:

a) ADC auslesen (in main)
b) Messwerte senden (in der ISR)

Diese beiden Threads dürfen nur abwechselnd auf den Buffer zugreifen. 
Dir fehlt eine entsprechende Ablaufsteuerung. Wenn du diese einführst 
dann brauchst du wohl auch Clock-Stretching, denn du musst dem Master 
irgendwie mitteilen, dass er bitte warten soll weil du gerade die von 
ihm angeforderte Messung durchführst und eben deswegen jetzt nicht 
sofort antworten kannst.

Alternative: Du machst drei Kommandos:

1) Messung starten. Es gibt keine Antwort (außer natürlich das ACK).
2) Abfrage ob die Messung fertig ist. Antwort ist 0 oder 1.
3) Messergebnis abfragen. Antwort sind die 4 Bytes.

Dann muss der Master den Status wiederholt pollen und die Daten erst 
dann abholen, wenn dein Slave dazu bereit ist.

von Heiner (Gast)


Lesenswert?

Muss ganz ehrlich sagen, habe deine Antwort erst mehrmals lesen müssen 
um es vielleicht zu verstehen. Es klingt recht plausibel. Was ich daran 
nicht verstehe, ohne Mittewertberechnung bzw. Aufruf geht es mit geht es 
nicht. Kann alles damit zusammenhängen.
Das andere Problem für mich ist die Lösung. Habe null Peilung wie ich 
das machen kann, da für mich so ein Problem noch nie aufgetreten ist. 
Die ADC Messung (einfach) habe ich ja in den Griff bekommen, tja der 
Rest ist noch unbekannt.

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> a) ADC auslesen (in main)
> b) Messwerte senden (in der ISR)

Wenn ich deine Worte richtig verstanden habe, muss das ADC auslesen 
fertig sein und dann darf erst Messwerte senden erfolgen. Damit sind 
korrekte Messwerte gegeben.
Dazu brauch ich doch die Info das das ADC auslesen fertig ist und dann 
über Freigabe 0 oder 1 die Werte zum Auslesen freigebe.
Sehe ich das richtig?

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Was ich daran
> nicht verstehe, ohne Mittewertberechnung bzw. Aufruf geht es

Weil dann die Messung immer schneller als die I²C Übertragung ist. Das 
Messergebnis steht immer rechtzeitig bereit.

> ...
> Sehe ich das richtig?

Ja

Das ist wirklich kein einfaches Thema. Aber da musst du durch - es sei 
denn du nutzt Clock-Stretching und machst die Messung innerhalb der ISR.

Dann hast du nämlich nur einen Thread, der auf die Messergebnisse 
zugreift. Zugriffskonflikte sind dann unmöglich.

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das ist wirklich kein einfaches Thema. Aber da musst du durch - es sei
> denn du nutzt Clock-Stretching und machst die Messung innerhalb der ISR.

Messung innerhalb der ISR ??? Dabei wird init_ADC gemacht wie bisher. 
Dann muss man innerhalb der ISR, Bereich Daten einlesen, auf die ADC 
Mittelwertbildung zugreifen. Die Mittelwertbildung greift dann ja wieder 
auf die eigentlich ADC Messung zu.
Habe ich das richtig verstanden?

Stefan ⛄ F. schrieb:
> Das ist wirklich kein einfaches Thema.

Da gebe ich dir Recht. Konnte auch sehr wenig im Netz dazu finden was 
ich verstehe. Gerade beim Attiny 841 gibt es scheinbar garnichts dazu. 
Sicher sagen einige, ist kein Problem. Für mich leider schon. Vielleicht 
gibt es noch ein Paar Tips dazu. Vielleicht....

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Messung innerhalb der ISR ???
> Habe ich das richtig verstanden?

Nein, ich meinte dass dein Mikrocontroller nach Empfang des Kommandos 
die 5 Messungen innerhalb der ISR macht, den Mittelwert bildet und erst 
dann das Kommando mit ACK bestätigt. Danach sendest du die Antwort an 
den Master.

Die unschöne Konsequenz aus dieser simplen Umsetzung ist aber, dass das 
ACK erheblich verzöger wird, nämlich so lange wie die 5 ADC Messungen 
dauern. Um dies zu ermöglichen, musst du das Clock-Stretching Feature 
von I²C benutzen (welches der Raspberry Pi übrigens nicht unterstützt).

Die zweite unschöne Konsequenz ist, dass der Mikrocontroller während 
dieser Zeit vermutlich nicht anderes mehr tun kann, weil die ISR den 
Ablauf der main() eben so lange blockiert. Du kannst höchsten noch 
andere höher priorisierte ISR gleichzeitig ausführen, falls der µC das 
überhaupt unterstützt (die klassischen AVR tun es nicht).

Heiner schrieb:
> Gerade beim Attiny 841 gibt es scheinbar garnichts dazu.

Für den Anfang verwendest du besser einen Mikrocontroller, der unter 
Hobbyelektronikern beliebt und schon lange etabliert ist, denn dann 
findest du dazu die meisten leicht verständlichen Anleitungen. Vor ein 
paar Jahren war das noch der Atmega8, inzwischen wurde er (dank Arduino) 
durch den ATmega328 abgelöst. Bestelle dir einfach mal ein 5er Pack 
Arduino Nano Module, die kannst du immer mal gebrauchen. Zum 
Programmieren musst du ja nicht die Arduino IDE benutzen, es geht um die 
praktische Hardware.

von Heiner (Gast)


Lesenswert?

Habe mir das Datenblatt vorgenommem. Unter 20.3.7 steht was dazu. Leider 
für mich sehr unklar.
Habe im Netz dazu gesucht. Auch leider alles relativ theoretisch 
gehalten.
Habe aber eine Frage dazu.
Was passiert wenn ich verschiedene ADC abfrage ohne Mittelwertbildung. 
Da ja 4 Werte übertragen kann, kann ich 2x ADC mit jewels 8 Bit nehmen.
Tritt dann das Problem auch auf? Sorry, meine Hardware ist noch nicht so 
weit um zu testen.

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> 2) Abfrage ob die Messung fertig ist. Antwort ist 0 oder 1.

Kann man einfach die übertragung der Werte stoppen bevor die ADC Messung 
und Mittelwertbildung fertig ist?

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Tritt dann das Problem auch auf?

Ja, denn es ist ein Timing Problem. DU kannst froh sein, dass du 
wenigstens eine ADC Abfrage auf diese Art machen kannst. Takte den mal 
langsamer, dann geht nicht einmal das mehr.

Heiner schrieb:
> Kann man einfach die übertragung der Werte stoppen bevor die ADC Messung
> und Mittelwertbildung fertig ist?

Dazu dient das von mir genannte Clock Stretching. Lies doch mal, was 
dieser Begriff beim I²C Bus bedeutet. Ich hoffe du hast die 
Spezifikation vorliegen: 
https://www.nxp.com/docs/en/user-guide/UM10204.pdf Das ist für dich 
Pflichtlektüre!

von Peter D. (peda)


Lesenswert?

Stefan ⛄ F. schrieb:
> Heiner schrieb:
>> Gerade beim Attiny 841 gibt es scheinbar garnichts dazu.

Der ATtiny841 ist eine Spätgeburt. D.h. viele haben schon mit früheren 
AVRs angefangen und benutzen diese weiterhin.
Auch benutzen viele Bastler gerne MCs, die noch als DIP verfügbar sind. 
Die kann man schnell mal auf ein Steckbrett friemeln.

von Egonwalter M. (heiner1234)


Lesenswert?

Peter D. schrieb:

> Der ATtiny841 ist eine Spätgeburt. D.h. viele haben schon mit früheren
> AVRs angefangen und benutzen diese weiterhin.
> Auch benutzen viele Bastler gerne MCs, die noch als DIP verfügbar sind.
> Die kann man schnell mal auf ein Steckbrett friemeln.

Aber auch da kommt man nicht umhin, sich mit Clockstretching 
auseinanderzusetzen 😉 (dürfte da aber einfacher zu haendeln sein)

von Heiner (Gast)


Lesenswert?

Genug der Vorrede. Habt mir genug Angst gemacht. Es wird Zeit etwas zu 
machen. Habe angefangen das von NXP zu lesen. Habe mir schon einiges im 
Netz gesucht. Im Netz gibt es aber das Problem, das viele Sachen auf den 
Atmega 8 oder die älteren Attiny laufen. Da ja der Atiiny 841 etwas 
anders ist liegt dabei das Problem.

von Heiner (Gast)


Lesenswert?

Sorry vergessen.
Im DB des Attiny 841 steht was dazu drin, schon gesagt. Ist aber sowas 
von allgemein gehalten, das es mir kaum was nützt.

von Cyblord -. (cyblord)


Lesenswert?

Heiner schrieb:
> Im Netz gibt es aber das Problem, das viele Sachen auf den
> Atmega 8 oder die älteren Attiny laufen. Da ja der Atiiny 841 etwas
> anders ist liegt dabei das Problem.

Das Problem ist, dass du ohne Code aus dem Netz anscheinend gar nichts 
machen kannst. Mir ist es doch völlig egal ob es Code für diesen oder 
jenen Controller nicht gibt. Ich nehme das Datenblatt und programmiere 
für MEINEN Controller. Lerne programmieren. Dieses Defizit springt hier 
aus jedem deiner Posts geradezu heraus.

von Egonwalter M. (heiner1234)


Lesenswert?

Cyblord -. schrieb:

> Das Problem ist, dass du ohne Code aus dem Netz anscheinend gar nichts
> machen kannst. Mir ist es doch völlig egal ob es Code für diesen oder
> jenen Controller nicht gibt. Ich nehme das Datenblatt und programmiere
> für MEINEN Controller. Lerne programmieren. Dieses Defizit springt hier
> aus jedem deiner Posts geradezu heraus.

Kann man nichts gegen sagen, allerdings hat der TO wohl das Problem, 
dass er das Datenblatt (da in Englisch) nicht ohne Übersetzer lesen (und 
umsetzen) kann ... und die Übersetzung ist wohl manchmal nicht so 
zielführend...

Außerdem möchte der TO wohl ganz gerne den Code "mundgerecht" ;-)

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Egonwalter M. schrieb:

> Kann man nichts gegen sagen, allerdings hat der TO wohl das Problem,
> dass er das Datenblatt (da in Englisch) nicht ohne Übersetzer lesen (und
> umsetzen) kann ... und die Übersetzung ist wohl manchmal nicht so
> zielführend...

Ein englisches Datenblatt ist grundlegendes Handwerkszeug im Umgang mit 
Digitaltechnik. Da kommt man nicht drum rum. Aber technisches Englisch 
ist nicht besonders schwierig.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ein Problem, was noch auffällt: deine 'ADC_lesen_avg()' returniert ein 
uint16_t, aber du schickst das ohne Typecast auf ein uint8_t Array. Das 
kann klappen, muss aber nicht.

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Matthias S. schrieb:
> Ein Problem, was noch auffällt: deine 'ADC_lesen_avg()' returniert ein
> uint16_t, aber du schickst das ohne Typecast auf ein uint8_t Array. Das
> kann klappen, muss aber nicht.

Das habe ich auch gesehen und bereits korregiert.

Egonwalter M. schrieb:
> Außerdem möchte der TO wohl ganz gerne den Code "mundgerecht" ;-)

Möchte den Code nicht "mundgerecht" haben. Man kann das Datenblat 
auswendig lernen oder die englische Version als Grundlage nehmen, alles 
geht. Es gibt verschiedene Wege etwas zu machen. Ein Lehrling lernt aus 
Erfahrung und Erkenntnis was zu machen ist. Wenn ich ein Stück Code 
nehme und es zerlege und schaue wie es andere machen, lerne ich daran 
mehr als ein DB auswendig zu lernen. Für mich ist es zielführend wenn 
man nicht ständig auf ein Lehrbuch verwiesen wird und ständig als "Nicht 
Wissender" in der Edelforn genannt wird. Ein Anfänger hat den Vorteil 
oder auch Nachteil nicht alles zu wissen. Hat aber die Aufgabe den 
Lehrer zu fragen. Und der Lehrer kann es als Hinweis für eine LKösung 
machen.

von Cyblord -. (cyblord)


Lesenswert?

Heiner schrieb:
> Möchte den Code nicht "mundgerecht" haben. Man kann das Datenblat
> auswendig lernen oder die englische Version als Grundlage nehmen, alles
> geht. Es gibt verschiedene Wege etwas zu machen.

Kranke und nicht zielführende Einstellung. Man muss das Datenblatt nicht 
auswendig lernen, man hat es ja jederzeit zur Hand.
Man muss es nur verstehen und danach programmieren können. Daran 
scheitert es. Alles andere ist nur Rechtfertigung für diesen einfachen 
Umstand.

Und NATÜRLICH ist das englische Datenblatt die Grundlage. Nichts 
anderes.

von Heiner (Gast)


Lesenswert?

Da das DB die Grundlage ist, habe ich darin zwei Sachen gefunden, TWDIF 
und TWASIF. Da gibs den Hinweis im Register TWSSRA das SCL so lange auf 
GND liegen soll bis der Slave ihn wieder frei gibt bzw. verzögert. Ist 
leider bisher das einzige was gefunden habe.

von Cyblord -. (cyblord)


Lesenswert?

Heiner schrieb:
> Da das DB die Grundlage ist, habe ich darin zwei Sachen gefunden, TWDIF
> und TWASIF. Da gibs den Hinweis im Register TWSSRA das SCL so lange auf
> GND liegen soll bis der Slave ihn wieder frei gibt bzw. verzögert. Ist
> leider bisher das einzige was gefunden habe.

Das Datenblatt ist ja auch nicht dazu da dir den I2C Bus zu erklären, 
sondern wie du mit diesem Controller am Bus teilnimmst. Um den I2C Bus 
mit all seinen Spielarten zu verstehen gibt es andere Dokumente. Sobald 
du dann weißt WAS du eigentlich auf dem Bus tun willst, kann dir das 
Datenblatt sagen WIE du den Controller dazu bringst das zu tun.

von Stefan F. (Gast)


Lesenswert?

Heiner schrieb:
> Da ja der Atiiny 841 etwas
> anders ist liegt dabei das Problem.

Ich bin absolut sicher, dass ein älterer AVR bei dem aktuellen Problem 
technisch gesehen kein bisschen einfacher ist.

Cyblord -. schrieb:
> Das Datenblatt ist ja auch nicht dazu da dir den I2C Bus zu erklären

So ist es. Das Datenblatt setzt voraus, dass du mit der Funktionsweise 
des I²C vertraut bist, bevor du eigene Programme dafür schreibst. Das 
gilt für alle Schnittstellen die irgendein Protokoll fahren.

In der Bedienungsanleitung deines Autos werden auch nicht die 
Verkehrsregeln erklärt, z.B. wann man links blinken soll und wie man 
korrekt überholt. Die Anleitung erklärt nur, worauf du dazu drücken 
musst.

Ich persönlich habe den I²C Bus lange Zeit mit der sogenannten 
"bit-banging" Methode genutzt. Das bedeutet: Ich habe dafür zwei simple 
I/O generische Pins verwendet, anstatt die spezielle I²C Hardware. 
Angefangen hatte ich mit dem Parallel-Port meines PC, von dem ich 
einfach die Leitungen D0 und D1 zweckentfremdete*. Auf der Gegenseite 
habe ich fertige Slaves benutzt bei denen ich sicher sein konnte, dass 
sie sich an die Regeln halten.

*) Ich hatte eine I/O Karte mit bidirektionalem parallel-Port, nicht den 
einfachen unidirektionalen Standard von IBM. Mit DOS Programmen konnte 
man darauf damals noch "einfach so" zugreifen, genau wie der 
Mikrocontroller auf seine I/O Pins zugreift.

Wenn ich als Anfänger Master und Slave gleichzeitig programmiere, habe 
ich zwei Baustellen gleichzeitig. So will ich nicht lernen, ist mir viel 
zu unsicher. Wer so arbeitet kann auch einfach behaupten, dass der 
Himmel grün sei. Solange sich alle Komponenten darüber einig sind (und 
das sind sie, weil ich sie gemacht habe) fällt der Fehler nicht auf. Das 
ist nicht gut.

Heiner schrieb:
> Da gibs den Hinweis im Register TWSSRA das SCL so lange auf
> GND liegen soll bis der Slave ihn wieder frei gibt bzw. verzögert. Ist
> leider bisher das einzige was gefunden habe.

Das ist Clock-Stretching. Wenn der Slave nicht sofort antworten kann, 
zieht er SCL so lange auf Low, bis er antworten kann. Achtung: Damit 
blockiert man den Bus, andere Übertragungen müssen dann ebenfalls 
warten.

von Heiner (Gast)


Lesenswert?

Habe die letzten Tage damit zugebracht im Netz Beschreibungen und 
Angaben zu Clock Stretching zu suchen und zu lesen. Dazu zählen auch die 
Angaben von Atmel und Nachfolger. Leider ist sehr viel Rede von den 
allgemeinen Angaben, wie z.B. kurze Beschreibungen und allgemeine 
technische Angaben.

Stefan ⛄ F. schrieb:
> Das ist Clock-Stretching. Wenn der Slave nicht sofort antworten kann,
> zieht er SCL so lange auf Low, bis er antworten kann. Achtung: Damit
> blockiert man den Bus, andere Übertragungen müssen dann ebenfalls
> warten.

Diese Aussage ist schon fast das wichtigste was drin steht.

Warum gibt es dazu so gut wie keine Angaben? Weder in den Datenblättern 
noch in den Schriften der Hersteller steht was konkretes. Alle möglichen 
Leute beziehen sich darauf oder suchen was dazu, doch keiner nennt was 
konkretes.
Gibt es dieses Problem nur wenn man einen Attiny oder anderes kleines 
als Slave nutzt?

von c-hater (Gast)


Lesenswert?

Heiner schrieb:

> Warum gibt es dazu so gut wie keine Angaben?

Weil Clock-Stretching einfach fester Bestandteil der I²C-Spezifikation 
ist. Alles, was was taugt und I²C-kompatibel sein will, hat es zu 
unterstützen.

Das betrifft natürlich nur Master. Ein Client, der kein Clockstretching 
benötigt, um seine Aufgabe erledigen zu können, braucht über 
Clock-Stretching auch nichts zu wissen.

In deinem konkreten Fall (TWI-Client der Tiny 441/841) weiß allerdings 
die Client-Hardware bereits alles nötige über Clock-Stretching und 
wendet das ganz automatisch an, wenn der Programmierer ihr keine andere 
Wahl läßt. Das ist auch überhaupt kein Problem, jeder standardgerecht 
Master hat damit lt. Standard problemlos klarzukommen.

D.h.: normalerweise ist bereits der Drops gelutscht, egal wie Scheiße du 
als Programmierer bist. Nur dann, wenn der Master standardwidrig unfähig 
ist, mit Clock-Stretching umzugehen, dann ist es nicht mehr egal. Dann 
ist dein Job, dafür zu sorgen, dass der Client kein Clock-Stretching 
mehr anwenden muss. D.h. im Kern, dass dein Code schlicht in jeder 
denkbaren Situation schnell genug sinnvoll auf den Interrupt der 
TWI-Slave-Hardware reagieren muss.

> Leute beziehen sich darauf oder suchen was dazu, doch keiner nennt was
> konkretes.

Diese Leute haben wohl alle den Standard gelesen und verstanden. Das ist 
alles.

> Gibt es dieses Problem nur wenn man einen Attiny oder anderes kleines
> als Slave nutzt?

Nein. Das Problem gibt es vielmehr nur, wenn man nicht 
Clock-Stretching-fähige (d.h.: nicht standardgerechte) Master benutzt.

von Rainer V. (a_zip)


Lesenswert?

Heiner schrieb:
> Warum gibt es dazu so gut wie keine Angaben?

na weil das doch quasi trivial ist! Stefan und andere haben das doch 
schon beschrieben. Man muß sich eher Gedanken machen, wie man die 
Blockade in seinem Programm sinnvoll bearbeitet. Ich weiß nicht, ob das 
bei den diversen Programmpaketen drin ist, aber ich (als ASM) würde da 
auf jeden Fall sowas wie ein "timeout" einbauen, damit das System nicht 
auf ewig festhängt. Am Besten wäre doch für den TO einfach mal Spielen 
:-)
Gruß Rainer

von Heiner (Gast)


Lesenswert?

Wo liegt den das Problem, beim Master oder Slave?

von Rainer V. (a_zip)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das ist Clock-Stretching. Wenn der Slave nicht sofort antworten kann,
> zieht er SCL so lange auf Low, bis er antworten kann. Achtung: Damit
> blockiert man den Bus, andere Übertragungen müssen dann ebenfalls
> warten.

...was bitte verstehst du daran nicht???

von Heiner (Gast)


Lesenswert?

Rainer V. schrieb:
> Stefan ⛄ F. schrieb:
>> Das ist Clock-Stretching. Wenn der Slave nicht sofort antworten kann,
>> zieht er SCL so lange auf Low, bis er antworten kann. Achtung: Damit
>> blockiert man den Bus, andere Übertragungen müssen dann ebenfalls
>> warten.
>
> ...was bitte verstehst du daran nicht???

Das verstehe ich sehr wohl und bin daran was zu machen.
Darüber steht aber auch die Aussage:

c-hater schrieb:
> Nein. Das Problem gibt es vielmehr nur, wenn man nicht
> Clock-Stretching-fähige (d.h.: nicht standardgerechte) Master benutzt.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Wie gesagt kannst du einfach innerhalb der ISR deine 5 ADC abfragen 
machen, bevor du damit beginnst, die Antwort (das ACK) zurück zu 
liefern.

Zur Erinnerung: Das ist die Zeile wo du das ACK sendest:
> TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));

Mehr ist da gar nicht zu tun, der Rest (das Clock Stretching) ergibt 
sich dann von ganz alleine.

von Heiner (Gast)


Lesenswert?

In diesem Bereich erfolgt das lesen der ADC Wert im Slave:
1
if (TWSSRA & (1 << TWDIR))    // Master fordert Daten vom Slave an
2
      {
3
      if(tx_buf_index >= sizeof(tx_buf))
4
        {
5
        tx_buf_index=0;
6
        }
7
      TWSD = tx_buf[tx_buf_index];// Daten in Sendepuffer
8
      tx_buf_index++;
9
      TWSCRB = ((1<<TWCMD1)|(1<<TWCMD0)); //Das ist die Zeile wo das ACK sendet
10
      }
Wenn ich die Funktion richtig verstanden habe
- fordert der Master vom Slave Daten ab mit if (TWSSRA & (1 << TWDIR))
- diese Daten stehen dann im TWSD (Datenpuffer)
- tx_buf_index steht auf 0 und wird so oft hochgezählt wie es angegeben 
ist
- es werden die Daten in TWSD geladen mit tx_buf und dem tx_buf_index
- tx_buf_index wird hochgezählt
- mit TWSCRB = ((1<<TWCMD1)|(1<<TWCMD0)) erfolgt die übertragung der 
Daten zum Master

Dann müsste in der Zeile da vor die Abfrage ob ADC fertig ist bzw. die 
Verzögerung von SCL.

Noch eins zur Hardware. Möchte das ganze auch auf einen Joystick mit 2 x 
ADC, Encoder und vielleicht auf entprellte Taster (nach Peter) 
verwenden.

Habe das im DB gefunden:
Das Datenregister wird beim Senden und Empfangen von Daten verwendet. 
Während der Übertragung werden die Daten vom/zum TWSD-Register und 
zum/vom Bus geschoben. Daher kann während der Byte-Übertragung nicht auf 
das Datenregister zugegriffen werden. Dies ist in der Hardware 
geschützt. Auf das Datenregister kann nur zugegriffen werden, wenn die 
SCL-Leitung vom Slave auf Low gehalten wird, d. h. wenn TWCH gesetzt 
ist.
... und das wird im TWSSRA gemacht.
LG Heiner

von Heiner (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Zur Erinnerung: Das ist die Zeile wo du das ACK sendest:
>> TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0));
>
> Mehr ist da gar nicht zu tun, der Rest (das Clock Stretching) ergibt
> sich dann von ganz alleine.

Habe dazu die Tabelle 20-2 gefunden. Dort steht

TWCMD[1:0]   TWDIR     Betrieb/Operation

00   X     Keine Aktion
01   X     Reserviert

10   Wird verwendet, um die Transaktion abzuschließen
0   Acknowledge-Aktion ausführen, dann auf eine START (S/Sr)-Bedingung 
warten
1  Warten auf eine beliebige START (S/Sr)-Bedingung

11   Wird als Antwort auf ein Adressbyte verwendet (TWASIF ist gesetzt)
0     Acknowledge-Aktion ausführen, dann nächstes Byte empfangen
1   Acknowledge-Aktion ausführen, dann TWDIF setzenVerwendet als Antwort 
auf ein Datenbyte (TWDIF ist gesetzt)
0     Acknowledge-Aktion ausführen, dann auf nächstes Byte warten
1     Keine Aktion

Hoffe das die Formatierung auch so rüber kommt wie im ori.
In der Tabelle werden TWCMD 1 und 0 und TWDIR angegeben und ACK bzw. 
Einstellungen dazu.
Habe ich das richtig verstanden das TWCMD1=1 und TWCMD0=1 und TWDIR=0 
sein muss und damit Clock Stretching eingeschaltet wird?
Sorry, ist mir ganz unklar.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe gerade die Augen verdreht. Ist das denn wirklich so schwer?

Du sollst an dem Code für die Bits gar nichts ändern, sondern einfach 
nach dem Empfang des Kommandos erst den ADC 5x abfragen und danach das 
ACK senden. In der Zeitspanne zwischen ISR und dem Beschreiben des 
TWSCRB Registers passiert das Clock-Stretching von ganz alleine.
1
ISR( TWI_SLAVE_vect )
2
{
3
  uint8_t status = TWSSRA & 0xC0;
4
  if (status & I2C_DATA_INTERRUPT)
5
  {
6
    if (TWSSRA & (1 << TWDIR)) // Master fordert Daten vom Slave an
7
    {
8
      TWSD = ... // ein Byte antworten
9
      TWSCRB = (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0)); // Ack senden
10
    }
11
    else  // Master hat ein Byte (=Kommando) zum Slave gesendet
12
    {
13
      command = TWSD;
14
15
      // Wenn das Start-Kommando empfangen wurde
16
      // hier den ADC 5x abfragen
17
      // erst dann mit ACK antworten
18
19
      TWSCRB |= (uint8_t) ((1<<TWCMD1)|(1<<TWCMD0)); // Ack senden
20
    }
21
  }
22
  else if (status & I2C_ADDRESS_STOP_MATCH) 
23
  ...

TWDIR ist gar nicht zum Beschreiben vorgesehen. Dieses Bit kannst du nur 
lesen. Es zeigt an, ob der Master dir gerade ein Kommando-Byte 
gesendet hat, oder ob du ihm mit einem Daten-Byte antworten sollst.
1
Bit 1 – TWDIR: TWI Read/Write Direction
2
3
This bit indicates the direction bit from the last address packet received from a master. When this bit is one, a master read operation is in progress. When the bit is zero a master write operation is in progress.

von Hannes (Gast)


Lesenswert?

Noch mundgerechter geht es nicht

von c-hater (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:

> Ich habe gerade die Augen verdreht. Ist das denn wirklich so schwer?

Also manchmal bewundere ich wirklich deine Ausdauer und Geduld. Auch 
wenn selbst du hier scheinbar langsam an deine Grenzen stößt.

Aber vielleicht musst du dich am Ende doch mit dem Schluß abfinden, dass 
dieser Typ einfach mal vollständig lernresistent ist.

Das muss seinerseits kein böser Wille sein, aber wenn's das nicht ist, 
bleibt nur: IQ-Defizit. Bitter (für ihn), aber nicht zu ändern (für 
uns).

von Heiner (Gast)


Lesenswert?

c-hater schrieb:
> Aber vielleicht musst du dich am Ende doch mit dem Schluß abfinden, dass
> dieser Typ einfach mal vollständig lernresistent ist.
>
> Das muss seinerseits kein böser Wille sein, aber wenn's das nicht ist,
> bleibt nur: IQ-Defizit. Bitter (für ihn), aber nicht zu ändern (für
> uns).

Es ist auf keinen Fall ein böser Wille von mir. Leider ist bei diesen 
Sachen auch das Ende meines Verständnisses (IQ) erreicht.
Eine Sache habt ihr damit wunderbar geschafft, das ich das Datenblatt 
lese. Muss ganz offen sagen, so gründlich und oft wie in diesem Fall 
habe ich noch nie ein Datenblatt gelesen. Habe auch versucht (so weit 
möglich für mich) die Zusammenhänge zwischen den einzelnen Registern und 
Einstellungen nach zu vollziehen. Einige Sachen fehlen noch beim lesen.
Werde auf jeden Fall weiter machen mit dem Attiny 841 und dran arbeiten 
es zu verstehen. Manches geht leichter für mich andere Sachen sind sehr 
schwer zu verstehen.
Hatte einen anderen Rat befolgt und mit den Einstellungen probiert, 
leider ohne Erfolg. Wie ich jetzt sehe war ich auf dem richtigen Weg 
aber sehr halbherzig. Hatte nur die hälfte gemacht und den zweiten Teil 
total vergessen.
Werde alles testen und berichten. Sicher helfen wir und besonders ihr 
auch vielen anderen Lesern (Anfängern) beim programmieren und lernen. 
Allein dafür gebürt euch mein grosser Dank.
LG Heiner

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.