321 lines
8.7 KiB
Arduino
321 lines
8.7 KiB
Arduino
|
// Utility sketch to explore DS1307 and
|
||
|
// demonstrate SoftI2cMaster and TwiMaster
|
||
|
//
|
||
|
#include <avr/pgmspace.h>
|
||
|
#include <I2cMaster.h>
|
||
|
|
||
|
// select software or hardware i2c
|
||
|
#define USE_SOFT_I2C 1
|
||
|
|
||
|
#if USE_SOFT_I2C
|
||
|
// use analog pins 4 and 5 for this example
|
||
|
// this allows a 328 shield to be used on the Mega
|
||
|
// edit next two line to change pins
|
||
|
const uint8_t SDA_PIN = A4;
|
||
|
const uint8_t SCL_PIN = A5;
|
||
|
|
||
|
// An instance of class for software master
|
||
|
SoftI2cMaster rtc(SDA_PIN, SCL_PIN);
|
||
|
|
||
|
#else // USE_SOFT_I2C
|
||
|
|
||
|
// Pins for DS1307 with hardware i2c
|
||
|
// connect SCL to Arduino 168/328 analog pin 5
|
||
|
// connect SDA to Arduino 168/328 analog pin 4
|
||
|
|
||
|
// Instance of class for hardware master with pullups enabled
|
||
|
TwiMaster rtc(true);
|
||
|
|
||
|
#endif // USE_SOFT_I2C
|
||
|
|
||
|
// i2c 8-bit address for DS1307. low bit is read/write
|
||
|
#define DS1307ADDR 0XD0
|
||
|
//------------------------------------------------------------------------------
|
||
|
/*
|
||
|
* Read 'count' bytes from the DS1307 starting at 'address'
|
||
|
*/
|
||
|
uint8_t readDS1307(uint8_t address, uint8_t *buf, uint8_t count) {
|
||
|
// issue a start condition, send device address and write direction bit
|
||
|
if (!rtc.start(DS1307ADDR | I2C_WRITE)) return false;
|
||
|
|
||
|
// send the DS1307 address
|
||
|
if (!rtc.write(address)) return false;
|
||
|
|
||
|
// issue a repeated start condition, send device address and read direction bit
|
||
|
if (!rtc.restart(DS1307ADDR | I2C_READ))return false;
|
||
|
|
||
|
// read data from the DS1307
|
||
|
for (uint8_t i = 0; i < count; i++) {
|
||
|
|
||
|
// send Ack until last byte then send Ack
|
||
|
buf[i] = rtc.read(i == (count-1));
|
||
|
}
|
||
|
|
||
|
// issue a stop condition
|
||
|
rtc.stop();
|
||
|
return true;
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
/*
|
||
|
* write 'count' bytes to DS1307 starting at 'address'
|
||
|
*/
|
||
|
uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count) {
|
||
|
// issue a start condition, send device address and write direction bit
|
||
|
if (!rtc.start(DS1307ADDR | I2C_WRITE)) return false;
|
||
|
|
||
|
// send the DS1307 address
|
||
|
if (!rtc.write(address)) return false;
|
||
|
|
||
|
// send data to the DS1307
|
||
|
for (uint8_t i = 0; i < count; i++) {
|
||
|
if (!rtc.write(buf[i])) return false;
|
||
|
}
|
||
|
|
||
|
// issue a stop condition
|
||
|
rtc.stop();
|
||
|
return true;
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void setup(void) {
|
||
|
Serial.begin(9600);
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
/** Store and print a string in flash memory.*/
|
||
|
#define PgmPrint(x) Serial.print(F(x))
|
||
|
/** Store and print a string in flash memory followed by a CR/LF.*/
|
||
|
#define PgmPrintln(x) Serial.println(F(x))
|
||
|
//-------------------------------------------------------------------------------
|
||
|
// day of week U.S. convention
|
||
|
char *Ddd[] = {"Bad", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||
|
//------------------------------------------------------------------------------
|
||
|
void hexPrint(uint8_t v) {
|
||
|
Serial.print(v >> 4, HEX);
|
||
|
Serial.print(v & 0XF, HEX);
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void hexPrintln(uint8_t v) {
|
||
|
hexPrint(v);
|
||
|
Serial.println();
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
// read hex input
|
||
|
uint8_t hexRead(uint16_t* v) {
|
||
|
uint16_t n = 0;
|
||
|
while (!Serial.available());
|
||
|
while (Serial.available()) {
|
||
|
uint8_t c = Serial.read();
|
||
|
// exit if end-of-line
|
||
|
if (c == '\n' || c == '\r') break;
|
||
|
n <<= 4;
|
||
|
if ('a' <= c && c <= 'f') {
|
||
|
n += c - ('a' - 10);
|
||
|
}
|
||
|
else if ('A' <= c && c <= 'F') {
|
||
|
n += c - ('A' - 10);
|
||
|
}
|
||
|
else if ('0' <= c && c <= '9') {
|
||
|
n += c - '0';
|
||
|
}
|
||
|
else {
|
||
|
PgmPrintln("Invalid entry");
|
||
|
return false;
|
||
|
}
|
||
|
delay(10);
|
||
|
}
|
||
|
*v = n;
|
||
|
return true;
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t* n) {
|
||
|
uint16_t v;
|
||
|
if (!hexRead(&v)) return false;
|
||
|
uint8_t d = 10 * (v >> 4) + (v & 0XF);
|
||
|
if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) {
|
||
|
PgmPrintln("Invalid");
|
||
|
return false;
|
||
|
}
|
||
|
*n = v;
|
||
|
return true;
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void displayTime(void) {
|
||
|
uint8_t r[8];
|
||
|
if (!readDS1307(0, r, 8)) {
|
||
|
PgmPrintln("Read Failed for display time");
|
||
|
return;
|
||
|
}
|
||
|
PgmPrint("The current time is 20");
|
||
|
// year
|
||
|
hexPrint(r[6]);
|
||
|
Serial.write('-');
|
||
|
|
||
|
// month
|
||
|
hexPrint(r[5]);
|
||
|
Serial.write('-');
|
||
|
|
||
|
// day
|
||
|
hexPrint(r[4]);
|
||
|
Serial.write(' ');
|
||
|
|
||
|
Serial.print(Ddd[r[3] < 8 ? r[3] : 0]);
|
||
|
Serial.write(' ');
|
||
|
// hour
|
||
|
hexPrint(r[2]);
|
||
|
Serial.write(':');
|
||
|
// minute
|
||
|
hexPrint(r[1]);
|
||
|
Serial.write(':');
|
||
|
// second
|
||
|
hexPrintln(r[0]);
|
||
|
PgmPrint("Control: ");
|
||
|
hexPrintln(r[7]);
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
// dump registers and 56 bytes of RAM
|
||
|
void dumpAll(void) {
|
||
|
uint8_t buf[8];
|
||
|
for (uint8_t a = 0; a < 64; a += 8) {
|
||
|
hexPrint(a);
|
||
|
Serial.write(' ');
|
||
|
if (!readDS1307(a, buf, 8)) {
|
||
|
PgmPrint("read failed for dumpAll");
|
||
|
return;
|
||
|
}
|
||
|
for (uint8_t i = 0; i < 8; i++) {
|
||
|
Serial.write(' ');
|
||
|
hexPrint(buf[i]);
|
||
|
}
|
||
|
Serial.println();
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
// set control register
|
||
|
/*
|
||
|
The DS1307 control register is used to control the operation of the SQW/OUT pin.
|
||
|
+-----------------------------------------------+
|
||
|
|BIT 7|BIT 6|BIT 5|BIT 4|BIT 3|BIT 2|BIT 1|BIT 0|
|
||
|
+-----------------------------------------------+
|
||
|
|OUT | 0 | 0 |SQWE | 0 | 0 | RS1 | RS0 |
|
||
|
+-----------------------------------------------+
|
||
|
|
||
|
OUT (Output control): This bit controls the output level of the SQW/OUT pin
|
||
|
when the square wave output is disabled. If SQWE = 0, the logic level on the
|
||
|
SQW/OUT pin is 1 if OUT = 1 and is 0 if OUT = 0.
|
||
|
|
||
|
SQWE (Square Wave Enable): This bit, when set to a logic 1, will enable the
|
||
|
oscillator output. The frequency of the square wave output depends upon the
|
||
|
value of the RS0 and RS1 bits. With the square wave output set to 1Hz, the
|
||
|
clock registers update on the falling edge of the square wave.
|
||
|
|
||
|
Square wave Output Frequency for SQWE = 1.
|
||
|
RS1 RS0 FREQUENCY
|
||
|
0 0 1Hz
|
||
|
0 1 4.096kHz
|
||
|
1 0 8.192kHz
|
||
|
1 1 32.768kHz
|
||
|
*/
|
||
|
void setControl(void) {
|
||
|
PgmPrintln("SQW/OUT pin: ");
|
||
|
PgmPrintln("(00) Low");
|
||
|
PgmPrintln("(10) 1Hz");
|
||
|
PgmPrintln("(11) 4.096kHz");
|
||
|
PgmPrintln("(12) 8.192kHz");
|
||
|
PgmPrintln("(13) 32.768kHz");
|
||
|
PgmPrintln("(80) High");
|
||
|
PgmPrint("Enter control: ");
|
||
|
uint16_t r;
|
||
|
if (!hexRead(&r)) return;
|
||
|
hexPrintln(r);
|
||
|
if (!writeDS1307(7, (uint8_t *)&r, 1)) {
|
||
|
PgmPrint("Write Failed for setControl");
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void setDate(void) {
|
||
|
uint8_t r[4];
|
||
|
PgmPrint("Enter year (00-99): ");
|
||
|
if (!bcdRead(0, 99, &r[3])) return;
|
||
|
hexPrintln(r[3]);
|
||
|
PgmPrint("Enter month (01-12): ");
|
||
|
if (!bcdRead(1, 12, &r[2])) return;
|
||
|
hexPrintln(r[2]);
|
||
|
PgmPrint("Enter day (01-31): ");
|
||
|
if (!bcdRead(1, 31, &r[1])) return;
|
||
|
hexPrintln(r[1]);
|
||
|
PgmPrint("Enter day of week (01-07): ");
|
||
|
if (!bcdRead(1, 7, &r[0])) return;
|
||
|
hexPrintln(r[0]);
|
||
|
|
||
|
if (!writeDS1307(3, r, 4)) {
|
||
|
PgmPrintln("Write failed for setDate");
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void setNvRam(void) {
|
||
|
uint8_t buf[8];
|
||
|
PgmPrint("Enter HEX value for all NV RAM locations (00-FF): ");
|
||
|
uint16_t v;
|
||
|
if (!hexRead(&v)) return;
|
||
|
hexPrint(v);
|
||
|
for (uint8_t a = 8; a < 64; a ++) {
|
||
|
if (!writeDS1307(a, (uint8_t *)&v, 1)) {
|
||
|
PgmPrintln("write failed for setNvRam");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void setTime(void) {
|
||
|
uint8_t r[3];
|
||
|
PgmPrint("Enter hours (00-23): ");
|
||
|
if (!bcdRead(0, 23, &r[2])) return;
|
||
|
hexPrintln(r[2]);
|
||
|
PgmPrint("Enter minutes (00-59): ");
|
||
|
if (!bcdRead(0, 59, &r[1])) return;
|
||
|
hexPrintln(r[1]);
|
||
|
PgmPrint("Enter seconds (00-59): ");
|
||
|
if (!bcdRead(0, 59, &r[0])) return;
|
||
|
hexPrintln(r[0]);
|
||
|
|
||
|
if (!writeDS1307(0, r, 3)) {
|
||
|
PgmPrintln("write failed in setTime");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
//------------------------------------------------------------------------------
|
||
|
void loop(void) {
|
||
|
Serial.println();
|
||
|
displayTime();
|
||
|
while (Serial.read() >= 0) {}
|
||
|
PgmPrintln("\nOptions are:");
|
||
|
PgmPrintln("(0) Display date and time");
|
||
|
PgmPrintln("(1) Set time");
|
||
|
PgmPrintln("(2) Set date");
|
||
|
PgmPrintln("(3) Set Control");
|
||
|
PgmPrintln("(4) Dump all");
|
||
|
PgmPrintln("(5) Set NV RAM");
|
||
|
PgmPrint("Enter option: ");
|
||
|
|
||
|
uint16_t n;
|
||
|
if (!hexRead(&n)) return;
|
||
|
Serial.println(n, DEC);
|
||
|
if (n == 0) return;
|
||
|
Serial.println();
|
||
|
if (n == 1) {
|
||
|
setTime();
|
||
|
}
|
||
|
else if (n == 2) {
|
||
|
setDate();
|
||
|
}
|
||
|
else if (n == 3) {
|
||
|
setControl();
|
||
|
}
|
||
|
else if (n == 4) {
|
||
|
dumpAll();
|
||
|
}
|
||
|
else if (n == 5) {
|
||
|
setNvRam();
|
||
|
}
|
||
|
else {
|
||
|
PgmPrintln("Invalid option");
|
||
|
}
|
||
|
}
|