//Include Arduino Library
#include <Arduino.h>
//Define Parameters and pins
#define MINRPM 10 // in tenths rpm, 10 = 1 rpm
#define MAXRPM 120 // in tenths rpm, 120 = 12 rpm
#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
//Declare variables for the motor pins on 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; // number of steps per full revolution
// support different output devices by using 'conditional compilation'
#define SHOW_OUTPUT 0 // 0-Serial mode, 1-LCD in 4-bit mode, 2-I2C/IIC mode (Just Results)
#define LCDWIDTH 16
//Option 1 parameters
#if SHOW_OUTPUT == 0 // output functions for Serial
//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("Potival: ");Serial.println(potival);
Serial.print("Average: ");Serial.println(potiAvg);
}
//Option 2 parameters
#elif SHOW_OUTPUT == 1 // output functions for LCD in 4-bit mode
//Include additional libraries and plugin parameters
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,4,5,6,7);
//Display Begin
void displayBegin()
{
lcd.begin(LCDWIDTH,2);
lcd.print("Rotations: ");
}
//Display Rotations
void displayRotations(unsigned int steps2go)
{ // round steps2go to full revolutions
int rotationsLeft= (steps2go+countsperrev/2-1)/countsperrev;
lcd.setCursor(10,0);
if (rotationsLeft<10) lcd.print(' ');
lcd.print(rotationsLeft);
}
//Display Results
void displayResults(int potival, int potiAvg)
{
char buf[LCDWIDTH+1];
lcd.clear();
snprintf(buf,sizeof(buf),"Potival: %d", potival);
lcd.print(buf);
Serial.println(buf);
snprintf(buf,sizeof(buf),"Average: %d", potiAvg);
lcd.setCursor(0,1);
lcd.print(buf);
Serial.println(buf);
}
//Option 3 Parameters
#elif SHOW_OUTPUT == 2 // output functions for your LCD
//Include additional libraries and plugin parameters
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
//Define variables for LCD display
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, POSITIVE);
LCD *myLCD = &lcd;
//Display Begin
void displayBegin()
{
lcd.begin(LCDWIDTH,2);
lcd.print("Testing");
}
//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)
{
char buf[LCDWIDTH+1];
lcd.clear();
snprintf(buf,sizeof(buf),"Potival: %d", potival);
lcd.print(buf);
Serial.println(buf);
snprintf(buf,sizeof(buf),"Average: %d", potiAvg);
lcd.setCursor(0,1);
lcd.print(buf);
Serial.println(buf);
}
#endif
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));
}
void rpmTask(unsigned long time, int &rpm, int &steptime)
{ // input time in microseconds since cycle started
// returns rpm and steptime in microseconds
#define ACCELLTIME 10000000L // microseconds for accelleration from MINRPM to MAXRPM
if (time>=ACCELLTIME) rpm=MAXRPM;
else rpm= MINRPM+ time*(MAXRPM-MINRPM)/ACCELLTIME;
steptime= 60000000L*10/rpm/countsperrev;
}
//Calibration for Load Cell
float loadA = 0; //Calibration weight 1 (grams)
int analogvalA = 103; //Change this for calibration
float loadB = 2000; //Calibration weight 2 (grams)
int analogvalB = 1023; //Change this for calibration
float analogValueAverage = 0;
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;
}
void potentiometerTask(int &value)
{
int analogValue = analogRead(potentiometerPin);
value = analogToLoad(analogValue);
}
//Stepper tasks
void stepperTask(int stepTime)
{
doOneStep(1,stepTime);
}
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;
}
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);
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);
}
void setup()
{
// Start Serial for debugging
Serial.begin(9600);
displayBegin();
// 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);
}
void loop()
{
Serial.println("Press STARTBUTTON to start new cycle");
while (!startStop()) ; // do nothing until start/stop condition is true
Serial.println("START");
unsigned long time=micros();
doOneCycle();
Serial.print("This cycle took [s]: ");
Serial.println((micros()-time)/1000000.0);
Serial.println("FINISHED");
Serial.println("");
delay(500); // half second pausing to prevent next start due to possible button bouncing
}