Clocks, I2C, Serial and You
I bought a bunch of parts awhile back with the good intention of building a bright, blue LED clock for my desk at work. Unfortunately, I got side tracked and the parts sat in my parts bin for a month or two. When I had a little too much caffeine in my system last weekend, I hit the parts box and built that clock. Needless to say it wasn’t as easy as it looked…
Parts List
- 1x Arduino
- 1x Sparkfun Serial 7-Segment Display
- 1x Macetech Chronodot
- 1x Solderless Breadboard
Wiring
- SFE Display Slave Select to Pin 10
- SFE Display MOSI to 11
- SFE Display MISO to 12
- SFE Display SCK to 13
- SFE Display VCC to 5v
- SFE Display GND to GND
- Chronodot SDA to Arduino Pin 4
- Chronodot SCL to Arduino Pin 5
- Chronodot VCC to 5v
- Chronodot GND to GND
Code
The code below is a modified version of the Chronodot demo code. If you uncomment the set_time() call, it will set the time to the HH:MM passed to the function.
#include
#include
int ss = 10; //csn
int mosi = 11;
int miso = 12;
int sck = 13;
void setup()
{
//chronodot
Wire.begin();
//Display
Serial.begin(9600);
//Set baud
Serial.write(0x7F);
Serial.write(0x02);
//Reset display
Serial.write(0x7A);
Serial.write(0x76);
//Set brightness
Serial.write(0x7A);
Serial.write(0x01);
//Set colon
Serial.write(0x77);
Serial.write(0x10);
// clear /EOSC bit
// Sometimes necessary to ensure that the clock
// keeps running on just battery power. Once set,
// it shouldn't need to be reset but it's a good
// idea to make sure.
Wire.beginTransmission(0x68); // address DS3231
Wire.send(0x0E); // select register
Wire.send(0b00011100); // write register bitmap, bit 7 is /EOSC
Wire.endTransmission();
//set_time(23, 59, 00);
}
void loop()
{
// send request to receive data starting at register 0
Wire.beginTransmission(0x68); // 0x68 is DS3231 device address
Wire.send(0); // start at register 0
Wire.endTransmission();
Wire.requestFrom(0x68, 3); // request three bytes (seconds, minutes, hours)
while(Wire.available())
{
int seconds = Wire.receive(); // get seconds
int minutes = Wire.receive(); // get minutes
int hours = Wire.receive(); // get hours
seconds = (((seconds & 0b11110000)>>4)*10 + (seconds & 0b00001111)); // convert BCD to decimal
minutes = (((minutes & 0b11110000)>>4)*10 + (minutes & 0b00001111)); // convert BCD to decimal
hours = (((hours & 0b00100000)>>5)*20 + ((hours & 0b00010000)>>4)*10 + (hours & 0b00001111)); // convert BCD to decimal (assume 24 hour mode)
//Serial.print(hours); Serial.print(":"); Serial.print(minutes); Serial.print(":"); Serial.println(seconds);
displayTime(hours, minutes);
}
//Set colon on
Serial.write(0x77);
Serial.write(0x10);
delay(500);
//Set colon off
Serial.write(0x77);
Serial.write(0x01);
delay(1000);
}
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
void displayTime(int hours, int minutes){
String h_str = String(hours);
if(h_str.length() < 2){
h_str = '0'+h_str;
}
String m_str = String(minutes);
if(m_str.length() < 2){
m_str = '0'+m_str;
}
String timeStr = h_str;
timeStr.concat(m_str);
Serial.write(timeStr.charAt(0));
Serial.write(timeStr.charAt(1));
Serial.write(timeStr.charAt(2));
Serial.write(timeStr.charAt(3));
}
void set_time(int hours, int minutes, int seconds)
{
Wire.beginTransmission(104);
Wire.send(0);
Wire.send(decToBcd(seconds));
Wire.send(decToBcd(minutes));
Wire.send(decToBcd(hours));
Wire.endTransmission();
}
We need to see if we can grab the i2c pins on the ATMEGA328 that is on the back of that 7-segment display and have it talk directly to the chronodot – it would greatly reduce the parts cost…and be the basis for an awesome digital watch 🙂