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

Jak używać I2C z zegarkiem PCF8583 na ATmega8 w C?

gbr3 28 Paź 2007 02:30 3649 9
REKLAMA
  • #1 4421882
    gbr3
    Poziom 15  
    Posty: 206
    Pomógł: 1
    Ocena: 1
    Witam
    Zmagam się z zegarkiem pcf8583 na i2c. W bascomie nie było problemu ale z C to juz co innego. Chce wykorzystać sprzętowe i2c atmega8.
    Korzystam z biblioteki Petera Fleury'ego która znalazłem gdzies na elektrodzie ale coś nie chce działać.
    Za wszelkie podpowiedzi dziękuje
    Pozdrawiam Gbr3
    oto kod:
    
    #include <stdlib.h> 
    #include "twimaster.c"
    #include "i2cmaster.h"
    #include "lcd.c"
    unsigned char s;
    unsigned char ds;
    char buffer[7];
    unsigned char address;
    unsigned char data;
    int main (void)
    {
    lcd_init(LCD_DISP_ON);
    lcd_clrscr();
    i2c_init();
    for(;;)
    {
    address=0xA0;
    
    i2c_start(address);
    
    data=0x02;
    
    i2c_write(data);
    
    address=0xA1;
    
    i2c_rep_start(address);
    
    i2c_write(data);
    
    i2c_readNak();
    
    i2c_stop();
    TWDR=s;
    s = s & 0x0F;			
    ds = (s & 0xF0) >> 4;
    lcd_home();
    itoa(ds,buffer,10);
    lcd_puts(buffer);
    itoa(s,buffer,10);
    lcd_puts(buffer);
    }
    }
    
  • REKLAMA
  • #2 4424583
    mick
    Poziom 15  
    Posty: 212
    Pomógł: 2
    Ocena: 204
    Nie chce mi sie sprawdzać, jak chcesz to użyj tych które napisał mój kolega.
    Sprawdzone działa, przykład jak użyć masz w pliku progr.c
    Załączniki:
    • progr.c (2.49 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • I2C.H (3.73 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • REKLAMA
  • #3 4424744
    gbr3
    Poziom 15  
    Posty: 206
    Pomógł: 1
    Ocena: 1
    Dzięki Mick ale jakoś nie mogę załapać , w c pisze od niedawna. To co znalazłem w sieci trochę bardziej rozumiem tylko nie wiem w jakiej kojejnosci to ma być wykonywane wzorowałem sie bascomem... Jakby ktoś mógł to proszę o wyjaśnienie co ma byc pierwsze
    Pozdrawiam
    
    /*************************************************************************
    * Title:    I2C master library using hardware TWI interface
    * Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
    * File:     $Id: twimaster.c,v 1.2 2005/02/27 21:56:13 Peter Exp $
    * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
    * Target:   any AVR device with hardware TWI 
    * Usage:    API compatible with I2C Software Library i2cmaster.h
    **************************************************************************/
    #include <inttypes.h>
    #include <compat/twi.h>
    
    #include <i2cmaster.h>
    
    
    /* define CPU frequency in Mhz here if not defined in Makefile */
    #ifndef F_CPU
    #define F_CPU 11059200UL
    #endif
    
    /* I2C clock in Hz */
    #define SCL_CLOCK  100000L
    
    
    /*************************************************************************
     Initialization of the I2C bus interface. Need to be called only once
    *************************************************************************/
    void i2c_init(void)
    {
      /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
      
      TWSR = 0;                         /* no prescaler */
      TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
    
    }/* i2c_init */
    
    
    /*************************************************************************	
      Issues a start condition and sends address and transfer direction.
      return 0 = device accessible, 1= failed to access device
    *************************************************************************/
    unsigned char i2c_start(unsigned char address)
    {
        uint8_t   twst;
    
    	// send START condition
    	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    
    	// wait until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
    
    	// send device address
    	TWDR = address;
    	TWCR = (1<<TWINT) | (1<<TWEN);
    
    	// wail until transmission completed and ACK/NACK has been received
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if( twst != TW_MT_SLA_ACK) return 1;
    
    	return 0;
    
    }/* i2c_start */
    
    
    /*************************************************************************
     Issues a start condition and sends address and transfer direction.
     If device is busy, use ack polling to wait until device is ready
     
     Input:   address and transfer direction of I2C device
    *************************************************************************/
    void i2c_start_wait(unsigned char address)
    {
        uint8_t   twst;
    
    
        while ( 1 )
        {
    	    // send START condition
    	    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
        
        	// wait until transmission completed
        	while(!(TWCR & (1<<TWINT)));
        
        	// check value of TWI Status Register. Mask prescaler bits.
        	twst = TW_STATUS & 0xF8;
        	if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
        
        	// send device address
        	TWDR = address;
        	TWCR = (1<<TWINT) | (1<<TWEN);
        
        	// wail until transmission completed
        	while(!(TWCR & (1<<TWINT)));
        
        	// check value of TWI Status Register. Mask prescaler bits.
        	twst = TW_STATUS & 0xF8;
        	if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
        	{    	    
        	    /* device busy, send stop condition to terminate write operation */
    	        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    	        
    	        // wait until stop condition is executed and bus released
    	        while(TWCR & (1<<TWSTO));
    	        
        	    continue;
        	}
        	//if( twst != TW_MT_SLA_ACK) return 1;
        	break;
         }
    
    }/* i2c_start_wait */
    
    
    /*************************************************************************
     Issues a repeated start condition and sends address and transfer direction 
    
     Input:   address and transfer direction of I2C device
     
     Return:  0 device accessible
              1 failed to access device
    *************************************************************************/
    unsigned char i2c_rep_start(unsigned char address)
    {
        return i2c_start( address );
    
    }/* i2c_rep_start */
    
    
    /*************************************************************************
     Terminates the data transfer and releases the I2C bus
    *************************************************************************/
    void i2c_stop(void)
    {
        /* send stop condition */
    	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    	
    	// wait until stop condition is executed and bus released
    	while(TWCR & (1<<TWSTO));
    
    }/* i2c_stop */
    
    
    /*************************************************************************
      Send one byte to I2C device
      
      Input:    byte to be transfered
      Return:   0 write successful 
                1 write failed
    *************************************************************************/
    unsigned char i2c_write( unsigned char data )
    {	
        uint8_t   twst;
        
    	// send data to the previously addressed device
    	TWDR = data;
    	TWCR = (1<<TWINT) | (1<<TWEN);
    
    	// wait until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits
    	twst = TW_STATUS & 0xF8;
    	if( twst != TW_MT_DATA_ACK) return 1;
    	return 0;
    
    }/* i2c_write */
    
    
    /*************************************************************************
     Read one byte from the I2C device, request more data from device 
     
     Return:  byte read from I2C device
    *************************************************************************/
    unsigned char i2c_readAck(void)
    {
    	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    	while(!(TWCR & (1<<TWINT)));    
    
        return TWDR;
    
    }/* i2c_readAck */
    
    
    /*************************************************************************
     Read one byte from the I2C device, read is followed by a stop condition 
     
     Return:  byte read from I2C device
    *************************************************************************/
    unsigned char i2c_readNak(void)
    {
    	TWCR = (1<<TWINT) | (1<<TWEN);
    	while(!(TWCR & (1<<TWINT)));
    	
        return TWDR;
    
    }/* i2c_readNak */
    
  • #4 4425288
    mick
    Poziom 15  
    Posty: 212
    Pomógł: 2
    Ocena: 204
    Hmm, no dobra ale czy program w ogóle się kompiluje?
  • #5 4425351
    gbr3
    Poziom 15  
    Posty: 206
    Pomógł: 1
    Ocena: 1
    Kompiluje się, ale znalazłem już rozwiązanie na stronie autora biblioteki której używam ,jednak temat pozostawiam otwarty(jeszcze odczyt daty który jest dosyć dziwny :D) Pozdrawiam Gbr3
  • REKLAMA
  • #6 4435343
    gbr3
    Poziom 15  
    Posty: 206
    Pomógł: 1
    Ocena: 1
    Mam jeszcze pytanie jak zapisać do tego scalaka dane jak cokolwiek chce zapisać to zapisuje się co innego , czy ta procegura zapisu jest poprawna

    i2c_init();
    i2c_start_wait(0xA0+I2C_WRITE);
    i2c_write(h);
    i2c_rep_start(0xA0+I2C_WRITE);
    i2c_write(i);
    i2c_stop();
  • #7 4436270
    mick
    Poziom 15  
    Posty: 212
    Pomógł: 2
    Ocena: 204
    a skąd wiesz że zapisuje się co innego? dostajesz inne odpowiedzi?
    Zegar masz 11.059MHz?

    Dodano po 2 [minuty]:

    Procedura wygląda poprawnie.
  • #8 4436348
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    gbr3 napisał:
    ... czy ta procegura zapisu jest poprawna
    
    i2c_init(); 
    i2c_start_wait(0xA0+I2C_WRITE);     
    i2c_write(h);
    i2c_rep_start(0xA0+I2C_WRITE);
    i2c_write(i);
    i2c_stop();


    Ja uważam , że nadeszła pora , byś zapoznał się z dokumentacją PCF-ka.
    Nie każe Ci czytać , wystarczy popatrzeć na tabele i rysunki , które jasno "pokazują" co,gdzie i jak zapisać/odczytać.
    Programowanie , to nie zgaduj zgadula ;)
    Zapis do rejestru minut:
    
    i2c_init(); 
    i2c_start_wait(0xA0+I2C_WRITE); //zaadresuj PCF-ka do zapisu
    i2c_write(3); //ustaw wewnętrzny rejestr adresowy na rejestr minut(3)
    i2c_write(0x22); // zapisz daną (0x22) do rejestru minut(3)
    i2c_stop();

    Proste :?:
    Ponad to , należy sprawdzać wartości(status) zwracane przez poszczególne funkcje np.
    
    if(!(i2c_start_wait(0xA0+I2C_WRITE))
    {
       //slave odpowiedział ACK
    }
    else
    {
       //brak ACK - urządzenie o adresie 0xA0 nie istnieje lub jest zajęte
    }
         
    


    Piotrek
  • REKLAMA
  • #9 4436926
    gbr3
    Poziom 15  
    Posty: 206
    Pomógł: 1
    Ocena: 1
    Zegar jest 8Mhz to kopia nie zmienionego pliku.

    Dokumentacje pcf-ka znam wiem gdzie co zapisać,procedura na początku była dobra(taka jak napisałeś Zumek) problem leżał w tym ze aby zapisać np 59 to trzeba wpisać 0x59 a nie 0x3B (przynajmniej tak wywnioskowałem)
  • #10 4436997
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    gbr3 napisał:
    ...Dokumentacje pcf-ka znam wiem gdzie co zapisać,procedura na początku była dobra(taka jak napisałeś Zumek) problem leżał w tym ze aby zapisać np 59 to trzeba wpisać 0x59 a nie 0x3B (przynajmniej tak wywnioskowałem)

    To nie "wywnioskowywuj"( pamiętasz zgaduj zgadula ? ) , tylko sprawdź w dokumentacji , że rejestry zegara przechowują dane w kodzie BCD , czyli 22 minuty to 0x22 lub 34, a nie 22 czy 0x16.

    Piotrek

Podsumowanie tematu

✨ Dyskusja dotyczy wykorzystania interfejsu I2C sprzętowego w mikrokontrolerze ATmega8 do komunikacji z zegarkiem czasu rzeczywistego PCF8583 w języku C. Autor ma trudności z implementacją, mimo że w Bascomie działało poprawnie. Korzysta z biblioteki Petera Fleury'ego do obsługi TWI, jednak kod nie działa zgodnie z oczekiwaniami. Wskazano, że ważne jest prawidłowe adresowanie urządzenia (0xA0 dla zapisu, 0xA1 dla odczytu) oraz odpowiednia kolejność wywołań funkcji i2c_start, i2c_write, i2c_rep_start, i2c_readNak i i2c_stop. Podkreślono konieczność sprawdzania statusów zwracanych przez funkcje I2C, aby potwierdzić poprawną komunikację. Zwrócono uwagę, że rejestry PCF8583 przechowują dane w kodzie BCD, co ma wpływ na sposób zapisu wartości, np. 59 minut należy zapisać jako 0x59, a nie 0x3B. Przykład poprawnego zapisu do rejestru minut został podany wraz z sugestią, by dokładnie zapoznać się z dokumentacją układu. Procedura zapisu danych do PCF8583 została oceniona jako poprawna, a problem leżał w interpretacji formatu danych. Dyskusja zawiera fragmenty kodu i wskazówki dotyczące implementacji I2C na ATmega8 z użyciem biblioteki Petera Fleury'ego.
Podsumowanie wygenerowane przez AI na podstawie treści dyskusji.
REKLAMA