Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - Software I2C, TWI/de: what changed

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

Title: AVR Embedded Tutorial - Software I2C, TWI/de

OldNewLine
1+Zur Übersichtseite [[AVR Embedded Tutorial/de]].
2+
3+# Software-I2C/TWI für ATmega328 / Arduino
4+
5+Viele AVR Controller bieten eine Hardware-I2C-Schnittstelle. Mitunter benötigt man aber einen I2C auf anderen Pins, oder mehrere I2C. Dann hilft ein Software-I2C.
6+
7+Zu den Grundlagen von I2C siehe Wikipedia: <https://de.wikipedia.org/wiki/I2c>
8+
9+## Software TWI Master
10+
11+### TWI Header
12+
13+``` pascal
14+unit test_twi;
15+
16+{$mode objfpc}
17+{$goto on}
18+
19+interface
20+
21+uses
22+ ;
23+
24+procedure twi_start();
25+procedure twi_stop();
26+
27+function twi_write(data : uint8) : boolean;
28+function twi_readbyte(ackn : boolean) : uint8;
29+function twi_readword(ackn : boolean) : uint16;
30+
31+const
32+ Psclin = 1 shl 5; // PC5 beliebige Pins, aber auf gleichem Port
33+ Psdain = 1 shl 4; // PC4
34+
35+var
36+ DDRtwi : byte absolute DDRC; // TWI Pins auf Port C
37+ PRTtwi : byte absolute PORTC;
38+ PINtwi : byte absolute PINC;
39+
40+implementation
41+```
42+
43+Die Pins für SCL und SDA können beliebig festgelegt werden, müssen aber auf einem Port liegen. Bei Pins auf verschiedenen Ports müssen die Pinzugriffe in den folgenden Routinen angepasst werden.
44+
45+### Pausen
46+
47+``` pascal
48+// Pause TWI
49+
50+procedure delay2();
51+label
52+ loop;
53+begin
54+ asm
55+ ldi r16, 9
56+ loop:
57+ dec r16
58+ brne loop
59+ end['r16'];
60+end;
61+
62+procedure delay3();
63+label
64+ loop;
65+begin
66+ asm
67+ ldi r16, 10
68+ loop:
69+ dec r16
70+ brne loop
71+ end['r16'];
72+end;
73+```
74+
75+Die Taktrate wird über die Laufzeit der Pausen angepasst, die Zahlen hiner ldi r16. Inline-Assembler läßt hier keine Kommentare zu und aus Timinggründen sollten die Werte direkt eingetragen und nicht als Variablen übergeben werden.
76+
77+Mit den angegebenen Werten 9 und 10 ergibt sich bei 8MHz Taktfrequenz eine Clockrate von 100kHz, mit 59 und 60 erreicht man 10kHz für lange Datenleitungen.
78+
79+### TWI Start
80+
81+``` pascal
82+// Start TWI
83+
84+procedure twi_start();
85+begin
86+ DDRtwi := DDRtwi or Psdain; // SDA low
87+ delay3();
88+ DDRtwi := DDRtwi or Psclin; // SCL low
89+ delay3();
90+end;
91+```
92+
93+Die Startsequenz für eine Übertragung.
94+
95+### TWI Stop
96+
97+``` pascal
98+// Stop TWI
99+
100+procedure twi_stop();
101+begin
102+ DDRtwi := DDRtwi or Psdain; // SDA low
103+ delay3();
104+ DDRtwi := DDRtwi and (not Psclin); // SCL high
105+ delay3();
106+ DDRtwi := DDRtwi and (not Psdain); // SDA high
107+ delay3();
108+end;
109+```
110+
111+Die Stopsequenz. Für ein Restart, wie es manche Datenblätter fordern nimmt man einfach eine Stopsequenz gefolgt von einer Startsequenz.
112+
113+### TWI Byte schreiben
114+
115+``` pascal
116+// TWI schreiben
117+
118+function twi_write(data : uint8) : boolean;
119+var
120+ i : uint8;
121+begin
122+ for i := 0 to 7 do begin // 8 Bit ausgeben
123+ if (data and (1 shl 7)) <> 0 then
124+ DDRtwi := DDRtwi and (not Psdain) // SDA high, wenn Bit gesetzt
125+ else
126+ DDRtwi := DDRtwi or Psdain; // SDA low, wenn Bit nicht gesetzt
127+ data := data shl 1; // Bit schieben, 7 bis 0
128+ delay2();
129+ DDRtwi := DDRtwi and (not Psclin); // SCL high
130+ delay3();
131+ DDRtwi := DDRtwi or Psclin; // SCL low
132+ end;
133+
134+ DDRtwi := DDRtwi and (not Psdain); // SDA high
135+ delay2();
136+ DDRtwi := DDRtwi and (not Psclin); // SCL high
137+ delay2();
138+
139+ if (PINtwi and Psdain) = 0 then // Testen SDA auf Acknowledge low
140+ twi_write := true // Flag Ack setzen
141+ else
142+ twi_write := false; // sonst Flag Ack löschen
143+
144+ DDRtwi := DDRtwi or Psclin; // SCL low
145+end;
146+```
147+
148+Byte übergeben und los. Dauer ist etwa 10x Taktdauer, das heisst 100µsec bei 100kHz. Die Routine darf von Interrupts unterbrochen werden, der Slave wartet dann.
149+
150+### TWI Datenbyte lesen
151+
152+``` pascal
153+// TWI Byte lesen
154+
155+function twi_readbyte(ackn : boolean) : uint8;
156+var
157+ data : uint8 = 0;
158+ i : uint8;
159+begin
160+ for i := 0 to 7 do begin // 8 Bit ausgeben
161+ data := data shl 1; // Bit schieben, 7 bis 0
162+ delay2();
163+ DDRtwi := DDRtwi and (not Psclin); // SCL high
164+ delay2();
165+ if (PINtwi and (Psdain)) <> 0 then // Testen SDA auf high
166+ data := data or (1 shl 0); // wenn high, Bit 0 setzen
167+ DDRtwi := DDRtwi or Psclin; // SCL low
168+ end;
169+
170+ if ackn then
171+ DDRtwi := DDRtwi or Psdain // SDA low, Acknowledge
172+ else
173+ DDRtwi := DDRtwi and (not Psdain); // SDA high, No Acknowledge
174+ delay2();
175+ DDRtwi := DDRtwi and (not Psclin); // SCL high
176+ delay3();
177+ DDRtwi := DDRtwi or Psclin; // SCL low
178+ DDRtwi := DDRtwi and (not Psdain); // SDA high
179+
180+ twi_readbyte := data; // Daten zurückgeben
181+end;
182+```
183+
184+### TWI Datenword lesen
185+
186+``` pascal
187+// TWI Word lesen, MSB + LSB
188+
189+function twi_readword(ackn : boolean) : uint16;
190+var
191+ data : uint16 = 0;
192+ i : uint8;
193+begin
194+ for i := 0 to 7 do begin // 8 Bit ausgeben
195+ data := data shl 1; // Bit schieben, 7 bis 0
196+ delay2();
197+ DDRtwi := DDRtwi and (not Psclin); // SCL high
198+ delay2();
199+ if (PINtwi and (Psdain)) <> 0 then // Testen SDA auf high
200+ data := data or (1 shl 0); // wenn high, Bit 0 setzen
201+ DDRtwi := DDRtwi or Psclin; // SCL low
202+ end;
203+
204+ DDRtwi := DDRtwi or Psdain; // SDA low, Acknowledge
205+ delay2();
206+ DDRtwi := DDRtwi and (not Psclin); // SCL high
207+ delay3();
208+ DDRtwi := DDRtwi or Psclin; // SCL low
209+ DDRtwi := DDRtwi and (not Psdain); // SDA high
210+
211+ for i := 0 to 7 do begin // 8 Bit ausgeben
212+ data := data shl 1; // Bit schieben, 7 bis 0
213+ delay2();
214+ DDRtwi := DDRtwi and (not Psclin); // SCL high
215+ delay2();
216+ if (PINtwi and (Psdain)) <> 0 then // Testen SDA auf high
217+ data := data or (1 shl 0); // wenn high, Bit 0 setzen
218+ DDRtwi := DDRtwi or Psclin; // SCL low
219+ end;
220+
221+ if ackn then
222+ DDRtwi := DDRtwi or Psdain // SDA low, Acknowledge
223+ else
224+ DDRtwi := DDRtwi and (not Psdain); // SDA high, No Acknowledge
225+ delay2();
226+ DDRtwi := DDRtwi and (not Psclin); // SCL high
227+ delay3();
228+ DDRtwi := DDRtwi or Psclin; // SCL low
229+ DDRtwi := DDRtwi and (not Psdain); // SDA high
230+
231+ twi_readword := data; // Daten zurückgeben
232+end;
233+```
234+
235+### End
236+
237+Mit folgender Zeile ist die Unit komplett.
238+
239+``` pascal
240+end.
241+```
242+
243+## Siehe auch
244+
245+- Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]]
246+
247+---
248+*From the Free Pascal wiki, page "AVR Embedded Tutorial - Software I2C, TWI/de", as it stood on 2020-03-07 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