// Fan cart driver version 2.0
// Eric Ayars
// 11/12/10
#define MOTORPWM 11
#define MOTORDIR 12
#define POWERINDICATOR 13
#define MODESWITCH 2
#define SPEEDSWITCH 5
#define TIMESWITCH 7
#define MAGNETSWITCH 8
#define MODELIGHT 3
#define SPEEDLIGHT 4
#define TIMELIGHT 6
#define DEBOUNCE 10
#define FLASHTIME 150
byte UserInput = 0;
boolean ProgramState = false;
long int CurrentTime;
byte Speed = 2; // Ranges from 1 to 3 (0 not used).
byte PowerLevel[] = {0, 130, 200, 255};
byte Mode = 1; // Ranges from 1 to 3.
byte Time = 2; // Ranges from 1 to 4 (0 not used).
int TimeLevel[] = {0, 1000, 2000, 3000, 4000};
boolean MotorState = false;
boolean MotorDirection = false;
byte LastMagnetState = HIGH;
byte ButtonDown() {
// Returns 3-bit indicator of which buttons are currently down.
// bit 0 - Mode
// bit 1 - Speed
// bit 2 - Time
byte result = 0; // Default case -- nothing is pressed
if (digitalRead(MODESWITCH) == LOW) {
// Mode button is down
result = result | B0001;
}
if (digitalRead(SPEEDSWITCH) == LOW) {
// Speed button is down
result = result | B0010;
}
if (digitalRead(TIMESWITCH) == LOW) {
// Time button is down
result = result | B0100;
}
delay(DEBOUNCE);
return result;
}
boolean MagnetSensed() {
boolean state;
byte CurrentState = digitalRead(MAGNETSWITCH);
if ((LastMagnetState == HIGH) && (CurrentState == LOW)) {
// Cart has just passed a magnet
state = true;
delay(DEBOUNCE);
} else {
state = false;
}
LastMagnetState = CurrentState;
return state;
}
void AnnounceReady() {
digitalWrite(MODELIGHT, HIGH);
digitalWrite(SPEEDLIGHT, HIGH);
digitalWrite(TIMELIGHT, HIGH);
}
void ShowStatus(byte Light, byte Blinks) {
// Blinks a light some number of times.
digitalWrite(Light, LOW);
delay(FLASHTIME);
for (byte j=0; j<Blinks; j++) {
digitalWrite(Light, HIGH);
delay(FLASHTIME);
digitalWrite(Light, LOW);
delay(FLASHTIME);
}
delay(FLASHTIME);
delay(FLASHTIME);
}
void MotorOn() {
// turns motor on in direction set by global MotorDirection.
digitalWrite(POWERINDICATOR, HIGH);
digitalWrite(MOTORDIR, MotorDirection);
if (MotorDirection) {
// set pwm appropriately for backward spin
analogWrite(MOTORPWM, 255-PowerLevel[Speed]);
} else {
// set pwm for forward spin
analogWrite(MOTORPWM, PowerLevel[Speed]);
}
MotorState = true;
}
void MotorOff() {
// turns motor off.
digitalWrite(MOTORDIR, LOW);
digitalWrite(MOTORPWM, LOW);
digitalWrite(POWERINDICATOR, LOW);
MotorState = false;
}
void ProgramMode(byte ProgramThis) {
// Sets mode, speed, time...
boolean State = false;
boolean Exit = false;
if (ProgramThis & B0001) { // Program the Mode.
// Turn mode light off and the other two lights on.
digitalWrite(MODELIGHT, LOW);
digitalWrite(SPEEDLIGHT, HIGH);
digitalWrite(TIMELIGHT, HIGH);
while (!Exit) {
delay(DEBOUNCE);
if (ButtonDown() == 1) {
// Mode button has been pressed. Increment mode.
Mode += 1;
if (Mode > 3) {
Mode = 1;
}
ShowStatus(MODELIGHT, Mode);
}
UserInput = ButtonDown();
if (UserInput > 1) {
Exit = true;
}
}
}
if (ProgramThis & B0010) { // Program the Speed.
// Turn speed light off and the other two lights on.
digitalWrite(MODELIGHT, HIGH);
digitalWrite(SPEEDLIGHT, LOW);
digitalWrite(TIMELIGHT, HIGH);
while (!Exit) {
delay(DEBOUNCE);
if (ButtonDown() == 2) {
// Speed button has been pressed. Increment Speed.
Speed += 1;
if (Speed > 3) {
Speed = 1;
}
ShowStatus(SPEEDLIGHT, Speed);
}
UserInput = ButtonDown();
if ((UserInput & B0001) || (UserInput & B0100)) {
Exit = true;
}
}
}
if (ProgramThis & B0100) { // Program the Time.
// Turn Time light off and the other two lights on.
digitalWrite(MODELIGHT, HIGH);
digitalWrite(SPEEDLIGHT, HIGH);
digitalWrite(TIMELIGHT, LOW);
while (!Exit) {
delay(DEBOUNCE);
if (ButtonDown() == 4) {
// Time button has been pressed. Increment Time.
Time += 1;
if (Time > 4) {
Time = 1;
}
ShowStatus(TIMELIGHT, Time);
}
UserInput = ButtonDown();
if ((UserInput & B0001) || (UserInput & B0010)) {
Exit = true;
}
}
}
}
void DoMode(byte Mode) {
// This routine runs the desired mode until a button is pressed.
AnnounceReady();
MotorDirection = false; // false is forward, true is backwards.
while (!ButtonDown()) {
// No button has been pressed, so keep going.
// Mode 1
//
// In mode 1, the fan turns on and off on alternating magnets.
if (Mode==1) {
MotorDirection = false;
if (MagnetSensed()) {
if (MotorState) {
// Motor is currently on. Turn it off.
MotorOff();
} else {
// Motor is currently off. Turn it on.
MotorOn();
}
}
}
// Mode 2
//
// In mode 2, the fan turns on at the first magnet, then turns off
// a set time later.
if (Mode==2) {
MotorDirection = false;
if (MagnetSensed()) {
// Turn the motor on...
MotorOn();
// Wait a given time...
delay(TimeLevel[Time]);
// And turn the motor off.
MotorOff();
}
}
// Mode 3
//
// In mode 3, the motor turns on when it first sees a magnet, then
// reverses each time it passes a magnet.
if (Mode==3) {
if (MagnetSensed()) {
// Reverse the motor...
MotorDirection = !MotorDirection;
// And turn it on in the new direction.
MotorOn();
}
}
}
// Button has been pressed, so...
MotorDirection = false;
MotorOff();
}
void setup() {
// Set appropriate pins to output.
pinMode(POWERINDICATOR, OUTPUT);
pinMode(MODELIGHT, OUTPUT);
pinMode(SPEEDLIGHT, OUTPUT);
pinMode(TIMELIGHT, OUTPUT);
pinMode(MOTORPWM, OUTPUT);
pinMode(MOTORDIR, OUTPUT);
// Set appropriate pins to input, with pull-up resistors as needed.
pinMode(MODESWITCH, INPUT);
digitalWrite(MODESWITCH, HIGH);
pinMode(SPEEDSWITCH, INPUT);
digitalWrite(SPEEDSWITCH, HIGH);
pinMode(TIMESWITCH, INPUT);
digitalWrite(TIMESWITCH, HIGH);
pinMode(MAGNETSWITCH, INPUT);
digitalWrite(MAGNETSWITCH, HIGH); // This one may not need the
// pull-up resistor, but...
// Turn off motor just in case.
MotorOff();
// Indicate Status.
ShowStatus(MODELIGHT, Mode);
ShowStatus(SPEEDLIGHT, Speed);
ShowStatus(TIMELIGHT, Time);
// Indicate ready-to-go
AnnounceReady();
}
void loop() {
// The main loop checks for user input, passes any input to
// the "ProgramMode" routine, then runs "DoMode". That's it!
// Check to see whether the user wants anything
UserInput = ButtonDown();
CurrentTime = millis(); // Check what time it is
while (ButtonDown()) {
// Wait until button is up to decide what to do.
delay(10);
}
if (millis()-CurrentTime > 2000) {
// Button was held for more than 2 seconds, so program the device.
ProgramMode(UserInput);
} else {
if (UserInput & B0001) {
// The mode button was pressed.
ShowStatus(MODELIGHT, Mode);
}
if (UserInput & B0010) {
// The speed button was pressed.
ShowStatus(SPEEDLIGHT, Speed);
}
if (UserInput & B0100) {
// The Time button was pressed.
ShowStatus(TIMELIGHT, Time);
}
}
DoMode(Mode);
}