Difference between revisions of "AVR Embedded Tutorial - I²C, TWI/de"

From Lazarus wiki
Jump to navigationJump to search
Line 18: Line 18:
 
{{Note|Anmerkung: Wenn die Slave-Adresse falsch ist, bleibt das Programm in der TWIRead-Funktion hängen !}}
 
{{Note|Anmerkung: Wenn die Slave-Adresse falsch ist, bleibt das Programm in der TWIRead-Funktion hängen !}}
  
==Beispiel Code==
+
== I²C Funktionen ==
<syntaxhighlight lang="pascal">program Project1;
 
  
 +
=== Konstanten ===
 +
<syntaxhighlight lang="pascal">
 
const
 
const
 
   CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
 
   CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
  Baud      = 9600;    // Baudrate UART
 
 
   ADSaddr0  = $48;      // Adresse Wandler 0
 
   ADSaddr0  = $48;      // Adresse Wandler 0
 
   ADSaddr1  = $49;      // Adresse Wandler 1
 
   ADSaddr1  = $49;      // Adresse Wandler 1
Line 29: Line 29:
 
   TWI_Write = 0;
 
   TWI_Write = 0;
 
   TWI_Read  = 1;
 
   TWI_Read  = 1;
  UCSZ01    = 2;        // Gibt es nicht in der Unit Atmega328p.
+
</syntaxhighlight>
 
 
 
 
  // === UART-Schnittstelle
 
 
 
  procedure UARTInit;
 
  const
 
    teiler = CPU_Clock div (16 * Baud) - 1;
 
  begin
 
    UBRR0 := Teiler;
 
    UCSR0A := (0 shl U2X0);
 
    UCSR0B := (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);
 
    UCSR0C := (%011 shl UCSZ0);
 
  end;
 
 
 
  procedure UARTSendChar(c: char);
 
  begin
 
    while UCSR0A and (1 shl UDRE0) = 0 do begin
 
    end;
 
    UDR0 := byte(c);
 
  end;
 
 
 
  function UARTReadChar: char;
 
  begin
 
    while UCSR0A and (1 shl RXC0) = 0 do begin
 
    end;
 
    Result := char(UDR0);
 
  end;
 
 
 
  procedure UARTSendString(s: ShortString);
 
  var
 
    i: integer;
 
  begin
 
    for i := 1 to length(s) do begin
 
      UARTSendChar(s[i]);
 
    end;
 
  end;
 
 
 
  // === I2C Bus
 
  
 +
=== I²C inizialisieren ===
 +
<syntaxhighlight lang="pascal">
 
   procedure TWIInit;
 
   procedure TWIInit;
 
   const
 
   const
Line 76: Line 40:
 
     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 91: Line 58:
 
     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 104: Line 77:
 
     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 113: Line 93:
 
   end;
 
   end;
  
 +
  // Letzten Zeichen lesen.
 
   function TWIReadNACK: byte;
 
   function TWIReadNACK: byte;
 
   begin
 
   begin
Line 120: Line 101:
 
     Result := TWDR;
 
     Result := TWDR;
 
   end;
 
   end;
 +
</syntaxhighlight>
  
  // === Ende I2C
+
== 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 144: Line 127:
 
     TWIStop;
 
     TWIStop;
 
   end;
 
   end;
 +
</syntaxhighlight>
  
 +
== Beispiel ==
 +
<syntaxhighlight lang="pascal">
 
var
 
var
 
   Data: integer;
 
   Data: integer;
Line 150: Line 136:
  
 
begin
 
begin
   asm
+
   asm cli end; // Interrupt sperren.
          Cli
 
  end;
 
 
   UARTInit;
 
   UARTInit;
 
   TWIInit;
 
   TWIInit;
   asm
+
   asm sei end; // Interrupt frei geben.
          Sei
 
  end;
 
  
 
   repeat
 
   repeat
Line 175: Line 157:
 
     UARTSendString(#13#10);
 
     UARTSendString(#13#10);
 
   until 1 = 2;
 
   until 1 = 2;
end.</syntaxhighlight>
+
end.
 +
</syntaxhighlight>
  
 
==Parameter ADS1115==
 
==Parameter ADS1115==

Revision as of 22:21, 15 December 2017

Template:Translate

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.

Light bulb  Hinweis: Anmerkung: Wenn die Slave-Adresse falsch ist, bleibt das Programm in der TWIRead-Funktion hängen !

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;

  // Letzten 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;

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 kleine Auflistung der wichtigsten Parameter des ADS1115. Mehr Infos im Datenblatt.

Low: 11100011

???00011: SPS Bit [7:5]

Bit SPS
000 8
001 16
010 32
011 64
100 128
101 250
110 475
111 860 (default)


High: 11000011

1???0011: Kanal (Multiplex) Bit [14:12]

Bit Kanal
100 0 (default)
101 1
110 2
111 3


1100???1: Gain Bit [11:9] (Volt)

Bit Volt
000 FS = ±6.144
001 FS = ±4.096
010 FS = ±2.048 (default)
011 FS = ±1.024
100 FS = ±0.512
101 FS = ±0.256
110 FS = ±0.256
111 FS = ±0.256

Siehe auch