Difference between revisions of "AVR Embedded Tutorial - I²C, TWI/de"
m (Mathias moved page AVR Embedded Tutorial - I²C / TWI/de to AVR Embedded Tutorial - I²C, TWI/de) |
m (Added page template; removed categories in template) |
||
(15 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
+ | {{I2C}} | ||
− | |||
=I²C / TWI= | =I²C / TWI= | ||
+ | |||
+ | ==Vorwort== | ||
+ | |||
+ | Dieser Code ist für einen Atmega328/Arduino mit 16MHz. | ||
+ | |||
+ | Wie man die UART ansteuert, steht hier: | ||
+ | |||
+ | * [[AVR Embedded Tutorial - UART/de|UART]] ''UARTInit'' und ''UARTSendString(...'' | ||
==Beschreibung== | ==Beschreibung== | ||
+ | |||
Dieses Beispiel demonstriert die Kommunikation mit der I²C/TWI - Schnittstelle. | Dieses Beispiel demonstriert die Kommunikation mit der I²C/TWI - Schnittstelle. | ||
Line 11: | Line 20: | ||
PulUp-Widerstände sind nicht nötig, da diese schon auf der Platine des ADS1115 verbaut sind. | PulUp-Widerstände sind nicht nötig, da diese schon auf der Platine des ADS1115 verbaut sind. | ||
− | + | == I²C Funktionen == | |
− | == | + | === Konstanten === |
− | |||
+ | <syntaxhighlight lang="pascal"> | ||
const | const | ||
CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz. | CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz. | ||
− | |||
ADSaddr0 = $48; // Adresse Wandler 0 | ADSaddr0 = $48; // Adresse Wandler 0 | ||
ADSaddr1 = $49; // Adresse Wandler 1 | ADSaddr1 = $49; // Adresse Wandler 1 | ||
Line 24: | Line 32: | ||
TWI_Write = 0; | TWI_Write = 0; | ||
TWI_Read = 1; | TWI_Read = 1; | ||
− | + | </syntaxhighlight> | |
− | |||
− | + | === I²C inizialisieren === | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <syntaxhighlight lang="pascal"> | ||
procedure TWIInit; | procedure TWIInit; | ||
const | const | ||
Line 71: | Line 44: | ||
TWBR := byte(TWBR_val); | TWBR := byte(TWBR_val); | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | === I²C Senden/Empfangen starten === | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
procedure TWIStart(addr: byte); | procedure TWIStart(addr: byte); | ||
begin | begin | ||
− | // Senden einleiten | + | // Senden/Empfangen einleiten |
TWCR := 0; | TWCR := 0; | ||
TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN); | TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN); | ||
Line 86: | Line 63: | ||
end; | end; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | === I²C Senden/Empfang beendet === | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
procedure TWIStop; | procedure TWIStop; | ||
begin | begin | ||
TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN); | TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN); | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Zeichen Senden === | ||
+ | <syntaxhighlight lang="pascal"> | ||
procedure TWIWrite(u8data: byte); | procedure TWIWrite(u8data: byte); | ||
begin | begin | ||
Line 99: | Line 84: | ||
end; | end; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Zeichen Empfangen === | ||
+ | |||
+ | Bis auf das vorletzte Zeichen muss mit '''TWIReadACK(...''' gelesen werden. | ||
+ | Das letzte Zeichen muss mit '''TWIReadNACK(...''' gelesen werden. | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | // Lesen bis zum vorletzten Zeichen. | ||
function TWIReadACK: byte; | function TWIReadACK: byte; | ||
begin | begin | ||
Line 108: | Line 101: | ||
end; | end; | ||
+ | // Letztes Zeichen lesen. | ||
function TWIReadNACK: byte; | function TWIReadNACK: byte; | ||
begin | begin | ||
Line 115: | Line 109: | ||
Result := TWDR; | Result := TWDR; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | {{Note|Anmerkung: Diese Funktionen bleibt bei einem Hardware-Fehler, oder die Slave-Adresse falsch ist, hängen !}} | ||
+ | |||
+ | === Zeichen Empfangen mit Fehlerabfrage === | ||
+ | |||
+ | Das diese Funktionen nicht hängen bleiben, muss man in der while-Schleife einen Zähler einbauen. | ||
+ | |||
+ | Wen der Zähler 255 erreicht, wird die Schleife unterbrochen und ein Fehler ausgegeben. | ||
+ | |||
+ | 255 wird erreicht, wen an der I²C-Adresse kein Gerät gefunden wird. | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | // Lesen bis zum vorletzten Zeichen. | ||
+ | function TWIReadACK_Error: byte; | ||
+ | var | ||
+ | err:byte; | ||
+ | begin | ||
+ | err := 0; | ||
+ | TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA); | ||
+ | while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin | ||
+ | Inc(err); | ||
+ | end; | ||
+ | if err = 255 then begin | ||
+ | UARTSendString('I²C-Timeout'); | ||
+ | Result := 0; | ||
+ | end else begin | ||
+ | Result := TWDR; | ||
+ | end; | ||
+ | end; | ||
+ | |||
+ | // Letztes Zeichen lesen. | ||
+ | function TWIReadNACK_Error: byte; | ||
+ | var | ||
+ | err:byte; | ||
+ | begin | ||
+ | err := 0; | ||
+ | TWCR := (1 shl TWINT) or (1 shl TWEN); | ||
+ | while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin | ||
+ | Inc(err); | ||
+ | end; | ||
+ | if err = 255 then begin | ||
+ | UARTSendString('I²C-Timeout'); | ||
+ | Result := 0; | ||
+ | end else begin | ||
+ | Result := TWDR; | ||
+ | end; | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
− | + | == ADS1115 spezifischen Code == | |
+ | Dieser Code ist ADS1115 spezifischen, andere I²C-Geräte müssen im Datenblatt nachgeguckt werden. | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
// Parameter an ADS1115 schicken und Messen einleiten | // Parameter an ADS1115 schicken und Messen einleiten | ||
procedure WriteADS1115(addr: UInt16); | procedure WriteADS1115(addr: UInt16); | ||
Line 139: | Line 185: | ||
TWIStop; | TWIStop; | ||
end; | end; | ||
+ | </syntaxhighlight> | ||
+ | == Beispiel == | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
var | var | ||
− | Data: | + | Data: Integer; |
− | s: ShortString; | + | s: ShortString; |
begin | begin | ||
− | asm | + | asm cli end; // Interrupt sperren. |
− | |||
− | |||
UARTInit; | UARTInit; | ||
TWIInit; | TWIInit; | ||
− | asm | + | asm sei end; // Interrupt frei geben. |
− | |||
− | |||
repeat | repeat | ||
Line 170: | Line 216: | ||
UARTSendString(#13#10); | UARTSendString(#13#10); | ||
until 1 = 2; | until 1 = 2; | ||
− | end.</syntaxhighlight> | + | end. |
+ | </syntaxhighlight> | ||
==Parameter ADS1115== | ==Parameter ADS1115== | ||
− | Eine | + | |
+ | Eine Auflistung der Parameter des ADS1115. | ||
Mehr Infos im Datenblatt. | Mehr Infos im Datenblatt. | ||
+ | |||
+ | '''Bit-Belegung des ADS1115:''' | ||
'''Low:''' 11100011 | '''Low:''' 11100011 | ||
+ | '''High:''' 11000011 | ||
− | |||
{| class="wikitable" | {| class="wikitable" | ||
+ | !Bit !! Bezeichnung !! Beschreibung | ||
|- | |- | ||
− | + | | 15 ||''' OS:''' Operational status or single-shot conversion start || | |
+ | '''0''' : no effect<br> | ||
+ | '''1''' : Start a single conversion (when in power-down state) | ||
|- | |- | ||
− | | | + | | 14:12 || '''MUX[2:0]:''' Input multiplexer configuration (ADS1115 only) || |
+ | '''000''' : AINP = AIN0 and AINN = AIN1 (default)<br> | ||
+ | '''001''' : AINP = AIN0 and AINN = AIN3<br> | ||
+ | '''010''' : AINP = AIN1 and AINN = AIN3<br> | ||
+ | '''011''' : AINP = AIN2 and AINN = AIN3<br> | ||
+ | '''100''' : AINP = AIN0 and AINN = GND<br> | ||
+ | '''101''' : AINP = AIN1 and AINN = GND<br> | ||
+ | '''110''' : AINP = AIN2 and AINN = GND<br> | ||
+ | '''111''' : AINP = AIN3 and AINN = GND | ||
|- | |- | ||
− | | | + | | 11:9 || '''PGA[2:0]:'''Programmable gain amplifier configuration || |
+ | '''000''' : FSR = ±6.144 V<br> | ||
+ | '''001''' : FSR = ±4.096 V<br> | ||
+ | '''010''' : FSR = ±2.048 V (default)<br> | ||
+ | '''011''' : FSR = ±1.024 V<br> | ||
+ | '''100''' : FSR = ±0.512 V<br> | ||
+ | '''101''' : FSR = ±0.256 V<br> | ||
+ | '''110''' : FSR = ±0.256 V<br> | ||
+ | '''111''' : FSR = ±0.256 V<br> | ||
|- | |- | ||
− | | | + | | 8 || '''MODE:''' Device operating mode || |
+ | '''0''' : Continuous-conversion mode<br> | ||
+ | '''1''' : Single-shot mode or power-down state (default) | ||
|- | |- | ||
− | | | + | | 7:5 || '''DR[2:0]:''' Data rate || |
+ | '''000''' : 8 SPS<br> | ||
+ | '''001''' : 16 SPS<br> | ||
+ | '''010''' : 32 SPS<br> | ||
+ | '''011''' : 64 SPS<br> | ||
+ | '''100''' : 128 SPS (default)<br> | ||
+ | '''101''' : 250 SPS<br> | ||
+ | '''110''' : 475 SPS<br> | ||
+ | '''111''' : 860 SPS<br> | ||
|- | |- | ||
− | | | + | | 4 || '''COMP_MODE:''' Comparator mode || |
+ | '''0''' : Traditional comparator (default)<br> | ||
+ | '''1''' : Window comparator | ||
|- | |- | ||
− | | | + | | 3 || '''COMP_POL:''' Comparator polarity || |
+ | '''0''' : Actice low (default)<br> | ||
+ | '''1''' : Actice high | ||
|- | |- | ||
− | | | + | | 2 || '''COMP_LAT:''' Latching comparator || |
+ | '''0''' : Nonlatching comparator (default)<br> | ||
+ | '''1''' : Latching comparator | ||
|- | |- | ||
− | | | + | | 1:0 || '''COMP_QUE[1:0]:''' Comparator queue and disable || |
+ | '''00''' : Assert after one conversion<br> | ||
+ | '''01''' : Assert after two conversions<br> | ||
+ | '''10''' : Assert after four conversions<br> | ||
+ | '''11''' : Disable comparator and set ALERT/RDY pin to high-impedance (default) | ||
|} | |} | ||
+ | = Siehe auch = | ||
− | + | * Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | [[ | + | Autor: [[User:Mathias|Mathias]] |
Latest revision as of 08:20, 6 March 2020
│
Deutsch (de) │
English (en) │
I²C / TWI
Vorwort
Dieser Code ist für einen Atmega328/Arduino mit 16MHz.
Wie man die UART ansteuert, steht hier:
- UART UARTInit und UARTSendString(...
Beschreibung
Dieses Beispiel demonstriert die Kommunikation mit der I²C/TWI - Schnittstelle.
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.
PulUp-Widerstände sind nicht nötig, da diese schon auf der Platine des ADS1115 verbaut sind.
I²C Funktionen
Konstanten
const
CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
ADSaddr0 = $48; // Adresse Wandler 0
ADSaddr1 = $49; // Adresse Wandler 1
I2C_Takt = 400000; // I²C-Takt (400KHz)
TWI_Write = 0;
TWI_Read = 1;
I²C inizialisieren
procedure TWIInit;
const
TWBR_val = byte((CPU_Clock div I2C_Takt) - 16) div 2;
begin
TWSR := 0;
TWBR := byte(TWBR_val);
end;
I²C Senden/Empfangen starten
procedure TWIStart(addr: byte);
begin
// Senden/Empfangen einleiten
TWCR := 0;
TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
// Adresse des Endgerätes senden
TWDR := addr;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
end;
I²C Senden/Empfang beendet
procedure TWIStop;
begin
TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN);
end;
Zeichen Senden
procedure TWIWrite(u8data: byte);
begin
TWDR := u8data;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
end;
Zeichen Empfangen
Bis auf das vorletzte Zeichen muss mit TWIReadACK(... gelesen werden. Das letzte Zeichen muss mit TWIReadNACK(... gelesen werden.
// Lesen bis zum vorletzten Zeichen.
function TWIReadACK: byte;
begin
TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
while (TWCR and (1 shl TWINT)) = 0 do begin
end;
Result := TWDR;
end;
// Letztes Zeichen lesen.
function TWIReadNACK: byte;
begin
TWCR := (1 shl TWINT) or (1 shl TWEN);
while (TWCR and (1 shl TWINT)) = 0 do begin
end;
Result := TWDR;
end;
Zeichen Empfangen mit Fehlerabfrage
Das diese Funktionen nicht hängen bleiben, muss man in der while-Schleife einen Zähler einbauen.
Wen der Zähler 255 erreicht, wird die Schleife unterbrochen und ein Fehler ausgegeben.
255 wird erreicht, wen an der I²C-Adresse kein Gerät gefunden wird.
// Lesen bis zum vorletzten Zeichen.
function TWIReadACK_Error: byte;
var
err:byte;
begin
err := 0;
TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin
Inc(err);
end;
if err = 255 then begin
UARTSendString('I²C-Timeout');
Result := 0;
end else begin
Result := TWDR;
end;
end;
// Letztes Zeichen lesen.
function TWIReadNACK_Error: byte;
var
err:byte;
begin
err := 0;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin
Inc(err);
end;
if err = 255 then begin
UARTSendString('I²C-Timeout');
Result := 0;
end else begin
Result := TWDR;
end;
end;
ADS1115 spezifischen Code
Dieser Code ist ADS1115 spezifischen, andere I²C-Geräte müssen im Datenblatt nachgeguckt werden.
// Parameter an ADS1115 schicken und Messen einleiten
procedure WriteADS1115(addr: UInt16);
begin
TWIStart((addr shl 1) or TWI_Write);
TWIWrite(1);
TWIWrite(%11000011); // High
TWIWrite(%11100011); // Low
TWIStop;
end;
// Messung von ADS1115 auslesen.
function ReadADS1115(addr: UInt16): UInt16;
begin
TWIStart((addr shl 1) or TWI_Write);
TWIWrite(0);
TWIStop;
TWIStart((addr shl 1) or TWI_Read);
Result := TWIReadACK * $100 + TWIReadNACK;
TWIStop;
end;
Beispiel
var
Data: Integer;
s: ShortString;
begin
asm cli end; // Interrupt sperren.
UARTInit;
TWIInit;
asm sei end; // Interrupt frei geben.
repeat
WriteADS1115(ADSaddr0);
Data := ReadADS1115(ADSaddr0);
str(Data: 6, s);
UARTSendString('Kanal 0: ');
UARTSendString(s);
WriteADS1115(ADSaddr1);
Data := ReadADS1115(ADSaddr1);
str(Data: 6, s);
UARTSendString(' Kanal 1: ');
UARTSendString(s);
UARTSendString(#13#10);
until 1 = 2;
end.
Parameter ADS1115
Eine Auflistung der Parameter des ADS1115. Mehr Infos im Datenblatt.
Bit-Belegung des ADS1115:
Low: 11100011 High: 11000011
Bit | Bezeichnung | Beschreibung |
---|---|---|
15 | OS: Operational status or single-shot conversion start |
0 : no effect |
14:12 | MUX[2:0]: Input multiplexer configuration (ADS1115 only) |
000 : AINP = AIN0 and AINN = AIN1 (default) |
11:9 | PGA[2:0]:Programmable gain amplifier configuration |
000 : FSR = ±6.144 V |
8 | MODE: Device operating mode |
0 : Continuous-conversion mode |
7:5 | DR[2:0]: Data rate |
000 : 8 SPS |
4 | COMP_MODE: Comparator mode |
0 : Traditional comparator (default) |
3 | COMP_POL: Comparator polarity |
0 : Actice low (default) |
2 | COMP_LAT: Latching comparator |
0 : Nonlatching comparator (default) |
1:0 | COMP_QUE[1:0]: Comparator queue and disable |
00 : Assert after one conversion |
Siehe auch
- Übersichtseite AVR Embedded Tutorial
Autor: Mathias