add minutes and hours into a memory

General discussion on mikroC PRO for PIC.
Post Reply
Author
Message
Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

add minutes and hours into a memory

#1 Post by Olivia » 01 Sep 2010 16:48

Hi, Can anybody give me an example how to retrieve minutes and hours from a PCF8583 and add them to previously retrieved minutes and hours, and store them in a 24LC512?

Thank you.

drdoug
Posts: 1074
Joined: 16 Aug 2007 03:49
Location: St. Louis, MO

Re: add minutes and hours into a memory

#2 Post by drdoug » 01 Sep 2010 21:15

A quick start would be to check out the RTC example and Eeprom examples that mE provides. Post some code and we can help with that. Is this for a class project?

Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

Re: add minutes and hours into a memory

#3 Post by Olivia » 03 Sep 2010 13:35

Thanks for reply.

The project is for monitoring the hours and minutes an engine was on (for a diesel generator).
This is the whole code:

Code: Select all

//Declarations------------------------------------------------------------------
char usecs, seconds, minutes, hours, day, month, year;    // Global date/time variables
//--------------------------------------------------------------end-declarations

// Glcd module connections
char GLCD_DataPort at PORTD;

sbit GLCD_CS1 at LATB7_bit;  // for writing to output pin always use latch (PIC18 family)
sbit GLCD_CS2 at LATB6_bit;
sbit GLCD_RS  at LATB2_bit;
sbit GLCD_RW  at LATB3_bit;
sbit GLCD_EN  at LATB4_bit;
sbit GLCD_RST at LATB5_bit;  // for writing to output pin always use latch (PIC18 family)

sbit GLCD_CS1_Direction at TRISB7_bit;
sbit GLCD_CS2_Direction at TRISB6_bit;
sbit GLCD_RS_Direction  at TRISB2_bit;
sbit GLCD_RW_Direction  at TRISB3_bit;
sbit GLCD_EN_Direction  at TRISB4_bit;
sbit GLCD_RST_Direction at TRISB5_bit;
// End Glcd module connections


const char *Msg_0 = "Welcome"                ; // Message 0 for GLCD
const char *Msg_1 = "Olivia"                 ; // Message 1 for LCD
const char *Msg_2 = "Time:"                  ; // Message 2 for LCD
const char *Msg_3 = "Date:"                  ; // Message 3 for LCD
const char *Msg_4 = "Total time engine on:"  ; // Message 4 for LCD
const char *Msg_5 = "Bat:"                   ; // Message 9 for LCD    Battery level

char texts[20] ;     // copy constants from ROM to RAM
unsigned char ch, ch_0, ch_1;          // ADC
unsigned int adc_rd;       //
long tlong;                //

char aaa, aab, aac,aad,aae,aaf,aag,aah,aai, aga, agb, agc, agd ;

///////////////////////////////////////////////////////////////////////////////////////////////////
void strConstCpy(char *dest, const char *source) {      // --- Copying strings from ROM to RAM   //
  while(*source)                                                                                 //
    *dest++ = *source++ ;                                                                        //
                                                                                                 //
  *dest = 0 ;                                                                                    //
}//////////////////////////////////////////////////////////////////////////////////////////////////

void Beep() {
  PortA.F5 = 1     ;
    Delay_ms(100)  ;
  PortA.F5 = 0     ;
}

void Read_Time() {          // Reads time and date information from RTC (PCF8583)

  I2C1_Start();             // Issue start signal
  I2C1_Wr(0xA0);            // Address PCF8583, see PCF8583 datasheet
  I2C1_Wr(1);               // Start from address 1 ; was 2
  I2C1_Repeated_Start();    // Issue repeated start signal
  I2C1_Wr(0xA1);            // Address PCF8583 for reading R/W=1

  usecs = I2C1_Rd(1);     // Read useconds byte
  seconds = I2C1_Rd(1);     // Read seconds byte
  minutes = I2C1_Rd(1);     // Read minutes byte
  hours = I2C1_Rd(1);       // Read hours byte
  day = I2C1_Rd(1);         // Read year/day byte
  month = I2C1_Rd(0);       // Read weekday/month byte
  I2C1_Stop();              // Issue stop signal

}

void Transform_Time() {   //-------------------- Formats date and time
  usecs =  ((usecs & 0xF0) >> 4)*10 + (usecs & 0x0F);  // Transform useconds
  seconds  =  ((seconds & 0xF0) >> 4)*10 + (seconds & 0x0F);  // Transform seconds
  minutes  =  ((minutes & 0xF0) >> 4)*10 + (minutes & 0x0F);  // Transform months
  hours    =  ((hours & 0xF0)  >> 4)*10  + (hours & 0x0F);    // Transform hours
  year     =   (day & 0xC0) >> 6;                             // Transform year
  day      =  ((day & 0x30) >> 4)*10    + (day & 0x0F);       // Transform day
  month    =  ((month & 0x10)  >> 4)*10 + (month & 0x0F);     // Transform month

   aga = (hours / 10)   ;
   agb = (hours % 10)   ;
   agc = (minutes / 10) ;
   agd = (minutes % 10) ;

}

void Display_Time() {    //-------------------- Output values to LCD

   Glcd_Set_Font(font5x7, 5, 7, 32);          // Change font

    Glcd_Write_Char((hours / 10)   + 48, 33, 2, 1);
    Glcd_Write_Char((hours % 10)   + 48, 39, 2, 1);
    Glcd_Write_Char((minutes / 10) + 48, 50, 2, 1);
    Glcd_Write_Char((minutes % 10) + 48, 56, 2, 1);
    Glcd_Write_Char((seconds / 10) + 48, 67, 2, 1);
    Glcd_Write_Char((seconds % 10) + 48, 73, 2, 1);
    Glcd_Write_Char((usecs / 10) + 48, 84, 2, 1);
    Glcd_Write_Char((usecs % 10) + 48, 90, 2, 1);

    Glcd_Write_Char((day / 10)   + 48, 33, 4, 1);    // Print tens digit of day variable
    Glcd_Write_Char((day % 10)   + 48, 39, 4, 1);    // Print oness digit of day variable
    Glcd_Write_Char((month / 10) + 48, 51, 4, 1);
    Glcd_Write_Char((month % 10) + 48, 57, 4, 1);

   year += 10; // Print year vaiable + 10 (start from year 2010)
   Glcd_Write_Char((year/ 10) + 48, 81, 4, 1);
   Glcd_Write_Char((year% 10) + 48, 87, 4, 1);

}

void Set_Time() {

   I2C1_Init(100000);       // Initialize full master mode
   I2C1_Start();      // Issue start signal
   I2C1_Wr(0xA0);  // Address PCF8583, see PCF8583 datasheet
   I2C1_Wr(0);     // Start from address 0 (configuration memory location)
   I2C1_Wr(0x80);  // Write 0x80 to configuration memory location (pause counter...)
   I2C1_Wr(0);     // Write 0 to cents memory location
   I2C1_Wr(0x45);     // Write 0 to seconds memory location
   I2C1_Wr(0x15);  // Write 0x30 to minutes memory location
   I2C1_Wr(0x15);  // Write 0x12 to hours memory location

   I2C1_Wr(0x02);  // Write 0x24 to year/date memory location
   I2C1_Wr(0x06);  // Write 0x08 to weekday/month memory location
   I2C1_Stop();       // Issue stop signal

   I2C1_Start();      // Issue start signal
   I2C1_Wr(0xA0);  // Address PCF8530
   I2C1_Wr(0);     // Start from address 0
   I2C1_Wr(0);     // Write 0 to configuration memory location (enable counting)
   I2C1_Stop();       // Issue stop signal

  Delay_ms(2000);
}
void Show_Display_1() {

    Beep()   ;
    
  Glcd_Fill(0x00)  ;                         // Clear GLCD
  Glcd_Set_Font(font5x7, 5, 7, 32);     // Change font


    strConstCpy(texts,Msg_2)   ;
    Glcd_Write_Text(texts, 0, 2, 1)         ;    //Time:

    strConstCpy(texts,Msg_3)   ;
    Glcd_Write_Text(texts, 0, 4, 1)         ;    //Date:

    strConstCpy(texts,Msg_4)  ;
    Glcd_Write_Text(texts, 0, 6, 1)         ;     //Total time engine on:

    strConstCpy(texts,Msg_5)   ;
    Glcd_Write_Text(texts, 0, 0, 1)         ;      //Bat:

   Glcd_Write_Char(':', 45, 2, 1);
   Glcd_Write_Char(':', 62, 2, 1);
   Glcd_Write_Char(':', 79, 2, 1);

   Glcd_Write_Char('/', 45, 4, 1);
  Glcd_Write_Text("/20", 63, 4, 1);

 }
void Welcome() {

        Beep()   ;
  Glcd_Fill(0x00)  ;                         // Clear GLCD
  Glcd_Set_Font(Character8x7, 8, 7, 32);// Change font


    strConstCpy(texts,Msg_0)        ;
    Glcd_Write_Text(texts, 32, 2, 1)              ;

    strConstCpy(texts,Msg_1)        ;
    Glcd_Write_Text(texts, 36, 4, 1)              ;

    Delay_ms(2500)                  ;
  Glcd_Fill(0x00)  ;                         // Clear GLCD

    Show_Display_1()      ;
 }
void Read_ADC() {       //-----------Read ADC PortA.0-----------------------

    ADCON0.ADON = 1 ;                    //Turn ON the AD module
    adc_rd  = ADC_read(0);               // get ADC value from 2nd channel

    tlong = (long)adc_rd * 5000;         // covert adc reading to milivolts
    tlong = tlong / 1023;                // 0..1023 -> 0-5000mV

    ch_0     = tlong / 1000;               // extract volts digit
    Glcd_Write_Char(48+ch_0, 27, 0, 1);    // write ASCII digit at 2nd row, 5th column

    ch_1    = (tlong / 100) % 10;          // extract 0.1 volts digit
    Glcd_Write_Char(48+ch_1, 33, 0, 1);    // write ASCII digit at cursor point
    Glcd_Write_Char('.', 39, 0, 1);

    ch    = (tlong / 10) % 10;           // extract 0.01 volts digit
    Glcd_Write_Char(48+ch, 43, 0, 1);    // write ASCII digit at cursor point

     ch    = tlong % 10;                 // extract 0.001 volts digit
     Glcd_Write_Char(48+ch, 49, 0, 1);   // write ASCII digit at cursor point
    Glcd_Write_Char('V', 55, 0, 1);
    
    if(ch_0 >= 1) {
    if(ch_1 > 3) {
    
  I2C1_Start();           // issue I2C start signal
  I2C1_Wr(0b10100010);          // send byte via I2C  (device address + W)
  I2C1_Wr(0x00);      // send byte (address of EEPROM location)
  I2C1_Wr(0x0B);
  
//    I2C1_Wr(hours) ;
//    I2C1_Wr(minutes) ;
       I2C1_Wr(48) ;
       I2C1_Wr(48) ;
       I2C1_Wr(48) ;
       I2C1_Wr(48) ;
       I2C1_Wr(aga) ;
       I2C1_Wr(agb) ;
       I2C1_Wr(agc) ;
       I2C1_Wr(agd) ;
       

  I2C1_Stop();            // issue I2C stop signal
  Delay_ms(100);
//  I2C1_Repeated_Start();  // issue I2C signal repeated start
  I2C1_Start();           // issue I2C start signal
  
  I2C1_Wr(0b10100010);          // send byte via I2C  (device address + Write)
//  I2C1_Wr(2);             // send byte (data address)
  I2C1_Wr(0x00);      // send byte (address of EEPROM location)
  I2C1_Wr(0x0B);

  I2C1_Repeated_Start();  // issue I2C signal repeated start
  I2C1_Wr(0b10100011);          // send byte (device address + Read)
  aaa = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aab = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aac = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aad = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aae = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aaf = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aag = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aah = I2C1_Rd(0);    // Read the data (no acknowledge)

  I2C1_Stop();            // issue I2C stop signal
   Glcd_Write_Char(aaa ,32,7,1);
   Glcd_Write_Char(aab ,38,7,1);
   Glcd_Write_Char(aac ,44,7,1);
   Glcd_Write_Char(aad ,50,7,1);
   Glcd_Write_Char((aae / 10) + 48,56,7,1);
   Glcd_Write_Char((aaf % 10) + 48,62,7,1);
   Glcd_Write_Char(58,67,7,1);
   Glcd_Write_Char((aag / 10) + 48,72,7,1);
   Glcd_Write_Char((aah % 10) + 48,78,7,1);
   
    }
   }
    ADCON0.ADON = 0 ;                    //Turn OFF the AD module

    Delay_ms(1);
}

void main() {

    PORTA = 0      ;        //all pins are low
    TRISA = 0b00011111 ;    //pin0 is input for AD, pin4 input 
    LATA  = 0      ;

    PORTB = 0b00000000 ;    //pin1 is high for RTC init, rest of pins are low
    TRISB = 0;              //all pins are output
    LATB  = 0   ;

    PORTC = 0b10111000 ;    //pins3&4 are high for I2C, rest of pins are low
    TRISC = 0b10100000 ;    //pin5&7 are input
    LATC  = 0 ;

    PORTD = 0b00000000 ;    //all pins are low
    TRISD = 0b00011111 ;    //all pins are output
    LATD  = 0 ;

    PORTE = 0 ;             //all pins are low
    TRISE = 0b111 ;         //all pins are input 
    LATE  = 0 ;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ADCON0 = 0b00000010 ;    // controls the operation of the A/D module                                     //
    ADCON1 = 0b00011100 ;    // configures the functions of the port pins;  AN0 only                                 //
    ADCON2 = 0b10010100 ;    // configures the A/D clock source, acquisition time and justification
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  CMCON  |= 7;            //0b00000111                  // Disable comparators

  Glcd_Init();                                   // Initialize GLCD
  Glcd_Fill(0x00);                               // Clear GLCD

  I2C1_Init(100000);           // Initialize Soft I2C communication

  Delay_ms(400);

   Welcome() ;
   Show_Display_1() ;

while(1) {        // Endless loop

    Read_Time();             // Read time from RTC(PCF8583)
    Transform_Time();        // Format date and time
    Display_Time();          // Prepare and display on LCD

//    Delay_ms(1000);          // Wait 1 second

      Read_ADC()         ;         // Read AN0
  }

}
I know this is far from what I want, but I started like this.
With this code as it is now I can read the time and date and write them into the memory, but when I read them back I get 0 (zero) for tens of hours and for tens of minutes.

I think this is the way to go:
when starting the engine read the time and keep it into a variable -a-
when engine is stopped, read again the time and put it into another variable -b-
then b-a = c (time that engine was on this time)
then d = c + d (global time engine was on)

As you see from the code, if analog reading is >13V it will add the time into the memory (when engine is on, the alternator produces more than 13.4V. so this is the way I am monitoring if the engine is on or off)


Any suggestions?

Thank you.

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: add minutes and hours into a memory

#4 Post by Sobrietytest » 04 Sep 2010 11:07

Any suggestions?
Yes, don't use an RTCC for this application! You're going to run into all sorts of bother with the maths especially if the generator is running across midnight on New Years Eve.

Maxim make chips exactly for this purpose, such as the DS1682 (http://datasheets.maxim-ic.com/en/ds/DS1682.pdf), which can record up to 34 years of usage on its own EEPROM - it's all done internally and automatically so you won't have to worry about any of the code for the accumulator. And it also has it's own temperature stabilised oscillator which means it will be much more accurate than an external 32kHz xtal.

Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

Re: add minutes and hours into a memory

#5 Post by Olivia » 05 Sep 2010 13:55

Thanks Sobrietytest

I didn't know about such chips.
I'll use it.

Thanks again.

Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

Re: add minutes and hours into a memory

#6 Post by Olivia » 08 Sep 2010 16:31

Hi,

I've got the chip (DS1682+) in the circuit up and running.

Only...
it seems to increment every 26 countings
and it does not increment at a second interval.

The datasheet is too cryptic for me to understand.

Can anybody help?

this is the code:

Code: Select all

void Read_Rec() {   // read recordings

  I2C1_Start();           // issue I2C start signal
  I2C1_Wr(0b11010110);    // send DS1682 device address + Write
  I2C1_Wr(0x05);      // address of Elapsed Time Counter ETC location
  I2C1_Repeated_Start();  // issue I2C signal repeated start
  I2C1_Wr(0b11010111);    // send DS1682 device address + Read
  aaa = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aab = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aac = I2C1_Rd(1);    // Read the data (yes acknowledge)
  aad = I2C1_Rd(1);    // Read the data (yes acknowledge)
  
  aae = I2C1_Rd(0);    // Read the data (no acknowledge)

  I2C1_Stop();            // issue I2C stop signal
  

  aaa  =  ((aaa & 0xF0) >> 4)*10 + (aaa & 0x0F);
  aab  =  ((aab & 0xF0) >> 4)*10 + (aab & 0x0F);
  aac  =  ((aac & 0xF0) >> 4)*10 + (aac & 0x0F);
  aad  =  ((aad & 0xF0) >> 4)*10 + (aad & 0x0F);
  aae  =  ((aae & 0xF0) >> 4)*10 + (aae & 0x0F);

   Glcd_Write_Char((aad / 10) + 48, 12,7,1);
   Glcd_Write_Char((aad % 10) + 48, 18,7,1);
   
   Glcd_Write_Char((aac / 10) + 48, 24,7,1);
   Glcd_Write_Char((aac % 10) + 48, 30,7,1);

   Glcd_Write_Char((aab / 10) + 48, 36,7,1);
   Glcd_Write_Char((aab % 10) + 48, 42,7,1);

   Glcd_Write_Char((aaa / 10) + 48, 49,7,1);
   Glcd_Write_Char((aaa % 10) + 48, 55,7,1);

   Glcd_Write_Char((aae / 10) + 48, 102,7,1);    //  event counter
   Glcd_Write_Char((aae % 10) + 48, 108,7,1);    //  event counter
   
}
So, as soon as the event pin goes high, I can see the numbers going up
(aaa % 10) goes from 0 (zero) to 9, then again 0-9, then 0-5, then (aae / 10) is incremented and aaa goes again to 0-9, 0-9, 0-5
(aae / 10) goes from 0 (zero) to I (capital i)

????
what am I doing wrong?

Regards

User avatar
ranko.rankovic
Posts: 433
Joined: 11 Jun 2010 09:22

Re: add minutes and hours into a memory

#7 Post by ranko.rankovic » 09 Sep 2010 11:57

Hello Olivia,

Please consider our examples for RTC and EEPROM that come within our software bundle. They can be found in folder where compiler is installed (\Examples\Extra Boards\). They may lead you to solution.

Best regards
Ranko Rankovic
mikroElektronika [Support Department]

Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

Re: add minutes and hours into a memory

#8 Post by Olivia » 09 Sep 2010 14:26

Thanks for trying ranko

This is exactly what I have done.

I copied your example for RTC, and just changed the seconds, minutes, hours to my aaa,aab,aac....and of course the chip address

The problem is that in your example the RTC chip increments every second (that's why the code works);
But in my application the DS1682 chip increments in quarter of a second (and that's why my code does not work).

What should I add/modify so it will work correctly?

Regards.

Olivia
Posts: 39
Joined: 12 Feb 2010 12:31

Re: add minutes and hours into a memory

#9 Post by Olivia » 12 Sep 2010 00:07

Sorry, maybe I did not explain corectly what I want and what the problem is:

So I want to record the total time an engine was runing for.
Not just the last run, but the total run over the years.
So let's say it is running for 2 hours daily for 20 years that would give a total of 14600 hours.
You see, a diesel generator doesn't do any miles, like a car, so you wouldn't know when it's been 6000 miles so you change the oil and the filters.
Recording the time will tell you when it needs a new oil and filters.


Now the problem is that this chip (DS1682) increments every quarter of a second.
So, I got the reading from the chip, I divide it by 4 and still it looses about 6 or 7 secons every minute.
It supposed to be more accurate than an external 32k crystal.
And probably is.
I just need to see how to do it.

The previous aproach was wrong, as this chip does not give the output in BCD format as an RTC chip.
So I found that doing:

Code: Select all

aaa = I2C1_Rd(1);    // Read the data (yes acknowledge)
ByteToStr(aaa, txt) ;
Glcd_Write_Text(txt, 49,7,1);
gives a better result.
Now I can see the readings going up from 0 to 255, then next bit aab is incremented, and aaa starts again from 0
And if I do:

Code: Select all

aaa /=4.2667 ;
ByteToStr(aaa, txt) ;
Glcd_Write_Text(txt, 49,7,1);
I can see it going up from 0 to 59, like real seconds in a RTC chip.
But it is not acurate. It looses about 7 seconds every minute. Even if I don't divide it by 4.2667 it looses the same seconds.


Is there a way to close a thread?
Because I opened another one about the same problem, and I would like to close this one, carry on on the other.

Regards.

Post Reply

Return to “mikroC PRO for PIC General”