logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Procedury ASM do emulacji I2C na mikroprocesorach PIC16FXXX

centipede 15 Lip 2004 22:42 4550 38
Najlepsze odpowiedzi

Jak napisać w asemblerze procedury programowej obsługi magistrali I2C dla PIC16FXXX?

Najprościej skorzystać z działającego zestawu procedur START/STOP/SEND z piclist i dopasować go do swojego układu, bo w wątku został pokazany kod, który działał z EEPROM/układami Dallas przy 4 MHz i opóźnieniach rzędu 5 cykli oraz 4,7 kΩ pull-upach [#758469] Do odczytu trzeba dodać procedurę I2C_READ: ustawić SDA jako wejście, taktować SCL osiem razy, zbierać bity do bufora, a po bajcie wysłać ACK albo NACK osobną procedurą [#758570] Przy emulacji „pasywnej” na PIC16FXXX linie SDA/SCL powinny być sterowane przez TRIS przy włączonych podciągających rezystorach, a przed transmisją trzeba mieć wyzerowane bity PORT dla SDA/SCL i ustawione odpowiednie TRIS, zgodnie z przykładem z piclist [#777700][#779025][#781405] Problem może też wynikać z efektu RMW: jeśli na tym samym porcie są inne wyjścia lub przerwania zmieniające PORTB, mogą one psuć stany I2C, więc należy unikać takich operacji albo zerować bity portu należące do I2C po innych modyfikacjach [#766020][#780674?].
Wygenerowane przez model językowy.
REKLAMA
  • #1 745035
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    Witam.
    Ma ktoś może gotowe procedurki do programowej obsługi magistrali I2C ?
    Oczywiście interesuję mnie tylko i wyłącznie rozwiązanie w asm na Mikroprocesory PIC16FXXX.
  • REKLAMA
  • #2 745065
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    www.piclist.com <- z tamtąd kiedyś wygrzebałem działającą wersje.
  • #3 748297
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    Szczerze mówiąc, to mi to nie działa :/ chcę poprostu odczytać 24C16 z PIC 16F628, skopiowałem ten program, ale on działa tak samo z kością jak i bez kości .. :/ tzn, odczytuje ciemny prostokąt, w miejscu, gdzie jest litera "I" .. :/
  • #4 749458
    diag
    Poziom 29  
    Posty: 1401
    Pomógł: 45
    Ocena: 209
    O ile pamietam to jest kilka programów na piclist. Z którego korzystasz?
  • #5 750453
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    Kurcze, Centipede. Napisales tego posta 15.07. Dzisiaj jest 19.07. W tym czasie przeciez 15 razy sam napisalbys sobie procedurki do I2C, ktore jest wyjatkowo prostym protokolem. Do tego moglbys maksymalnie je wysrubowac pod Twoje zastosowanie. Nie szkoda Ci czasu na takie poszukiwania ?

    Marmur99
  • #6 757611
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    jakby to powiedziec - najpierw napisalem swoje na podstawie paru opisow I2C, ale niestety, nie dalem sobie rady ..
  • #7 757636
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    To je podeślij. Założe się, że jest tam tylko drobny błąd.

    Marmur99
  • #8 757961
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    do Diaga:
    z tego
    
    ;------------------------------------------------------------------------
    ;
    ; I^2C master send/receive routines for 24Cxx EEPROM memory chips
    ; by Andrew D. Vassallo
    ;
    ; email: snurple@hotmail.com
    ;
    ; Timing set for 4MHz clock, 4.7K pullup resistors to SDA and SCL lines.
    ; Checks provided for failed ACK during EEPROM write access.
    ; Optimized for speed and clarity of function.
    ; Full comments provided.
    ; Bank switching correct.
    ; http://www.piclist.com/techref/microchip/i2c-dv.htm
    ;------------------------------------------------------------------------
    
    ;------ NOTE: Locate all variables in Bank 1!!
    
    	CBLOCK
    	  GenCount			; generic counter/temp register (use with caution)
    	  Mem_Loc			; EEPROM memory address to be accessed
    	  Data_Buf			; byte read from EEPROM is stored in this register
    	  OutputByte			; used for holding byte to be output to EEPROM
    	  flags				; flag bit register
    	ENDC
    
    
    ;------ Define port pins: RB2=SDA=data, RB1=SCL=clock
    ;------ Pins are connected via 4.7K pullup resistors for passive control
    ;------ Any port pins can be used.
    
    	#define	SDA	TRISB, 2
    	#define	SCL	TRISB, 1
    
    
    ;------ The memory address is predefined as Mem_Loc coming in to this routine to 
    read from EPROM.;------ Note that using the 24Cxx requires an address for bits 
    <1:3> for control bytes.  For a one-;------ memory circuit used here, just use 
    address 000.  This routine uses "random addressing.";------ This code has been 
    optimized for speed at 4MHz, assuming Temperature is between -40 and +85 deg. 
    C.;; Call with: EEPROM address in Mem_Loc
    ; Returns with: byte in Data_Buf
    
    ReadEPROM:
    	bcf	STATUS, RP0
    	movf	PORTB, 0		; for EEPROM operation,
    	andlw	0xF9			; load zero into RB1 and RB2
    	movwf	PORTB			; for passive control of bus
    	bsf	STATUS, RP0		; select Bank 1 for TRISB access (passive SCL/SDA control)
    	bsf	SDA			; let SDA line get pulled high
    	bsf	SCL			; let SCL line get pulled high
    	bcf	SDA			; START - data line low
    	movlw	0xA0			; send "dummy" write (10100000) to set address
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine		; NOTE: MUST USE "RETURN" FROM THERE
    	movf	Mem_Loc, 0
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine
    	bcf	SCL			; pull clock line low in preparation for 2nd START bit
    	nop
    	bsf	SDA			; pull data line high - data transition during clock low
    	bsf	SCL			; pull clock line high to begin generating START
    	bcf	SDA			; 2nd START - data line low
    	movlw	0xA1			; request data read from EPROM (read=10100001)
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine
    
    ;------ Note that Byte_Out leaves with SDA line freed to allow slave to send 
    ;------	data in to master.
    
    	call	Byte_In
    	movf	Data_Buf, 0		; put result into W register for returning to CALL
    	bcf	SCL			; extra cycle for SDA line to be freed from EPROM
    	nop
    	bcf	SDA			; ensure SDA line low before generating STOP
    	bsf	SCL			; pull clock high for STOP
    	bsf	SDA			; STOP - data line high
    	bcf	STATUS, RP0		; leave with Bank 0 active as default
    
    	return
    
    ;------ Save each byte as it's written (not page write mode).
    ;------ We can speed this up to ~1.5ms for fast page write capable EEPROMs,
    ;------but in case we want to
    ;------ use another slower memory chip, the default is 10ms delay per write.
    ; Call with:  EEPROM address in Mem_Loc, byte to be sent in Data_Buf
    ; Returns with:  nothing returned
    
    WriteEPROM:
    	bcf	STATUS, RP0
    	movf	PORTB, 0		; for EEPROM operation,
    	andlw	0xF9			; load zero into RB1 and RB2
    	movwf	PORTB			; for passive control of bus
    	bsf	STATUS, RP0		; select Bank 1 for TRISB access (passive SCL/SDA control)
    	bsf	SDA			; ensure SDA line is high
    	bsf	SCL			; pull clock high
    	bcf	SDA			; START - data line low
    	movlw	0xA0			; send write (10100000) to set address
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine		; NOTE: MUST USE "RETURN" FROM THERE
    	movf	Mem_Loc, 0
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine
    	movf	Data	_Buf, 0		; move data to be sent to W
    	call	Byte_Out
    	btfsc	flags, 0
    	goto	Error_Routine
    	bcf	SCL			; extra cycle for SDA line to be freed from EPROM
    	nop
    	bcf	SDA			; ensure SDA line low before generating STOP
    	bsf	SCL			; pull clock high for STOP
    	bsf	SDA			; STOP - data line high
    	call	Delay10ms		; 10ms delay max. required for EPROM write cycle
    	bcf	STATUS, RP0		; leave with Bank 0 active by default
    
    	return
    
    ;------ This routine reads one byte of data from the EPROM into Data_Buf
    Byte_In:
    	clrf	Data_Buf
    	movlw	0x08			; 8 bits to receive
    	movwf	GenCount
    ControlIn:
    	rlf	Data_Buf, 1		; shift bits into buffer
    	bcf	SCL			; pull clock line low
    	nop
    	bsf	SCL			; pull clock high to read bit
    	bcf	STATUS, RP0		; select Bank 0 to read PORTB bits directly!
    	btfss	SDA			; test bit from EPROM (if bit=clear, skip because Data_Buf is clear)
    	goto	$+3
    	bsf	STATUS, RP0		; select Bank 1 to access variables
    	bsf	Data_	Buf, 0		; read bit into 0 first, then eventually shift to 7
    	bsf	STATUS, RP0		; select Bank 1 to access variables
    	decfsz	GenCount, 1
    	goto	ControlIn
    
    	return
    
    ;------ This routine sends out the byte in the W register and then waits for ACK 
    ;------ from EPROM (256us timeout period)
    
    Byte_Out:
    	movwf	OutputByte
    	movlw	0x08			; 8 bits to send
    	movwf	GenCount
    	rrf	OutputByte, 1		; shift right in preparation for next loop
    ControlOut:
    	rlf	OutputByte, 1		; shift bits out of buffer
    	bcf	SCL			; pull clock line low
    	nop
    	btfsc	OutputByte, 7		; send current "bit 7"
    	goto	BitHigh
    	bcf	SDA
    	goto	ClockOut
    BitHigh:
    	bsf	SDA
    ClockOut:
    	bsf	SCL			; pull clock high after sending bit
    	decfsz	GenCount, 1
    	goto	ControlOut
    	bcf	SCL			; pull clock low for ACK change
    	bsf	SDA			; free up SDA line for slave to generate ACK
    	nop
    	nop
    	nop				; wait for slave to pull down ACK
    	bsf	SCL			; pull clock high for ACK read
    	clrf	GenCount		; reuse this register as a timeout counter (to 256us) to test for ACK
    WaitForACK:
    	bsf	STATUS, RP0		; select Bank1 for GenCount access
    	incf	GenCount, 1		; increase timeout counter each time ACK is not received
    	btfsc	STATUS, Z
    	goto	No_ACK_Rec
    	bcf	STATUS, RP0		; select Bank0 to test SDA PORTB input directly!
    	btfsc	SDA			; test pin. If clear, EEPROM is pulling SDA low for ACK
    	goto	WaitForACK		; ...otherwise, continue to wait
    	bsf	STATUS, RP0		; select Bank1 as default during these routines
    	bcf	flags, 0		; clear flag bit (ACK received)
    
    	return
    
    ;------ No ACK received from slave (must use "return" from here)
    ;------ Typically, set a flag bit to indicate failed write and check for it upon return.
    
    No_ACK_Rec:
    	bsf	flags, 0		; set flag bit
    	return				; returns to Byte_Out routine (Bank 1 selected)
    
    
    ;------ No ACK received from slave.  This is the error handler.
    
    Error_Routine:
    	bcf	STATUS, RP0		; select Bank0 as default before returning home
    	return				; returns to INITIAL calling routine
    
    
    Delay10ms:
    	movlw	0x0A
    	movwf	GenCount
    Delay_Start:
    	nop
    	movlw	0x07			; 249 cycles * 4us per cycle + 5us = 1.000ms
    Delay:
    	addlw	0x01
    	btfss	STATUS, Z
    	goto	Delay
    	decfsz	GenCount, 1
    	goto	Delay_Start
    
    	return
    
    

    kodu korzystam to jest ten z piclist.
    a ten mojej roboty usunąłem niechcący przy formatowaniu dysku
  • REKLAMA
  • #9 757979
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    Jasne, dawaj.

    Marmur99
  • REKLAMA
  • #10 757982
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    mojego juz nie mam, ale przed chwila wrzucilem inny, ktory mi tez nie dziala ..
  • REKLAMA
  • #11 758310
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    A mógłbyś jeszcze do tego wszystkiego napisać, w jaki sposób korzystałeś z tych procedur?
    Chodzi mi o kolejność i parametry. A może masz jeszcze programik, który z nich korzystał?
    Ten przykład powyżej stosuje technikę, której osobiście nie lubię - pasywną kontrolę magistrali (ale wiem, że kolega Gummis, który na pewno tutaj zerka, stosuje taką technikę i może by coś podpowiedział).
    Upewniłeś się, że masz zewnętrzne pull-up? Przy tej technice jest wprawdzie wewnętrzne, ale musi być włączone.

    Marmur99
  • #12 758469
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    Załączam fragment programu który działał na 100% z potencjometrami cyfromi dallasa:
    1. Wywołania zmiany położenia suwaka:
    call	I2C_START
    movlw	b'01010000';zapis
    call	I2C_SEND
    movlw	b'10101111';oba
    call	I2C_SEND
    movf	BAJT1,W
    call	I2C_SEND		
    call	I2C_STOP

    2. Procedury komunikacji I2C i opóźnienia:
    d5u: ;razem z CALL 5 cykli
    GOTO	$+1;2 cykle
    return	;2 cykle 
    
    I2C_START                        ;  Send the Start Bit on the I2C Bus
    	bsf	I2C_PORT,I2C_SDA               ;  Make the Data Line High
    	goto	$ + 1
    	bcf	I2C_PORT,I2C_SCL               ;  Make the Clock Line Low
    	nop
    	bsf	I2C_PORT,I2C_SCL               ;  Set the Clock High
    	CALL	d5u;5 cykli
    	nop
    	bcf	I2C_PORT,I2C_SDA               ;  Drop the Clock Line to Go into Start Mode
    	CALL	d5u;5 cykli
    	bcf	I2C_PORT,I2C_SCL               ;  Start Clock Train
    	goto	$ + 1
    	return
    
    I2C_STOP                         ;  Send the Stop Bit to the I2C Bus
    	bcf    I2C_PORT,I2C_SDA               ;  Data Line Low
    	CALL	d5u;5 cykli
    	bsf    I2C_PORT,I2C_SCL               ;  Set the Clock Line High
    	CALL	d5u;5 cykli
    	bsf    I2C_PORT,I2C_SDA               ;  Data goes high whil Clock is High for Stop Bit
    	goto   $ + 1
    	bcf    I2C_PORT,I2C_SCL               ;  Set Clock Low Again
    	goto   $ + 1
    	nop
    	return
    
    I2C_SEND  ;wyslij W do I2C                       
    	MOVWF	DATA_OUT               
    	MOVLW	8
    	MOVWF	INDEX
    I2C_SEND_LOOP
    	RLF	DATA_OUT
    	BTFSC	STATUS, C              ;  JEDYNKA jesli nie to :pomin i ZERO
    	GOTO	I2C_1
    	bcf	I2C_PORT,I2C_SDA	;Ustaw 0
    	goto	I2C_CLK
    I2C_1                        
    	bsf	I2C_PORT,I2C_SDA	;Ustaw 1
    I2C_CLK
    	BSF	I2C_PORT,I2C_SCL	;USTAW CLK
    	CALL	d5u;5 cykli
    	BCF	I2C_PORT,I2C_SCL	;ZERUJ CLK
    				;drugie 5 cykli to petla :)
    	DECFSZ	INDEX, F
    	GOTO	I2C_SEND_LOOP
    	BSF	I2C_PORT,I2C_SDA	;Ustawienie SDA zeby uklad mogl ACK wyslac
    	BSF	I2C_PORT,I2C_SCL	;Takt zegara na ACK.ACK NIE jest sprawdzane
    	CALL	d5u;5 cykli
    	BCF	I2C_PORT,I2C_SCL
    	CALL	d5u;5 cykli
    	RETURN
    

    PS część komentarzy była przetłumaczona przezemnie żeby lepiej zrozumieć jak to działa. Prosze nie pytać jak to działa, ten kod leży od roku.
  • #13 758570
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    Tan, ten kody wygląda bardzo logicznie. Brakuje w nim tylko I2C_Read, ale postaram się napisać to z głowy. Błędy proszę mi śmiało wytykać.

    I2C_READ
            BSF         STATUS,RP0
            BSF         I2C_PORT,I2C_SDA ;     KIERUNEK WEJSCIOWY PORTU 
            BCF         STATUS,RP0
            BSF         I2C_PORT,I2C_SDA
            MOVLW    8
            MOVWF  INDEX
    IR1
            BSF    I2C_PORT,I2C_SCL
            CALL   d5u;5 cykli         
            BCF    STATUS,C
            BTFSC I2C_PORT,I2C_SDA
            BSF     STATUS,C
            RLF      DATA_IN,F
            BCF    I2C_PORT,I2C_SCL
            DECFSZ INDEX,F
            GOTO IR1
            MOFV DATA_IN,W
            BSF         STATUS,RP0
            BCF         I2C_PORT,I2C_SDA ;     KIERUNEK WYJSCIOWY PORTU 
            BCF         STATUS,RP0
            RETURN

    Do tego przydadzą się jeszcze funkcja generowania ACK i funkcja nie-generowania ACK

    I2C_NACK
           BSF        I2C_PORT,I2C_SDA
           GOTO     IA1
    I2C_ACK
            BCF       I2C_PORT,I2C_SDA
    IA1
            BSF       I2C_PORT,I2C_SCL
            CALL   d5u;5 cykli         
            BCF       I2C_PORT,I2C_SCL
            RETURN



    Marmur99
  • #14 758792
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    wielkie dzieki chlopaki, co do mojego korzystania z tego kodu co zamiescielem to robilem to tak:
    
    movlw h'00'
    movwf Mem_loc
    movlw A'8'
    movwf Data_Buf
    call WriteEPROM
    

    jezeli chodzi o pull-up, to stosowałem zewnetrzne rezystory 4,7k.
  • #15 759659
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    marmur99 napisał:
    Tan, ten kody wygląda bardzo logicznie. Brakuje w nim tylko I2C_Read, ale postaram się napisać to z głowy.
    Z orginalnego kodu skasowałem ten kawałek bo nie był mi potrzebny, jeszcze jedna drobna uwaga przebiegi czasowe były wyliczone do zegara 4MHz i częstotliwość sygnału zegarowego na i2c jest circa 100kHz.
  • #16 765092
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    kurdę, nie działa mi to ;( wrzuciłem ten kod elektryka ..
    a od siebie dodałem:
    
    	call	I2C_START 
    	movlw	b'10100000'
    	call	I2C_SEND 
    	movlw	h'00'
    	call	I2C_SEND 
    	movlw	A't' 
    	call	I2C_SEND
    	movlw	A'e' 
    	call	I2C_SEND
    	movlw	A's' 
    	call	I2C_SEND
    	movlw	A't' 
    	call	I2C_SEND       
    	call	I2C_STOP
    

    i nic mi sie nie zapisalo do 24C16 :/
  • #17 766020
    gummis
    Poziom 15  
    Posty: 162
    Pomógł: 4
    Ocena: 1
    Witam.Faktycznie uzywam takiej procedurki ktora wymaga zewnetrznego podpiecia lub wewnetrznego jesli akurat jest w danym porcie(czyli tylko PORTB).Jest to taka niby realizacja otwartego kolektora na porcie z para komplementarna.W specyfikacji i2c jest otwarty kolektor.Jednak jesli w sieci i2c jest tylko jednak jeden MASTER to nie jest to potrzebne.

    Dlatego chyba sobie jednak zmienie na inna metode bo ma powazna wade.A mianowicie sa problemy gdy sie uzywa na tym samym porcie lecz na innych liniach instrukcji RMW typu bcf i bsf.Najprawdopodobniej tu jest pies porzebany u ciebie.Jesli tak to procedure najprawdopodobniej masz sprawna.Tylko ze jesli na tym samym porcie masz jeszcze podpiety np. przekaznik to poprzez instrukcje

    #define SDA portB,0
    #define SCL portB,1
    #define pkz portB,2

    i teraz jesli linia SDA i2c jest ustawiona na 1 czyli w bicie PORTB,0=0 TRISB=1 (co powoduje stan wysoki gdyz jest rezystor podpinajacy)
    to gdy wykonamy instrukcje (np. w czasie przerwania przerywajacego komunikacje i2c)

    bsf pkz lub bcf pkz

    to ustawia sie bit PORTB,0 z racji tego ze jest to instrukcja RMW i rezystor podpinajacy spowoduje ze odczytana zostanie wartosc na lini SDA i wpisana do PORTB,0 pomimo ze z pozoru bcf pkz powinna zmieniac tylko ta linie.To jest efekt instrukcji RMW i jest dokladnie opisany na stronie microchipa.

    Jest to niepozadane przy tej metodzie.
    I wtedy gdy ustawiamy kierunek SDA na wyjsciowy tam sie pojawia mocna jedynka.A poniewaz przy tej metodzie steruje sie TRISEM linie SDA to przy ustawionym bicie PORTB,0 beda wychodzily same jedynki obojetnie czy TRISB,0 jest 1 czy 0.
    Jedyna sposob na ta niepozadana wlasciwosc jest tak zeby po kazdej instrukcji modyfikujacej inne linie portu niz te nalezace do i2c tzreba wyzerowac bity rejestru PORTB nalezace do i2c.Czyli cos takiego:

    bsf pkz

    movlw b'11111100'
    andwf PORTB
  • #18 766458
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    kurdę, rzeczywiście, do tego portu mam jeszcze podpięty przycisk, linie RS i E wyświetlacza Alfanumerycznego, oraz (to chyba najbardziej mąci) linie data i clock klawiatury od PC, te ostatnie jeszcze wywołują przerwanie ..
    będę musiał pokombinować, tak mi się jakoś zapomniało o RMW . Dzięki .
  • #19 766606
    marmur99
    Poziom 17  
    Posty: 285
    Pomógł: 5
    Ocena: 4
    No to szybko się zorientowałeś, że masz takie przedszkole podpięte do tego pinu.

    Marmur99
  • #20 766638
    gummis
    Poziom 15  
    Posty: 162
    Pomógł: 4
    Ocena: 1
    Marmur99: nie do pinu tylko do tego samego portu co i2c.
  • #21 766652
    gummis
    Poziom 15  
    Posty: 162
    Pomógł: 4
    Ocena: 1
    Mozez zrobic tak ze na porcie gdzie jest i2c, to oprocz i2c nie bedzie lini wyjsciowych , same wejsciowe.
  • #22 766657
    gummis
    Poziom 15  
    Posty: 162
    Pomógł: 4
    Ocena: 1
    Mozez zrobic tak ze na porcie gdzie jest i2c, to oprocz i2c nie bedzie lini wyjsciowych , same wejsciowe.Lub wyjsciowe tez moga byc ale takie ktore niepracuja w przerwaniu.I wtedy zawsze na poczatku komunikacji i2c zeruj bity PORTB nalezace do i2c.
  • #23 767036
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    ok, ten kod elektryka działa - sprawdzilem, to przez napisanie programu, który tylko wysyła do I2C (bez innych operacji na tym samym porcie) ..
    Potem (= jeszcze dzisiaj)wrzuce glowny program - mysle, ze pomozecie mi to obejsc, bo nie wiem, jak sie wziac .
    Dzięki wszystkim ..
  • #24 769633
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    szczerze mówiąc, to ja nie wiem, czemu to nie działa - do tego portu mam podpięte to co pisałem wcześniej (razem 2 wejścia, w tym jedno z obsługą przerwania). Przecież w tej obsłudze I2C podanej prze elektryka nie ma operacji na TRIS'ach .. to I2C nie sprawdza przecież ACK, ani nie odbiera danych, tylko je wysyła, więc nie wiem, co ma do tego RMW.
    ja robię to tak, że wyłączam przerwanie, wysyłam .. i koniec, nie działa ..
    pomórzcie.
  • #25 770712
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    centipede napisał:
    ok, ten kod elektryka działa - sprawdzilem, to przez napisanie programu, który tylko wysyła do I2C (bez innych operacji na tym samym porcie) ..

    centipede napisał:
    szczerze mówiąc, to ja nie wiem, czemu to nie działa - do tego portu mam podpięte to co pisałem wcześniej (razem 2 wejścia, w tym jedno z obsługą przerwania).

    To w końcu działa czy nie działa? Może lepiej napisz co i jak masz tam podpięte do portu.
  • #26 771323
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    No to po kolei, żeby nie było motaniny.
    Ta obsługa I2C działa tylko wtedy, gdy nic innego nie mam wrzucone do uP, tzn.
    
    	LIST P=16F628
    	#INCLUDE "p16f628.inc"
    	__CONFIG h'3f10'
    	ERRORLEVEL -302
    
    ;  Define Information
    	#DEFINE	 I2C_PORT	PORTB
    	#DEFINE	 I2C_SCL	6
    	#DEFINE	 I2C_SDA	5
    
                CBLOCK     20H
    		data_out
    		index
                 ENDC
    
    	org h'00'
    	goto main
    ;-------------------------------------------------------------------------;
    ;                       Initialize the ports                              ;
    ;-------------------------------------------------------------------------;
    Init:	movlw	h'07'
    	movwf	cmcon
    	clrf	PORTA
    	clrf	PORTB
    	movlw	.9
    	movwf	count
    
    	bsf	status, rp0
    	clrf	trisa
    	clrf	trisb
    	bcf	status, rp0
    	
    	return
    ;-----------------------------------------------------------------------;
    ;                            I2C routine                                ;
    ;-----------------------------------------------------------------------;
    d5u:					;razem z CALL 5 cykli 
    	GOTO	$+1			;2 cykle
    
    	return				;2 cykle 
    
    I2C_START				;  Send the Start Bit on the I2C Bus 
    	bsf	I2C_PORT, I2C_SDA	;  Make the Data Line High 
    	goto	$+1 
    	bcf	I2C_PORT, I2C_SCL	;  Make the Clock Line Low 
    	nop 
    	bsf	I2C_PORT, I2C_SCL	;  Set the Clock High 
    	CALL	d5u			;5 cykli 
    	nop 
    	bcf	I2C_PORT, I2C_SDA	;  Drop the Clock Line to Go into Start Mode 
    	CALL	d5u			;5 cykli 
    	bcf	I2C_PORT, I2C_SCL	;  Start Clock Train 
    	goto	$+1 
    
    	return 
    
    I2C_STOP				;  Send the Stop Bit to the I2C Bus 
    	bcf    I2C_PORT, I2C_SDA	;  Data Line Low 
    	CALL   d5u			;5 cykli 
    	bsf    I2C_PORT, I2C_SCL	;  Set the Clock Line High 
    	CALL   d5u			;5 cykli 
    	bsf    I2C_PORT, I2C_SDA	;  Data goes high whil Clock is High for Stop Bit 
    	goto   $+1 
    	bcf    I2C_PORT, I2C_SCL	;  Set Clock Low Again 
    	goto   $+1 
    	nop
     
    	return 
    
    I2C_SEND				;wyslij W do I2C                        
    	MOVWF	DATA_OUT                
    	MOVLW	.8 
    	MOVWF	INDEX 
    I2C_SEND_LOOP 
    	RLF	DATA_OUT, f
    	BTFSC	STATUS, C		;  JEDYNKA jesli nie to :pomin i ZERO 
    	GOTO	I2C_1 
    	bcf	I2C_PORT, I2C_SDA	;Ustaw 0 
    	goto	I2C_CLK 
    I2C_1                        
    	bsf	I2C_PORT, I2C_SDA	;Ustaw 1 
    I2C_CLK 
    	BSF	I2C_PORT, I2C_SCL	;USTAW CLK 
    	CALL	d5u			;5 cykli 
    	BCF	I2C_PORT,I2C_SCL	;ZERUJ CLK 
    					;drugie 5 cykli to petla :) 
    	DECFSZ	INDEX, F 
    	GOTO	I2C_SEND_LOOP 
    	BSF	I2C_PORT, I2C_SDA	;Ustawienie SDA zeby uklad mogl ACK wyslac 
    	BSF	I2C_PORT, I2C_SCL	;Takt zegara na ACK.ACK NIE jest sprawdzane 
    	CALL	d5u			;5 cykli 
    	BCF	I2C_PORT, I2C_SCL 
    	CALL	d5u			;5 cykli
    
    	RETURN
    ;-------------------------------------------------------------------------;
    ;                           The Main routine                              ;
    ;-------------------------------------------------------------------------;
    main:	call	init
    
    	call	I2C_START
    
    	movlw	b'01110000'
    	call	I2C_SEND 
    	movlw	b'01110110'
    	call	I2C_SEND
    
    	call	I2C_STOP
    
     	goto	$
    
    	end
    

    to co wrzuciłem wyrzej działa.
    Ale gdy wrzucam ten fragmencik kodu do mojego głównego programu to juz nie działa ..
    W końcowej wersji ustaliło się tak:

    RB0 - Klawiatura (wejście) z obsługą przerwania, którą wyłączam, przed wysyłaniem na I2C .
    RB1 - linia RS Wyświetlacza LCD (wyjście)
    RB2 - linia E Wyświetlacza LCD (wyjście)
    RB3 - Klawiatura (wejście)
    RB4 - uSwitch (wejście)
    RB5 - SDA (wyjście)
    RB6 - SCK (wyjście)
    RB7 - n.c. (wyjście)

    w trakcie programu nie operuję na rejestrach trisX - nie zmieniam kierunków linii portów.To by było na tyle. Nie mam pojęcia, czemu to nie dział i wg mnie RMW nie ma to nic do rzeczy, ponieważ SDA i SCL są u mnie cały czas wyjściami. Jak ktoś wie, czemu to może nie działać, to byłbym bardzo wdzięczny.

    Pozdrawiam.
  • #27 771537
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    centipede napisał:
    to co wrzuciłem wyrzej działa.
    Ale gdy wrzucam ten fragmencik kodu do mojego głównego programu to juz nie działa ..
    Sorry że marudze ale jak oczekujesz że ktoś znajdzie bład w Twoim programie nie widząc kodu?
  • #28 772198
    centipede
    Poziom 16  
    Posty: 234
    Pomógł: 1
    Ocena: 4
    przeprasz, za estetyke kodu, za mala ilosc komentarzy i za to, ze sa w dwóch językach ..
    
               LIST P=16F628           ;  16F84 Runs at 4 MHz
               INCLUDE "p16f628.inc"
               __CONFIG h'3f10'
               ERRORLEVEL -302        ;  supress message because of page change
    
    ;  Define Information
    	#DEFINE	 Kdata		PORTB, 0
    	#DEFINE	 RS		PORTB, 1
    	#DEFINE	 E		PORTB, 2
    	#DEFINE	 Kclk		PORTB, 3
    	#DEFINE	 SW		PORTB, 4
    	#DEFINE	 wsk		reg, 0
    	#DEFINE	 result		reg, 1
    	#DEFINE	 cl		reg, 2
    	#DEFINE	 Kerr		reg, 3
    	#DEFINE	 I2C_PORT	PORTB
    	#DEFINE	 I2C_SCL	6
    	#DEFINE	 I2C_SDA	5
    ;------ Define port pins: RB2=SDA=data, RB1=SCL=clock
    ;------ Pins are connected via 4.7K pullup resistors for passive control
    ;------ Any port pins can be used.
    	
                                      ;  RB0-RB3 are D4-D7 of LCD
    ;  Macro
    
    EStrobe	MACRO                   ;  Strobe the "E" Bit
    	bsf	E
    	call	Edelay
    	bcf	E
    	call	Edelay
    	ENDM
    
    wait10	MACRO
    	btfsc	Kclk
    	goto	$-1
    	ENDM
    
    wait01	MACRO
    	btfss	Kclk
    	goto	$-1
    	ENDM
    
    trans	MACRO key, ascii, sascii
    	movlw	key
    	call	compare
    	btfss	result
    	goto	$+6
    	movlw	ascii
    	btfsc	cl
    	addlw	h'100'
    	call	sendCHAR
    	return
    	ENDM
    
                CBLOCK     20H
                    Temp            ; a temporary variable
                    count			; counter
                    precount		; holds value for prescalar
                    bin			; binary number to be converted to BCD
                    hundreds		; BCD hundreds result
                    tens_and_ones		; BCD tens and ones result
    		reg
    	  	flags			; flag bit register
    		position
    		l1
    		l2
    		keycount
    		rxdata
    		txdata
    		data_out
    		index
    		_w
    		_status
    		_pclath
                 ENDC
              
    	org h'00'               	; start at location 0
    	goto main           	; jump over to main routine
    	org h'04'
    	goto int
    ;-------------------------------------------------------------------------;
    ;                       Initialize the ports                              ;
    ;-------------------------------------------------------------------------;
    Init:	movlw	h'07'
    	movwf	cmcon
    	clrf	PORTA
    	clrf	PORTB
    
    	bsf	status, rp0
    	bcf	pcon, oscf
    	movlw	B'00000000'          ; all outputs
    	movwf	trisa
    	movlw	B'00011001'          ; RB4, input, others outputs
    	movwf	trisb
    	movlw	B'00100001'          ; pull-ups enabled                                    
    	movwf	option_reg
    	bcf	status, rp0
    	clrf	precount
    	clrf	reg
    	movlw	b'10010000'
    	movwf	intcon
    	movlw	h'01'
    	movwf	position
    
    	return
    ;-------------------------------------------------------------------------;
    ;                       Initialize the ports                              ;
    ;-------------------------------------------------------------------------;
    Edelay:     nop
    	    nop
                nop
                nop
                nop
    
                return
    ;-------------------------------------------------------------------------;
    ;                 Initialize the LCD                                      ;
    ;-------------------------------------------------------------------------;
    initlcd:
    	movlw	D'40'
    	call	nmsec			;  Wait 40 msecs before Reset
    	bcf	RS			;  send an 8 bit instruction
    	movlw	0x03			;  Reset Command
    	call	NybbleOut		;  Send the Nybble
    	call	Dlay5			;  Wait 5 msecs before Sending Again
    	EStrobe
    	nop  
    	nop				;  Wait 244 usecs before Sending the Second Time
    	EStrobe
    	nop
    	nop				;  Wait 244 usecs before Sending the Third Time
    	bcf	RS			; send an 8 bit instruction
    	movlw	0x02			;  Set 4 Bit Mode
    	call	NybbleOut              
    	nop
    	nop                
    	movlw	0x028			;  4 bit, 2 Line, 5x7 font
    	call	SendINS
    	movlw	0x010			;  display shift off
    	call	SendINS
    	movlw	0x001			;  Clear the Display RAM
    	call	SendINS
    	call	Dlay5			;  Note, Can take up to 4.1 msecs
    	movlw	0x006			;  increment cursor
    	call	SendINS
    	movlw	0x00F			;  display on cursor off
    	call	SendINS
    
    	return
    ;-------------------------------------------------------------------------;
    ;              Send the character in W out to the LCD                     ;
    ;-------------------------------------------------------------------------;
    int:	movwf	_w
    	swapf	status, w
    	clrf	status
    	movwf	_status
    	swapf	pclath, w
    	movwf	_pclath
    
    	call	getch
    
    	movlw	.25
    	subwf	position, w
    	btfsc	status, z
    	call	f2
    	movlw	.49
    	subwf	position, w
    	btfsc	status, z
    	call	f1
    
    	call	key2ascii
    
    	bsf	status, rp0
    	bcf	pcon, oscf
    	bcf	status, rp0
    
    	call	msec250
    
    	bsf	status, rp0
    	bsf	pcon, oscf
    	bcf	status, rp0
    
    	bcf	intcon, intf
    
    	swapf	_pclath, w
    	movwf	pclath
    	swapf	_status, w
    	movwf	status
    	swapf	_w, f
    	swapf	_w, w
    
    	retfie
    ;-------------------------------------------------------------------------;
    ;              Send the character in W out to the LCD                     ;
    ;-------------------------------------------------------------------------;
    SendASCII
     	addlw	'0'			;  Send nbr as ASCII character
    SendCHAR				;  Send the Character to the LCD
     	bsf	status, rp0
    	bcf	pcon, oscf
    	bcf	status, rp0
    	movwf	Temp			;  Save the Temporary Value
    	swapf	Temp, w			;  Send the High Nybble
    	bsf	RS			;  RS = 1
    	call	NybbleOut
    	movf	Temp, w			;  Send the Low Nybble
    	bsf	RS
    	call	NybbleOut
    	bsf	status, rp0
    	bsf	pcon, oscf
    	bcf	status, rp0
    	incf	position, f
    
    	return
    ;-------------------------------------------------------------------------;
    ;              Send an instruction in W out to the LCD                    ;
    ;-------------------------------------------------------------------------;
    SendINS					;  Send the Instruction to the LCD
    	bsf	status, rp0
    	bcf	pcon, oscf
    	bcf	status, rp0
    	movwf	Temp			;  Save the Temporary Value
    	swapf	Temp, w			;  Send the High Nybble
    	bcf	RS			;  RS = 0
    	call	NybbleOut
    	movf	Temp, w			;  Send the Low Nybble
    	bcf	RS
    	call	NybbleOut
    	bsf	status, rp0
    	bsf	pcon, oscf
    	bcf	status, rp0
    
    	return
    ;-------------------------------------------------------------------------;
    ;              Send the nibble in W out to the LCD                        ;
    ;-------------------------------------------------------------------------;
    NybbleOut				;  Send a Nybble to the LCD
    	movwf	PORTA                            
    	EStrobe				;  Strobe out the LCD Data
    	nop
    	nop
    
    	return
    ;-------------------------------------------------------------------------;
    ;                   Output the message on the LCD                           ;
    ;-------------------------------------------------------------------------;
    OutMessage:
      	movwf	FSR                    ;  Point at first letter
    OutLoop:
    	movf	FSR, w                 ;  Get pointer into W
    	incf	FSR, f                 ;  Set up for next letter
    	call	shomsg                 ;  Get character to output
    	iorlw	0                      ;  At the End of the Message?
    	btfsc	STATUS, Z              ;  Skip if not at end
    	return                        ;  Yes - Equal to Zero
    	call	SendCHAR               ;  Output the ASCII Character
    	goto	OutLoop                ;  Get the next character
    
    ;-----------------------------------------------------------------------;
    ;                           Delay routine                               ;
    ;-----------------------------------------------------------------------;
    msec250:
    	movlw 0				; 250 msec delay (adjusted to try and
    					; allow for 2.5% low loop time)
    	goto	$+2
    Dlay5:	movlw	5			; delay for 5 milliseconds
    nmsec:					; delay for # msec in W on entry
    	nop				; each nop is 0.122 milliseconds
    	nop
    	nop				; each total loop is 8 X 0.122 = 0.976 msec
    	nop
    	addlw	H'FF'			; same as subtracting 1 from W
    	btfss	STATUS, Z		; skip if result is zero
    	goto	nmsec			; this is  2 X 0.122 msec
    
    	return				; back to calling point
    ;-----------------------------------------------------------------------;
    ;                         odbior z klawiatury                           ;
    ;-----------------------------------------------------------------------;
    getch:	movlw	.8
    	movwf	keycount
    
    	wait10
    	wait01
    
    nextb:	wait10
    	btfss	Kdata
    	bcf	status, c
    	btfsc	Kdata
    	bsf	status, c
    	rrf	rxdata, f
    	wait01
    
    	decfsz	keycount, f
    	goto	nextb
    
    	return
    ;-----------------------------------------------------------------------;
    ;                             porównanie                                ;
    ;-----------------------------------------------------------------------;
    compare:
    	subwf	rxdata, w
    	btfss	status, z
    	bcf	result
    	btfsc	status, z
    	bsf	result
    
    	return
    ;-----------------------------------------------------------------------;
    ;                              key2ascii                                ;
    ;-----------------------------------------------------------------------;
    key2ascii:
    	trans	h'1C', A'a'
    	trans	h'32', A'b'
    	trans	h'21', A'c'
    	trans	h'23', A'd'
    	trans	h'24', A'e'
    	trans	h'2b', A'f'
    	trans	h'34', A'g'
    	trans	h'33', A'h'
    	trans	h'43', A'i'
    	trans	h'3B', A'j'
    	trans	h'42', A'k'
    	trans	h'4B', A'l'
    	trans	h'3A', A'm'
    	trans	h'31', A'n'
    	trans	h'44', A'o'
    	trans	h'4D', A'p'
    	trans	h'15', A'q'
    	trans	h'2D', A'r'
    	trans	h'1B', A's'
    	trans	h'2C', A't'
    	trans	h'3C', A'u'
    	trans	h'2A', A'v'
    	trans	h'1D', A'w'
    	trans	h'22', A'x'
    	trans	h'35', A'y'
    	trans	h'1A', A'z'
    	trans	h'45', A'0'
    	trans	h'16', A'1'
    	trans	h'1E', A'2'
    	trans	h'26', A'3'
    	trans	h'25', A'4'
    	trans	h'2E', A'5'
    	trans	h'36', A'6'
    	trans	h'3D', A'7'
    	trans	h'3E', A'8'
    	trans	h'46', A'9'
    	trans	h'41', A','
    	trans	h'49', A'.'
    	trans	h'4A', A'/'
    	trans	h'4C', A';'
    	trans	h'52', h'27'
    	trans	h'54', A'['
    	trans	h'5B', A']'
    	trans	h'0E', A'`'
    	trans	h'4E', A'-'
    	trans	h'55', A'='
    	trans	h'29', A' '
    
    	return
    ;-----------------------------------------------------------------------;
    ;                            I2C routine                                ;
    ;-----------------------------------------------------------------------;
    d5u:					;razem z CALL 5 cykli 
    	GOTO	$+1			;2 cykle
    
    	return				;2 cykle 
    
    I2C_START				;  Send the Start Bit on the I2C Bus 
    	bsf	I2C_PORT, I2C_SDA	;  Make the Data Line High 
    	goto	$+1 
    	bcf	I2C_PORT, I2C_SCL	;  Make the Clock Line Low 
    	nop 
    	bsf	I2C_PORT, I2C_SCL	;  Set the Clock High 
    	CALL	d5u			;5 cykli 
    	nop 
    	bcf	I2C_PORT, I2C_SDA	;  Drop the Clock Line to Go into Start Mode 
    	CALL	d5u			;5 cykli 
    	bcf	I2C_PORT, I2C_SCL	;  Start Clock Train 
    	goto	$+1 
    
    	return 
    
    I2C_STOP				;  Send the Stop Bit to the I2C Bus 
    	bcf    I2C_PORT, I2C_SDA	;  Data Line Low 
    	CALL   d5u			;5 cykli 
    	bsf    I2C_PORT, I2C_SCL	;  Set the Clock Line High 
    	CALL   d5u			;5 cykli 
    	bsf    I2C_PORT, I2C_SDA	;  Data goes high whil Clock is High for Stop Bit 
    	goto   $+1 
    	bcf    I2C_PORT, I2C_SCL	;  Set Clock Low Again 
    	goto   $+1 
    	nop
     
    	return 
    
    I2C_SEND				;wyslij W do I2C                        
    	MOVWF	DATA_OUT                
    	MOVLW	.8 
    	MOVWF	INDEX 
    I2C_SEND_LOOP 
    	RLF	DATA_OUT, f
    	BTFSC	STATUS, C		;  JEDYNKA jesli nie to :pomin i ZERO 
    	GOTO	I2C_1 
    	bcf	I2C_PORT, I2C_SDA	;Ustaw 0 
    	goto	I2C_CLK 
    I2C_1                        
    	bsf	I2C_PORT, I2C_SDA	;Ustaw 1 
    I2C_CLK 
    	BSF	I2C_PORT, I2C_SCL	;USTAW CLK 
    	CALL	d5u			;5 cykli 
    	BCF	I2C_PORT,I2C_SCL	;ZERUJ CLK 
    					;drugie 5 cykli to petla :) 
    	DECFSZ	INDEX, F 
    	GOTO	I2C_SEND_LOOP 
    	BSF	I2C_PORT, I2C_SDA	;Ustawienie SDA zeby uklad mogl ACK wyslac 
    	BSF	I2C_PORT, I2C_SCL	;Takt zegara na ACK.ACK NIE jest sprawdzane 
    	CALL	d5u			;5 cykli 
    	BCF	I2C_PORT, I2C_SCL 
    	CALL	d5u			;5 cykli
    
    	RETURN
    ;-----------------------------------------------------------------------;
    ;                              Przycisk                                 ;
    ;-----------------------------------------------------------------------;
    test:   btfsc sw
            goto zeruj
            bsf wsk
            call msec250
            btfsc sw
    zeruj:  bcf wsk
    
            return
    ;-------------------------------------------------------------------------;
    ;                           The Main routine                              ;
    ;-------------------------------------------------------------------------;
    main:	call	msec250
    	call	Init			; initialize ports, set up timer
    	call	initlcd			; initialize the LCD
    	call	init2
    	movlw	H'80'
    	call	SendINS
    	
    	bcf	intcon, gie
    	btfsc	intcon, gie
    	goto	$-2
    	clrf	PORTB
    
    	call	I2C_START
    
    	movlw	b'01110000'		;zapis 
    	call	I2C_SEND 
    	movlw	b'01100110'		;oba 
    	call	I2C_SEND 
           
    	call	I2C_STOP
    
    	bsf	intcon, gie
    
    	goto	$
    
    	end
    

    generalnie chodzi o to, że w tym programie obsługa I2C nie działa, pomóżcie ..
  • #29 772332
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    Program "wygląda" poprawnie, spróbuj 2 rzeczy:
    1. wykomentować obsługe LCD
    2. zamienić kolejność procedur w kodzie.
  • #30 772764
    gummis
    Poziom 15  
    Posty: 162
    Pomógł: 4
    Ocena: 1
    Widze teraz ze ten problem ktory opisalem ciebie nie dotyczy bo ty masz inne rozwiazanie.
    Dokladnie nie analizowalem tego programu ale nie widze nigdzie wyzerownia rp0 w rejestrze STATUS i jesli procedura LCD ustawia ten bit to normalne ze te i2c ci niepojdzie bo zamiast PORTB sterujesz TRISB.

Podsumowanie tematu

✨ Dyskusja dotyczy procedur w asemblerze do programowej emulacji magistrali I2C na mikroprocesorach PIC16FXXX, ze szczególnym uwzględnieniem PIC16F628. Użytkownicy wymieniają się fragmentami kodu i wskazówkami dotyczącymi implementacji I2C w asemblerze, w tym obsługi startu, stopu, wysyłania i odbioru bajtów oraz generowania sygnałów ACK/NACK. Podkreślono konieczność stosowania zewnętrznych rezystorów podciągających 4,7kΩ na liniach SDA i SCL oraz prawidłowego ustawienia rejestrów TRIS i PORT, zwłaszcza w kontekście sterowania liniami I2C metodą pasywną (otwarty kolektor). Zwrócono uwagę na problemy wynikające z jednoczesnego używania linii portu do innych celów (np. przycisków, wyświetlacza alfanumerycznego, klawiatury PC z przerwaniami), co może powodować konflikty i błędy w komunikacji I2C. Omówiono także znaczenie poprawnego ustawienia banków rejestrów (bit RP0 w STATUS) podczas manipulacji liniami I2C. Wskazano, że błędy często wynikają z nieprawidłowego sterowania liniami SDA i SCL, zwłaszcza gdy stosowane są instrukcje RMW (read-modify-write) na tym samym porcie, co magistrala I2C. Zaproponowano korzystanie z gotowych, sprawdzonych procedur dostępnych na stronie www.piclist.com, które implementują metodę pasywną sterowania liniami I2C przez rejestr TRIS. Użytkownicy dzielą się fragmentami kodu asemblerowego, w tym procedurami startu, stopu, wysyłania i odbioru danych, oraz omawiają prawidłową inicjalizację portów i obsługę przerwań, aby uniknąć zakłóceń w komunikacji. Wskazano również na konieczność testowania sprzętowego, gdyż uszkodzenie układów (np. ekspandera PCF8574) może powodować problemy z transmisją. Podsumowując, kluczowe jest prawidłowe zarządzanie liniami I2C na poziomie sprzętowym i programowym, stosowanie odpowiednich rezystorów podciągających, właściwe ustawienie rejestrów TRIS i PORT oraz unikanie konfliktów z innymi urządzeniami podłączonymi do tych samych portów PIC16FXXX.
Wygenerowane przez model językowy.
REKLAMA