Sign in Join
Wiki copytemporary

AVR Embedded Tutorial - Software I2C, TWI/de

Deutsch · English

Zur Übersichtseite AVR Embedded Tutorial/de.

Software-I2C/TWI für ATmega328 / Arduino

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.

Zu den Grundlagen von I2C siehe Wikipedia: https://de.wikipedia.org/wiki/I2c

Software TWI Master

TWI Header

pascal
unit test_twi;

{$mode objfpc}
{$goto on}

interface

uses
  ;

procedure twi_start();
procedure twi_stop();

function twi_write(data : uint8) : boolean;
function twi_readbyte(ackn : boolean) : uint8;
function twi_readword(ackn : boolean) : uint16;

const
  Psclin    = 1 shl 5;  // PC5 beliebige Pins, aber auf gleichem Port
  Psdain    = 1 shl 4;  // PC4

var
  DDRtwi : byte absolute DDRC;  // TWI Pins auf Port C
  PRTtwi : byte absolute PORTC;
  PINtwi : byte absolute PINC;

implementation

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.

Pausen

pascal
// Pause TWI

procedure delay2();
label
  loop;
begin
  asm
    ldi r16, 9
    loop:
      dec r16
      brne loop
  END['r16'];
end;        

procedure delay3();
label
  loop;
begin
  asm
    ldi r16, 10
    loop:
      dec r16
      brne loop
  END['r16'];
end;

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.

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.

TWI Start

pascal
// Start TWI

procedure twi_start();
begin
    DDRtwi := DDRtwi or Psdain;  // SDA low
    delay3();
    DDRtwi := DDRtwi or Psclin;  // SCL low
    delay3();
end;

Die Startsequenz für eine Übertragung.

TWI Stop

pascal
// Stop TWI

procedure twi_stop();
begin
    DDRtwi := DDRtwi or Psdain;  // SDA low
    delay3();
    DDRtwi := DDRtwi and (not Psclin);  // SCL high
    delay3();
    DDRtwi := DDRtwi and (not Psdain);  // SDA high
    delay3();
end;

Die Stopsequenz. Für ein Restart, wie es manche Datenblätter fordern nimmt man einfach eine Stopsequenz gefolgt von einer Startsequenz.

TWI Byte schreiben

pascal
// TWI schreiben

function twi_write(data : uint8) : boolean;
var
  i : uint8;
begin
    for i := 0 to 7 do begin  // 8 Bit ausgeben
        if (data and (1 shl 7)) <> 0 then
            DDRtwi := DDRtwi and (not Psdain)  // SDA high, wenn Bit gesetzt
        else
            DDRtwi := DDRtwi or Psdain;  // SDA low, wenn Bit nicht gesetzt
        data := data shl 1;         // Bit schieben, 7 bis 0
        delay2();
        DDRtwi := DDRtwi and (not Psclin);  // SCL high
        delay3();
        DDRtwi := DDRtwi or Psclin;  // SCL low
    end;

    DDRtwi := DDRtwi and (not Psdain);  // SDA high
    delay2();
    DDRtwi := DDRtwi and (not Psclin);  // SCL high
    delay2();

    if (PINtwi and Psdain) = 0 then  // Testen SDA auf Acknowledge low
        twi_write := true  // Flag Ack setzen
    else
        twi_write := false;  // sonst Flag Ack löschen

    DDRtwi := DDRtwi or Psclin;  // SCL low
end;

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.

TWI Datenbyte lesen

pascal
// TWI Byte lesen

function twi_readbyte(ackn : boolean) : uint8;
var
  data : uint8 = 0;
  i    : uint8;
begin
    for i := 0 to 7 do begin  // 8 Bit ausgeben
        data := data shl 1;         // Bit schieben, 7 bis 0
        delay2();
        DDRtwi := DDRtwi and (not Psclin);  // SCL high
        delay2();
        if (PINtwi and (Psdain)) <> 0 then  // Testen SDA auf high
            data := data or (1 shl 0);  // wenn high, Bit 0 setzen
        DDRtwi := DDRtwi or Psclin;  // SCL low
    end;

    if ackn then
        DDRtwi := DDRtwi or Psdain  // SDA low, Acknowledge
    else
        DDRtwi := DDRtwi and (not Psdain);  // SDA high, No Acknowledge
    delay2();
    DDRtwi := DDRtwi and (not Psclin);  // SCL high
    delay3();
    DDRtwi := DDRtwi or Psclin;  // SCL low
    DDRtwi := DDRtwi and (not Psdain);  // SDA high

    twi_readbyte := data;  // Daten zurückgeben
end;

TWI Datenword lesen

pascal
// TWI Word lesen, MSB + LSB

function twi_readword(ackn : boolean) : uint16;
var
  data : uint16 = 0;
  i    : uint8;
begin
    for i := 0 to 7 do begin  // 8 Bit ausgeben
        data := data shl 1;         // Bit schieben, 7 bis 0
        delay2();
        DDRtwi := DDRtwi and (not Psclin);  // SCL high
        delay2();
        if (PINtwi and (Psdain)) <> 0 then  // Testen SDA auf high
            data := data or (1 shl 0);  // wenn high, Bit 0 setzen
        DDRtwi := DDRtwi or Psclin;  // SCL low
    end;

    DDRtwi := DDRtwi or Psdain;  // SDA low, Acknowledge
    delay2();
    DDRtwi := DDRtwi and (not Psclin);  // SCL high
    delay3();
    DDRtwi := DDRtwi or Psclin;  // SCL low
    DDRtwi := DDRtwi and (not Psdain);  // SDA high

    for i := 0 to 7 do begin  // 8 Bit ausgeben
        data := data shl 1;         // Bit schieben, 7 bis 0
        delay2();
        DDRtwi := DDRtwi and (not Psclin);  // SCL high
        delay2();
        if (PINtwi and (Psdain)) <> 0 then  // Testen SDA auf high
            data := data or (1 shl 0);  // wenn high, Bit 0 setzen
        DDRtwi := DDRtwi or Psclin;  // SCL low
    end;

    if ackn then
        DDRtwi := DDRtwi or Psdain  // SDA low, Acknowledge
    else
        DDRtwi := DDRtwi and (not Psdain);  // SDA high, No Acknowledge
    delay2();
    DDRtwi := DDRtwi and (not Psclin);  // SCL high
    delay3();
    DDRtwi := DDRtwi or Psclin;  // SCL low
    DDRtwi := DDRtwi and (not Psdain);  // SDA high

    twi_readword := data;  // Daten zurückgeben
end;

End

Mit folgender Zeile ist die Unit komplett.

pascal
end.

Siehe auch


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.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.