#include <DualVNH5019MotorShield.h>
// Arduino Uno code based hugely on the work of SilentChill, Avenga76, and a number of others.
// Forked off to support right and left speed commands (R000 and L000, etc) as well as traditional S000 format.
// Version - 02_23_2021
#define FALSE 0
#define TRUE 1
#define BRAKEVCC 0
#define CW 1
#define CCW 2
#define BRAKEGND 3
#define CS_THRESHOLD 100
// If left and right fan control is swapped, just swap the values defined here for LEFT and RIGHT.
#define BOTH 0
#define LEFT 1
#define RIGHT 2
// Idle speed setting if you want the Arduino to reset or cold start with some air flow. Useful for
// providing a light wind for VR comfort. Range is 0 to 255. I use 20 with TerraBloom fans. Default
// value is 0 to not surprise anyone but change as you wish. There are no checks on this so you can
// break the code if you use values less than 0 or more than 255.
#define IDLESPEED 0
int inApin[2] = {2, 7}; // INA: Clockwise output
int inBpin[2] = {4, 8}; // INB: Counter-clockwise output
int pwmpin[2] = {9, 10}; // PWM output
int cspin[2] = {0, 1}; // CS: Current sense ANALOG input
int enpin[2] = {0, 1}; // EN: Status of switches output (Analog pin)
int statpin = 13;
// pwmMode - sets the PWM frequency, valid options as follows:
// pwmMode = 0 will use 980Hz PWM, default mode which will work with all fan types, will cause coil whine if using a MM.
// pwmMode = 1 will use 4kHz PWM, might reduce coil whine for blowers, use heatsinks on the MM - check MM temp at a low fan speed.
// pwmMode = 2 will use 8kHz PWM, might be OK for blowers with active cooling on the MM - check MM temp at a low fan speed.
// pwmMode = 3 will use 31kHz PWM, use with caution - not for blowers with MM as it will cause very high temps. Check MM temp at a low fan speed.
// server fans - should be able to use pwmMode = 2 or 3. If you are using the PWM control on the server fan, leave this at default 0.
// if you have blowers with a monster moto, try pwmMode = 1 or 2 and check whether your monster moto temp at low speeds.
int pwmMode = 1; // value of 0, 1, 2 or 3 - modes 2 and 3 will overheat a Monster Moto if used with blowers
int Speed = 40;
int bufferArray[4];
int whichFan = BOTH;
void setup()
{
Serial.begin(115200, SERIAL_8N1);
// initialize digital pins as outputs
for (int i=0; i<2; i++)
{
pinMode(inApin, OUTPUT);
pinMode(inBpin, OUTPUT);
pinMode(pwmpin, OUTPUT);
digitalWrite(inApin, LOW);
digitalWrite(inBpin, LOW);
}
// disable timer0's interrupt handler - this will disable Arduino's time keeping functions such as delay()
TIMSK0 &= B11111110;
if (pwmMode == 1)
{
// Set pins 5 & 6 to Phase-correct PWM of 3.9 kHz (prescale factor of 8)
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
TCCR0B = _BV(CS01); // prescaler of 8, gives frequency 61kHz/8/2 = 3.9kHz
}
else if (pwmMode == 2)
{
// Set pins 5 & 6 to Fast PWM of 7.8 kHz (prescale factor of 8)
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
TCCR0B = _BV(CS01); // prescaler of 8, gives frequency 61kHz/8 = 7.8kHz
}
else if (pwmMode == 3)
{
// Set pins 5 & 6 to Phase-correct PWM of 31.25 kHz (prescale factor of 1)
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); // phase-correct PWM
TCCR0B = _BV(CS00); // prescaler of 1, gives frequency 61kHz/1/2 = 31.25kHz
}
else
{
// Set pins 5 & 6 to Fast PWM of 980Hz (prescale factor of 64)
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); // fast PWM
TCCR0B = _BV(CS01) | _BV(CS00); // prescaler of 64, gives frequency 61kHz/64 = 980Hz
}
// Just throw on a low speed in case no wind support in application...
motorGo(0, CW, IDLESPEED); //Motor1
motorGo(1, CW, IDLESPEED); //Motor2
}
void loop()
{
ReadData();
if (whichFan == BOTH)
{
motorGo(0, CW, Speed); //Motor1
motorGo(1, CW, Speed); //Motor2
if (Speed == 0) motorOff(0);
if (Speed == 0) motorOff(1);
}
if (whichFan == LEFT)
{
motorGo(0, CW, Speed); //Motor1
if (Speed == 0) motorOff(0);
}
if (whichFan == RIGHT)
{
motorGo(1, CW, Speed); //Motor2
if (Speed == 0) motorOff(1);
}
}
void motorOff(int motor)
{
// Initialize braked
for (int i=0; i<2; i++)
{
digitalWrite(inApin, LOW);
digitalWrite(inBpin, LOW);
}
}
void motorGo(uint8_t motor, uint8_t direct, uint8_t Speed)
{
if (motor <= 1)
{
if (direct <=4)
{
// Set inA[motor]
if (direct <=1)
digitalWrite(inApin[motor], HIGH);
else
digitalWrite(inApin[motor], LOW);
// Set inB[motor]
if ((direct==0)||(direct==2))
digitalWrite(inBpin[motor], HIGH);
else
{
digitalWrite(inBpin[motor], LOW);
analogWrite(pwmpin[motor], Speed);
}
}
}
}
void ReadData()
{
// We need 4 characters - the command followed by three digits
bool haveCommand = FALSE;
bool haveStart = FALSE;
while (haveCommand == FALSE) // can't exit until have a full valid cddd command
{
// where c is a valid char and ddd is a valid 3
// character representation of three digits
// Valid command always starts with an S (legacy for both fans), L (left fan), or R (right fan)
while (haveStart == FALSE)
{
while (Serial.available() == 0); // spin and wait for data
bufferArray[0] = Serial.read(); // have data, read it
if (bufferArray[0] == 'S') //S
{
whichFan = BOTH;
haveStart = TRUE;
}
else if (bufferArray[0] == 'L') //L
{
whichFan = LEFT;
haveStart = TRUE;
}
else if (bufferArray[0] == 'R') //R
{
whichFan = RIGHT;
haveStart = TRUE;
}
}
// Now need the numbers - will just read three and throw them away if any don't qualify
// if we unsynchronize, it will fail valid digits and go back to waiting for command char
for (int i = 1; i < 4; i++) // read and label each byte.
{
while (Serial.available() == 0); // spin and wait for each character to arrive
bufferArray = Serial.read(); // store as they come in
}
// Check the numbers for validity
if (isDigit(bufferArray[1]) && isDigit(bufferArray[2]) && isDigit(bufferArray[3]))
// all are numbers - have a full cddd command
haveCommand = TRUE; // otherwise start over looking for a new and valid command
}
// Now turn that into a number and clip to 255 - rely on Game Dash for proper scaling
Speed = ((bufferArray[1]-48)*100) + ((bufferArray[2]-48)*10) + ((bufferArray[3]-48)*1);
//Serial.println(SpeedGameDash);
if (Speed > 255)
Speed = 255;