Implemented Arduino code

This commit is contained in:
Mark van Renswoude 2017-08-31 21:55:23 +02:00
commit 1c0ecea038

224
SimulatorFans.ino Normal file
View File

@ -0,0 +1,224 @@
/*
* SimulatorFans
* Copyright (c) 2017 Mark van Renswoude
* https://git.x2software.net/pub/SimulatorFans
*
*
* Accepts serial commands to control one or more fans using PWM.
*
* All commands are terminated with a #10 character and are case sensitive.
* Values are passed as ASCII text. This makes it easy to test it using the
* Arduino's Serial Monitor.
*
* Baud rate is 19200 by default.
*
*
* Commands:
* >Info
* Used for validating that the device is actually a SimulatorFans device.
* Returns the number of connected fans.
*
* Example response:
* <Info:Fans=2
*
* >GetFans
* Returns the currently set values for all fans.
*
* Example response:
* <GetFans:0,255
*
* >SetFans:v1,v2,v...
* Updates the fan values. Each value ranges from 0 to 255.
*
* Example response:
* <SetFans
*/
/*
* Configuration
*/
// The number of fans connected. Each fan must connect to it's own
// PWM-enabled pin through a transistor (or preferably MOSFET).
#define FanCount 2
// The pin on which each of the fans is connected. The number of
// values must be equal to FanCount (not sure why the compiler
// doesn't enforce this if FanCount is bigger). The order is
// assumed to be left to right. In a setup of more than 180 degrees,
// start counting behind the point of view and in a clockwise manner.
//
// Possibly the PC software could support remapping at some point in the
// future as that's easier than recompiling for the Arduino, but I
// wanted to keep it simple until then.
const byte FanPin[FanCount] =
{
5,
6
};
// When a fan goes from completely off to a value below full, this
// determines how long the fan will run on full power before changing
// to the actual value, to give it a chance to start up.
#define StartingFansTime 200
/*
* Actual code. Lasciate ogne speranza, voi ch'intrate.
*/
typedef struct
{
byte value;
unsigned long startTime;
} FanStatus;
unsigned long currentTime = 0;
FanStatus fanStatus[FanCount];
// Forward declarations
void handleInfoCommand();
void handleGetFansCommand();
void handleSetFansCommand();
void handleUnknownCommand();
void checkStartingFans();
void setFan(byte fan, byte value);
void setup()
{
memset(fanStatus, 0, sizeof(fanStatus));
for (byte fan = 0; fan < FanCount; fan++)
pinMode(FanPin[fan], OUTPUT);
// Set up serial communication (through USB or the default pins)
// 19.2k is fast enough for our purpose, and according to the ATMega's datasheet
// has a low error percentage across the common oscillator frequencies.
Serial.begin(19200);
}
char command[50];
byte commandLength;
char* token;
void loop()
{
currentTime = millis();
checkStartingFans();
if (Serial.available() > 0)
{
// Try to read a serial command
memset(command, 0, sizeof(command));
commandLength = Serial.readBytesUntil('\n', command, sizeof(command) - 1);
if (commandLength > 0 && commandLength < sizeof(command))
{
token = strtok(&command[0], ":");
if (token != NULL)
{
if (strcmp(token, ">Info") == 0)
handleInfoCommand();
else if (strcmp(token, ">GetFans") == 0)
handleGetFansCommand();
else if (strcmp(token, ">SetFans") == 0)
handleSetFansCommand();
else
handleUnknownCommand();
}
}
}
}
void handleInfoCommand()
{
Serial.write("<Info:Fans=");
Serial.print(FanCount);
Serial.write("\n");
}
void handleGetFansCommand()
{
Serial.write("<GetFans:");
for (byte fan = 0; fan < FanCount; fan++)
{
if (fan > 0)
Serial.write(",");
Serial.print(fanStatus[fan].value);
}
Serial.write("\n");
}
void handleSetFansCommand()
{
for (byte fan = 0; fan < FanCount; fan++)
{
token = strtok(NULL, ",");
if (token == NULL)
break;
int value = atoi(token);
if (value < 0) value = 0;
if (value > 255) value = 0;
setFan(fan, value);
}
Serial.write("<SetFans\n");
}
void handleUnknownCommand()
{
Serial.write("<Error:unknown command\n");
}
void checkStartingFans()
{
// Check if any of the fans are currently starting up and
// have been for at least StartingFansTime
for (byte fan = 0; fan < FanCount; fan++)
{
if ((fanStatus[fan].startTime > 0) &&
(currentTime - fanStatus[fan].startTime >= StartingFansTime))
{
fanStatus[fan].startTime = 0;
setFan(fan, fanStatus[fan].value);
}
}
}
void setFan(byte fan, byte value)
{
if ((fanStatus[fan].value == 0 || fanStatus[fan].startTime > 0) && value > 0)
{
// Fan was off or still starting up, start with full power to kick it off
analogWrite(FanPin[fan], 255);
if (fanStatus[fan].startTime == 0)
{
fanStatus[fan].startTime = currentTime;
}
}
else
{
// Already running, simply change the speed and reset the start time if necessary
fanStatus[fan].startTime = 0;
analogWrite(FanPin[fan], value);
}
fanStatus[fan].value = value;
}