Allgemeines zum I2C-Bus findet man auf dieser Seite.
Nicht alle PICs verfügen über ein SSP (MSSP)-Modul, das als I2C-Interface verwendet werden kann. Aber auch ohne unterstützende Hardware lässt sich ein PIC als z.B. I2C-Master benutzen. Ich möchte das am Beispiel des PIC16F628 zeigen.
zu Beginn eine allgemeine
I2C-Beschreibung
Allgemeines
(auf einer anderen Seite)
ab hier wird
es
spezifisch für 16F628
Verdrahtung
Initialisierung
Daten auf I2C-Bus
schreiben
Daten vom I2C-Bus
lesen
Dieser
Artikel bedarf einer Überarbeitung. Die nötigen zwei
open-drain-Ausgänge lassen sich einfacher mit nur zwei Pins
erzeugen, indem man anstelle der PORTA-Bits die TRISA-Bits schaltet.
Zur Ansteuerung des I2C-Busses
benötigt
man 2 open-drain- oder open-kollektor-Ausgänge, die auch als
Eingänge
funktionieren. Das Pin RA4 ist das einzige Pin, das diese Voraussetzung
erfüllt. Allerdings ist es aufgrund der RA4-Falle,
nicht ganz einfach zu nutzen. Ich bastle mir lieber aus jeweils 2 Pins des Ports A einen bidirektionalen open-drain-Leitungstreiber. Folglich sind die Pins RA0..RA3 für den I2C-Bus reserviert.
|
Ich lege per #define-Befehl
eingängige Namen für diese 4 Pins fest:
list
p=16f628 ;************************************************************** ;* Pinbelegung ;* ---------------------------------- ;* PORTA: 0 SDA out ;* 1 CLK in ;* 2 SDA in ;* 3 CLK out ;* 4 - ;************************************************************** ; ;sprut (zero) Bredendiek 12/2002 ; I2C-Bus am 16F628 ; Prozessor 16F628 ; Prozessor-Takt 10 MHz ; ; I2C am PortA ; ;********************************************************** ; Includedatei für den 16F628 einbinden #include <P16f628.INC> ; Configuration festlegen:
; für I2C |
; Das Programm beginnt mit der
Initialisierung Init bsf STATUS, RP0 ; Bank 1 movlw B'11100110' ; PortA alle input außer RA0,3,4 movwf TRISA bcf STATUS, RP0 ; Bank 0 clrf PORTA ; 16F628 alle
Comparatoreingänge auf
Digital umschalten call i2c_reset |
Da das gesamte Busprotokoll per
Software
erzeugt wird, hängt die Busgeschwindigkeit von der Kompaktheit der
Softwareroutinen und dem Takt des PICs ab. Die hier vorgestellten
Routinen
erreichen bei 10 MHz-PIC-Takt einen I2C-Bus-Takt von 210 kHz. Sie
können
für low-speed-I2C-Slaves verwendet werden, wenn der PIC mit 4 MHz
getaktet wird:
|
|
(100 kHz) |
(400 kHz) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Natürlich kann der I2C-Takt auch durch das Einfügen einiger NOP-Befehle in die Routinen verringert werden. Eine Beschleunigung ist aber nur möglich, wenn man nicht alle Feinheiten des I2C-Busses nutzen will. Meine Routinen berücksichtigen die Möglichkeit, dass ein Slave den I2C-Takt aktiv verlängert. Das macht aber in Wirklichkeit kaum ein I2C-Schaltkreis. Wer sich sicher ist, dass er dieses Feature nicht braucht, kann die I2C-Routinen verschlanken, und einen schnelleren I2C-Takt erreichen.
Um Daten auf den I2C-Bus zu schreiben,
wird der Bus mit i2c_on übernommen.
Danach
wird das zu schreibende Byte nach 'w' geladen, und danach i2c_txt
aufgerufen.
Ist der Datentransfer beendet, gibt man
mit i2c_off den Bus wieder frei.
Nachfolgendes Beispiel steuert
einenTDA8444
an. Dieser Chip enthält acht 6-Bit-Digital-Analog-Wandler (DAC).
Die
ersten 6 DACs des TDA8444 werden auf 6 unterschiedliche Spannungen
eingestellt:
; Achtung PIC-Takt maximal 4 MHz
call i2c_on ; Bus übernehmen
movlw
H'40'
; Adresse des TDA8444 (A0..A2=0)
movlw
H'00'
; kanal 0 increment adress
movlw
H'00'
; DAC0: 0V
movlw
H'01'
; DAC1: 1/64 Vcc
movlw
H'02'
; DAC2: 1/32 Vcc
movlw
H'04'
; DAC3: 1/16 Vcc
movlw
H'08'
; DAC4: 1/8 Vcc
movlw
H'10'
; DAC5: 1/4 Vcc
movlw
H'20'
; DAC6: 1/2 Vcc call i2c_off ; Bus freigeben |
Da der TDA8444 ein Standard-Mode-Chip (max. 100 kHz) ist, darf der PIC dabei mit nur 4 MHz getaktet werden. Der TDA benötigt offiziell eine Betriebsspannung (Vcc) von mindestens 4,5V. Meiner Erfahrung nach läuft er aber erst ab 6V. Diese Betriebsspannung darf natürlich nicht mit dem Vcc-Pin des PIC verbunden werden. Der braucht seine eigenen 5 V.
Um Daten vom den I2C-Bus zu lesen, wird
der Bus mit i2c_on übernommen. Danach
wird die Adresse des auszulesenden I2C-Bausteins mit gesetztem Bit0 in
'w' geladen, und dieser Baustein dann mit i2c_tx
adressiert. Danach wird i2c_rx oder
i2c_rxack aufgerufen. Diese Routine liest ein Byte vom I2C-Bus, und
schreibt es nach 'w'. i2c_rxack erzeugt zusätzlich ein ACK-Signal
für den gelesenen I2C-Baustein. Das ist nötig, wenn noch
weitere
Bytes gelsesen werden sollen..
Ist der Datentransfer beendet, gibt man
mit i2c_off den Bus wieder frei.
Nachfolgendes Beispiel steuert einen LM75-Temperatursensor
an, und liest die von ihm gemessene Temperatur aus (2 Byte) :
call
i2c_on
; Bus aktiv
movlw
H'91'
; 1001 0001 , LM75 (A0..A2=0)
call
i2c_rxack ;
lesen mit ACK
call
i2c_rx
; lesen ohne ACK - letztes Byte call i2c_off ; Bus freigeben |
Folgende Routinen werden benötigt:
;*****************************************************************
; Routinen für I2C ; Bus zurücksetzen i2c_reset ; Bus übernehmen i2c_on ; W senden i2c_tx ; Byte empfangen i2c_rx (nach w und buf) ; Byte empfangen & ACK i2c_rxack (nach w und buf) ; Bus freigeben i2c_off ;***************************************************************** i2c_reset bsf SDAo bsf SCLo nop movlw 9 movwf buf i2c_reset1 nop bcf SCLo nop nop nop nop nop bsf SCLo nop decfsz buf, f goto i2c_reset1 nop call i2c_on nop bsf SCLo nop nop bcf SCLo nop call i2c_off return i2c_on i2c_tx i2c_rxack i2c_rx i2c_off ;*****************************************************
;schiebt das Byte aus W in den I2C
;liest das Byte aus I2C nach W
|