Hallo Klaus,
hast du diese veränderte Version auch noch?
Natürlich, die ist seit etwa 2 Monaten auf einem T24 im Einsatz und tut ihren Dienst.
Code:
; USI_TWI_master Routinen
;**************************************************
.macro TRANSFER_8_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
rcall USI_TWI_master_transfer
.endmacro
.macro TRANSFER_1_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
rcall USI_TWI_master_transfer
.endmacro
.macro READ_ACK
set
rcall USI_TWI_master_read
.endmacro
.macro READ_NACK
clt
rcall USI_TWI_master_read
.endmacro
.macro START_I2C
ldi param1,(@0)
rcall USI_TWI_master_start
.endmacro
;USI Pin Konfiguration fuer tiny 24
.equ PORT_USI = PORTA
.equ DDR_USI = PORT_USI- 1
.equ PIN_USI = DDR_USI - 1
.equ PORT_USI_SDA = PORTA6
.equ PORT_USI_SCL = PORTA4
.equ PIN_USI_SDA = PINA6
.equ PIN_USI_SCL = PINA4
.equ WRITE = 0
.equ READ = 1
; I2C Master init
;keine Parameter, keine Rueckgabewerte
;************************************************************************
USI_TWI_master_init:
ldi tmp1,(1<<PORT_USI_SDA)|(1<<PORT_USI_SCL);Pullups an SDA u. SCL an
out PORT_USI,tmp1
out DDR_USI,tmp1;SDA u. SCL als Ausgaenge
ser tmp1 ;Lade Dataregister mit High Bytes
out USIDR,tmp1
;USI Interrupts inaktiv, USI im 2 Wire Modus Software Clock
ldi tmp1,(1<<USIWM1)|(1<<USICS1)|(1<<USICLK)
out USICR,tmp1
ldi tmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC);Lösche USI Flags
out USISR,tmp1 ;und resete den Counter
ret
;************************************************************************
; USI_TWI_master_start
; Sendet Startbedingung und die Slaveadresse
; Parameter, Slaveadresse im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;************************************************************************
USI_TWI_master_start:
sbi PORT_USI,PIN_USI_SCL;zieht SCL High
USI_TWI_master_start_1:
sbis PIN_USI,PIN_USI_SCL;warte bis SCL High ist
rjmp USI_TWI_master_start_1
rcall delay
cbi PORT_USI,PIN_USI_SDA ; zieht SDA LOW
rcall delay
cbi PORT_USI,PIN_USI_SCL ;SCL wieder LOW
sbi PORT_USI,PIN_USI_SDA ;SDA High
out USIDR,param1; Slaveadresse/Data in den USI Dataregister schreiben
;mastertransfer aufrufen
TRANSFER_8_BIT
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT
ret
;***********************************************************************
; USI_TWI_master_write
; Sendet ein Byte am den Master
; Parameter: Data im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;***********************************************************************
USI_TWI_master_write:
out USIDR,param1; Data in den USI Dataregister schreiben
;mastertransfer aufrufen für die
TRANSFER_8_BIT ;Byte Uebergabe
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT;um ACK/Nack Abzuholen
ret
;***********************************************************************
; USI_TWI_master_read
; Liest ein Byte vom Slave aus
; Parameter: Sende ACK/Nack im param1 1 == ACK senden; 0 == kein ACK senden(Nack)
; Rueckgabe gelesene Daten in param1
USI_TWI_master_read:
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen
TRANSFER_8_BIT
push param1
brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK
;sonst muss ein ACK erfolgen
out USIDR,null
rjmp USI_TWI_master_read_end
USI_TWI_master_read_send_NACK:
out USIDR,full
USI_TWI_master_read_end:
TRANSFER_1_BIT
pop param1
ret
;***********************************************************************
; USI_TWI_master_transfer
; sorgt für die Komunikation mit dem slave
;mit param1 wird übergeben ob ein Byte empfange/gesendet wird, oder nur 1 Bit für ACK/NACK
USI_TWI_master_transfer:
out USISR,param1;der Counter wird vorgeladen
USI_TWI_master_transfer_1:
rcall delay
sbi USICR,USITC ;Positive Flanke an SCL erzeugen
USI_TWI_master_transfer_2:
sbis PIN_USI,PIN_USI_SCL ; warten bis SCL High ist
rjmp USI_TWI_master_transfer_2
rcall delay
sbi USICR,USITC;negative Flanke an SCL erzeugen
sbis USISR,USIOIF;testen ob Counter ubergelaufen ist
rjmp USI_TWI_master_transfer_1 ;wenn nicht mit dem nächstem Bit
rcall delay ;wenn gelesen wird
in param1,USIDR;Daten holen
out USIDR,full
sbi DDR_USI,PIN_USI_SDA; SDA auf Ausgang stellen
ret
;***********************************************************************
; USI_TWI_master_stop:
;Sendet die Stop Bedingung
;***********************************************************************
USI_TWI_master_stop:
cbi PORT_USI,PIN_USI_SDA
sbi PORT_USI,PIN_USI_SCL
USI_TWI_master_stop_1:
sbis PIN_USI,PIN_USI_SCL
rjmp USI_TWI_master_stop_1
rcall delay
sbi PORT_USI,PIN_USI_SDA
rcall delay
ret
;***********************************************************************
; delay
;Eine kurze Pause von insgesammt 10 Takten
;***********************************************************************
delay:
;Rcall hat 3 Takte gedauert
nop ;1 Takt
nop ;1 Takt
nop ;1 Takt
ret ; 4 Takte
;***********************************************************************
das Ganze ist als usi_master.asm gespeichert und im Hauptprogramm eingebunden.
Mögliche Verwendung sieht dann so aus:
Code:
;EEPROM Slave Adresse von HP03
.equ HP03_sEEPROM = 0xA0
.org 0x0000
rjmp reset
.org OVF1addr
rjmp timer1
.include "usi_master.asm"
reset:
ldi tmp1,RAMEND
out SPL,tmp1
rcall USI_TWI_master_init
loop:
rcall HP03_EEPROM_read
rjmp loop
HP03_EEPROM_read:
;es sind insgesamt 18 Bytes zu empfangen und schoen der Reihe nach bei C1
;angefangen abzulegen
ldi tmp1,0x12 ;Readzaehler belegen
ldi XH,HIGH(C1)
ldi XL,LOW(C1)
START_I2C HP03_sEEPROM+WRITE ;Start an HP03 EEPROM senden
ldi param1,HP03_dEEPROM ;EEPROM Adresse einstallen
rcall USI_TWI_master_write
START_I2C HP03_sEEPROM+READ ;RepStart an HP03 EEPROM senden
HP03_EEPROM_read1:
cpi tmp1,2
brlo HP03_EEPROM_read2
READ_ACK
st X+,param1
dec tmp1
rjmp HP03_EEPROM_read1
HP03_EEPROM_read2:
READ_NACK
st X,param1
rcall USI_TWI_master_stop
ret
Was man anpassen muß ist das hier:
Code:
;USI Pin Konfiguration fuer tiny 24
.equ PORT_USI = PORTA
.equ DDR_USI = PORT_USI- 1
.equ PIN_USI = DDR_USI - 1
.equ PORT_USI_SDA = PORTA6
.equ PORT_USI_SCL = PORTA4
.equ PIN_USI_SDA = PINA6
.equ PIN_USI_SCL = PINA4
Und ein paar Register benennen, welche, findest Du raus, wenn es Fehler wegen unbekannte Register hagelt
Am sonsten ist es ziemlich einfach:
rcall USI_TWI_master_init beim Reset durchführen
START_I2C HP03_sEEPROM+WRITE
Start senden an I2C Adresse HP03_sEEPROM mit WRITE Bit
rcall USI_TWI_master_write
sendet ein Byte an den Slave,davor mußt Du in param1 laden, was Du senden möchtest...
START_I2C HP03_sEEPROM+READ
start/repstart mit READ Bit
READ_ACK
empfängt ein Byte und sendet ACK an den Slave, in param1 befndet sich das, was empfangen wurde
READ_NACK
sehe READ_ACK nur mit NACK
rcall USI_TWI_master_stop
ohne Komentar(Anmerkung, ich weiß im Moment selber nicht, warum ich das nicht auch in ein Makro verpackt habe )
Am sonsten hab ich das einigermassen gut komentiert...
Ja dann schau mal
Gruß Sebastian
P.S.
Nochwas , solltest Du Dich über Fehler wegen Register null und full wundern, ehm ich lege mir am Anfang 2 untere Register null mit 0 und full mit 255 an, das erleichtet einiges beim programmieren...
Lesezeichen