I have an Arduino Uno which has pins 2-9 connected to an 8 relay module. The module is rated for 5V actuating 24VDC. If you need the specs I'm happy to get them but they're not in this post cause it's a pretty standard relay module.
I have code attached below which accepts serial input to set the arduino pins (2-9) high or low to actuate the relays. The relays are connected to valves which can be turned on and off through the serial monitor (or in practice a processing sketch). In addition, the sketch reads data off analog pins 0 and 1 every second and sends that data along with some other information back to the serial monitor. The VCC bit at the end is supposed to help adjust for the fact that the 5V reference isn't exactly 5V and it's slightly different on each arduino. That section of code seems to work fine for it's purpose.
The Problem
The code works great to actuate the relays depending on what I input into the serial monitor. However, when I turn on the power supply so the relays will actually close and power the valves, the program hangs up after a couple relays are switched.
If I type 2 to turn on relay 1, it turns on. When I type 2 again to turn it off, I think my Serial connection over USB breaks (based on println() I've seen in stop in both the for loop and the switch statement, sometimes stopping in the middle of printing a Serial.println().) The Tx light keeps flashing but the serial monitor stop listing the data. If I send the arduino another command over the Serial monitor I get the error listed in the next post.
Here's the code:
/*
This program accepts Serial inputs to toggle the state of pins 2-8 between high and low upon receiving a string with the corresponding pin as the first character.
Input strings are limited to 10 chars.
In addition, it accepts the character 9 followed by 3 characters to set the PWM Value of pin 9 (i.e. '9123' sets pin 9 to 123).
It also sends out a serial string which is 'A0,A1,pause, Vcc' where A0 and A1 are the values of the corresponding analog pins,
pause is the time in milliseconds between serial outputs, and Vcc is the measured voltage of default 5V pin.
*/
int timesThrough = 0;
String output1; //data point 1
String output2; //data point 2
int pause = 1000; //loop delay in ms
char input[4];
char input1;
char input2;
char input3;
char input4;
int pumpSpeed = 0;
void setup() { //9600 baud serial monitor output
Serial.begin(9600);
for(int i = 2; i<11;i++)
{
pinMode(i, OUTPUT);
digitalWrite(i, HIGH);
}
digitalWrite(10,LOW);
}
void loop() {
if(Serial.available())
{
for(int j = 0; j < 4; j++)
{
//Serial.println(j);
input[j] = Serial.read();
delay(5);
//Serial.println(input[j]);
}
switch(input[0])
{
case '1':
if(digitalRead(9)==HIGH)
{
digitalWrite(9,LOW);
}
else
{
digitalWrite(9,HIGH);
}
break;
case '2':
if(digitalRead(2)==HIGH)
{
digitalWrite(2,LOW);
}
else
{
digitalWrite(2,HIGH);
}
break;
case '3':
if(digitalRead(3)==HIGH)
{
digitalWrite(3,LOW);
}
else
{
digitalWrite(3,HIGH);
}
break;
case '4':
if(digitalRead(4)==HIGH)
{
digitalWrite(4,LOW);
}
else
{
digitalWrite(4,HIGH);
}
break;
case '5':
if(digitalRead(5)==HIGH)
{
digitalWrite(5,LOW);
}
else
{
digitalWrite(5,HIGH);
}
break;
case '6':
if(digitalRead(6)==HIGH)
{
digitalWrite(6,LOW);
}
else
{
digitalWrite(6,HIGH);
}
break;
case '7':
if(digitalRead(7)==HIGH)
{
digitalWrite(7,LOW);
}
else
{
digitalWrite(7,HIGH);
}
break;
case '8':
if(digitalRead(8)==HIGH)
{
digitalWrite(8,LOW);
}
else
{
digitalWrite(8,HIGH);
}
break;
case '9':
pumpSpeed = 0;
for(int k = 1; k < 4;k++) //code that should work that doesn't
{
int value = (input[k]-'0');
int power = round(pow(10,(3-k)));
pumpSpeed += value*power;
}
//Serial.println(pumpSpeed);
if(pumpSpeed == 0)
{
digitalWrite(10,LOW);
}
else
{
analogWrite(10, pumpSpeed);
}
break;
default:
break;
}
}
if(millis() / (pause-1) > timesThrough) //send data every 'pause' in ms
{
analogReference(DEFAULT); //set reference to 5V
output1 = String(analogRead(A0)); //read analog pin A0
output1 = String(analogRead(A0)); //read analog pin A0 second time. Allows time for the analog reference to fully switch
analogReference(INTERNAL); //set reference to 1.1V
output2 = String(analogRead(A1)); //read analog pin A1
delay(10);
output2 = String(analogRead(A1)); //read analog pin A1 second time. Allows time for the analog reference to fully switch
delay(10);
output2 = String(analogRead(A1)); //read analog pin A1 third time. As above
delay(10);
Serial.println(output1 + "," + output2 + "," + pause + "," + readVcc() + "," + pumpSpeed);
//delay(pause);
if(digitalRead(13)==HIGH) { //flash and led every loop iteration
digitalWrite(13,LOW);
}
else{
digitalWrite(13,HIGH);
}
timesThrough++; //update count
}
}
long readVcc() {
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA,ADSC)); // measuring
/*uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high<<8) | low;
result = 2618880L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000*/
long result = 1125300 / ADC; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return result; // Vcc in millivolts
}
What I've Tried Serial.read() returns -1 when there's nothing and I've verified that it's fine being called when there's nothing to read. With println() statements I've seen it capture the -1 perfectly fine. I've also tried bracketing the Serial.read with if(Serial.available()) so it wouldn't call the read if there wasn't anything more for it. I also tried removing the char array and string each byte into it's own char variable manually which doesn't solve the problem either. It seems like the serial communication is breaking as the arduino is still trying to send data, according to the Tx light, but the serial monitor doesn't seem to receive it. The most confusing part of this is that if I unplug the power source from the relay so the valves don't actually flip, (relays still turn on and off) then the program works fine. So maybe there's a feedback problem or something... Any help would be greatly appreciated.