Hi everyone,
I try since few weeks now to communicate between a homemade board with ATMEGA328P running at 20MHZ
and a TINY RTC MODULE bought on ebay for few dollars.
I checked twice my wiring (SCL and SDA, VCC and GND, pullup resistors etc)
I’ve already try :
-
Cut the charging circuit to work with CR2032 instead of LIR2032
-
Change the crystal oscillator by one picked up in a wall clock
-
I made a SMT board home with the essential : DS1307, quartz and battery holder
My display always show the DS1307 adress instead of hour, minute, seconds :
68/68/68
68h68m.68s
I’m quite sure the problem comes from the code. I post it so that everyone can see it
#define F_SCL 100000L // I2C clock speed 100 KHz
#define READ 1
#define TW_START 0xA4 //condition de départ (TWINT,TWSTA,TWEN)
#define TW_STOP 0x94 //condition d'arret (TWINT,TWSTO,TWEN)
#define TW_ACK 0xC4 //Retour de l'ACK (acknowledgment) a l'esclave
#define TW_NACK 0x84 //Pas de retour de l'ACK (acknowledgment) a l'esclave
#define TW_SEND 0x84 //Commande d'envoi de donnée (TWINT,TWEN)
#define TW_READY (TWCR & 0x80) // Prêt quand TWINT repasse a 1 (registre de controle TWCR)
#define TW_STATUS (TWSR & 0xF8) // Valeur retournée au registre de status TWSR
#define I2C_Stop() TWCR = TW_STOP // Macro de stop
//**********************************DS1307 RTC********************************
#define DS1307 0x68 //adresse DS1307
#define SECONDS_REGISTER 0x00
#define MINUTES_REGISTER 0x01
#define HOURS_REGISTER 0x02
#define DAYOFWK_REGISTER 0x03
#define DAYS_REGISTER 0x04
#define MONTHS_REGISTER 0x05
#define YEARS_REGISTER 0x06
#define CONTROL_REGISTER 0x07
#define RAM_BEGIN 0x08
#define RAM_END 0x3F
void dateheure(){
char* Affjour=" ";
char* Affmois=" ";
char* Affannee=" ";
char* Affheure=" ";
char* Affminute=" ";
char* Affseconde=" ";
sortie=1;
lcd_clrscr();
lcd_gotoxy(3,0);
lcd_puts("DATE ET HEURE");
DDRC|= (1<<PC4);
PORTC |=(1<<PC4);
_delay_ms(10);
PORTC&=~ (1<<PC4);
_delay_ms(10);
DDRC&=~(1<<PC4)|(1<<PC5);
while (sortie !=0){
keyboard=kbd();
switch (keyboard){
case 0 : main();
break;
case 13 :
I2C_Init();
DS1307_GetDate(&months,&days,&years);
DS1307_GetTime(&hours,&minutes,&seconds);
sprintf(Affjour, "%i", bcdToDec(days));
sprintf(Affmois, "%i", bcdToDec(months));
sprintf(Affannee, "%i", bcdToDec(years));
sprintf(Affheure, "%i", bcdToDec(hours));
sprintf(Affminute, "%i", bcdToDec(minutes));
sprintf(Affseconde, "%i", bcdToDec(seconds));
lcd_gotoxy(0,1);
lcd_puts(Affjour);
lcd_puts("/");
lcd_puts(Affmois);
lcd_puts("/");
lcd_puts(Affannee);
lcd_gotoxy(0,2);
lcd_puts(Affheure);
lcd_puts("h");
lcd_puts(Affminute);
lcd_puts(".");
lcd_puts(Affseconde);
break;
}
}
}
byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
return ( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val){
// Convert binary coded decimal to normal decimal numbers
return ( (val/16*10) + (val%16) );
}
// ---------------------------------------------------------------------------
// I2C (TWI) ROUTINES
//
// On the AVRmega series, PA4 is the data line (SDA) and PA5 is the clock (SCL
// The standard clock rate is 100 KHz, and set by I2C_Init. It depends on the AVR osc. freq.
void I2C_Init()
// TWBR=16/(16+2(TWBR)), prescalar = 0.
// Pour 100KHz SCL, TWBR = ((F_CPU/F_SCL)-16)/2 = ((16/0.1)-16)/2 = 184/2 = 92.
{
//PORTC&=~(1<<PC4)|(1<<PC5);
TWSR = 0; // set prescalar to zero
//TWBR = ((F_CPU/F_SCL)-16)/2; // set SCL frequency in TWI bit register
TWBR =0x5c;
}
byte I2C_Start (byte slaveAddr)
{
TWCR = TW_START; //condition de depart
while (!TW_READY); //Attente
TWDR = slaveAddr; //on charge l'adresse de l'esclave
TWCR = TW_SEND; //on lance l'envoi
while (!TW_READY); //Et on attent
return (TW_STATUS==0x18); // return 1 if found; 0 otherwise
}
byte I2C_Write (byte data) //envoi de donnees a l'esclave
{
TWDR = data; //On charge la donnée dans le registre de données
TWCR = TW_SEND; //on lance l'envoi
while (!TW_READY); //Attente
return (TW_STATUS!=0x28);
}
byte I2C_ReadACK () // reads a data byte from slave
{
TWCR = TW_ACK; // ack = will read more data
while (!TW_READY); // wait
return TWDR;
//return (TW_STATUS!=0x28);
}
byte I2C_ReadNACK () // reads a data byte from slave
{
TWCR = TW_NACK; // nack = not reading more data
while (!TW_READY); // wait
return TWDR;
//return (TW_STATUS!=0x28);
}
void I2C_WriteByte(byte busAddr, byte data)
{
I2C_Start(busAddr); // send bus address
I2C_Write(data); // then send the data byte
I2C_Stop();
}
void I2C_WriteRegister(byte busAddr, byte deviceRegister, byte data)
{
I2C_Start(busAddr); // send bus address
I2C_Write(deviceRegister); // first byte = device register address
I2C_Write(data); // second byte = data for device register
I2C_Stop();
}
byte I2C_ReadRegister(byte busAddr, byte deviceRegister)
{
byte data = 0;
I2C_Start(busAddr); // send device address
I2C_Write(deviceRegister); // set register pointer
I2C_Start(busAddr+READ); // restart as a read operation
data = I2C_ReadACK(); // read the register data
I2C_Stop(); // stop
return data;
}
void DS1307_GetTime(byte *hours, byte *minutes, byte *seconds)
// returns hours, minutes, and seconds in BCD format
{
*hours = I2C_ReadRegister(DS1307,HOURS_REGISTER);
*minutes = I2C_ReadRegister(DS1307,MINUTES_REGISTER);
*seconds = I2C_ReadRegister(DS1307,SECONDS_REGISTER);
if (*hours & 0x40) // 12hr mode:
*hours &= 0x1F; // use bottom 5 bits (pm bit = temp & 0x20)
else *hours &= 0x3F; // 24hr mode: use bottom 6 bits
}
void DS1307_GetDate(byte *months, byte *days, byte *years)
// returns months, days, and years in BCD format
{
*months = I2C_ReadRegister(DS1307,MONTHS_REGISTER);
*days = I2C_ReadRegister(DS1307,DAYS_REGISTER);
*years = I2C_ReadRegister(DS1307,YEARS_REGISTER);
}
void SetTimeDate()
// simple, hard-coded way to set the date.
{
I2C_WriteRegister(DS1307,MONTHS_REGISTER, 0x08);
I2C_WriteRegister(DS1307,DAYS_REGISTER, 0x31);
I2C_WriteRegister(DS1307,YEARS_REGISTER, 0x13);
I2C_WriteRegister(DS1307,HOURS_REGISTER, 0x08+0x40); // add 0x40 for PM
I2C_WriteRegister(DS1307,MINUTES_REGISTER, 0x51);
I2C_WriteRegister(DS1307,SECONDS_REGISTER, 0x00);
}