Problem in arduino code... you'll have to run this one to understand - Word Clock?
I have been writing this code for the Word clock. I am trying to customize the code to fit into an atmega8, and use DS1307 RTC. Both of these is fine, but what is wrong is that when I upload my code and try to set the time by using the buttons, the time is not setting properly. I can increment minutes with the minutes button to 16, but not further. Hours works fine, but if, lets say the time is 6:36 on the arduino, then If I press the hour button, I find that time changes to 7:31. Five minutes less than what I expected.
What am I overlooking here?
I advise to run the code and understand the problem.
On the other hand Binary sketch size: 7164 bytes (of a 7168 byte maximum), this is just 4 bytes short of max. Can that be a part of the problem
Code:
#include <Wire.h>
// Display output pin assignments
#define MTEN Display1=Display1 | (1<<0)
#define HALF Display1=Display1 | (1<<1)
#define QUARTER Display1=Display1 | (1<<2)
#define TWENTY Display1=Display1 | (1<<3)
#define MFIVE Display1=Display1 | (1<<4)
#define MINUTES Display1=Display1 | (1<<5)
#define PAST Display1=Display1 | (1<<6)
#define UNUSED1 Display1=Display1 | (1<<7)
#define TO Display2=Display2 | (1<<0)
#define ONE Display2=Display2 | (1<<1)
#define TWO Display2=Display2 | (1<<2)
#define THREE Display2=Display2 | (1<<3)
#define FOUR Display2=Display2 | (1<<4)
#define HFIVE Display2=Display2 | (1<<5)
#define SIX Display2=Display2 | (1<<6)
#define UNUSED2 Display2=Display2 | (1<<7)
#define SEVEN Display3=Display3 | (1<<0)
#define EIGHT Display3=Display3 | (1<<1)
#define NINE Display3=Display3 | (1<<2)
#define HTEN Display3=Display3 | (1<<3)
#define ELEVEN Display3=Display3 | (1<<4)
#define TWELVE Display3=Display3 | (1<<5)
#define OCLOCK Display3=Display3 | (1<<6)
#define UNUSED3 Display3=Display3 | (1<<7)
#define DS1307_I2C_ADDRESS 0x68 // This is the I2C address
#if defined(ARDUINO) && ARDUINO >= 100 // Arduino v1.0 and newer
#define I2C_WRITE Wire.write
#define I2C_READ Wire.read
#else // Arduino Prior to v1.0
#define I2C_WRITE Wire.send
#define I2C_READ Wire.receive
#endif
int hr=12, mn=00, scnd=0;
static unsigned long msTick =0; // the number of Millisecond Ticks since we last
// incremented the second counter
int count;
boolean selftestmode;
boolean DS1307Present=false; // flag to indicate that the 1307 is there.. 1 = present
char Display1=0, Display2=0, Display3=0;
// hardware constants
static unsigned int LEDClockPin=5; //11 d5 ok
static unsigned int LEDDataPin=3; //5 d3
static unsigned int LEDStrobePin=4; //6 d4
static unsigned int MinuteButtonPin=6; //d6 12
static unsigned int HourButtonPin=7; //d7 13
static unsigned int PWMPin = 11;
char buf[50]; // time output string for debugging
byte decToBcd(byte b)
{ return ( ((b/10) << 4) + (b%10) );}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte b)
{ return ( ((b >> 4)*10) + (b%16) );}
void getTime()
{
//read from chip and store in hr, mn, scnd
Wire.beginTransmission(DS1307_I2C_ADDRESS);
I2C_WRITE((uint8_t) 0x00);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 3);
scnd = bcdToDec(I2C_READ());
mn = bcdToDec(I2C_READ());
hr = bcdToDec(I2C_READ());
}
void setTime()
{
//to be paranoid, we're going to first stop the clock
//to ensure we don't have rollovers while we're
//writing:
writeRTCreg(0,0x80);
//now, we'll write everything *except* the second
Wire.beginTransmission(DS1307_I2C_ADDRESS);
I2C_WRITE((uint8_t) 0x01);
I2C_WRITE(mn);
I2C_WRITE(hr);
Wire.endTransmission();
//now, we'll write the seconds; we didn't have to keep
//track of whether the clock was already running, because
//scnd already knows what we want it to be. This
//will restart the clock as it writes the new seconds value.
writeRTCreg(0,scnd);
}
byte readRTCreg(byte adr)
{
if(adr > 0x3F) { return 0xff; }
Wire.beginTransmission(DS1307_I2C_ADDRESS);
I2C_WRITE(adr);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 1);
return I2C_READ();
}
void writeRTCreg(byte adr, byte val)
{
if(adr > 0x3F) { return; }
Wire.beginTransmission(DS1307_I2C_ADDRESS);
I2C_WRITE(adr);
I2C_WRITE(val);
Wire.endTransmission();
}
void print_DS1307time()
{
/* Format the time and date and insert into the temporary buffer */
snprintf(buf, sizeof(buf), "RTC time: %02d:%02d:%02d",
hr, mn, scnd);
/* Print the formatted string to serial so we can see the time */
Serial.println(buf);
}
void setup()
{
// initialise the hardware
// initialize the appropriate pins as outputs:
pinMode(LEDClockPin, OUTPUT);
pinMode(LEDDataPin, OUTPUT);
pinMode(LEDStrobePin, OUTPUT);
//pinMode(BrightnessPin, INPUT);
pinMode(MinuteButtonPin, INPUT);
pinMode(HourButtonPin, INPUT);
digitalWrite(MinuteButtonPin, HIGH); //set internal pullup
digitalWrite(HourButtonPin, HIGH); //set internal pullup
pinMode(PWMPin, OUTPUT);
Serial.begin(9600);
Wire.begin();
// test whether the DS1302 is there
Serial.print("Verifying DS1307 ");
// start by verifying that the chip has a valid signature
if (readRTCreg(0x20) == 0x55) {
// Signature is there - set the present flag and mmove on
DS1307Present=true;
Serial.println("Valid Signature");
}
else
{
// Signature isnt there - may be a new chip -
// do a write to see if it will hold the signature
writeRTCreg(0x20,0x55);
if (readRTCreg(0x20) == 0x55) {
// We can store data - assume that it is a new chip that needs initialisation
/* // Start by clearing the clock halt flag.
//"Bit 7 of register 0 is the clock halt (CH) bit.
//When this bit is set to a 1, the oscillator is disabled."
byte _reg0_sec = decToBcd(scnd);
_reg0_sec = _reg0_sec & ~0x80;
writeRTCreg(0,_reg0_sec);
*/
// Set the time and date on the chip
scnd = 0;
mn = 0;
hr = 12;
setTime();
// set the DS1302 present flag
DS1307Present=true;
Serial.println("present - new chip initialised.");
}
else Serial.println("absent");
}
msTick=millis(); // Initialise the msTick counter
selftest();
selftestmode=false;
if (DS1307Present) {
// Get the current time and date from the chip
getTime();
}
displaytime(); // display the current time
}
void ledsoff(void) {
Display1=0;
Display2=0;
Display3=0;
}
void WriteLEDs(void) {
// Now we write the actual values to the hardware
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display3);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display2);
shiftOut(LEDDataPin, LEDClockPin, MSBFIRST, Display1);
digitalWrite(LEDStrobePin,HIGH);
delay(2);
digitalWrite(LEDStrobePin,LOW);
}
void selftest(void){
Serial.print("TEST");
analogWrite(PWMPin, 255);
ledsoff(); MTEN; WriteLEDs(); delay(500);
ledsoff(); HALF; WriteLEDs(); delay(500);
ledsoff(); QUARTER; WriteLEDs(); delay(500);
ledsoff(); TWENTY; WriteLEDs(); delay(500);
ledsoff(); MFIVE; WriteLEDs(); delay(500);
ledsoff(); MINUTES; WriteLEDs(); delay(500);
ledsoff(); PAST; WriteLEDs(); delay(500);
ledsoff(); TO; WriteLEDs(); delay(500);
ledsoff(); ONE; WriteLEDs(); delay(500);
ledsoff(); TWO; WriteLEDs(); delay(500);
ledsoff(); THREE; WriteLEDs(); delay(500);
ledsoff(); FOUR; WriteLEDs(); delay(500);
ledsoff(); HFIVE; WriteLEDs(); delay(500);
ledsoff(); SIX; WriteLEDs(); delay(500);
ledsoff(); SEVEN; WriteLEDs(); delay(500);
ledsoff(); EIGHT; WriteLEDs(); delay(500);
ledsoff(); NINE; WriteLEDs(); delay(500);
ledsoff(); HTEN; WriteLEDs(); delay(500);
ledsoff(); ELEVEN; WriteLEDs(); delay(500);
ledsoff(); TWELVE; WriteLEDs(); delay(500);
ledsoff(); OCLOCK; WriteLEDs(); delay(500);
}
void displaytime(void){
// start by clearing the display to a known state
ledsoff();
Serial.print("It is ");
// now we display the appropriate minute counter
if ((mn>4) && (mn<10)) {
MFIVE;
MINUTES;
Serial.print("Five Minutes ");
}
if ((mn>9) && (mn<15)) {
MTEN;
MINUTES;
Serial.print("Ten Minutes ");
}
if ((mn>14) && (mn<20)) {
QUARTER;
Serial.print("Quarter ");
}
if ((mn>19) && (mn<25)) {
TWENTY;
MINUTES;
Serial.print("Twenty Minutes ");
}
if ((mn>24) && (mn<30)) {
TWENTY;
MFIVE;
MINUTES;
Serial.print("Twenty Five Minutes ");
}
if ((mn>29) && (mn<35)) {
HALF;
Serial.print("Half ");
}
if ((mn>34) && (mn<40)) {
TWENTY;
MFIVE;
MINUTES;
Serial.print("Twenty Five Minutes ");
}
if ((mn>39) && (mn<45)) {
TWENTY;
MINUTES;
Serial.print("Twenty Minutes ");
}
if ((mn>44) && (mn<50)) {
QUARTER;
Serial.print("Quarter ");
}
if ((mn>49) && (mn<55)) {
MTEN;
MINUTES;
Serial.print("Ten Minutes ");
}
if (mn>54) {
MFIVE;
MINUTES;
Serial.print("Five Minutes ");
}
if ((mn <5))
{
switch (hr) {
case 1:
ONE;
Serial.print("One ");
break;
case 2:
TWO;
Serial.print("Two ");
break;
case 3:
THREE;
Serial.print("Three ");
break;
case 4:
FOUR;
Serial.print("Four ");
break;
case 5:
HFIVE;
Serial.print("Five ");
break;
case 6:
SIX;
Serial.print("Six ");
break;
case 7:
SEVEN;
Serial.print("Seven ");
break;
case 8:
EIGHT;
Serial.print("Eight ");
break;
case 9:
NINE;
Serial.print("Nine ");
break;
case 10:
HTEN;
Serial.print("Ten ");
break;
case 11:
ELEVEN;
Serial.print("Eleven ");
break;
case 12:
TWELVE;
Serial.print("Twelve ");
break;
}
OCLOCK;
Serial.println("O'Clock");
}
else
if ((mn < 35) && (mn >4))
{
PAST;
Serial.print("Past ");
switch (hr) {
case 1:
ONE;
Serial.println("One ");
break;
case 2:
TWO;
Serial.println("Two ");
break;
case 3:
THREE;
Serial.println("Three ");
break;
case 4:
FOUR;
Serial.println("Four ");
break;
case 5:
HFIVE;
Serial.println("Five ");
break;
case 6:
SIX;
Serial.println("Six ");
break;
case 7:
SEVEN;
Serial.println("Seven ");
break;
case 8:
EIGHT;
Serial.println("Eight ");
break;
case 9:
NINE;
Serial.println("Nine ");
break;
case 10:
HTEN;
Serial.println("Ten ");
break;
case 11:
ELEVEN;
Serial.println("Eleven ");
break;
case 12:
TWELVE;
Serial.println("Twelve ");
break;
}
}
else
{
// if we are greater than 34 minutes past the hour then display
// the next hour, as we will be displaying a 'to' sign
TO;
Serial.print("To ");
switch (hr) {
case 1:
TWO;
Serial.println("Two ");
break;
case 2:
THREE;
Serial.println("Three ");
break;
case 3:
FOUR;
Serial.println("Four ");
break;
case 4:
HFIVE;
Serial.println("Five ");
break;
case 5:
SIX;
Serial.println("Six ");
break;
case 6:
SEVEN;
Serial.println("Seven ");
break;
case 7:
EIGHT;
Serial.println("Eight ");
break;
case 8:
NINE;
Serial.println("Nine ");
break;
case 9:
HTEN;
Serial.println("Ten ");
break;
case 10:
ELEVEN;
Serial.println("Eleven ");
break;
case 11:
TWELVE;
Serial.println("Twelve ");
break;
case 12:
ONE;
Serial.println("One ");
break;
}
}
WriteLEDs();
}
void incrementtime(void){
// increment the time counters keeping care to rollover as required
scnd=0;
if (++mn >= 60) {
mn=0;
if (++hr == 13) {
hr=1;
}
}
// debug outputs
Serial.println();
// if (DS1307Present)
// print_DS1307time();
// else{
// Serial.print("Arduino Time: " );
Serial.print(hr);
Serial.print(":");
Serial.print(mn);
Serial.print(":");
Serial.println(scnd);
// }
}
void loop(void)
{
//selftest();
int aread = sq(analogRead(3)/4)+3;
//Uncomment the following line and comment the next one in order to
// enable dimming via a potentiometer connected to pin 0:
analogWrite(PWMPin, aread>255 ? 255:aread);
//analogWrite(PWMPin, 255);
// heart of the timer - keep looking at the millisecond timer on the Arduino
// and increment the seconds counter every 1000 ms
if ( millis() - msTick >999) {
msTick=millis();
scnd++;
/* // Flash the onboard Pin13 Led so we know something is hapening!
digitalWrite(13,HIGH);
delay(100);
digitalWrite(13,LOW);
*/ }
//test to see if we need to increment the time counters
if (scnd==60)
{
incrementtime();
displaytime();
}
if (DS1307Present) {
// Get the current time and date from the chip
getTime();
}
// test to see if a forward button is being held down
// for time setting
if ( (digitalRead(MinuteButtonPin) ==0 ) && scnd!=1)
// the forward button is down
// and it has been more than one second since we
// last looked
{
mn=(((mn/5)*5) +5);
scnd=0;
incrementtime();
scnd++; // Increment the second counter to ensure that the name
// flash doesnt happen when setting time
if (DS1307Present) {
// Set the time on the chip
setTime();
}
delay(100);
displaytime();
}
// test to see if the back button is being held down
// for time setting
if ((digitalRead(HourButtonPin)==0 ) && scnd!=1)
{
/*
minute=(((minute/5)*5) -5);
second=0; // decrement the minute counter
if (minute<0) {
minute=55;
if (--hour <0) hour=12;
}
*/
mn = (mn/5)*5; //round minute down to previous 5 min interval
if (++hr == 13) {
hr=1;
}
incrementtime();
scnd++; // Increment the second counter to ensure that the name
// flash doesnt happen when setting time
if (DS1307Present) {
// Set the time and date on the chip
setTime();
}
delay(100);
displaytime();
}
}
Comments
Best Answer 9 years ago
I can't compile it to give real advice;
debugging; you need to find exactly where it goes wrong. Is your time number correct and the word count wrong -- or is the time math wrong?
I'd write a nested for loop that goes through every possible time from 00:00 to 11:59, and outputs that number to serial monitor, and to the screen. perhaps add a delay to make it obvious whats happening. Increment the time with a procedure rather than just 'set time = x loop', so more like time = time++
If the time counting math is proper, and outputs to the serial and display correctly, then its a problem with your 'hour incrementing' procedure.
Answer 9 years ago
I have a hunch that:
minute=(((minute/5)*5) -5);
second=0; // decrement the minute counter
if (minute<0) {
minute=55;
if (--hour <0) hour=12;
}
*/
is causing the problem...right at the end -- are you making the minutes step by increments of 5 while setting the time? in which case it might prevent you from stepping above 16 for some ridiculous reason.
I would personally keep the minutes stored as proper minutes and only convert them during the 'output' calculations.
Answer 9 years ago
Yes, thats right, it increments five minutes at a time. But that part you just read is commented out, instead there's an increment function. I should probably post my code again after clearing it out a bit.. shall I?
Answer 9 years ago
+1
Answer 9 years ago
Normal time increment is fine. When it is incrementing itself it runs well and good. Just when setting time using the 'minute' button, it goes wrong. Lately I realised that its not just for 16 but any value above 15...
9 years ago
Latest update! It worked... I flashed the AVR with the same code again and it worked fine :D but strange
thanks all... which one should I mark the best answer?
Answer 9 years ago
Glad you got it working, and thanks for the BA :)
Keep coding and if it works well -- post your iteration as an ible!
Answer 9 years ago
I will... Just waiting for a camera to take the pics.. :)
9 years ago
Forgot to add.. The code is a mix of a couple of codes found on the net. The base being Doug Jackson's word clock. The interaction with the RTC is based on I2C (Wire library)