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

[PCF8583][ATmega32][C][WinAVR], problem zkodem

juchasr 16 Lis 2010 22:29 1756 2
REKLAMA
  • #1 8753163
    juchasr
    Poziom 2  
    Piszę obsługę zegara PCF8583. W moim programie występują jakieś błędy, i nie wiem jak je rozwiązać. Proszę o pomoc.
    Poniżej zamieszczam kod do obsługi I2C (TWI), i zegara PCF8583.
    W wyniku działania programu dostaję dziwne wyniki na wyświetlaczu.

    Kod:
    
    #define F_CPU 1000000UL 
    #include <avr/io.h> 
    #include <util/delay.h> 
    #include <stdio.h> 
    
    #define ACK 1 
    #define NOACK 0 
    #define PCF8583 1 
    
    static void i2cInit(void) 
    { 
      TWSR = 0; 
      TWBR = 6; 
    } 
    
    static void i2cStart(void) 
    { 
        TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); 
        while (!(TWCR & (1<<TWINT))); 
    } 
    
    static void i2cStop(void) 
    { 
        TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); 
        while ((TWCR & (1<<TWSTO))); 
    } 
    
    static void i2cWrite(char data) 
    { 
        TWDR = data; 
        TWCR = (1<<TWINT) | (1<<TWEN); 
        while (!(TWCR & (1<<TWINT))); 
    } 
    
    static char i2cRead(char ack) 
    { 
        TWCR = ack ? ((1 << TWINT) | (1 << TWEN) | (1 << TWEA)) : ((1 << TWINT) | (1 << TWEN)) ; 
        while (!(TWCR & (1<<TWINT))); 
        return TWDR; 
    } 
    
    static volatile uint8_t PCF8583_status; 
    
    static volatile uint8_t PCF8583_alarm; 
    
    
    static uint8_t bcd2bin(uint8_t bcd) 
    { 
        return (10*(bcd>>4) + (bcd&0x0f)); 
    } 
    static uint8_t bin2bcd(uint8_t bin) 
    { 
        return ( ( ( bin / 10 ) << 4) | ( bin % 10 ) ); 
    } 
    
    static uint8_t PCF8583_read(uint8_t address) 
    { 
        uint8_t a; 
        a = (PCF8583_A0 << 1) | 0xa0;       // tu musiałem zmienić na 0x50 nie wiem 
                                                         // czemu 0xa0 nie działa 
        i2cStart(); 
        i2cWrite(a); 
        i2cWrite(address); 
        i2cStart(); 
        i2cWrite(a | 1);                           // tu mam   i2cWrite(a); też nie wiem 
                                                        // dlaczego   i2cWrite(a | 1); nie działa  
        a = i2cRead(NOACK); 
        i2cStop(); 
        return a; 
    } 
    
    
    static void PCF8583_write(uint8_t address,uint8_t data) 
    { 
        i2cStart(); 
        i2cWrite((PCF8583_A0 << 1) | 0xa0);  // tu musiałem zmienić na 0x50 nie wiem 
                                                            // czemu 0xa0 nie dział 
        i2cWrite(address); 
        i2cWrite(data); 
        i2cStop(); 
    } 
    
    
    static uint8_t PCF8583_read_bcd(uint8_t address) 
    { 
        return bcd2bin(PCF8583_read(address)); 
    } 
    
    static void PCF8583_write_bcd(uint8_t address,uint8_t data) 
    { 
        PCF8583_write(address,bin2bcd(data)); 
    } 
    
    static uint8_t PCF8583_get_status(void) 
    { 
        PCF8583_status = PCF8583_read(0); 
        PCF8583_alarm = (PCF8583_status & 2); 
        return PCF8583_status; 
    } 
    
    
    static void PCF8583_init(void) 
    { 
        PCF8583_status=0; 
        PCF8583_alarm=0; 
        PCF8583_write(0, 0); 
        PCF8583_write(4, PCF8583_read(4) & 0x3f); 
        PCF8583_write(8, 0x90); 
    } 
    
    static void PCF8583_stop(void) 
    { 
        PCF8583_get_status(); 
        PCF8583_status |= 0x80; 
        PCF8583_write(0, PCF8583_status); 
    } 
    
    static void PCF8583_start(void) 
    { 
        PCF8583_get_status(); 
        PCF8583_status &= 0x7f; 
        PCF8583_write(0, PCF8583_status); 
    } 
    
    static void PCF8583_hold_off(void) 
    { 
      PCF8583_get_status(); 
      PCF8583_status &= 0xbf; 
      PCF8583_write(0, PCF8583_status); 
    } 
    
    static void PCF8583_hold_on(void) 
    { 
      PCF8583_get_status(); 
      PCF8583_status |= 0x40; 
      PCF8583_write(0, PCF8583_status); 
    } 
    
    
    static void PCF8583_alarm_off(void) 
    { 
        PCF8583_get_status(); 
        PCF8583_status &= 0xfb; 
        PCF8583_write(0, PCF8583_status); 
    } 
    
    static void PCF8583_alarm_on(void) 
    { 
      PCF8583_get_status(); 
      PCF8583_status |= 0x04; 
      PCF8583_write(0, PCF8583_status); 
    } 
    
    
    static void PCF8583_write_word(uint8_t address,uint16_t data) 
    { 
      PCF8583_write(address, (uint8_t)(data & 0xff)); 
      PCF8583_write(++address, (uint8_t)(data >> 8)); 
    } 
    
    
    static void PCF8583_write_date(uint8_t address,uint8_t day,uint16_t year) 
    { 
        PCF8583_write(address, bin2bcd(day) | ( ( (uint8_t)year & 0x03) << 6 ) ); 
    } 
    
    static void PCF8583_get_time(uint8_t *hour,uint8_t *min,uint8_t *sec,uint8_t *hsec) 
    { 
        PCF8583_hold_on(); 
        *hsec=PCF8583_read_bcd(1); 
        *sec=PCF8583_read_bcd(2); 
        *min=PCF8583_read_bcd(3); 
        *hour=PCF8583_read_bcd(4); 
        PCF8583_hold_off(); 
    } 
    
    static void PCF8583_get_time_bcd(uint8_t *hour,uint8_t *min,uint8_t *sec,uint8_t *hsec) 
    { 
        PCF8583_hold_on(); 
        *hsec=PCF8583_read(1); 
        *sec=PCF8583_read(2); 
        *min=PCF8583_read(3); 
        *hour=PCF8583_read(4) & 0b00111111; 
        PCF8583_hold_off(); 
    } 
    static void PCF8583_set_time(uint8_t hour,uint8_t min,uint8_t sec,uint8_t hsec) 
    { 
        PCF8583_stop(); 
        PCF8583_write_bcd(1,hsec); 
        PCF8583_write_bcd(2,sec); 
        PCF8583_write_bcd(3,min); 
        PCF8583_write_bcd(4,hour); 
        PCF8583_start(); 
    } 
    
    static void PCF8583_get_date(uint8_t *day,uint8_t *month,uint16_t *year) 
    { 
        uint8_t dy; 
        uint16_t y1; 
        PCF8583_hold_on(); 
        dy = PCF8583_read(5); 
        *month = bcd2bin(PCF8583_read(6) & 0x1f); 
        PCF8583_hold_off(); 
        *day = bcd2bin(dy & 0x3f); 
        dy >>= 6; 
        y1 = PCF8583_read(16) | ( (uint16_t)PCF8583_read(17) << 8); 
        if ( ( (uint8_t) y1 & 3 ) != dy ) 
                PCF8583_write_word(16, ++y1); 
        *year = y1; 
    } 
    
    static void PCF8583_set_date(uint8_t day,uint8_t month,uint16_t year) 
    { 
        PCF8583_write_word(16, year); 
        PCF8583_stop(); 
        PCF8583_write_date(5, day, year); 
        PCF8583_write_bcd(6, month); 
        PCF8583_start(); 
    } 
    
    static void PCF8583_get_alarm_time(uint8_t *hour, uint8_t *min, uint8_t *sec, uint8_t *hsec) 
    { 
      *hsec=PCF8583_read_bcd(0x9); 
      *sec=PCF8583_read_bcd(0xa); 
      *min=PCF8583_read_bcd(0xb); 
      *hour=PCF8583_read_bcd(0xc); 
    } 
    
    static void PCF8583_set_alarm_time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t hsec) 
    { 
      PCF8583_write_bcd(0x9, hsec); 
      PCF8583_write_bcd(0xa, sec); 
      PCF8583_write_bcd(0xb, min); 
      PCF8583_write_bcd(0xc, hour); 
    } 
    
    static void PCF8583_get_alarm_date(uint8_t *day, uint8_t *month) 
    { 
      *day = bcd2bin( PCF8583_read(0xd) & 0x3f ); 
      *month = bcd2bin( PCF8583_read(0xe) & 0x1f ); 
    } 
    
    static void PCF8583_set_alarm_date (uint8_t day, uint8_t month ) 
    { 
      PCF8583_write_date( 0xd, day, 0 ); 
      PCF8583_write_bcd( 0xe, month ); 
    } 
    
    
    uint8_t godz, min, sek, hsek; 
    uint8_t dzien, miesiac; 
    uint16_t rok; 
    
    // w funkcji main są tylko fragmenty programy 
    
    int main ( void ) 
    { 
        i2cInit(); 
        PCF8583_init(); 
        PCF8583_set_time( 10, 11, 31, 0 ); 
        PCF8583_set_date( 16, 11, 2010 ); 
    while(1) 
        { 
                    
            PCF8583_get_time( &godz, &min, &sek, &hsek ); 
            PCF8583_get_date( &dzien, &miesiac, &rok ); 
            
        }; 
        return 0; 
    } 
    
    
    


    Na wyświetlacz idzie otrzymana liczba bez przekształceń.

    Szukałem i przerabiałem już tematy o PCF8583, przerobiłem też kod ale dalej mi ten zegar nie działa jak powinien, już od tygodnia nad tym siedzę. Proszę o pomoc, wskazówki.
  • REKLAMA
  • #2 8753226
    mirekk36
    Poziom 42  
    W kodzie widać co chwilę twoje komentarze, że

    "tu musiałem coś zmienić bo tak nie działa, ..."

    "tam musiałem dać inaczej bo też tak nie działa,... "

    Co to znaczy? To ty pisałeś ten program ? czy ktoś ci pisał ? czy może zassałeś z netu jakieś strzępy programów i próbowałeś to wszystko poskładać do kupy - nie rozumiejąc o co w tym chodzi ???

    No bo jak inaczej wyjaśnić te komentarze? ,,,, proponuję więc po kolei pisać program wtedy wyjdzie a teraz to wrzuciłeś 2 hektolitry kodu i masz małą prośbę

    "naprawcie mi to"
  • #3 8754843
    juchasr
    Poziom 2  
    Kod jest przerobiony, z innego ale go ogarniam,
    a teraz co znaczą komentarze.

    jeśli chodzi o wartość 0xa0, która jest w kodzie, a ja napisałem że to nie działa, natomiast działa dla 0x50.

    0x50 = 01010000;
    0xa0 = 10100000;

    Według noty katalogowej PCF8583, adres scalaka jest 10100000 = 0xa0, z czego 1010 - to adres stały
    000 - to adres zmienny i zależy od nóżki A0 układu, jak nóżka jest podłączona do uziemienia to (000), a jak do napięcia to (001), natomiast ostatni element to R/W.
    jak jest zero to odczyt a jak jeden to zapis z urządzenia.

    właśnie dlatego drugi opis dotyczy i2cWrite(a | 1);. Ta jedynka która się tu znajduje jest po to żeby ustawić wartość R/W na 1, i w tedy adres urządzenia wygląda tak 10100011 (u mnie nóżka A0 jest podpięta do napięci).

    Dodam jeszcze, że po operacji a = (PCF8583_A0 << 1) | 0xa0;
    a powinno być równe 10100010, bo u nie nóżka A0 jest podpięta do zasilania, dlatego wartość PCF8583_A0 jest ustawiona na 1

    Zamieściłem tyle funkcji żeby nikt się nie czepiał, dlaczego brakuje jakiś elementów. Natomiast jeśli chodzi o funkcje do obsługi I2C to funkcje te zostały sprawdzone. Za ich pomocą zaprogramowałem pamięć EEPROM przez port I2C (TWI).
REKLAMA