|
|
View previous topic :: View next topic |
Author |
Message |
maxikys
Joined: 25 Jul 2013 Posts: 17
|
RTC with DS3232 |
Posted: Thu Feb 06, 2014 2:19 am |
|
|
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: 19541
|
|
Posted: Thu Feb 06, 2014 4:29 am |
|
|
Hint: what is the difference between 00000100, and 0b0000010?...... |
|
|
maxikys
Joined: 25 Jul 2013 Posts: 17
|
|
Posted: Thu Feb 06, 2014 4:57 am |
|
|
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
|
DS3232 |
Posted: Fri Feb 07, 2014 3:08 am |
|
|
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
|
|
Posted: Sun Feb 09, 2014 1:58 am |
|
|
Please help to deal with the alarm clock, I had never worked with I2с? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Sun Feb 09, 2014 6:46 am |
|
|
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
|
|
Posted: Sun Feb 09, 2014 7:30 am |
|
|
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
|
|
Posted: Sun Feb 09, 2014 8:11 am |
|
|
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
|
|
Posted: Sun Feb 09, 2014 11:30 am |
|
|
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
|
|
Posted: Sun Feb 09, 2014 4:06 pm |
|
|
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. |
|
|
|
|
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
|