Led clock thermometer with DS1302 |
LM35 is connected to analogue pin 5 (A5) and rtc module pins can be configured in the sketch (14,15,16 ie analogue pin A0, A1 and A2) .
Connect all the components as shown in figure and upload the sketch below. Make sure that led module is connected with a 220 ohm resistor to limit the current and prevent the damage to atmega/led (see here).
// Arduino Clock thermometer with RTC1302 and LM35 by Riyas (blog.riyas.org)
// Uses arduino uno and seven segment led display (direct drive)
// LM 35 for temperature sensing
// Credits to krodal (arduino.cc) and hobbycomponents.com
// Set your own pins with these defines !
#define DS1302_SCLK_PIN 14 // Arduino pin for the Serial Clock
#define DS1302_IO_PIN 15 // Arduino pin for the Data I/O
#define DS1302_CE_PIN 16 // Arduino pin for the Chip Enable
#define bcd2bin(h,l) (((h)*10) + (l))
#define bin2bcd_h(x) ((x)/10)
#define bin2bcd_l(x) ((x)%10)
#define DS1302_SECONDS 0x80
#define DS1302_MINUTES 0x82
#define DS1302_HOURS 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_ENABLE 0x8E
#define DS1302_TRICKLE 0x90
#define DS1302_CLOCK_BURST 0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_CLOCK_BURST_READ 0xBF
#define DS1302_RAMSTART 0xC0
#define DS1302_RAMEND 0xFC
#define DS1302_RAM_BURST 0xFE
#define DS1302_RAM_BURST_WRITE 0xFE
#define DS1302_RAM_BURST_READ 0xFF
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7
#define DS1302_READBIT DS1302_D0
#define DS1302_RC DS1302_D6
#define DS1302_CH DS1302_D7 // 1 = Clock Halt, 0 = start
// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302_D7 // 0 = 24 hour, 1 = 12 hour
// Enable Register
#define DS1302_WP DS1302_D7 // 1 = Write Protect, 0 = enabled
// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0 DS1302_D2
#define DS1302_DS1 DS1302_D2
#define DS1302_TCS0 DS1302_D4
#define DS1302_TCS1 DS1302_D5
#define DS1302_TCS2 DS1302_D6
#define DS1302_TCS3 DS1302_D7
#define LM35Pin 5
// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
uint8_t Seconds:4; // low decimal digit 0-9
uint8_t Seconds10:3; // high decimal digit 0-5
uint8_t CH:1; // CH = Clock Halt
uint8_t Minutes:4;
uint8_t Minutes10:3;
uint8_t reserved1:1;
union
{
struct
{
uint8_t Hour:4;
uint8_t Hour10:2;
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 0 for 24 hour format
} h24;
struct
{
uint8_t Hour:4;
uint8_t Hour10:1;
uint8_t AM_PM:1; // 0 for AM, 1 for PM
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 1 for 12 hour format
} h12;
};
uint8_t Date:4; // Day of month, 1 = first day
uint8_t Date10:2;
uint8_t reserved3:2;
uint8_t Month:4; // Month, 1 = January
uint8_t Month10:1;
uint8_t reserved4:3;
uint8_t Day:3; // Day of week, 1 = first day (any day)
uint8_t reserved5:5;
uint8_t Year:4; // Year, 0 = year 2000
uint8_t Year10:4;
uint8_t reserved6:7;
uint8_t WP:1; // WP = Write Protect
};
/* Controller for the 7 segment display */
#include "Arduino.h"
/* Pin order for digit select DIO */
const byte u8PinOut_Digit[] = {13,6,5,2};
/* Pin order for segment DIO. The segment order is A,B,C,D,E,F,G,DP */
const byte u8PinOut_Segment[] = {3,7,11,9,8,4,12,10};
const byte u8Digit_Map[] = {252,96,218,242,102,182,190,224,254,230,2};
class HC7Segment
{
public:
HC7Segment(byte Digits, bool DigitSelectState);
void vDisplay_Number(int u16Value);
void vDisplay_Number(int Value, byte DecimalPoint);
private:
void vWrite_Digit(byte Value, bool IncludeDecimalPoint);
void vSelect_Digit(byte u8Value);
void vDeselect_Digits(void);
byte _Digits;
bool _DigitSelectState;
};
/* Create an instance of HC7Segment(). In this example we will be using a 4 digit
common cathode display (CAI5461AH) */
HC7Segment HC7Segment(4, LOW);
//storage for temperature
float Temperature;
int decimal;
/* Place any setup code that you require here */
void setup()
{
ds1302_struct rtc;
analogReference(INTERNAL);
Serial.begin(9600);
// Start by clearing the Write Protect bit
// Otherwise the clock data cannot be written
// The whole register is written,
// but the WP-bit is the only bit in that register.
DS1302_write (DS1302_ENABLE, 0);
// Disable Trickle Charger.
DS1302_write (DS1302_TRICKLE, 0x00);
// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE
// Fill these variables with the date and time.
int seconds, minutes, hours, dayofweek, dayofmonth, month, year;
// Example for May 17, 2014, 17:21, thursday is 5th day of Week.
// Set your own time and date in these variables.
seconds = 0;
minutes = 21;
hours = 17;
dayofweek = 4; // Day of week, any day can be first, counts 1...7
dayofmonth = 15; // Day of month, 1...31
month = 5; // month 1...12
year = 2014;
// Set a time and date
// This also clears the CH (Clock Halt) bit,
// to start the clock.
// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));
rtc.Seconds = bin2bcd_l( seconds);
rtc.Seconds10 = bin2bcd_h( seconds);
rtc.CH = 0; // 1 for Clock Halt, 0 to run;
rtc.Minutes = bin2bcd_l( minutes);
rtc.Minutes10 = bin2bcd_h( minutes);
// To use the 12 hour format,
// use it like these four lines:
// rtc.h12.Hour = bin2bcd_l( hours);
// rtc.h12.Hour10 = bin2bcd_h( hours);
// rtc.h12.AM_PM = 0; // AM = 0
// rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
rtc.h24.Hour = bin2bcd_l( hours);
rtc.h24.Hour10 = bin2bcd_h( hours);
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date = bin2bcd_l( dayofmonth);
rtc.Date10 = bin2bcd_h( dayofmonth);
rtc.Month = bin2bcd_l( month);
rtc.Month10 = bin2bcd_h( month);
rtc.Day = dayofweek;
rtc.Year = bin2bcd_l( year - 2000);
rtc.Year10 = bin2bcd_h( year - 2000);
rtc.WP = 0;
// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
}
void loop()
{
ds1302_struct rtc;
char buffer[80]; // the code uses 70 characters.
char charBuf[20]; // for thermometer
char decBuf[4]; // for thermometer
int k;
Temperature = analogRead(LM35Pin) / 9.31;
decimal=Temperature*100;
decimal=decimal%100;
//make string for serial
itoa (Temperature,charBuf,10);
strcat( charBuf, "." );
itoa (decimal,decBuf,10);
strcat( charBuf,decBuf);
// Read all clock data at once (burst mode).
DS1302_clock_burst_read( (uint8_t *) &rtc);
//Display the time for ~2 seconds
for ( k=0; k<2000; k++)
HC7Segment.vDisplay_Number( 100*bcd2bin( rtc.h24.Hour10, rtc.h24.Hour)+bcd2bin( rtc.Minutes10, rtc.Minutes),3);
sprintf( buffer, "Time = %02d:%02d:%02d,\n ", \
bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
bcd2bin( rtc.Minutes10, rtc.Minutes), \
bcd2bin( rtc.Seconds10, rtc.Seconds));
//Serial.print(buffer); //time
//Display the temperature for ~2 seconds
for ( k=0; k<2000; k++)
HC7Segment.vDisplay_Number( Temperature*10,2);
Serial.println(charBuf); //temperature to the serial port for web viewer
}
// --------------------------------------------------------
// DS1302_clock_burst_read
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_read( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_READ command is issued
// the I/O-line is released for the data
_DS1302_togglewrite( DS1302_CLOCK_BURST_READ, true);
for( i=0; i<8; i++)
{
*p++ = _DS1302_toggleread();
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_WRITE command is issued.
// the I/O-line is not released
_DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);
for( i=0; i<8; i++)
{
// the I/O-line is not released
_DS1302_togglewrite( *p++, false);
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_read
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
uint8_t DS1302_read(int address)
{
uint8_t data;
// set lowest bit (read bit) in address
bitSet( address, DS1302_READBIT);
_DS1302_start();
// the I/O-line is released for the data
_DS1302_togglewrite( address, true);
data = _DS1302_toggleread();
_DS1302_stop();
return (data);
}
// --------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{
// clear lowest bit (read bit) in address
bitClear( address, DS1302_READBIT);
_DS1302_start();
// don't release the I/O-line
_DS1302_togglewrite( address, false);
// don't release the I/O-line
_DS1302_togglewrite( data, false);
_DS1302_stop();
}
// --------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
pinMode( DS1302_CE_PIN, OUTPUT);
digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
pinMode( DS1302_SCLK_PIN, OUTPUT);
pinMode( DS1302_IO_PIN, OUTPUT);
digitalWrite( DS1302_CE_PIN, HIGH); // start the session
delayMicroseconds( 4); // tCC = 4us
}
// --------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
// Set CE low
digitalWrite( DS1302_CE_PIN, LOW);
delayMicroseconds( 4); // tCWH = 4us
}
// --------------------------------------------------------
// _DS1302_toggleread
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
uint8_t _DS1302_toggleread( void)
{
uint8_t i, data;
data = 0;
for( i = 0; i <= 7; i++)
{
// Issue a clock pulse for the next databit.
// If the 'togglewrite' function was used before
// this function, the SCLK is already high.
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);
// Clock down, data is ready after some time.
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
// read bit, and set it in place in 'data' variable
bitWrite( data, i, digitalRead( DS1302_IO_PIN));
}
return( data);
}
// --------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
int i;
for( i = 0; i <= 7; i++)
{
// set a bit of the data on the I/O-line
digitalWrite( DS1302_IO_PIN, bitRead(data, i));
delayMicroseconds( 1); // tDC = 200ns
// clock up, data is read by DS1302
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1); // tCH = 1000ns, tCDH = 800ns
if( release && i == 7)
{
// If this write is followed by a read,
// the I/O-line should be released after
// the last bit, before the clock line is made low.
// This is according the datasheet.
// I have seen other programs that don't release
// the I/O-line at this moment,
// and that could cause a shortcut spike
// on the I/O-line.
pinMode( DS1302_IO_PIN, INPUT);
// For Arduino 1.0.3, removing the pull-up is no longer needed.
// Setting the pin as 'INPUT' will already remove the pull-up.
// digitalWrite (DS1302_IO, LOW); // remove any pull-up
}
else
{
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
}
}
}
/* Constructor to initiliase the GPIO as outputs and in the OFF state*/
HC7Segment::HC7Segment(byte Digits, bool DigitSelectState)
{
byte LED_Cur_Digit;
byte LED_Cur_Segment;
_Digits = Digits;
_DigitSelectState = DigitSelectState;
for (LED_Cur_Digit = 0; LED_Cur_Digit < _Digits; LED_Cur_Digit++)
{
pinMode (u8PinOut_Digit[LED_Cur_Digit], OUTPUT);
digitalWrite(u8PinOut_Digit[LED_Cur_Digit], !_DigitSelectState);
}
for (LED_Cur_Segment = 0; LED_Cur_Segment < 8; LED_Cur_Segment++)
{
pinMode (u8PinOut_Segment[LED_Cur_Segment], OUTPUT);
digitalWrite(u8PinOut_Segment[LED_Cur_Segment], _DigitSelectState);
}
}
void HC7Segment::vDisplay_Number(int Value)
{
byte Loop;
bool IsNegative = Value < 0;
for (Loop = 0; Loop < _Digits; Loop++)
{
vDeselect_Digits();
if (Loop == (_Digits - 1) && IsNegative)
{
vWrite_Digit(10, 0);
}else
{
vWrite_Digit(abs(Value) % 10, 0);
}
Value /= 10;
vSelect_Digit(Loop);
}
vDeselect_Digits();
}
void HC7Segment::vDisplay_Number(int Value, byte DecimalPoint)
{
byte Loop;
bool IsNegative = Value < 0;
for (Loop = 0; Loop < _Digits; Loop++)
{
vDeselect_Digits();
if (Loop == (_Digits - 1) && IsNegative)
{
vWrite_Digit(10, 0);
}else
{
vWrite_Digit(abs(Value) % 10, Loop + 1 == DecimalPoint);
}
Value /= 10;
vSelect_Digit(Loop);
}
vDeselect_Digits();
}
void HC7Segment::vWrite_Digit(byte Value, bool IncludeDecimalPoint)
{
byte Loop;
for(Loop = 0; Loop < 8; Loop++)
{
digitalWrite(u8PinOut_Segment[Loop], (~((u8Digit_Map[Value] >> 7-Loop) ^ !_DigitSelectState))&1);
}
if(IncludeDecimalPoint)
digitalWrite(u8PinOut_Segment[7], !_DigitSelectState);
}
void HC7Segment::vSelect_Digit(byte Value)
{
byte Loop;
for (Loop = 0; Loop < _Digits; Loop++)
{
digitalWrite(u8PinOut_Digit[Loop],!_DigitSelectState);
}
digitalWrite(u8PinOut_Digit[Value],_DigitSelectState);
}
void HC7Segment::vDeselect_Digits(void)
{
byte Loop;
for (Loop = 0; Loop < _Digits; Loop++)
{
digitalWrite(u8PinOut_Digit[Loop],!_DigitSelectState);
}
}
A video of the clock is shown below
The same clock has been updated with hourly chime or beeps using a buzzer and the whole setup has been ported in to a prototype pcb along with an arduino pro mini. The arduino sketch and some of the pictures are given below.
Take care of the led pins as am using a direct drive ( a more efficient way is to use serial type led modules which can work with 2-3 pins on the arduino)
DS1302 is hooked and one buzzer is hooked to Digital pin 3 in the sketch below.
A simple arduino rtc clock with chime/ hourly buzzer |
Connecting usb uart to pro min for programming |
Arduino promini for a simple rtc clock |
Sketch (updated for the chime/buzzer function)
// DS1302 RTC
// ----------
//
// Open Source / Public Domain
//
// Version 1
// By arduino.cc user "Krodal".
// June 2012
// Using Arduino 1.0.1
// Version 2
// By arduino.cc user "Krodal"
// March 2013
// Using Arduino 1.0.3, 1.5.2
// The code is no longer compatible with older versions.
// Added bcd2bin, bin2bcd_h, bin2bcd_l
// A few minor changes.
//
//
// Documentation: datasheet
//
// The DS1302 uses a 3-wire interface:
// - bidirectional data.
// - clock
// - chip select
// It is not I2C, not OneWire, and not SPI.
// So the standard libraries can not be used.
// Even the shiftOut() function is not used, since it
// could be too fast (it might be slow enough,
// but that's not certain).
//
// I wrote my own interface code according to the datasheet.
// Any three pins of the Arduino can be used.
// See the first defines below this comment,
// to set your own pins.
//
// The "Chip Enable" pin was called "/Reset" before.
//
// The chip has internal pull-down registers.
// This keeps the chip disabled, even if the pins of
// the Arduino are floating.
//
//
// Range
// -----
// seconds : 00-59
// minutes : 00-59
// hour : 1-12 or 0-23
// date : 1-31
// month : 1-12
// day : 1-7
// year : 00-99
//
//
// Burst mode
// ----------
// In burst mode, all the clock data is read at once.
// This is to prevent a rollover of a digit during reading.
// The read data is from an internal buffer.
//
// The burst registers are commands, rather than addresses.
// Clock Data Read in Burst Mode
// Start by writing 0xBF (as the address),
// after that: read clock data
// Clock Data Write in Burst Mode
// Start by writing 0xBE (as the address),
// after that: write clock data
// Ram Data Read in Burst Mode
// Start by writing 0xFF (as the address),
// after that: read ram data
// Ram Data Write in Burst Mode
// Start by writing 0xFE (as the address),
// after that: write ram data
//
//
// Ram
// ---
// The DS1302 has 31 of ram, which can be used to store data.
// The contents will be lost if the Arduino is off,
// and the backup battery gets empty.
// It is better to store data in the EEPROM of the Arduino.
// The burst read or burst write for ram is not implemented
// in this code.
//
//
// Trickle charge
// --------------
// The DS1302 has a build-in trickle charger.
// That can be used for example with a lithium battery
// or a supercap.
// Using the trickle charger has not been implemented
// in this code.
//
// Set your own pins with these defines !
#define DS1302_SCLK_PIN 2 // Arduino pin for the Serial Clock
#define DS1302_IO_PIN 15 // Arduino pin for the Data I/O
#define DS1302_CE_PIN 17 // Arduino pin for the Chip Enable
// Macros to convert the bcd values of the registers to normal
// integer variables.
// The code uses seperate variables for the high byte and the low byte
// of the bcd, so these macros handle both bytes seperately.
#define bcd2bin(h,l) (((h)*10) + (l))
#define bin2bcd_h(x) ((x)/10)
#define bin2bcd_l(x) ((x)%10)
// Register names.
// Since the highest bit is always '1',
// the registers start at 0x80
// If the register is read, the lowest bit should be '1'.
#define DS1302_SECONDS 0x80
#define DS1302_MINUTES 0x82
#define DS1302_HOURS 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_ENABLE 0x8E
#define DS1302_TRICKLE 0x90
#define DS1302_CLOCK_BURST 0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_CLOCK_BURST_READ 0xBF
#define DS1302_RAMSTART 0xC0
#define DS1302_RAMEND 0xFC
#define DS1302_RAM_BURST 0xFE
#define DS1302_RAM_BURST_WRITE 0xFE
#define DS1302_RAM_BURST_READ 0xFF
// Defines for the bits, to be able to change
// between bit number and binary definition.
// By using the bit number, using the DS1302
// is like programming an AVR microcontroller.
// But instead of using "(1<<X)", or "_BV(X)",
// the Arduino "bit(X)" is used.
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7
// Bit for reading (bit in address)
#define DS1302_READBIT DS1302_D0 // READBIT=1: read instruction
// Bit for clock (0) or ram (1) area,
// called R/C-bit (bit in address)
#define DS1302_RC DS1302_D6
// Seconds Register
#define DS1302_CH DS1302_D7 // 1 = Clock Halt, 0 = start
// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302_D7 // 0 = 24 hour, 1 = 12 hour
// Enable Register
#define DS1302_WP DS1302_D7 // 1 = Write Protect, 0 = enabled
// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0 DS1302_D2
#define DS1302_DS1 DS1302_D2
#define DS1302_TCS0 DS1302_D4
#define DS1302_TCS1 DS1302_D5
#define DS1302_TCS2 DS1302_D6
#define DS1302_TCS3 DS1302_D7
#define LM35Pin 7
// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
uint8_t Seconds:4; // low decimal digit 0-9
uint8_t Seconds10:3; // high decimal digit 0-5
uint8_t CH:1; // CH = Clock Halt
uint8_t Minutes:4;
uint8_t Minutes10:3;
uint8_t reserved1:1;
union
{
struct
{
uint8_t Hour:4;
uint8_t Hour10:2;
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 0 for 24 hour format
} h24;
struct
{
uint8_t Hour:4;
uint8_t Hour10:1;
uint8_t AM_PM:1; // 0 for AM, 1 for PM
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 1 for 12 hour format
} h12;
};
uint8_t Date:4; // Day of month, 1 = first day
uint8_t Date10:2;
uint8_t reserved3:2;
uint8_t Month:4; // Month, 1 = January
uint8_t Month10:1;
uint8_t reserved4:3;
uint8_t Day:3; // Day of week, 1 = first day (any day)
uint8_t reserved5:5;
uint8_t Year:4; // Year, 0 = year 2000
uint8_t Year10:4;
uint8_t reserved6:7;
uint8_t WP:1; // WP = Write Protect
};
/* Include the 7 segment display library */
#include <HC7Segment.h>
/* Pin order for digit select DIO */
const byte u8PinOut_Digit[] = {14,12,13,10};
/* Pin order for segment DIO. The segment order is A,B,C,D,E,F,G,DP */
const byte u8PinOut_Segment[] = {8,9,6,4,5,11,7,16};
/* Create an instance of HC7Segment(). In this example we will be using a 4 digit
common cathode display (CAI5461AH) */
HC7Segment HC7Segment(4, LOW);
//storage for temperature
float Temperature;
int decimal;
/* Place any setup code that you require here */
void setup()
{
ds1302_struct rtc;
analogReference(INTERNAL);
pinMode(3, OUTPUT);
Serial.begin(9600);
beep(50);
//Serial.println(F("DS1302 Real Time Clock"));
//Serial.println(F("Version 2, March 2013"));
// Start by clearing the Write Protect bit
// Otherwise the clock data cannot be written
// The whole register is written,
// but the WP-bit is the only bit in that register.
DS1302_write (DS1302_ENABLE, 0);
// Disable Trickle Charger.
DS1302_write (DS1302_TRICKLE, 0x00);
// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE
// Fill these variables with the date and time.
int seconds, minutes, hours, dayofweek, dayofmonth, month, year;
// Example for april 15, 2013, 10:08, monday is 2nd day of Week.
// Set your own time and date in these variables.
seconds = 0;
minutes = 24;
hours = 20;
dayofweek = 2; // Day of week, any day can be first, counts 1...7
dayofmonth = 26; // Day of month, 1...31
month = 5; // month 1...12
year = 2014;
// Set a time and date
// This also clears the CH (Clock Halt) bit,
// to start the clock.
// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));
rtc.Seconds = bin2bcd_l( seconds);
rtc.Seconds10 = bin2bcd_h( seconds);
rtc.CH = 0; // 1 for Clock Halt, 0 to run;
rtc.Minutes = bin2bcd_l( minutes);
rtc.Minutes10 = bin2bcd_h( minutes);
// To use the 12 hour format,
// use it like these four lines:
// rtc.h12.Hour = bin2bcd_l( hours);
// rtc.h12.Hour10 = bin2bcd_h( hours);
// rtc.h12.AM_PM = 0; // AM = 0
// rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
rtc.h24.Hour = bin2bcd_l( hours);
rtc.h24.Hour10 = bin2bcd_h( hours);
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date = bin2bcd_l( dayofmonth);
rtc.Date10 = bin2bcd_h( dayofmonth);
rtc.Month = bin2bcd_l( month);
rtc.Month10 = bin2bcd_h( month);
rtc.Day = dayofweek;
rtc.Year = bin2bcd_l( year - 2000);
rtc.Year10 = bin2bcd_h( year - 2000);
rtc.WP = 0;
// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
}
void loop()
{
ds1302_struct rtc;
char buffer[80]; // the code uses 70 characters.
char charBuf[20]; // for thermometer
char decBuf[4]; // for thermometer
int k;
Temperature = analogRead(LM35Pin) / 9.31;
decimal=Temperature*100;
decimal=decimal%100;
//make string for serial
itoa (Temperature,charBuf,10);
strcat( charBuf, "." );
itoa (decimal,decBuf,10);
strcat( charBuf,decBuf);
// Read all clock data at once (burst mode).
DS1302_clock_burst_read( (uint8_t *) &rtc);
//sprintf( buffer, "Time = %02d:%02d:%02d, ", \
// bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
// bcd2bin( rtc.Minutes10, rtc.Minutes), \
// bcd2bin( rtc.Seconds10, rtc.Seconds));
//Serial.print(buffer);
for ( k=0; k<2000; k++)
HC7Segment.vDisplay_Number( 100*bcd2bin( rtc.h24.Hour10, rtc.h24.Hour)+bcd2bin( rtc.Minutes10, rtc.Minutes),3);
sprintf( buffer, "Time = %02d:%02d:%02d,\n ", \
bcd2bin( rtc.h24.Hour10, rtc.h24.Hour), \
bcd2bin( rtc.Minutes10, rtc.Minutes), \
bcd2bin( rtc.Seconds10, rtc.Seconds));
//Serial.print(buffer); //time
for ( k=0; k<2000; k++)
HC7Segment.vDisplay_Number( Temperature*10,2);
Serial.println(charBuf); //temperature
if((rtc.Minutes10+rtc.Minutes+rtc.Seconds10==0) && (bcd2bin( rtc.h24.Hour10, rtc.h24.Hour)>4) && rtc.Seconds<4)
{
beep(50);
beep(50);
beep(50);
}
//every 30minutes
if( (bcd2bin( rtc.Minutes10, rtc.Minutes) ==30)&& (rtc.Seconds<2)&& (rtc.Seconds10==0) && (bcd2bin( rtc.h24.Hour10, rtc.h24.Hour)>4) )
{
beep(50);
}
}
// --------------------------------------------------------
// DS1302_clock_burst_read
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_read( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_READ command is issued
// the I/O-line is released for the data
_DS1302_togglewrite( DS1302_CLOCK_BURST_READ, true);
for( i=0; i<8; i++)
{
*p++ = _DS1302_toggleread();
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
int i;
_DS1302_start();
// Instead of the address,
// the CLOCK_BURST_WRITE command is issued.
// the I/O-line is not released
_DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);
for( i=0; i<8; i++)
{
// the I/O-line is not released
_DS1302_togglewrite( *p++, false);
}
_DS1302_stop();
}
// --------------------------------------------------------
// DS1302_read
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
uint8_t DS1302_read(int address)
{
uint8_t data;
// set lowest bit (read bit) in address
bitSet( address, DS1302_READBIT);
_DS1302_start();
// the I/O-line is released for the data
_DS1302_togglewrite( address, true);
data = _DS1302_toggleread();
_DS1302_stop();
return (data);
}
// --------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{
// clear lowest bit (read bit) in address
bitClear( address, DS1302_READBIT);
_DS1302_start();
// don't release the I/O-line
_DS1302_togglewrite( address, false);
// don't release the I/O-line
_DS1302_togglewrite( data, false);
_DS1302_stop();
}
// --------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
pinMode( DS1302_CE_PIN, OUTPUT);
digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
pinMode( DS1302_SCLK_PIN, OUTPUT);
pinMode( DS1302_IO_PIN, OUTPUT);
digitalWrite( DS1302_CE_PIN, HIGH); // start the session
delayMicroseconds( 4); // tCC = 4us
}
// --------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
// Set CE low
digitalWrite( DS1302_CE_PIN, LOW);
delayMicroseconds( 4); // tCWH = 4us
}
// --------------------------------------------------------
// _DS1302_toggleread
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
uint8_t _DS1302_toggleread( void)
{
uint8_t i, data;
data = 0;
for( i = 0; i <= 7; i++)
{
// Issue a clock pulse for the next databit.
// If the 'togglewrite' function was used before
// this function, the SCLK is already high.
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);
// Clock down, data is ready after some time.
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
// read bit, and set it in place in 'data' variable
bitWrite( data, i, digitalRead( DS1302_IO_PIN));
}
return( data);
}
// --------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
int i;
for( i = 0; i <= 7; i++)
{
// set a bit of the data on the I/O-line
digitalWrite( DS1302_IO_PIN, bitRead(data, i));
delayMicroseconds( 1); // tDC = 200ns
// clock up, data is read by DS1302
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1); // tCH = 1000ns, tCDH = 800ns
if( release && i == 7)
{
// If this write is followed by a read,
// the I/O-line should be released after
// the last bit, before the clock line is made low.
// This is according the datasheet.
// I have seen other programs that don't release
// the I/O-line at this moment,
// and that could cause a shortcut spike
// on the I/O-line.
pinMode( DS1302_IO_PIN, INPUT);
// For Arduino 1.0.3, removing the pull-up is no longer needed.
// Setting the pin as 'INPUT' will already remove the pull-up.
// digitalWrite (DS1302_IO, LOW); // remove any pull-up
}
else
{
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1); // tCL=1000ns, tCDD=800ns
}
}
}
void beep(unsigned char delayms){
analogWrite(3, 55); // Almost any value can be used except 0 and 255
// experiment to get the best tone
delay(delayms); // wait for a delayms ms
analogWrite(3, 0); // 0 turns it off
delay(delayms); // wait for a delayms ms
}
No comments:
Post a Comment