My sketch woes continue. I have been modifying a sketch very kindly provided by a forum member and very nearly have it doing exactly what i want except a couple of things.
It is a interface receiving serial data from a digital master clock and is to provide a pulse out put for driving electro mechanical slave clocks.
the issue is, when it automatically tries to advance the slave clocks when summer time changes to winter time, it misses on of the pulses. This is occuring because the signal to start advancing the clocks one hour comes one nano second after the ordinary clock pulse is sent out at the top of the minute, giving nowhere near enough time for the relay to release. relay is essentially locked on for a second.
The normal pulses are every thirty seconds and i can combat this problem by setting the pulses at 29 and 59 seconds rather than 00 and 30, but obviously this means they run 1 second fast.
How can I either add, say, 600ms to the end of the normal pulse (preferrable) or make the incoming bit of the byte stall for say a second before advancing the clocks.
I will explain the other issue when (hopefully) this one is resolved.
any assistance is as usual greatly appreciated.
(code posted seperately due to size)
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
int relayPin = 8;
int syncPin = 9;
int testPin = 10;
int correctingPin = 11;
const int retardPin = 2;
const int advancePin = 3;
int retardState = 0;
int advanceState = 0;
//char summerTime = bitRead(receivedChars[12],1);
byte summerTime = bitRead(receivedChars[12], 1); //will intialize as 0 winterTime
boolean relayRunning = false;
unsigned long relayStartTime = 0;
unsigned long lastRelayStartTime = 0;
byte missedCount = 0;
boolean summerAdvance = false;
boolean winterRetard = false;
boolean missedPulseAdvance = false;
boolean manualAdvance = false;
byte seconds = 0;
void setup() {
Serial.begin(9600);
Serial.println("Arduino is ready --");
pinMode(relayPin, OUTPUT);
pinMode(syncPin, OUTPUT);
pinMode(testPin, OUTPUT);
pinMode(correctingPin, OUTPUT);
pinMode(retardPin, INPUT_PULLUP);
pinMode(advancePin, INPUT_PULLUP);
//bitRead(receivedChars[12],1); not useful here before message arrives
}
void loop() {
recvWithStartEndMarkers();
retardState = digitalRead(retardPin);
advanceState = digitalRead(advancePin);
if (newData == true)
processNewData();
if (relayRunning == true && summerAdvance == false && winterRetard == false && missedPulseAdvance == false && manualAdvance == false)
runRelayCycle();
if bitRead(receivedChars[12], 1 == 1)
digitalWrite (testPin, HIGH);
else digitalWrite (testPin, LOW);
if bitRead(receivedChars[12], 2 == 1)
digitalWrite (syncPin, HIGH);
else digitalWrite (syncPin, LOW);
if (summerAdvance == true)
advanceClock(10); // 1 hour each pulse advances slave 30 seconds
if (winterRetard == true)
retardClock(11); //11 hours advance = 1 hour back
if (manualAdvance == true)
manualAdvanceClock(999999999);
if ((summerAdvance == true) || (winterRetard == true))
digitalWrite (correctingPin, HIGH);
else digitalWrite (correctingPin, LOW);
//if (missedPulseAdvance == true)
// advanceClock(missedCount);
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = 0x02;
char endMarker = 0x03;
char rc;
if (Serial.available() > 0) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void processNewData()
{
//if (newData == true)
//{
checkStatusBit();
checkAdvanceState();
if ((receivedChars[1] == '3' && receivedChars[0] == '0') || (receivedChars[1] == '0' &&
receivedChars[0] == '0'))
{
if (relayRunning == true)//set true during fast advance
{
missedCount++;
Serial.print("missedCount = ");
Serial.println(missedCount);
}
if (relayRunning == false) //back to normal from fast advance
{
relayStartTime = millis();
if ((relayStartTime - lastRelayStartTime >= 14000) && (retardState == HIGH)) //some lock out period
{
digitalWrite (relayPin, HIGH);
relayRunning = true;
lastRelayStartTime = relayStartTime;
}
//if (missedCount > 0)
//{
//missedPulseAdvance = true; //make up pulses next loop pass
//}
//digitalWrite (relayPin, HIGH);
//relayRunning = true;
//relayStartTime = millis();
Serial.println("on");
}
}
Serial.print("Time Now ... ");
Serial.print(retardState);
Serial.print(bitRead(receivedChars[12], 1));
Serial.print(bitRead(receivedChars[12], 2));
Serial.print(receivedChars[5]);
Serial.print(receivedChars[4]);
Serial.print(receivedChars[3]);
Serial.print(receivedChars[2]);
Serial.print(receivedChars[1]);
Serial.println(receivedChars[0]);
newData = false;
// }
}
void runRelayCycle()
{
const unsigned long relayInterval = 400;
if (millis() - relayStartTime >= relayInterval)
{
digitalWrite(relayPin, LOW);
relayRunning = false;
}
}
and the other half---
void advanceClock(unsigned int numberOfPulses)
{
const unsigned long intervalOn = 400; //adjust these numbers for fastest reliable advance
const unsigned long intervalOff = 600;
static byte relayState = LOW;//initial state starts off
static unsigned long interval = intervalOff;
static unsigned long previousMillis = millis();
static unsigned int fastCount = 0;
relayRunning = true;//blocks regular 30 second pulses
unsigned long currentMillis = millis();
//interval switchs between intervalOn and intervalOff
if (currentMillis - previousMillis >= interval)
{
previousMillis = millis();
if (relayState == LOW)
{
relayState = HIGH;
digitalWrite(relayPin, relayState);
interval = intervalOn; //switch interval
}
else //relay was HIGH
{
relayState = LOW;
digitalWrite(relayPin, relayState);
interval = intervalOff;
fastCount++; //count at end of pulse
Serial.println(fastCount);
}
}
if (fastCount >= numberOfPulses)
{
fastCount = 0;
interval = intervalOff;
summerAdvance = false;
winterRetard = false;
manualAdvance = false;
if (missedPulseAdvance == true)
{
missedPulseAdvance = false;
missedCount = 0;
}
relayRunning = false;
}
}
void retardClock(unsigned int numberOfPulses)
{
const unsigned long intervalOn = 1; //adjust these numbers for fastest reliable advance
const unsigned long intervalOff = 29999;
static byte relayState = LOW;//initial state starts off
static unsigned long interval = intervalOff;
static unsigned long previousMillis = millis();
static unsigned int fastCount = 0;
relayRunning = true;//blocks regular 30 second pulses
unsigned long currentMillis = millis();
//interval switchs between intervalOn and intervalOff
if (currentMillis - previousMillis >= interval)
{
previousMillis = millis();
if (relayState == LOW)
{
relayState = HIGH;
digitalWrite(relayPin, relayState);
interval = intervalOn; //switch interval
}
else //relay was HIGH
{
relayState = LOW;
digitalWrite(relayPin, relayState);
interval = intervalOff;
fastCount++; //count at end of pulse
Serial.println(fastCount);
}
}
if (fastCount >= numberOfPulses)
{
fastCount = 0;
interval = intervalOff;
summerAdvance = false;
winterRetard = false;
manualAdvance = false;
if (missedPulseAdvance == true)
{
missedPulseAdvance = false;
missedCount = 0;
}
relayRunning = false;
Serial.println("relayRunning = false");
}
}
void manualAdvanceClock(unsigned int numberOfPulses)
{
const unsigned long intervalOn = 400; //adjust these numbers for fastest reliable advance
const unsigned long intervalOff = 600;
static byte relayState = LOW;//initial state starts off
static unsigned long interval = intervalOff;
static unsigned long previousMillis = millis();
static unsigned int fastCount = 0;
relayRunning = true;//blocks regular 30 second pulses
unsigned long currentMillis = millis();
//interval switchs between intervalOn and intervalOff
if (currentMillis - previousMillis >= interval)
{
previousMillis = millis();
if (relayState == LOW)
{
relayState = HIGH;
digitalWrite(relayPin, relayState);
interval = intervalOn; //switch interval
}
else //relay was HIGH
{
relayState = LOW;
digitalWrite(relayPin, relayState);
interval = intervalOff;
fastCount++; //count at end of pulse
Serial.println(fastCount);
}
}
if (fastCount >= numberOfPulses)
{
fastCount = 0;
interval = intervalOff;
summerAdvance = false;
winterRetard = false;
manualAdvance = false;
if (missedPulseAdvance == true)
{
missedPulseAdvance = false;
missedCount = 0;
}
relayRunning = false;
Serial.println("relayRunning = false");
}
}
void checkStatusBit()
{
static byte lastSummerTime = 0; //initialize for winterTime
summerTime = bitRead(receivedChars[12], 1);
if (summerTime == 1 && lastSummerTime == 0)//state change
{
summerAdvance = true;
lastSummerTime = summerTime; //set to 1
}
if (summerTime == 0 && lastSummerTime == 1)//state change
{
winterRetard = true;
lastSummerTime = summerTime; //set to 0
}
}
void checkAdvanceState()
{
if (advanceState == LOW)
manualAdvance = true;
else manualAdvance = false;
}
Several things wrong here...
void runRelayCycle()
{
const unsigned long relayInterval = 400;
if (millis() - relayStartTime >= relayInterval)
{
digitalWrite(relayPin, LOW);
relayRunning = false;
}
}
-
The name is wrong. This doesn't run a cycle. It turns it off when it feels like it.
-
The indentation is wrong. Run control-T autoformat. It will make the whole thing easier to read.
-
This is not the only code that turns the relay off. The digitalWrite()s are scattered across all of your code.
-
This has a timer but it never sets or resets the time. That is obviously done elsewhere. But the interval used is private to this function. So is it a private timer or a global one?
-
It does set a boolean to show that it did its job but it never really checked if the job needed doing in the first place.
Try to confine the physical pin writes to a maximum of 2 places in the code. One to turn it on and one to turn it off. This one is actually not too bad as the turn-off.
Think about how you could have only one digitalWrite(relayPin, HIGH). Maybe that goes in a function that checks the time since it was turned off. But that means that it is only a "maybe-turn-it-on". You do want a turn-on to always, eventually, be done. So maybe keep a count of pending relay cycles required. A regular clock tick just adds 1. A spring-forward adds 3600. Then the relay cycle functions work to get that count back to zero as fast as the relay is allowed to tick.
I had hoped the answer would be easier than that, unfortunately I'm not clued up enough on this to make the changes you suggest.
As I said, it's a pre existing sketch I am merely modifying. I don't have the knowledge to write something this complex from scratch
I've tried my best to study the code I have with a veiw to altering it as per your advice, but I'm simply getting lost with it. I just haven't yet got the brains to work it all out. I'm good at all the hardware side of things, but using arduino is somewhat new to me and it appears I'm trying to do something rather unusual that no amount of reading tutorials can assist me.
Is there any example code I could look at for inspiration?
Thanks in anticipation...
Sorry. Your code is generally competent but I forget that you didn't get there on your own.
If it is truly too hard, try posting in the Gigs and Collaboration forum. What you are doing is not very complex so maybe someone will help you out for $50.
I have created a oneTick function and tried to clean up the timing issues between the standard tick and the time adjustment fast advance. I can't test an external time source well, so there may be issues. I have put the missed pulse make up back. There is lots in your code which doesn't make sense to me, but I assume it was from trying to fix the timing error you saw.
forum_attchment.ino (8.48 KB)
I believe that the code I provided yesterday fixes the long/dual pulse issue with the seasonal time changes.
That issue still persists in the missedPulseAdvance. You can either eliminate that function as you previously did and just compensate with the number of pulse called at the time change, or try this modification to call one additional pulse for the make up.
if (missedPulseAdvance == true)
advanceClock(missedCount + 1);