Hi there! I'm running into a bit of a snag and thought I should ask for help since I'm seeing similar behavior after I "fixed" it (went from using digitalwrite() to digitalwritefast() ).
I've got some relays (see board in links below) connected to some output pins (sequential pins) and under certain circumstances I'd like to modify the output value of pin 2, then pin 3 (relay 1 then relay 2). The symptom was that the second change doesn't work as it should. After research I discovered that digitalwrite() was slow and I could try digitalwritefast(). I imported that library and now things work the way I expect. Except for a certain part of my code that calls 2 of my class methods (maybe they're called something else in Arduino, but they are methods within my program outside the main loop()) back to back. Very similar circumstances to my original problem.
After the switch to digitalwritefast(), I noticed an odd behavior with the LEDs on the relay board. I noticed that the 2nd change, when it was supposed to occur, instead produced a visible dimming of the LED associated to that output. However, this only happens in this block of code now (all of it below):
if (millis() > (whatTimeIsIt + idleMotorKill) ){
//digitalWriteFast(3,HIGH);
//digitalWriteFast(1,LOW);
engineKill(); // digitalWrite(Relay_1, RELAY_ON);
brakesEngage();
} // test millis()
I think this has something to do with a few words on a page that I can't find again where the author said something about calls to digitalwritefast() dropping down to normal speed within a conditional statement. i also seem to remember the author saying something to the effect of making the conditional a single line and adding braces. I found a page
that mentions the braces, but the "do" part of my conditional is 2 lines, each line calls one of my class methods. I'm not sure how to cram that into 1 line and I am not convinced that would even matter.
Right now I am just holding the pin/relay in one position. Later on I would like to make use of Timer (A library I found) to pulse certain outputs instead of latch them. I bring that up in case that has any bearing on the ability to change the pin status.
I read the page on port manipulation
and think that I am running into this problem because the pins are adjacent and the controller doesn't have enough time to finish the first pin operation to do the second. However, that doesn't make much sense, as the arduino would lose a lot of its value or a lot more people would be complaining about this sort of thing.
I don't think the problem is specific to certain pins, I've moved around which pins I'm using a few times to test that theory. The problem follows whatever pins I try to change the outputs on back to back.
Here's the test code I'm working on:
#include <ServoDecode.h>
#include <digitalWriteFast.h> // digitalWriteFast(pin,HIGH/LOW)
char * stateStrings[] = {
"NOT_SYNCHED", "ACQUIRING", "READY", "in Failsafe"};
// Define readable non-backwards states for relays.
// This is because relays are active LOW. That means you can ground the pin and activate the relay.
const byte RELAY_ON = 0;
const byte RELAY_OFF = 1;
// Give each relay friendly name and map to Arduino Digital I/O pin number
const byte Relay_1 = 2; // wire 1 of the engine kill actuator. Pulse to allow engine to run.
const byte Relay_2 = 3; // wire 2 of the engine kill actuator. Pulse to kill engine.
const byte Relay_3 = 4; // brake controller
const byte Relay_4 = 5;
const unsigned long idleMotorKill = 5000; // delay to kill the motor
long whatTimeIsIt = 0;
void setup(){
// ServoDecode setup
// Seems that some of this is debug info and maybe can be removed for runtime.
Serial.begin(38400);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
ServoDecode.begin();
ServoDecode.setFailsafe(3,1234); // set channel 3 failsafe pulse width
// Relay Setup
// Initialize Pins so relays are inactive at reset
digitalWrite(Relay_1, RELAY_OFF);
digitalWrite(Relay_2, RELAY_OFF);
digitalWrite(Relay_3, RELAY_OFF);
digitalWrite(Relay_4, RELAY_OFF);
// THEN set pins as outputs
pinMode(Relay_1, OUTPUT);
pinMode(Relay_2, OUTPUT);
pinMode(Relay_3, OUTPUT);
pinMode(Relay_4, OUTPUT);
delay(1000); // Check that all relays are inactive at Reset
//engage breaks
digitalWrite(Relay_3, RELAY_ON);
//whatTimeIsIt = millis();
} // end setup()
void loop(){
/*
// move old values to proper variable
for ( int i = 1; i <=numChannels; i++ ){
prevVal[i] = curVal[i];
curVal[i] = ServoDecode.GetChannelPulseWidth(i); // GetChannelPulseWidth technically requires a byte, but the number won't get high enough to cause problems
} // end move old values to proper variable
*/
if(ServoDecode.getState()!= READY_state) { // transmitter is off or out of range
engineKill(); // digitalWrite(Relay_4, RELAY_OFF); // kill motor
brakesEngage(); // digitalWrite(Relay_3, RELAY_ON); // engage brakes
whatTimeIsIt = 0;
// digitalWrite(Relay_1, RELAY_OFF);
} // end if
if(ServoDecode.getState()== READY_state) {
if(whatTimeIsIt==0){
whatTimeIsIt = millis();
}
engineAllow(); // digitalWrite(Relay_4, RELAY_ON); // allow motor to be cranked
brakesDisengage(); // digitalWrite(Relay_3, RELAY_OFF); //disengage brakes
if (millis() > (whatTimeIsIt + idleMotorKill) ){
//digitalWriteFast(3,HIGH);
//digitalWriteFast(1,LOW);
engineKill(); // digitalWrite(Relay_1, RELAY_ON);
brakesEngage();
} // test millis()
} // end if
} // end loop()
boolean userInputChanged(){
return false;
} // end userInputChanged
/*
const byte Relay_1 = 2; // wire 1 of the engine kill actuator. Pulse to allow engine to run.
const byte Relay_2 = 3; // wire 2 of the engine kill actuator. Pulse to kill engine.
const byte Relay_3 = 4; // brake controller
const byte Relay_4 = 5;
Turn pins LOW to engage/close relay and HIGH to disengage/open the relay
*/
void engineKill(){
digitalWriteFast(2,HIGH); // turn relay 1 (on pin 2) off, part 1 of disengaging the engine
digitalWriteFast(3,LOW); // turn relay 2 (on pin 3) on, part 2 of disengaging the engine
//digitalWrite(Relay_2, RELAY_OFF); // just in case
//digitalWrite(Relay_1, RELAY_ON); // eventually pulse it
} // end instantEngineKill
void engineAllow(){
digitalWriteFast(3,HIGH); // turn relay 2 (on pin 3) off, part 1 of allowing the engine to run
digitalWriteFast(2,LOW); // turn relay 1 (on pin 2) on, part 2 of allowing the engine to run
//digitalWrite(Relay_1, RELAY_OFF); // just in case
//digitalWrite(Relay_2, RELAY_ON); // eventually pulse it
} // end instantEngineKill
void brakesEngage(){
digitalWriteFast(4,LOW); // turn relay 3 (on pin 4) on, engaging the brakes
//digitalWrite(Relay_3, RELAY_ON);
} // end brakesEngage
void brakesDisengage(){
digitalWriteFast(4,HIGH); // turn relay 3 (on pin 4) off, disengaging the brakes
//digitalWrite(Relay_3, RELAY_OFF);
} // end brakesDisengage
If you could tell me why this code is not working the way I think it should, I would much appreciate it. I'm not sure if I did something stupid, or just didn't take into account the nature of the architecture.
This is a continuation of the same project I posted about previously, although it's a different problem.
Arduino that I'm using:
Older version of this: https://www.sparkfun.com/products/11021
I do have a rev 3 laying around if that would be better for what I am doing.
Hobby King Tranceiver pair:
http://www.hobbyking.com/hobbyking/store/uh_viewItem.asp?idProduct=9042
ServoDecode:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1228137503
Relay hardware (example):
Relay code
http://arduino-info.wikispaces.com/ArduinoPower
Actuator (example):