I have a broad question about how the Arduino, loops, and how timing work. Im a newbie, so don't assume Im doing this right.
The concept:
I have an AC fan motor that is powered by an opto-isolated TRIAC circuit that is driven by a Zero-Cross detection circuit. I want to control the FAN via Bluetooth... sounds simple?!
The Problem:
If I run the fan by itself and use a 3k pot to dim/slow the fan it works perfect... As soon as I add serial data, i.e. the Bluetooth it starts to loose timing and the fan flickers/stutters.
What I believe is happening is that the serial data, and any other functions, cause a delay in the AC zero-cross timing. Im not sure if there is a way to get around this since there is only one loop... Any ideas, I feel that the most stable way to do this is to have to arduinos, one dedicated to the AC motor and the other could control all other functions.
Take a look at the code below, The first works great, second has all the added functions and BT serial comm... this is the problem code.
Basic Zero-Cross and dimming code, works perfect:
/*
Purpose: to detect zero crossing pulse at
INT0 digital pin 2, which after delay determined by POT on analog A0
switches on a triac.
Power output to triac activated by external switch.
*/
#define triacPulse 5
#define SW 4
#define aconLed 13
int val;
void setup() {
pinMode(2, INPUT);
digitalWrite(2, HIGH); // pull up
pinMode(triacPulse, OUTPUT);
pinMode(SW, INPUT);
digitalWrite(SW, HIGH);
pinMode(aconLed, OUTPUT);
digitalWrite(aconLed, LOW);
}
void loop() {
// check for SW closed
if (!digitalRead(SW)) {
// enable power
attachInterrupt(0, acon, FALLING);
// HV indicator on
digitalWrite(aconLed, HIGH);
} // end if
else if (digitalRead(SW)) {
detachInterrupt(0); // disable power
// HV indicator off
digitalWrite(aconLed, LOW);
} // else
} // end loop
// begin ac int routine
// delay() will not work!
void acon()
{
if (analogRead(0) > 50)
{
delayMicroseconds((analogRead(0) * 6) + 1000); // read AD1
digitalWrite(triacPulse, HIGH);
delayMicroseconds(200);
// delay 200 uSec on output pulse to turn on triac
digitalWrite(triacPulse, LOW);
}
else
{
delayMicroseconds(1300); // read AD1
digitalWrite(triacPulse, HIGH);
delayMicroseconds(200);
// delay 200 uSec on output pulse to turn on triac
digitalWrite(triacPulse, LOW);
}
}
This is code w/Bluetooth and some other routines added, this is the problem code (removed variables for Blog size limits):
void setup()
{
// LCD control
lcd.begin(16, 2); // LCD setup
lcd.clear(); // LCD, initial clear
// End LCD Control
// Initialize set Target temp
globalAnalogReadVariable = (analogRead(getTempInputPin)); // gets pot reading and sets it into an integer
globalTargetTemp = (globalAnalogReadVariable / 4.052) + 150; //sets temp threshold integer
globalTargetTemp = ((globalTargetTemp+4)/5)*5; // round to nearest 5
//analogTargetTemp = globalTargetTemp;
// End Initialize set Target temp
// Set some variables
serialB = 0; // used in BT comm
//btTempChange = false; // sets the BT boolean to FALSE.
// End
/* Disabled
// AC Speed control section
pinMode(2, INPUT);
digitalWrite(2, HIGH); // pull up
pinMode(triacPulse, OUTPUT);
// End AC speed control section
*/
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(6, OUTPUT); // Used for the lamp output to mimic heat
pinMode(13, OUTPUT);
Serial.begin(115200); // serial print window initialize default 9600
}
void loop() // Main Loop
{
processTemps(); // Call funtion to process ALL temp info
processHeatingElement(); // Call to function to turn on Lamp based on temperature
blueToothComm1(); // Call to BT function 1
processSerialWindoData(); // Call to function to show data in Serial window
// speedControl(); // Call the function to control motor speed ***** TEMPORARY DISABLED, issue w/ timing *****
LCDdisplayTemps(); // displays current temp on LCD
delay(1000); // repeat once per second (change as you wish!)
} // End Loop
/*
void speedControl() // Speed & Motor control function
{
attachInterrupt(0, acon, FALLING);
}
*/
void processSerialWindoData()
{
Serial.print(grillTemp);
Serial.print(":");
Serial.println(globalTargetTemp);
}
void processTemps()
{
int localAnalogReadVariable; // Local temp variable to check if state of pot has changed
int LA;
int GV;
int GVup;
int GVdn;
localAnalogReadVariable = (analogRead(getTempInputPin)); // assign temp var the POT analog pin value
voltage = getVoltage(temperaturePin);
degreesC = (voltage - 0.5) * 100.0;
degreesF = degreesC * (9.0/5.0) + 32.0;
// grillTemp = ((degreesF + grillTemp) / 2); // replace with if statement below
if (grillTemp >= MinGrillTemp)
{
grillTemp = ((degreesF + grillTemp) / 2); // used to average the output
//grillTemp = degreesF + 200; // Test to LED output based on temp *** REMOVE +200 only for testing
}
else
{
grillTemp = 150; // Used for error handling, in the future we want to add text "Heating" until it reaches 150 deg
}
localAnalogReadVariable = (analogRead(getTempInputPin)); // assign temp var the POT analog pin value
LA = localAnalogReadVariable;
GV = globalAnalogReadVariable;
GVup = globalAnalogReadVariable +50;
GVdn = globalAnalogReadVariable -50;
if (LA >= GVup || LA <= GVdn)
{
globalAnalogReadVariable = (analogRead(getTempInputPin)); // gets pot reading and sets it into an integer
globalTargetTemp = (globalAnalogReadVariable / 4.052) + 150; //sets temp threshold integer
globalTargetTemp = ((globalTargetTemp+4)/5)*5; // round up to nearest multiple of 5
}
}
void LCDdisplayTemps()
{
lcd.clear();
lcd.print("Grill Temp ");
lcd.print(grillTemp);
lcd.setCursor(0,1);
lcd.print("Target Temp ");
lcd.print(globalTargetTemp);
}
/*
// begin ac int routine
// delay() will not work!
void acon()
{
delayMicroseconds((analogRead(0) * 6) + 1000); // read AD1
digitalWrite(triacPulse, HIGH);
delayMicroseconds(200);
// delay 200 uSec on output pulse to turn on triac
digitalWrite(triacPulse, LOW);
}
*/
float getVoltage(int pin) // gets voltage from analog pin and converts it
{
return (analogRead(pin) * 0.004882814);
}
void blueToothComm1()
{
if (Serial.available() > 0)
{
serialRead = Serial.read();
if (serialRead < 50)
{
serialA = serialRead;
//Serial.print("Serial A = ");
//Serial.println(serialRead);
}
else if (serialRead >= 50)
{
globalTargetTemp = (serialRead * 5) - 100;
}
}
switch (serialA) {
case 1:
digitalWrite(BTledPin, HIGH);
break;
case 2:
digitalWrite(BTledPin, LOW);
break;
case 3:digitalWrite(BTledPin, HIGH);
delay(100);
digitalWrite(BTledPin, LOW);
delay(100);
default:
break;
}
}
void processHeatingElement()
{
GtHi = globalTargetTemp;
GtLo = globalTargetTemp;
if (grillTemp < GtLo + GrillTempRange_Lo) // Red & Yellow LED
{
digitalWrite(6, HIGH); // Turn on Lamp, Used for the lamp output to mimic heat.
}
if (grillTemp > GtHi + GrillTempRange_Hi) // Yellow LED
{
digitalWrite(6, LOW); // Turn off Lamp, Used for the lamp output to mimic heat.
}
}
