//Include Arduino Library
#include <Arduino.h>
////////////////////////////////////////////////////////////////
//Define Parameters and pins
#define MINRPM 10 // in tenths rpm, 10 = 1 rpm (This is the startup RPM)
#define MAXRPM 100 // in tenths rpm, 100 = 10 rpm (This is maximum RPM after acceleration)
#define STARTBUTTONPIN A2
#define potentiometerPin A0
//Define interval for timing rpm calculation and analogRead
#define INTERVAL 25000L // 25000 µs = 25 ms = execution time, frequency 40 per second
//Define variables for the motor pins on ULN2003/ULN2004 motor driver
#define MOTOR1 8 // Blue - 28BYJ48 pin 1, driver IN1
#define MOTOR2 9 // Pink - 28BYJ48 pin 2, driver IN2
#define MOTOR3 10 // Yellow - 28BYJ48 pin 3, driver IN3
#define MOTOR4 11 // Orange - 28BYJ48 pin 4, driver IN4
// Red - 28BYJ48 pin 5 (VCC)
// Define Motor rotations per single shaft rotation (reduction)
const int countsperrev = 4075.7728395; // (4076??) number of steps per full revolution of external shaft
// Define tareValue for Tare function
int tareValue = 0;
//////////////////////////////////////////////////
// Setup Script (Beginning of each test, "once off')
void setup()
{
// Start Serial for debugging
Serial.begin(9600);
// Activate Internal Pullup Resistor for STARTBUTTONPIN
pinMode(STARTBUTTONPIN, INPUT_PULLUP);
// Set stepper pins as OUTPUT
pinMode(MOTOR1, OUTPUT);
pinMode(MOTOR2, OUTPUT);
pinMode(MOTOR3, OUTPUT);
pinMode(MOTOR4, OUTPUT);
}
/////////////////////////////////////////////////
// Loop script (Run once per cycle)
void loop()
{
Serial.println("Happy with the Machine Setup? Type 'S' or press STARTBUTTON to start the Test");
while (!startStop()) ; // do nothing until start/stop condition is true
tareValue = analogRead(potentiometerPin);
Serial.println("Test Started, this will take 60 seconds");
Serial.print("Tare Value: "); Serial.println(tareValue);
unsigned long time = micros();
doOneCycle();
Serial.print("Cycle Time [s]: ");
Serial.println((micros() - time) / 1000000.0);
Serial.println("Test Complete");
Serial.println("Please Unplug DC Jack While Cleaning The Device");
Serial.println("");
delay(500); // half second pausing to prevent next start due to possible button bouncing
}
////////////////////////////////////////////////
// Display Begin
void displayBegin() {}
// Display Rotations
void displayRotations(unsigned int steps2go)
{ // round steps2go to full revolutions
int rotationsLeft = (steps2go + countsperrev / 2 - 1) / countsperrev;
//Serial.print("rotations: ");Serial.println(rotationsLeft);
}
// Display Results
void displayResults(int potival, int potiAvg)
{
Serial.print("Final Value: "); Serial.println(potival);
Serial.print("Average Value: "); Serial.println(potiAvg);
Serial.print("Tare Value: "); Serial.println(tareValue);
}
//////////////////////////////////////////////////
// Calibration for Load Cell
long time = 0; //
int timeBetweenReadings = 400;
float loadA = 0; // Calibration weight 1 (grams)
int analogvalA = 0; // Change this for calibration
float loadB = 10000; // Calibration weight 2 (grams)
int analogvalB = 511; // Change this for calibration
float analogValueAverage = 0;
//////////////////////////////////////////////////////
// MapFloat condition for Load Cell Calibration
float analogToLoad(float analogval)
{
float load = mapfloat(analogval, analogvalA, analogvalB, loadA, loadB);
return load;
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
///////////////////////////////////////////////////
// Averaging Load cell values, Smoothing data
void potentiometerTask(int &load)
{
//analogValueAverage = 9*analogValueAverage/10 + analogRead(potentiometerPin); // running average
//analogValueAverage = (9 * analogValueAverage + analogRead(potentiometerPin))/10; // running average
analogValueAverage = 0.90 * analogValueAverage + 0.10 * analogRead(potentiometerPin); // running average
if (millis() - time >= timeBetweenReadings)
{
load = analogToLoad(analogValueAverage - tareValue);
Serial.print("load: "); Serial.println(load);
//time = millis();
long time = millis();
}
}
/////////////////////////////////////////////////////////
// Initiating Serial Read Commands for Start/Stop
boolean startStop()
{ // handles start/stop by recognising button press or serial 's' received
// returns 'true' if start/stop condition is detected
static byte oldState = false;
byte result = false;
// first check serial for small letter 's'
while (Serial.available())
{
if (Serial.read() == 's') result = true;
}
byte newState = !digitalRead(STARTBUTTONPIN);
if (newState != oldState)
{
oldState = newState;
if (newState) result = true;
}
return result;
}
/////////////////////////////////////////////////////////
// Motor Acceleration Parameters
void rpmTask(unsigned long time, int &rpm, int &steptime)
{ // input time in microseconds since cycle started
// returns rpm and steptime in microseconds
#define ACCELLTIME 1000000L // microseconds for accelleration from MINRPM to MAXRPM
if (time >= ACCELLTIME) rpm = MAXRPM;
else rpm = MINRPM + time * (MAXRPM - MINRPM) / ACCELLTIME;
steptime = 60000000L * 10 / rpm / countsperrev;
}
/////////////////////////////////////////////////////////////////////////////
// Create Parameters for 'OneStep' of Motor
void doOneStep(int8_t motorDirection, int motorSpeed)
{ // step motor one single step into 'motorDirection' -1 or 1
// if called in very short time, delay action up to desired 'motorSpeed'
static int8_t currentstep = 0;
static unsigned long lastSteptime;
long now = micros();
long diff = now - lastSteptime;
if (diff < motorSpeed)
{
delayMicroseconds(motorSpeed - diff);
lastSteptime += motorSpeed;
}
else lastSteptime = now;
currentstep += motorDirection;
if (currentstep >= 8) currentstep = 0;
else if (currentstep < 0) currentstep = 7;
byte stepperLookup[8] = {B00001, B00011, B00010, B00110, B00100, B01100, B01000, B01001};
digitalWrite(MOTOR1, bitRead(stepperLookup[currentstep], 0));
digitalWrite(MOTOR2, bitRead(stepperLookup[currentstep], 1));
digitalWrite(MOTOR3, bitRead(stepperLookup[currentstep], 2));
digitalWrite(MOTOR4, bitRead(stepperLookup[currentstep], 3));
}
///////////////////////////////////////////////////////
// Creating 'doOneStep' For Stepper Motor
void stepperTask(int stepTime)
{
doOneStep(1, stepTime);
}
//////////////////////////////////////////////////
// Creating 'OneCycle' using all Parameters
void doOneCycle()
{
unsigned int totalSteps = 10L * countsperrev; // total = 10 rotations to go
int rpm = 0;
int stepTime = 0;
int potentiometerValue = 0;
int potentiometerSamples = 0;
long potentiometerValueSum = 0;
boolean finished = false;
unsigned long cycleTime = 0;
unsigned long intervalTime = 0;
int intervalCount = 0;
rpmTask(0, rpm, stepTime); // initial calculation of rpm and stepTime
displayBegin(); // initial output
displayRotations(totalSteps); // initial output
unsigned long lastTime = micros();
while (!finished)
{
long now = micros();
long diff = now - lastTime;
lastTime = now;
cycleTime += diff;
intervalTime += diff;
if (intervalTime >= INTERVAL)
{
intervalTime = 0;
intervalCount++;
if (intervalCount >= 20) // after 20 intervals, update display
{
intervalCount = 0;
unsigned long tm = micros();
displayRotations(totalSteps);
//Serial.println(micros()-tm); //Debugging Monitor (Duration of Each process in Arduino)
//Serial.println(potentiometerValue);
}
else if (intervalCount % 4 == 1) rpmTask(cycleTime, rpm, stepTime);
else if (intervalCount % 4 == 2 && startStop()) totalSteps = 1; // cancelled, prepare for final last step
else // all other intervals
{
potentiometerTask(potentiometerValue); // measure value
potentiometerValueSum += potentiometerValue; // add up values
potentiometerSamples++; // increment number of samples
}
}
stepperTask(stepTime); // step the stepper
totalSteps--;
if (totalSteps == 0) finished = true;
}
int average = potentiometerValueSum/potentiometerSamples;
displayResults(potentiometerValue, average);
}