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

[Atmega162][C]scp1000-d11 - komunikacja i2c

wesol144 19 Sty 2011 00:21 1626 4
REKLAMA
  • #1 9025569
    wesol144
    Poziom 10  
    Witam kolegów,

    Jak napisałem w temacie mam problem z komunikacja Atmegi162 z czujnikiem ciśnienia i temperatury scp1000-d11. Generalnie problem w tym, że muszę zasymulować I2C bo ATmega162 nie ma sprzętowego, ale do rzeczy.

    Próbowałem skorzystać z gotowej biblioteki tutaj i przerobić załączony tam przykład na swoje potrzeby ale niestety nie udało się.

    Link do datasheeta scp1000-d11 tutaj. Generalnie próbowałem zrobić to na podstawie przykładu ze strony 27 a kod mojego programu wygląda następująco:

    void I2C_SCP1000()
    {
    	unsigned char ret1;
    	unsigned char ret2;
    	
    	i2c_init();
    	i2c_start_wait(0x11+I2C_WRITE); //0x11 to adres urządzenia
    	i2c_write(0x81);                        // 0x81 to adres rejestru zawierającego temperaturę (format 14-bit)
    	i2c_rep_start(0x11+I2C_READ);
    	
    	ret1 = i2c_readAck();
    	ret2 = i2c_readNak();
    	i2c_stop();
    	//while(1) {PORTC = ~PORTC; _delay_ms(1000);} //tylko do sprawdzenia niestety program nie dochodzi do tego momentu
    	
    	
    }
    


    Kody wykorzystywanych funkcji:

    
    
    ;*************************************************************************
    ; Initialization of the I2C bus interface. Need to be called only once
    ; 
    ; extern void i2c_init(void)
    ;*************************************************************************
    	.global i2c_init
    	.func i2c_init
    i2c_init:
    	cbi SDA_DDR,SDA		;release SDA
    	cbi SCL_DDR,SCL		;release SCL
    	cbi SDA_OUT,SDA
    	cbi SCL_OUT,SCL
    	ret
    	.endfunc
    
    
    
    ;*************************************************************************	
    ; Issues a start condition and sends address and transfer direction.
    ; If device is busy, use ack polling to wait until device is ready
    ;
    ; extern void i2c_start_wait(unsigned char addr);
    ;	addr = r24
    ;*************************************************************************
    
    	.global i2c_start_wait
    	.func   i2c_start_wait
    i2c_start_wait:
    	mov	__tmp_reg__,r24
    i2c_start_wait1:
    	sbi 	SDA_DDR,SDA	;force SDA low
    	rcall 	i2c_delay_T2	;delay T/2
    	mov	r24,__tmp_reg__
    	rcall 	i2c_write	;write address
    	tst	r24		;if device not busy -> done
    	breq	i2c_start_wait_done
    	rcall	i2c_stop	;terminate write operation
    	rjmp	i2c_start_wait1	;device busy, poll ack again
    i2c_start_wait_done:
    	ret
    	.endfunc	
    
    
    ;*************************************************************************
    ; Terminates the data transfer and releases the I2C bus
    ;
    ; extern void i2c_stop(void)
    ;*************************************************************************
    
    	.global	i2c_stop
    	.func	i2c_stop
    i2c_stop:
    	sbi	SCL_DDR,SCL	;force SCL low
    	sbi	SDA_DDR,SDA	;force SDA low
    	rcall	i2c_delay_T2	;delay T/2
    	cbi	SCL_DDR,SCL	;release SCL
    	rcall	i2c_delay_T2	;delay T/2
    	cbi	SDA_DDR,SDA	;release SDA
    	rcall	i2c_delay_T2	;delay T/2
    	ret
    	.endfunc
    
    ;*************************************************************************
    ; Send one byte to I2C device
    ; return 0 = write successful, 1 = write failed
    ;
    ; extern unsigned char i2c_write( unsigned char data );
    ;	data = r24,  return = r25(=0):r24
    ;*************************************************************************
    	.global i2c_write
    	.func	i2c_write
    i2c_write:
    	sec			;set carry flag
    	rol 	r24		;shift in carry and out bit one
    	rjmp	i2c_write_first
    i2c_write_bit:
    	lsl	r24		;if transmit register empty
    i2c_write_first:
    	breq	i2c_get_ack
    	sbi	SCL_DDR,SCL	;force SCL low
    	brcc	i2c_write_low
    	nop
    	cbi	SDA_DDR,SDA	;release SDA
    	rjmp	i2c_write_high
    i2c_write_low:
    	sbi	SDA_DDR,SDA	;force SDA low
    	rjmp	i2c_write_high
    i2c_write_high:
    	rcall 	i2c_delay_T2	;delay T/2
    	cbi	SCL_DDR,SCL	;release SCL
    	rcall	i2c_delay_T2	;delay T/2
    	rjmp	i2c_write_bit
    	
    i2c_get_ack:
    	sbi	SCL_DDR,SCL	;force SCL low
    	cbi	SDA_DDR,SDA	;release SDA
    	rcall	i2c_delay_T2	;delay T/2
    	cbi	SCL_DDR,SCL	;release SCL
    i2c_ack_wait:
    	sbis	SCL_IN,SCL	;wait SCL high (in case wait states are inserted)
    	rjmp	i2c_ack_wait
    	
    	clr	r24		;return 0
    	sbic	SDA_IN,SDA	;if SDA high -> return 1
    	ldi	r24,1
    	rcall	i2c_delay_T2	;delay T/2
    	clr	r25
    	ret
    	.endfunc
    
    



    Oczywiście w i2cmaster.S pozmieniałem wartości SDA i SCL na PORTE i dostosowałem opóźnienie do 8MHz oscylatora wewnętrznego.

    Rezystory podciągające podłączone, na pewno błąd tkwi w moim braku wystarczającej wiedzy na temat I2C.

    Środowisko w jakim programuje to WinAVR.

    Czy ktoś mógłby naprowadzić mnie na właściwą drogę jak dojść do ładu z transmisją?

    Pozdrawiam

    Poprawiłem tytuł - regulamin p.11.1
    [zumek]
  • REKLAMA
  • #2 9029782
    wesol144
    Poziom 10  
    Zbyt prozaiczne pytanie czy nikt nie ma pomysłu dlaczego to nie działa?
  • REKLAMA
  • #3 9030214
    kazokbukaj
    Poziom 1  
    am... raczej mało kto tak głęboko się wgryzał w atmege + scp1000 d11... ;\
    osobiście walczę z podobnym zestawem różni się atmegą16 i tym że chcę odczytywać ciśnienie ale to w sumie jest tylko wpisanie tryby pracy a jak i2c działa to powinien być pikuś... problem w tym że mi też i2c nie śmiga
    pozdro i powodzenia

    PS czy kolega pisze właśnie pracę inż na EiT?
  • REKLAMA
  • Pomocny post
    #4 9033783
    Andrzej__S
    Poziom 28  
    Cytat:

    Generalnie próbowałem zrobić to na podstawie przykładu ze strony 27...

    Przyjrzyj się dokładniej formatowi bajtu adresowego, bo chyba jednak zrobiłeś to niedokładnie. Adres 0x11 podany w datasheet scp1000-d11 zajmuje przecież starsze 7 bitów bajtu adresowego. Najmłodszy bit to bit kierunku transmisji, czyli powinieneś zamiast:
    
    i2c_start_wait(0x11+I2C_WRITE);
    

    użyć konstrukcji:
    
    i2c_start_wait((0x11<<1)+I2C_WRITE);
    //lub alternatywnie
    i2c_start_wait(0x22+I2C_WRITE);
    

    Prawdopodobnie funkcja i2c_start_wait() wysyła w kółko na magistralę nieistniejący adres nie otrzymując bitu potwierdzenia, i dlatego program nie dochodzi w ogóle do pętli while (jak napisałeś w komentarzach).

    Nie rozumiem, dlaczego próbowałeś wstawić pętlę nieskończoną w funkcji I2C_SCP1000(). Powinna być chyba w funcji main(). Podobnie funkcja i2c_init() powinna być użyta tylko raz w funkcji main() przed pętlą.

    Nie przedstawiłeś całości programu, ale zwróć też uwagę na Figure 2. SCP1000 start-up sequence. na stronie 7, bo podane tam opóźnienia przed rozpoczęciem komunikacji z układem mogą być dosyć istotne.
  • #5 9073527
    wesol144
    Poziom 10  
    Temat można uznać za zamknięty pomogła zmiana adresu na ((0x11<<1)+I2C_WRITE); Dzięki serdeczne Andrzej___S. Mój błąd, źle przeanalizowałem adresację.
REKLAMA