CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

RTC with DS3232

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

RTC with DS3232
PostPosted: Thu Feb 06, 2014 2:19 am     Reply with quote

Dear developers, in continuation of my topics of RTC, I decided to switch to chip DS3232 real time. Using driver http://www.ccsinfo.com/forum/viewtopic.php?t=43474&highlight=ds3232
I began to deal with the chip:
When you turn on the power, chip output INT / SQW attending generation 1Hz, although according to the code i2c_write (00000100) its prohibited.
Next I want to use 2 alarm, perform an action, can somebody show me how to do it?

Thanks in advance, previous threads on real time clock will need to be closed.
Code:

#include <16F1829.h>
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES WDT_SW                   //No Watch Dog Timer, enabled in Software
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#use delay(int=32M)

#use rs232(xmit=PIN_C4,RCV=PIN_C5,BAUD=9600,ERRORS)

#include "ds3232.c"

int1 flag_init_programm=false;
unsigned char Buffer[21],sec=0,min=0,hour=0,month=0,day=0,dow=0,year=14,i_buff=0,i=0,i_timer1=0;
int16 CRC;

#define         LED_PROGRAMM      PIN_C3
#define         EXTERNAL_POWER      PIN_A0
#define         INT_SQW            PIN_B7
#define         RESET_DS3232      PIN_C6
#define         DIRECT_MOC         PIN_C7
#define         OUT_HC251         PIN_B5
#define         A0               PIN_C2
#define         A1               PIN_C1
#define         A2               PIN_C0
#define         DIDECT_PWM         PIN_A2
#define         INT_PROGRAMM      PIN_A4



//=====================CRC=========================================
int16 Calc_Crc16(int8 *Buffer, int16 Len)
{
   int16 x;
   int16 crc = 0xFFFF;
   
   while(Len--)
   {
      x = make8(crc,1) ^ *Buffer++;
      x ^= x>>4;
     
      crc = (crc << 8) ^ (x << 12) ^ (x <<5) ^ x;
   }
   return crc;


void crc_detect(void)
 {
   CRC = Calc_Crc16(Buffer, sizeof(Buffer)-2);
    if( make8(CRC, 1)== Buffer[19] && make8(CRC, 0)== Buffer[20])
       {
       year=Buffer[13];
      month=Buffer[14];
      day=Buffer[15];
      hour=Buffer[16];
      min=Buffer[17];
      sec=Buffer[18];

      output_high(LED_PROGRAMM);
      delay_ms(500);
      output_low(LED_PROGRAMM);

      clear_interrupt(INT_RA4);
      enable_interrupts(INT_RA4);

      DS3232init();
      DS3232setTime(hour, min, sec);
      DS3232setDate(day, month, year);

      flag_init_programm=false;
      }
    
 }

#INT_TIMER1

 void TIMER1_isr(void)
{
   i_timer1++;
   if(i_timer1>=10)
   {
      i_timer1=0;
      DS3232getTime(hour, min, sec);
      DS3232getDate(dow,day,month,year);
      printf("\f\%02d/\%02d/\%02d\/\%02d\r\n",dow,day,month,year);
       printf("\%02d:\%02d:\%02d", hour,min,sec);
   }
   
}   



#INT_RA
void RA_isr()
   {
   if(input(INT_PROGRAMM))
      {
      flag_init_programm=true;
      //output_high(LED_PROGRAMM);
      clear_interrupt(INT_RA4);
      disable_interrupts(INT_RA4);
      }
   }



void main(void)
{
enable_interrupts(global);
setup_oscillator(OSC_8MHZ|OSC_NORMAL|OSC_PLL_ON,0);

for(i=0;i<22;i++)Buffer[i]=0;

output_low(RESET_DS3232);
delay_ms(1);
output_high(RESET_DS3232);

output_low(DIDECT_PWM);
output_low(A0);
output_low(A1);
output_low(A2);

setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);   
enable_interrupts(INT_TIMER1);
set_timer1(0);


delay_ms(10);
enable_interrupts(INT_RA4);
//sleep();


   while(true)
   {
   //if(flag_init_programm==false)sleep();
//   else{
      if(kbhit()&&flag_init_programm==true)
      {   
      buffer[i_buff]=getc();
       i_buff++; 

      if(i_buff==21)
            {
            i_buff=0;
            crc_detect();
            
            }
      }

//   }

   }


}



driver:

Code:

/* SUJET            : Driver de la RTC "DS3232"                                                                 */
/* librement inspire dehttp://www.cursomicros.com/control_i2c/c03_07_ds3232_prog.html et     */
/* porte vers CCS                                                                                                     */
/*                                                                                                                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * Definition des adresses * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*** Definition des adresses sur la RTC ***/
#define DS3232receive    11010000            //  0xD0 Adresse pour ecriture du µC vers la RTC
#define DS3232transmit    11010001            // 0xD1   Adresse pour lecture sur la RTC depuis le µC

/*** Configuration et initialisation du bus I?C ***/
//Considere comme deja connu, enlever le commentaire si necessaire
#define I2C_SDA         PIN_B4
#define I2C_SCL         PIN_B6
#use i2c(master, sda=I2C_SDA, scl=I2C_SCL)

/* * * Declaration des procedures et fonctions * * * * * * * * * * * * * * * * * * * * * * */
void DS3232init ();                                                                // Initalisation de la RTC
void DS3232setTime(BYTE h, BYTE min, BYTE s);                            // Configuration de l'heure
void DS3232setDate(BYTE day, BYTE month, BYTE year);                    // Configuration de la date
void DS3232getTime(BYTE &h, BYTE &min, BYTE &s);                        // Lecture de l'heure
void DS3232getDate(BYTE &dow, BYTE &day, BYTE &month, BYTE &year);// Lecture de la date

BYTE bin2bcd(BYTE binary_value);        // Convertion BIN --> BCD
BYTE bcd2bin(BYTE bcd_value);            // Convertion BCD --> BIN (plage d'entree 0 -> 99)

/* * * Code source des procedures et fonctions * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* BYTE BIN2bcd(BYTE binary_value)                                                                             */
/* Converti la "Binary Value" en BCD                                                                          */
/* Source : http://www.ccsinfo.com/forum/viewtopic.php?t=23255                                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;
  temp = binary_value;
  retval = 0;
  while(true)
  {
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else
    {
      retval += temp;
      break;
    }
  }
  return(retval);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* BYTE BIN2bcd(BYTE binary_value)                                                                             */
/* Converti la "Binary Value" en BCD                                                                          */
/* Source : http://www.ccsinfo.com/forum/viewtopic.php?t=23255                                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BYTE bcd2bin(BYTE bcd_value)        // Input range - 00 to 99.
{
  BYTE temp;
  temp = bcd_value;
  temp >>= 1;
  temp &= 0x78;
  return(temp + (temp >> 2) + (bcd_value & 0x0f));
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DAYOFTHEWEEK(day, month, year)                                                                             */
/* Retourne le jour de la semaine sous la forme d'un numero.  0 est le dimanche.                 */
/* Informations sur la Congruence de Zeller:  http://c-faq.com/misc/zeller.html                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int DayOfTheWeek(int Day, int Month, int16 Year) {   
    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    year=year+2000;
    year -= month < 3;
    return (year + year/4 - year/100 + year/400 + t[month-1] + day) % 7;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232INIT()                                                                                                     */
/* Initialisation de la RTC : Remise de tous les flags a 0 ; Activation de l'oscillateur ; */
/* Pas de compensation en temperature manuelle ; Compensation automatique toutes les 64s.     */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DS3232init () {
    // Initialisation de l'I?C
    output_float (I2C_SDA);
    output_float (I2C_SCL);
   
    // Initialisation du registre CONTROL
    i2c_start();
    i2c_write(DS3232receive);        // Transmission vers la RTC
    delay_us(10);
    i2c_write(0x0E);                    // Adresse du registre CONTROL
    delay_us(10);
    i2c_write(00000100);                // Data : Activation de l'oscillateur seulement
    delay_us(10);
    i2c_stop();   
   
    // Initialisation du registre CONTROL/STATUS
    i2c_start();
    i2c_write(DS3232receive);        // Transmission vers la RTC
    delay_us(10);
    i2c_write(0x0F);                    // Adresse du registre CONTROL/STATUS
    delay_us(10);
    i2c_write(00000000);                // Data : Aucune activation + remise des flags a 0
    delay_us(10);
    i2c_stop();   
   
    // Initialisation du registre AGING OFFSET
    i2c_start();
    i2c_write(DS3232receive);        // Transmission vers la RTC
    delay_us(10);
    i2c_write(0x10);                    // Adresse du registre AGNIG OFFSET
    delay_us(10);
    i2c_write(00000000);                // Data : Aucune compensation en temperature manuelle
    delay_us(10);
    i2c_stop();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232setTime(h, min, s)                                                                                     */
/* Regle l'heure (h), les minutes (min) et les secondes (s) de l'horlge                             */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DS3232setTime(BYTE h, BYTE min, BYTE s) {
    i2c_start();
    i2c_write(DS3232receive);            // Transmission vers la RTC
    i2c_write(0x00);                        // 0x00 Adresse du registre des secondes
    i2c_write(bin2bcd(s & 0x7F));        // 0x00 Data : Secondes
    i2c_write(bin2bcd(min & 0x7F));    // 0x01 Data : Minutes
    i2c_write(bin2bcd(h & 0x3F));        // 0x02 Data : Heures - Mode "24h"
    i2c_stop();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232setDate(day, month, year)                                                                             */
/* Regle la date : jour, mois, annee.  Le jour de la semaine est calcule par la                  */
/* Congruence de Zeller                                                                                               */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DS3232setDate(BYTE day, BYTE month, BYTE year) {
    i2c_start();
    i2c_write(DS3232receive);            // Transmission vers la RTC
    i2c_write(0x03);                        // 0x03 Adresse du registre du jour de la semaine
    i2c_write(bin2bcd(DayOfTheWeek(day,month,year) & 0x07));        // 0x03 Data : Nom du jour
    i2c_write(bin2bcd(day));            // 0x04 Data : Jour
    i2c_write(bin2bcd(month));            // 0x05 Data : Mois
    i2c_write(bin2bcd(year));            // 0x06 Data : Annee
    i2c_stop();
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232setAlarmA()                                                                                                 */
/*                                                                                                                       */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232setAlarmB()                                                                                                 */
/*                                                                                                                       */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232getTime(&h, &min, &s)                                                                                 */
/* Recupere l'heure au format Heure : Minutes : Secondes                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DS3232getTime(BYTE &h, BYTE &min, BYTE &s) {
    i2c_start();
    i2c_write(DS3232receive);
    i2c_write(0x00);                            // Positionnement sur le registre des secondes
    i2c_start();
    i2c_write(DS3232transmit);                // Transmission depuis la RTC vers le µC
    s=bcd2bin(i2c_read() & 0x7F);            // 0x00 Data : Secondes
    min=bcd2bin(i2c_read() & 0x7F);        // 0x01 Data : Minutes
    h=bcd2bin(i2c_read(0) & 0x3F);        // 0x02 Data : Heures
    i2c_stop();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* DS3232getDate(&dow, &day, &month, &year)                                                                 */
/* Recupere le jour de la semaine et la date au format jour / mois / annee                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DS3232getDate(BYTE &dow, BYTE &day, BYTE &month, BYTE &year) {
    i2c_start();
    i2c_write(DS3232receive);
    i2c_write(0x03);                            // Positionnement sur le registre des secondes
    i2c_start();
    i2c_write(DS3232transmit);                // Transmission depuis la RTC vers le µC
    dow=bcd2bin(i2c_read() & 0x07);            // 0x03 Data : Jour de la semaine
    day=bcd2bin(i2c_read() & 0x3F);        // 0x04 Data : Jour
    month=bcd2bin(i2c_read() & 0x1F);        // 0x05 Data : Mois
    year=bcd2bin(i2c_read(0));        // 0x06 Data : Annee
    i2c_stop();
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Thu Feb 06, 2014 4:29 am     Reply with quote

Hint: what is the difference between 00000100, and 0b0000010?......
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

PostPosted: Thu Feb 06, 2014 4:57 am     Reply with quote

Ttelmah wrote:
Hint: what is the difference between 00000100, and 0b0000010?......


UPSSS, thank you!!! I will understand more!
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

DS3232
PostPosted: Fri Feb 07, 2014 3:08 am     Reply with quote

Generate an interrupt task every day at the same time.
Wrote a function to set the alarm time
Code:

void DS3232setAlarm1(BYTE h, BYTE min, BYTE s){
   i2c_start();
    i2c_write(DS3232receive);            // Запись в DS3232
    i2c_write(0x07);                     // адрес регистра с которого начнется запись
   i2c_write(bin2bcd(s & 0x7F));        // 0x00 Data : Secondes
    i2c_write(bin2bcd(min & 0x7F));       // 0x01 Data : Minutes
    i2c_write(bin2bcd(h & 0x3F));        // 0x02 Data : Heures - Mode "24h"
   i2c_write(0x80);                 // Alarm when hours, minutes, seconds match
   i2c_stop();

use it like this:
Code:

DS3232setAlarm1(0, 0, 10);

control register:
Code:

i2c_start();
    i2c_write(DS3232receive);        // Transmission vers la RTC
    delay_us(10);
    i2c_write(0x0E);                    // Adresse du registre CONTROL
    delay_us(10);
    i2c_write(0b00000111);                // Разрешение на прерывание от будильника 1
    delay_us(10);
    i2c_stop();   

But no change in status of the port INT/SQW.
What could be the problem?
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

PostPosted: Sun Feb 09, 2014 1:58 am     Reply with quote

Please help to deal with the alarm clock, I had never worked with I2с?
temtronic



Joined: 01 Jul 2010
Posts: 9178
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Feb 09, 2014 6:46 am     Reply with quote

First, I would strongly urge you to create an 'LCDclock' program. Add an LCD module to your PIC and cut code to display the RTC time onto it.This would be a simple 'read the RTC regicters and display them, delay_ms(1000), in a while(true) loop.
Second,once you've got that working, then create an ISR for the 1Hz interrupt the RTC can output to the PIC.Be sure to add a pullup resisitor( 3k3 will work).Within the ISR, just set a flag and exit.In Main(), test if the flag is set,then get the RTC data,display them, reset flag, do nothing.
third.When that's working correctly, THEN cut code to test for the 'alarm' functions of the RTC.There are 2 or more ways to do t, the choice is yours.
You really need to do #1 and #2! If you don't use the LCD module you can send data to the PC,but a 'clock' normally has a local display.

hth
jay
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

PostPosted: Sun Feb 09, 2014 7:30 am     Reply with quote

temtronic wrote:
First, I would strongly urge you to create an 'LCDclock' program. Add an LCD module to your PIC and cut code to display the RTC time onto it.This would be a simple 'read the RTC regicters and display them, delay_ms(1000), in a while(true) loop.
Second,once you've got that working, then create an ISR for the 1Hz interrupt the RTC can output to the PIC.Be sure to add a pullup resisitor( 3k3 will work).Within the ISR, just set a flag and exit.In Main(), test if the flag is set,then get the RTC data,display them, reset flag, do nothing.
third.When that's working correctly, THEN cut code to test for the 'alarm' functions of the RTC.There are 2 or more ways to do t, the choice is yours.
You really need to do #1 and #2! If you don't use the LCD module you can send data to the PC,but a 'clock' normally has a local display.

hth
jay

Dear "temtronic" I get the time on the pc with ds3232, I can not setup my alarm clock to generate the signal for PIN RST/SQW.

Code:

void DS3232setAlarm1(BYTE h, BYTE min, BYTE s){
i2c_start();
i2c_write(DS3232receive); // Запись в DS3232
i2c_write(0x07); // адрес регистра с которого начнется запись
i2c_write(bin2bcd(s & 0x7F)); // 0x00 Data : Secondes
i2c_write(bin2bcd(min & 0x7F)); // 0x01 Data : Minutes
i2c_write(bin2bcd(h & 0x3F)); // 0x02 Data : Heures - Mode "24h"
i2c_write(0x80); // Alarm when hours, minutes, seconds match
i2c_stop();

use it like this:

Code:

DS3232setAlarm1(0, 0, 10);

SETING control register:
Code:

i2c_start();
    i2c_write(DS3232receive);        // Transmission vers la RTC
    delay_us(10);
    i2c_write(0x0E);                    // Adresse du registre CONTROL
    delay_us(10);
    i2c_write(0b00000111);                // Разрешение на прерывание от будильника 1
    delay_us(10);
    i2c_stop();   
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Feb 09, 2014 8:11 am     Reply with quote

maxikys wrote:
Ttelmah wrote:
Hint: what is the difference between 00000100, and 0b0000010?......


UPSSS, thank you!!! I will understand more!
Now you fixed that one, did you fix the others too?
Code:
#define DS3232receive    11010000            //  0xD0 Adresse pour ecriture du µC vers la RTC
#define DS3232transmit    11010001            // 0xD1   Adresse pour lecture sur la RTC depuis le µC


I know you are not the original author of this code, but personally, I don't like it when in the code it is written as 11010000 and then in the comment it says 0xD0. Why not write directly 0xD0 in the code? The compiler does understand the hexadecimal notation and it avoids problems where you change one value and forget to change the other.

Code:
#define DS3232receive   0xD0                // Adresse pour ecriture du µC vers la RTC
#define DS3232transmit  (DS3232receive + 1) // Adresse pour lecture sur la RTC depuis le µC



A minor problem is in the lines like this:
Code:
i2c_write(bin2bcd(s & 0x7F)); // 0x00 Data : Secondes
You want to set the highest bit always to 0, that is why the 0x7F filter is there. Good, but the location of the '()' is wrong. Change to:
Code:
i2c_write(bin2bcd(s) & 0x7F); // 0x00 Data : Secondes
maxikys



Joined: 25 Jul 2013
Posts: 17

View user's profile Send private message AIM Address

PostPosted: Sun Feb 09, 2014 11:30 am     Reply with quote

ckielstra wrote:
maxikys wrote:
Ttelmah wrote:
Hint: what is the difference between 00000100, and 0b0000010?......


UPSSS, thank you!!! I will understand more!
Now you fixed that one, did you fix the others too?
Code:
#define DS3232receive    11010000            //  0xD0 Adresse pour ecriture du µC vers la RTC
#define DS3232transmit    11010001            // 0xD1   Adresse pour lecture sur la RTC depuis le µC


I know you are not the original author of this code, but personally, I don't like it when in the code it is written as 11010000 and then in the comment it says 0xD0. Why not write directly 0xD0 in the code? The compiler does understand the hexadecimal notation and it avoids problems where you change one value and forget to change the other.

Code:
#define DS3232receive   0xD0                // Adresse pour ecriture du µC vers la RTC
#define DS3232transmit  (DS3232receive + 1) // Adresse pour lecture sur la RTC depuis le µC



A minor problem is in the lines like this:
Code:
i2c_write(bin2bcd(s & 0x7F)); // 0x00 Data : Secondes
You want to set the highest bit always to 0, that is why the 0x7F filter is there. Good, but the location of the '()' is wrong. Change to:
Code:
i2c_write(bin2bcd(s) & 0x7F); // 0x00 Data : Secondes


I did as you advised and alarm began to form on the leg microcontroller logic "0".
Now to reset to "0" pin INT/SQW I must clear the bit in the register A1F Control / Status Register (0Fh)?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Feb 09, 2014 4:06 pm     Reply with quote

I never used this chip, but if I understand the datasheet correctly then the interrupt signal from the DS3232 will be there for 1 second and disappears then automatically. No action for clearing the interrupt on the RTC chip is required.
For the PIC it is a bit different, when you use a level sensitive interrupt input then the PIC will get triggered the whole second. This is not what you want. Easiest is to use a level triggered input on the PIC.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group