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

[ATmega128] [C] DS1305 dziwne liczenie czasu

duke_luke 10 Sie 2010 19:02 2307 4
REKLAMA
  • #1 8385037
    duke_luke
    Poziom 15  
    Witam

    Postanowiłem pobawić się trochę układem DS1305. Ogólnie układ wydaje się działać, jednak kiedy bliżej przyjrzeć się temu w jaki sposób zliczany jest czas pojawia się pewne dziwne zjawisko. Mianowicie co jakiś (co 10 sekund/minut) czas zamiast inkrementacji sekund/minut o 1 inkrementują się one o 7 np. z 25 na 32. Poza tym wszystko wydaje się być w porządku, ogólna liczba sekund się zgadza, tylko nie są zliczane do 59 a do 80kilku (w wyniku tej dziwnej inkrementacji). Problem leży raczej gdzieś w części programowej, gdyż korzystam z modułu Mmega02 firmy Propox, w którym RTC jest montowany fabrycznie. Całość jest wyświetlana na LCD ze sterownikiem Toshiba T6963C. Poniżej zamieszczam listing programu głównego oraz inicjalizację SPI i DSa, z góry dziękuję za pomoc.

    
    #include <avr/io.h>
    #include <avr/iom128.h>
    #include <stdlib.h>
    #include "T6963C.h"
    #include "graphic.h"
    #include "DS1305.h"
    #include "SPI.h"
    
    void setup(void)
    {
    
    SPI_init();          // Initialize SPI
    DS1305_init();       // Initialize RTC SPI
    
    }
    
    
    // wyswietlenie liczby
    void lcd_sendnumber(unsigned int number,unsigned char wyr,char znak)
    {
      char buf[8]="        ";
      ltoa(number,buf,10);            // zamiana liczby na string (syst. dziesietny)
      if (wyr !=0)
      {
        unsigned char b;
        for (b=wyr;b>1;b--)
          if (buf[b]==' ') GLCD_WriteChar(znak);   // dodanie spacji na poczatek     
      }   
      GLCD_WriteString(buf);           // wyswietlenie na LCD
    }
    
    
    int main(void)
    {
    
    unsigned char hours,minutes,seconds;
    setup();
    DDRE = 0xff;
    
    GLCD_Initalize(); // Initalize LCD
    GLCD_ClearText(); // Clear text area
    GLCD_ClearCG(); // Clear character generator area
    GLCD_ClearGraphic(); // Clear graphic area
    
    // Eneble oscillator note: after power up oscillator is atopped
    DS1305_write_byte(0x8f,0x00);               // disable write protection
    DS1305_write_byte(0x8f,0x00);               // Enable oscilator
    /*
    // Ustawianie zegara
    DS1305_write_byte(0x80,0b00000000); // sekundy
    DS1305_write_byte(0x81,0b00100101); // minuty
    DS1305_write_byte(0x82,0b00000000); // godziny
    DS1305_write_byte(0x83,0b00000010); // dzien tygodnia
    DS1305_write_byte(0x84,0b00001010); // dzien miesiaca
    DS1305_write_byte(0x85,0b00001000); // miesiac
    DS1305_write_byte(0x86,0b00010000); // rok
    */
    
    for(;;)
    {
    // Read time from RTC DS1305
    hours=DS1305_read_byte(0x02);            // read hours
    minutes=DS1305_read_byte(0x01);          // read minutes
    seconds=DS1305_read_byte(0x00);          // read seconds
    PORTE = seconds;
    
    GLCD_TextGoTo(0,0);
    lcd_sendnumber(hours,2,'0');
    GLCD_TextGoTo(4,0);
    lcd_sendnumber(minutes,2,'0');
    GLCD_TextGoTo(8,0);
    lcd_sendnumber(seconds,2,'0');
    }
    
    return 0;
    }
    
    
    //-------------------------------------------------------------------------------------------------
    //
    // Delay function
    //   
    //-------------------------------------------------------------------------------------------------
    void delay(void)
    {
    volatile unsigned char i;
    for(i = 0; i < (F_CPU/1000000); i++)
      {
      asm("nop");
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Ports intalization
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_InitalizeInterface(void)
    {
    GLCD_DATA_DDR = 0xFF;
    GLCD_CTRL_DDR = ((1 << GLCD_WR) | (1 << GLCD_RD) | (1 << GLCD_CE) | (1 << GLCD_CD) | (1 << GLCD_RESET) | (1 << GLCD_FS));
    GLCD_CTRL_PORT |= ((1 << GLCD_WR) | (1 << GLCD_RD) | (1 << GLCD_CE) | (1 << GLCD_CD) | (1 << GLCD_RESET) | (1 << GLCD_FS));
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Reads dispay status
    //
    //-------------------------------------------------------------------------------------------------
    unsigned char GLCD_ChceckStatus(void)
    {
    uint8_t tmp;
    GLCD_DATA_DDR = 0x00;
    
    GLCD_CTRL_PORT &= ~((1 << GLCD_RD) | (1 << GLCD_CE));
    delay();
    tmp = GLCD_DATA_PIN;
    GLCD_DATA_DDR = 0xFF;
    GLCD_CTRL_PORT |= ((1 << GLCD_RD) | (1 << GLCD_CE));
    return tmp;
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes instruction
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteCommand(unsigned char command)
    {
    while(!(GLCD_ChceckStatus()&0x03));
    GLCD_DATA_PORT = command;
    
    GLCD_CTRL_PORT &= ~((1 << GLCD_WR) | (1 << GLCD_CE));
    delay();
    GLCD_CTRL_PORT |= ((1 << GLCD_WR) | (1 << GLCD_CE));
    }
    
    //-------------------------------------------------------------------------------------------------
    //
    // Writes data
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteData(unsigned char data)
    {
    while(!(GLCD_ChceckStatus()&0x03));
    GLCD_DATA_PORT = data;
    
    GLCD_CTRL_PORT &= ~((1 << GLCD_WR) | (1 << GLCD_CE) | (1 << GLCD_CD));
    delay();
    GLCD_CTRL_PORT |= ((1 << GLCD_WR) | (1 << GLCD_CE) | (1 << GLCD_CD));
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Reads data
    //
    //-------------------------------------------------------------------------------------------------
    unsigned char GLCD_ReadData(void)
    {
    uint8_t tmp;
    while(!(GLCD_ChceckStatus()&0x03));
    GLCD_DATA_DDR = 0x00;
    
    GLCD_CTRL_PORT &= ~((1 << GLCD_RD) | (1 << GLCD_CE) | (1 << GLCD_CD));
    delay();
    tmp = GLCD_DATA_PIN;
    GLCD_CTRL_PORT |= ((1 << GLCD_RD) | (1 << GLCD_CE) | (1 << GLCD_CD));
    GLCD_DATA_DDR = 0xFF;
    return tmp;
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Sets address pointer for display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_SetAddressPointer(unsigned int address)
    {
    GLCD_WriteData(address & 0xFF);
    GLCD_WriteData(address >> 8);
    GLCD_WriteCommand(T6963_SET_ADDRESS_POINTER);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Clears text area of display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_ClearText(void)
    {
    int i;
    GLCD_SetAddressPointer(GLCD_TEXT_HOME);
    
    for(i = 0; i < GLCD_TEXT_SIZE; i++)
      {
      GLCD_WriteDisplayData(0);
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Clears characters generator area of display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_ClearCG(void)
    {
    unsigned int i;
    GLCD_SetAddressPointer(GLCD_EXTERNAL_CG_HOME);
    
    for(i = 0; i < 256 * 8; i++)
      {
      GLCD_WriteDisplayData(0);
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Clears graphics area of display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_ClearGraphic(void)
    {
    int i;
    GLCD_SetAddressPointer(GLCD_GRAPHIC_HOME);
    for(i = 0; i < GLCD_GRAPHIC_SIZE; i++)
      {
      GLCD_WriteDisplayData(0x00);
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes a single character (ASCII code) to display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteChar(char charCode)
    {
    GLCD_WriteDisplayData(charCode - 32);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes null-terminated string to display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteString(char * string)
    {
    while(*string)
      {
      GLCD_WriteChar(*string++);
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes null-terminated string from program memory to display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteStringPgm(prog_char * string)
    {
    char ch;
    while((ch = pgm_read_byte(string++)))
      {
      GLCD_WriteChar(ch);
      }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Sets display coordinates
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_TextGoTo(unsigned char x, unsigned char y)
    {
    unsigned int address;
    
    address = GLCD_TEXT_HOME +  x + (GLCD_TEXT_AREA * y);
    
    GLCD_SetAddressPointer(address);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes single char pattern to character generator area of display RAM memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_DefineCharacter(unsigned char charCode, unsigned char * defChar)
    {
    unsigned int address;
    unsigned char i;
    
    address = GLCD_EXTERNAL_CG_HOME + (8 * charCode);
    
    GLCD_SetAddressPointer(address);
    
    for(i = 0; i < 8 ; i++)
      {
      GLCD_WriteDisplayData(*(defChar + i));
      }
    }
    
    //-------------------------------------------------------------------------------------------------
    //
    // Set (if color==1) or clear (if color==0) pixel on screen
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_SetPixel(unsigned char x, unsigned char y, unsigned char color)
    {
    unsigned char tmp;
    unsigned int address;
    
    address = GLCD_GRAPHIC_HOME + (x / GLCD_FONT_WIDTH) + (GLCD_GRAPHIC_AREA * y);
    
    GLCD_SetAddressPointer(address);
    
    GLCD_WriteCommand(T6963_DATA_READ_AND_NONVARIABLE);
    tmp = GLCD_ReadData();
    
    if(color)
      tmp |= (1 <<  (GLCD_FONT_WIDTH - 1 - (x % GLCD_FONT_WIDTH)));
    else
     tmp &= ~(1 <<  (GLCD_FONT_WIDTH - 1 - (x % GLCD_FONT_WIDTH)));
    
    GLCD_WriteDisplayData(tmp);
    
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Writes display data and increment address pointer
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_WriteDisplayData(unsigned char x)
    {
    GLCD_WriteData(x);
    GLCD_WriteCommand(T6963_DATA_WRITE_AND_INCREMENT);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Sets graphics coordinates
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_GraphicGoTo(unsigned char x, unsigned char y)
    {
    unsigned int address;
    address = GLCD_GRAPHIC_HOME + (x / GLCD_FONT_WIDTH) + (GLCD_GRAPHIC_AREA * y);
    GLCD_SetAddressPointer(address);
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Displays bitmap from program memory
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_Bitmap(unsigned char * bitmap, unsigned char x, unsigned char y, unsigned char width, unsigned char height)
    {
    unsigned char i, j;
    
    for(j = 0; j < height; j++)
    {
    GLCD_GraphicGoTo(x, y + j);
    for(i = 0; i < width/GLCD_FONT_WIDTH; i++)
      {
      GLCD_WriteDisplayData(pgm_read_byte(bitmap + i + (GLCD_GRAPHIC_AREA * j)));    
      }
    }
    }
    //-------------------------------------------------------------------------------------------------
    //
    // Display initalization
    //
    //-------------------------------------------------------------------------------------------------
    void GLCD_Initalize(void)
    {
    GLCD_InitalizeInterface();
    
    GLCD_CTRL_PORT &= ~(1 << GLCD_RESET);
    _delay_ms(1);
    GLCD_CTRL_PORT |= (1 << GLCD_RESET);
    
    #if (GLCD_FONT_WIDTH == 8)
    GLCD_CTRL_PORT &= ~(1 << GLCD_FS);
    #endif
    
    GLCD_WriteData(GLCD_GRAPHIC_HOME & 0xFF);
    GLCD_WriteData(GLCD_GRAPHIC_HOME >> 8);
    GLCD_WriteCommand(T6963_SET_GRAPHIC_HOME_ADDRESS);
    
    GLCD_WriteData(GLCD_GRAPHIC_AREA);
    GLCD_WriteData(0x00);
    GLCD_WriteCommand(T6963_SET_GRAPHIC_AREA);
    
    GLCD_WriteData(GLCD_TEXT_HOME);
    GLCD_WriteData(GLCD_TEXT_HOME >> 8);
    GLCD_WriteCommand(T6963_SET_TEXT_HOME_ADDRESS);
    
    GLCD_WriteData(GLCD_TEXT_AREA);
    GLCD_WriteData(0x00);
    GLCD_WriteCommand(T6963_SET_TEXT_AREA);
    
    GLCD_WriteData(GLCD_OFFSET_REGISTER);
    GLCD_WriteData(0x00);
    GLCD_WriteCommand(T6963_SET_OFFSET_REGISTER);
    
    GLCD_WriteCommand(T6963_DISPLAY_MODE  | T6963_GRAPHIC_DISPLAY_ON   | T6963_TEXT_DISPLAY_ON /*| T6963_CURSOR_DISPLAY_ON*/);
    
    GLCD_WriteCommand(T6963_MODE_SET | 0);
    
    }
    


    SPI :

    
    //ATmega103/128
    #define     SPI_PORT           PORTB
    #define     SPI_PORT_DIR       DDRB
    #define     SPI_SS             PB0
    #define     SPI_SCK            PB1                      // SPI signals
    #define     SPI_MOSI           PB2
    #define     SPI_MISO           PB3
    
    
    
    void SPI_init(void)
    {
    SPI_PORT_DIR|=((1<<SPI_SCK) | (1<<SPI_MOSI) | (1<<SPI_SS));             // set SPI lines as input or output
    SPI_PORT_DIR|=~(1<<SPI_MISO);                             
    SPCR = 0x5f;                                              // set SPI configuration
    } 
    
    void spi_wait(void)                                       // wait for data from SPI 
    {
     while (!SPSR);
    }
     
    


    DS1305 :

    
    
    #define     DS1305_CS_BIT            PB5            
    #define     DS1305_CS_PORT         PORTB      
    #define     DS1305_CS_PORT_DIR   DDRB  
    
    void DS1305_init(void)
    {
    DS1305_CS_PORT_DIR|= 1<<DS1305_CS_BIT;                            
    DS1305_CS_PORT&= ~(1<<DS1305_CS_BIT);                              
    }
    
    
    unsigned char DS1305_read_byte(unsigned char address)
    {
        DS1305_CS_PORT |=  1<<DS1305_CS_BIT;
        SPDR = address;
        while (!SPSR);
        SPDR = 0;
        while (!SPSR);
        DS1305_CS_PORT &=  ~(1<<DS1305_CS_BIT);
        return (SPDR);
    }   
    
    void DS1305_write_byte(unsigned char address,unsigned char data)
    {
        DS1305_CS_PORT |=  1<<DS1305_CS_BIT;
        SPDR = address;
        while (!SPSR);
        SPDR = data;
        while (!SPSR);
        DS1305_CS_PORT &=  ~(1<<DS1305_CS_BIT);
    }  
       
    
    


    Dodano po 1 [minuty]:

    problem rozwiązany, pisze odpowiedź bo może komuś się przydać. W funkcji ltoa jako podstawę trzeba dać 16 (system szesnastkowy) zamiast 10 (system dziesiętny).
  • REKLAMA
  • #2 8925558
    Alex_115
    Poziom 13  
    Witam!

    Na wstępie dziękuję za ww. kod :) Jednakże mam problem. Posiadam Atmega16 + DS1305 ( RTC na SPI ).

    Robie tak:

    
    	DS1305_init();  
    
    	// Eneble oscillator note: after power up oscillator is atopped 
    	DS1305_write_byte(0x8F,0x05);               // 0b0000 0101 => 0x05 ENABLE OSC, WP=0
    
    	// Ustawianie zegara 
    	DS1305_write_byte(0x80,0x00); // sekundy 0b00000000 - 00
    	DS1305_write_byte(0x81,0x00); // minuty 0b0000000 - 00 
    	DS1305_write_byte(0x82,0x00); // godziny 0b00000000 - 00
    	DS1305_write_byte(0x83,0x01); // dzien tygodnia 0b00000001 - poniedzialek
    	DS1305_write_byte(0x84,0x01); // dzien miesiaca 0b00000001 - 1
    	DS1305_write_byte(0x85,0x01); // miesiac 0b00000001 -> styczen
    	DS1305_write_byte(0x86,0x2A); // rok 0b00101010 -> 2010
    
    	// Przerwanie co 1 sek ( INT0 )
    	DS1305_write_byte(0x87,0x80);  
    	DS1305_write_byte(0x88,0x80); 
    	DS1305_write_byte(0x89,0x80); 
    	DS1305_write_byte(0x8A,0x80); 
    


    Czyli ustawiam sobie jakos wstepnie zegar i date oraz chciałbym, aby alarm0 co 1sek wystawiał flage przerwania dla atmegi i w tym czasie chciałbym zczytywać czas i wyświetlać go na LCD. Jak wrzuce kod w pętle główną to działa:


    
    
    int hours,minutes,seconds; // RTC HH,MM,SS
    char* buffer[5];		   // RTC BUFFER
    
    while(1)
    {
    	// Read time from RTC DS1305 
    	hours=DS1305_read_byte(0x02);            // read hours 
    	minutes=DS1305_read_byte(0x01);          // read minutes 
    	seconds=DS1305_read_byte(0x00);          // read seconds
    
    	LCD_Clear();
    	LCD_Home();
    	itoa(seconds,buffer,16);
    	LCD_WriteText(buffer);
              _delay_ms(200);
    }
    


    ...ale jak ten sam kod robie w przerwaniu to już nie działa :cry:

    
    ISR(INT2_vect) // Obsługa przerwania od RTC
    {
    
    	int hours,minutes,seconds; // RTC HH,MM,SS
    	char* buffer[5];		   // RTC BUFFER
    
    	// Read time from RTC DS1305 
    	hours=DS1305_read_byte(0x02);            // read hours 
    	minutes=DS1305_read_byte(0x01);          // read minutes 
    	seconds=DS1305_read_byte(0x00);          // read seconds
    
    	LCD_Clear();
    	LCD_Home();
    	itoa(seconds,buffer,16);
    	LCD_WriteText(buffer);
    
    }
    


    a tak ustawiam rejestry atmegi:
    
    GICR   |= 1 << INT2;  // Włączenie przerwania INT2
    	MCUCSR &= ~(1 << ISC2); // INT2 zglaszane bedzie na zboczu opadajacym
    	GIFR   |= 1 << INTF2;
    	sei();			// Odblokowanie przerwan
    


    Byłbym bardzo wdzięczny za pomoc !
  • REKLAMA
  • #3 8925664
    duke_luke
    Poziom 15  
    Pewien nie jestem, ale spróbuj zmienne używane w przerwaniu zadeklarować jako volatile, kiedy ja używałem zmiennych w przerwaniu które nie były zadeklarowane jako volatile to też mi program nie działał, wspomniana deklaracja pomogła, z tą różnicą, że u mnie zmienne te były zmiennymi globalnymi, no ale spróbować nie zaszkodzi, a pomóc może. ;)
  • REKLAMA
  • #4 8925702
    Alex_115
    Poziom 13  
    Dzięki za podpowiedź, ale niestety nie pomogło :( Umieściłem te zmienne jakos globalne i nadal nic się nie wyświetla :(

    SPI i DS1305 działa dobrze, bo jak wrzuce kod w pętle główną to mi to ładnie sekundy odczytuje i wyświetla, więc widoczenie coś jest nie tak z tym przerwaniem .. DS1305 powinno co 1 sekunde wystawiać flagę przerwania na INT0, a w Atmega16 powinno przy zmianie INT2 ( bo właśnie do tego przerwania jest podłączony układ DS1305 ) odczytać wartość czasu i ją wyświetlić.. Może jakieś rejestry są źle ustawione? Chociaż sprawdzałem już kilka razy i nic..ale jestem początkujący w avr i mogę czegoś nie dopatrzyć.
  • #5 8927159
    LordBlick
    VIP Zasłużony dla elektroda
    Nie stosuj itoa w przerwaniu, tylko jakąś flagę dla pętli głównej, że możesz przekonwertować czas.
REKLAMA