Hallo Stefan,
ich weiß zwar nicht, ob Du hier noch mitliest, aber egal.
Ich habe mich heute mit USI Master auseinandergesetzt und, es ist doch nicht ganz so wild, ich glaube die nackte Routine ergibt etwa 160 Bytes.
Testumgebung :
Tiny 25 als Master.
Mein I2C Display als Slave Nr.1 zur Ausgabe
DS1621 I2C Temperatursensor als Slave Nr.2
Eine Real Time Clock als Slave Nr.3
Der Aufbau läuft seit einer Stunde und zeigt mir schön in Sekundentakt die Temeratur und Uhrzeit abweschseln an \/
Der Master läuft mit 1MHz und 100 kHz Bustakt
ich poste einfach mal das Program:
Du mußt Dir 2 Register definieren tmp1, und param1, die nicht gesichert werden.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 .equ WRITE = 0 .equ READ = 1 .equ ACK = 1 .equ NACK = 0 ; 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: tst param1 ;Schaue ob zum Schluss NACK oder ACK soll breq USI_TWI_master_read_prepare_NACK set ;T Flag setzen rjmp USI_TWI_master_read_1 USI_TWI_master_read_prepare_NACK: clt ;T Flag loeschen USI_TWI_master_read_1: cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen TRANSFER_8_BIT push param1 ;gelesene Daten sichern brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK ;sonst muss ein ACK erfolgen clr param1 rjmp USI_TWI_master_read_end USI_TWI_master_read_send_NACK: ser param1 USI_TWI_master_read_end: out USIDR,param1 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 ldi tmp1,0xFF out USIDR,tmp1 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 ;Bei 1 MHz ergibt das 100 kHz Mastertakt ;;keine Parameter, keine Rueckgabewerte ;*********************************************************************** delay: ;Rcall hat 3 Takte gedauert nop ;1 Takt nop ;1 Takt nop ;1 Takt ret ; 4 Takte ;***********************************************************************
Ich habe es anhand der o.g. appnote geschrieben, aber so ziemlich umgekrämpelt, weil es mir nicht so gefallen hat.
Die ist etwa genauso zu benutzen, wie die Routine von Peter Fleury, da komm ich besser mit klar, als diese komische Pufferlösung von Atmel.
Ein Miniprogramm um den DS1621 Wandeln zu lassen und auszulesen könnte damit etwa so aussehen:
Noch etwas unaufgeräumt, ich denke bis zum Wochenende werde ich Zeit finden und alles besser dokumentieren.Code:.include "tn25def.inc" .equ PORT_USI = PORTB .equ DDR_USI = DDRB .equ PIN_USI = PINB .equ PORT_USI_SDA = PORTB0 .equ PORT_USI_SCL = PORTB2 .equ PIN_USI_SDA = PINB0 .equ PIN_USI_SCL = PINB2 .equ I2C_DISPLAY = 0x14 .equ THERMO = 0x90 .def nachkomma = r1 .def tmp1 = r16 .def tmp2 = r17 .def param1 = r18 .def param2 = r19 .def temperatur = r21 .cseg .org 0x0000 rjmp reset reset: clr ausgabe ldi tmp1,RAMEND out SPL,tmp1 rcall USI_TWI_master_init ;Thermometer einschalten ldi param1,THERMO+WRITE rcall USI_TWI_master_start ldi param1,0xEE rcall USI_TWI_master_write rcall USI_TWI_master_stop ;Thermometer eingeschaltet loop: ;Temperatur auslesen ldi param1,THERMO+WRITE rcall USI_TWI_master_start ldi param1,0xAA rcall USI_TWI_master_write ldi param1,THERMO+READ rcall USI_TWI_master_start ldi param1,ACK rcall USI_TWI_master_read mov temperatur,param1 ldi param1,NACK rcall USI_TWI_master_read mov nachkomma,param1 rcall USI_TWI_master_stop ;Temperatur ausgelesen loop1: loop1
Ich hoffe, das Du was mit tun kannst![]()
Gruß Sebastian







Zitieren

Lesezeichen