Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - I²C, TWI/de: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: AVR Embedded Tutorial - I²C, TWI/de

OldNewLine
1+# I²C / TWI
2+
3+## Vorwort
4+
5+Dieser Code ist für einen Atmega328/Arduino mit 16MHz.
6+
7+Wie man die UART ansteuert, steht hier:
8+
9+- [[AVR Embedded Tutorial - UART/de|UART]] *UARTInit* und *UARTSendString(...*
10+
11+## Beschreibung
12+
13+Dieses Beispiel demonstriert die Kommunikation mit der I²C/TWI - Schnittstelle.
14+
15+Als Slave-Geräte werden 2 AD1115 A/D-Wandler verwendet. Diese sind sehr einfach in der Handhabung und sind auch sehr einfach erhältlich. Was sehr wichtig ist, dass man bei TWIStart die Adresse um ein Bit nach links verschiebt und anschließend mittels Write/Read mit **or** verknüpft. Es gibt viele Tutorials dazu. Dort sieht man das leider sehr schlecht.
16+
17+PulUp-Widerstände sind nicht nötig, da diese schon auf der Platine des ADS1115 verbaut sind.
18+
19+## I²C Funktionen
20+
21+### Konstanten
22+
23+``` pascal
24+const
25+ CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
26+ ADSaddr0 = $48; // Adresse Wandler 0
27+ ADSaddr1 = $49; // Adresse Wandler 1
28+ I2C_Takt = 400000; // I²C-Takt (400KHz)
29+ TWI_Write = 0;
30+ TWI_Read = 1;
31+```
32+
33+### I²C inizialisieren
34+
35+``` pascal
36+ procedure TWIInit;
37+ const
38+ TWBR_val = byte((CPU_Clock div I2C_Takt) - 16) div 2;
39+ begin
40+ TWSR := 0;
41+ TWBR := byte(TWBR_val);
42+ end;
43+```
44+
45+### I²C Senden/Empfangen starten
46+
47+``` pascal
48+ procedure TWIStart(addr: byte);
49+ begin
50+ // Senden/Empfangen einleiten
51+ TWCR := 0;
52+ TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN);
53+ while ((TWCR and (1 shl TWINT)) = 0) do begin
54+ end;
55+
56+ // Adresse des Endgerätes senden
57+ TWDR := addr;
58+ TWCR := (1 shl TWINT) or (1 shl TWEN);
59+ while ((TWCR and (1 shl TWINT)) = 0) do begin
60+ end;
61+ end;
62+```
63+
64+### I²C Senden/Empfang beendet
65+
66+``` pascal
67+ procedure TWIStop;
68+ begin
69+ TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN);
70+ end;
71+```
72+
73+### Zeichen Senden
74+
75+``` pascal
76+ procedure TWIWrite(u8data: byte);
77+ begin
78+ TWDR := u8data;
79+ TWCR := (1 shl TWINT) or (1 shl TWEN);
80+ while ((TWCR and (1 shl TWINT)) = 0) do begin
81+ end;
82+ end;
83+```
84+
85+### Zeichen Empfangen
86+
87+Bis auf das vorletzte Zeichen muss mit **TWIReadACK(...** gelesen werden. Das letzte Zeichen muss mit **TWIReadNACK(...** gelesen werden.
88+
89+``` pascal
90+ // Lesen bis zum vorletzten Zeichen.
91+ function TWIReadACK: byte;
92+ begin
93+ TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
94+ while (TWCR and (1 shl TWINT)) = 0 do begin
95+ end;
96+ Result := TWDR;
97+ end;
98+
99+ // Letztes Zeichen lesen.
100+ function TWIReadNACK: byte;
101+ begin
102+ TWCR := (1 shl TWINT) or (1 shl TWEN);
103+ while (TWCR and (1 shl TWINT)) = 0 do begin
104+ end;
105+ Result := TWDR;
106+ end;
107+```
108+
109+> **Note:** Anmerkung: Diese Funktionen bleibt bei einem Hardware-Fehler, oder die Slave-Adresse falsch ist, hängen !
110+
111+### Zeichen Empfangen mit Fehlerabfrage
112+
113+Das diese Funktionen nicht hängen bleiben, muss man in der while-Schleife einen Zähler einbauen.
114+
115+Wen der Zähler 255 erreicht, wird die Schleife unterbrochen und ein Fehler ausgegeben.
116+
117+255 wird erreicht, wen an der I²C-Adresse kein Gerät gefunden wird.
118+
119+``` pascal
120+// Lesen bis zum vorletzten Zeichen.
121+function TWIReadACK_Error: byte;
122+var
123+ err:byte;
124+begin
125+ err := 0;
126+ TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
127+ while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin
128+ Inc(err);
129+ end;
130+ if err = 255 then begin
131+ UARTSendString('I²C-Timeout');
132+ Result := 0;
133+ end else begin
134+ Result := TWDR;
135+ end;
136+end;
137+
138+// Letztes Zeichen lesen.
139+function TWIReadNACK_Error: byte;
140+var
141+ err:byte;
142+begin
143+ err := 0;
144+ TWCR := (1 shl TWINT) or (1 shl TWEN);
145+ while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin
146+ Inc(err);
147+ end;
148+ if err = 255 then begin
149+ UARTSendString('I²C-Timeout');
150+ Result := 0;
151+ end else begin
152+ Result := TWDR;
153+ end;
154+end;
155+```
156+
157+## ADS1115 spezifischen Code
158+
159+Dieser Code ist ADS1115 spezifischen, andere I²C-Geräte müssen im Datenblatt nachgeguckt werden.
160+
161+``` pascal
162+ // Parameter an ADS1115 schicken und Messen einleiten
163+ procedure WriteADS1115(addr: UInt16);
164+ begin
165+ TWIStart((addr shl 1) or TWI_Write);
166+ TWIWrite(1);
167+ TWIWrite(%11000011); // High
168+ TWIWrite(%11100011); // Low
169+ TWIStop;
170+ end;
171+
172+ // Messung von ADS1115 auslesen.
173+ function ReadADS1115(addr: UInt16): UInt16;
174+ begin
175+ TWIStart((addr shl 1) or TWI_Write);
176+ TWIWrite(0);
177+ TWIStop;
178+
179+ TWIStart((addr shl 1) or TWI_Read);
180+ Result := TWIReadACK * $100 + TWIReadNACK;
181+ TWIStop;
182+ end;
183+```
184+
185+## Beispiel
186+
187+``` pascal
188+var
189+ Data: Integer;
190+ s: ShortString;
191+
192+begin
193+ asm cli end; // Interrupt sperren.
194+ UARTInit;
195+ TWIInit;
196+ asm sei end; // Interrupt frei geben.
197+
198+ repeat
199+ WriteADS1115(ADSaddr0);
200+ Data := ReadADS1115(ADSaddr0);
201+
202+ str(Data: 6, s);
203+ UARTSendString('Kanal 0: ');
204+ UARTSendString(s);
205+
206+ WriteADS1115(ADSaddr1);
207+ Data := ReadADS1115(ADSaddr1);
208+
209+ str(Data: 6, s);
210+ UARTSendString(' Kanal 1: ');
211+ UARTSendString(s);
212+ UARTSendString(#13#10);
213+ until 1 = 2;
214+end.
215+```
216+
217+## Parameter ADS1115
218+
219+Eine Auflistung der Parameter des ADS1115. Mehr Infos im Datenblatt.
220+
221+**Bit-Belegung des ADS1115:**
222+
223+**Low:** 11100011 **High:** 11000011
224+
225+<table>
226+<thead>
227+<tr>
228+<th>Bit</th>
229+<th>Bezeichnung</th>
230+<th>Beschreibung</th>
231+</tr>
232+</thead>
233+<tbody>
234+<tr>
235+<td>15</td>
236+<td><strong>OS:</strong> Operational status or single-shot conversion start</td>
237+<td><strong>0</strong> : no effect<br />
238+<strong>1</strong> : Start a single conversion (when in power-down state)</td>
239+</tr>
240+<tr>
241+<td>14:12</td>
242+<td><strong>MUX[2:0]:</strong> Input multiplexer configuration (ADS1115 only)</td>
243+<td><strong>000</strong> : AINP = AIN0 and AINN = AIN1 (default)<br />
244+<strong>001</strong> : AINP = AIN0 and AINN = AIN3<br />
245+<strong>010</strong> : AINP = AIN1 and AINN = AIN3<br />
246+<strong>011</strong> : AINP = AIN2 and AINN = AIN3<br />
247+<strong>100</strong> : AINP = AIN0 and AINN = GND<br />
248+<strong>101</strong> : AINP = AIN1 and AINN = GND<br />
249+<strong>110</strong> : AINP = AIN2 and AINN = GND<br />
250+<strong>111</strong> : AINP = AIN3 and AINN = GND</td>
251+</tr>
252+<tr>
253+<td>11:9</td>
254+<td><strong>PGA[2:0]:</strong>Programmable gain amplifier configuration</td>
255+<td><strong>000</strong> : FSR = ±6.144 V<br />
256+<strong>001</strong> : FSR = ±4.096 V<br />
257+<strong>010</strong> : FSR = ±2.048 V (default)<br />
258+<strong>011</strong> : FSR = ±1.024 V<br />
259+<strong>100</strong> : FSR = ±0.512 V<br />
260+<strong>101</strong> : FSR = ±0.256 V<br />
261+<strong>110</strong> : FSR = ±0.256 V<br />
262+<strong>111</strong> : FSR = ±0.256 V<br />
263+</td>
264+</tr>
265+<tr>
266+<td>8</td>
267+<td><strong>MODE:</strong> Device operating mode</td>
268+<td><strong>0</strong> : Continuous-conversion mode<br />
269+<strong>1</strong> : Single-shot mode or power-down state (default)</td>
270+</tr>
271+<tr>
272+<td>7:5</td>
273+<td><strong>DR[2:0]:</strong> Data rate</td>
274+<td><strong>000</strong> : 8 SPS<br />
275+<strong>001</strong> : 16 SPS<br />
276+<strong>010</strong> : 32 SPS<br />
277+<strong>011</strong> : 64 SPS<br />
278+<strong>100</strong> : 128 SPS (default)<br />
279+<strong>101</strong> : 250 SPS<br />
280+<strong>110</strong> : 475 SPS<br />
281+<strong>111</strong> : 860 SPS<br />
282+</td>
283+</tr>
284+<tr>
285+<td>4</td>
286+<td><strong>COMP_MODE:</strong> Comparator mode</td>
287+<td><strong>0</strong> : Traditional comparator (default)<br />
288+<strong>1</strong> : Window comparator</td>
289+</tr>
290+<tr>
291+<td>3</td>
292+<td><strong>COMP_POL:</strong> Comparator polarity</td>
293+<td><strong>0</strong> : Actice low (default)<br />
294+<strong>1</strong> : Actice high</td>
295+</tr>
296+<tr>
297+<td>2</td>
298+<td><strong>COMP_LAT:</strong> Latching comparator</td>
299+<td><strong>0</strong> : Nonlatching comparator (default)<br />
300+<strong>1</strong> : Latching comparator</td>
301+</tr>
302+<tr>
303+<td>1:0</td>
304+<td><strong>COMP_QUE[1:0]:</strong> Comparator queue and disable</td>
305+<td><strong>00</strong> : Assert after one conversion<br />
306+<strong>01</strong> : Assert after two conversions<br />
307+<strong>10</strong> : Assert after four conversions<br />
308+<strong>11</strong> : Disable comparator and set ALERT/RDY pin to high-impedance (default)</td>
309+</tr>
310+</tbody>
311+</table>
312+
313+# Siehe auch
314+
315+- Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]]
316+
317+Autor: Mathias
318+
319+---
320+*From the Free Pascal wiki, page "AVR Embedded Tutorial - I²C, TWI/de", as it stood on 2020-03-06 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history