Hi everyone,
For my project I’m trying control the speed of a stepper motor using a pot and at the same time displaying the speed in rpm on an i2c lcd display. The code which I have gotten in the beginning is shown below:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
// Include Stepper motor library from Arduino's database
#include <AccelStepper.h>
#include <Wire.h>
// Define the stepper pins for the easy driver and create stepper object - stepper1. You can name the object as you wish.
AccelStepper stepper1(AccelStepper::DRIVER, 9, 8);
// Define control switch pins
#define START_PIN 4
#define STOP_PIN 3
// Define our analog potentiometer input pin (Analog 0)
#define SPEED_PIN 0
// Define our maximum and minimum speed in steps per second (Scale potentiometer minimum and maximum using this as a reference)
#define MAX_SPEED 5000
#define MIN_SPEED 0.1
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(4, 0);
lcd.print("RPM");
stepper1.setMaxSpeed(5000.0 );
pinMode(START_PIN, INPUT_PULLUP);
pinMode(STOP_PIN, INPUT_PULLUP);
}
void loop() {
static float current_speed = 10000; // Holding current motor speed
static int analog_read_counter = 1000; // Counts down to 0 to fire analog read
static char sign = 0; // Holds -1, 1 or 0 to turn the motor on/off and control direction
static int analog_value = 0; // Holds raw analog value.
//If a switch is toggled down (low), set the sign value appropriately
if (digitalRead(START_PIN) == 0)
{
sign = 1;
}
else if (digitalRead(STOP_PIN) == 0)
{
sign = 0;
}
if (analog_read_counter > 0)
{
analog_read_counter--;
}
else
{
analog_read_counter = 20000;
// Now read the pot (from 0 to 1023)
analog_value = analogRead(SPEED_PIN);
// Give the stepper a chance to step if it needs to
stepper1.runSpeed();
// And scale the pot's value from min to max speeds
current_speed = sign * (((analog_value/1023.0) * (MAX_SPEED - MIN_SPEED)) + MIN_SPEED);
stepper1.setSpeed(current_speed);
int speedrpm;
speedrpm = ((current_speed)/1600)*60;
if (speedrpm > 0)
{
lcd.setCursor(0, 0);
lcd.print(speedrpm);
}
else if (speedrpm < 10)
{
lcd.setCursor(0, 0);
lcd.print("000");
}
if(speedrpm < 100)
{
lcd.setCursor(0, 0);
lcd.print("0");
lcd.setCursor(1, 0);
lcd.print(speedrpm);
}
}
stepper1.runSpeed();
}
The system works, however, the fundamental problems with generating step pulses in software like AccelStepper is that If you have another function (like updating an LCD) which takes much time at all, it will cause skips in the step pulses. I’m trying to avoid this by using a second arduino to share the workload and using the Wire library to create an I2C bus. The codes for the master and slave arduino are shown below:
Master arduino:
// Include Stepper motor library from Arduino's database
#include <AccelStepper.h>
#include <Wire.h>
// Define the stepper pins for the easy driver and create stepper object - stepper1. You can name the object as you wish.
AccelStepper stepper1(AccelStepper::DRIVER, 9, 8);
// Define control switch pins
#define START_PIN 4
#define STOP_PIN 3
// Define our analog potentiometer input pin (Analog 0)
#define SPEED_PIN 0
// Define our maximum and minimum speed in steps per second (Scale potentiometer minimum and maximum using this as a reference)
#define MAX_SPEED 10000
#define MIN_SPEED 0.1
void setup()
{
// Maximum stepper value
stepper1.setMaxSpeed(10000.0);
Wire.begin();
// Using pullups for control pins
pinMode(START_PIN, INPUT_PULLUP);
pinMode(STOP_PIN, INPUT_PULLUP);
}
void loop()
{
static float current_speed = 10000; // Holding current motor speed
static int analog_read_counter = 1000; // Counts down to 0 to fire analog read
static char sign = 0; // Holds -1, 1 or 0 to turn the motor on/off and control direction
static int analog_value = 0; // Holds raw analog value.
int speedrpm = 0;
//If a switch is toggled down (low), set the sign value appropriately
if (digitalRead(START_PIN) == 0)
{
sign = 1;
}
else if (digitalRead(STOP_PIN) == 0)
{
sign = 0;
}
if (analog_read_counter > 0)
{
analog_read_counter--;
}
else
{
analog_read_counter = 5000;
// Now read the pot (from 0 to 1023)
analog_value = analogRead(SPEED_PIN);
// Give the stepper a chance to step if it needs to
stepper1.runSpeed();
// And scale the pot's value from min to max speeds
current_speed = sign * (((analog_value/1023.0) * (MAX_SPEED - MIN_SPEED)) + MIN_SPEED);
stepper1.setSpeed(current_speed);
speedrpm = ((current_speed)/1600)*60;
Wire.beginTransmission(9);
Wire.write(speedrpm);
Wire.endTransmission();
}
// This will run the stepper at a constant speed
stepper1.runSpeed();
Slave arduino:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);
int speedrpm = 0;
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(4, 0);
lcd.print("RPM");
// Start the I2C Bus as Slave on address 9
Wire.begin(9);
// Attach a function to trigger when something is received.
Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes) {
speedrpm = Wire.read(); // read one character from the I2C
}
void loop() {
if (speedrpm > 0)
{
lcd.setCursor(0, 0);
lcd.print(speedrpm);
}
else
{
lcd.setCursor(0, 0);
lcd.print("000");
}
if(speedrpm < 100)
{
lcd.setCursor(0, 0);
lcd.print("0");
lcd.setCursor(1, 0);
lcd.print(speedrpm);
}
}
Basically, the idea is to have a master arduino controlling the motor while simultaneously sending information to a slave arduino which then displaying the speed in rpm on an i2c LCD screen. That was my takes on the solution, however, it doesn’t work because I only recently learned that you can’t have 2 masters on one i2c bus and having the slave arduino controlling the i2c lcd display basically makes the slave arduino a master. Another approach which I’m thinking of is to have the slave arduino controlling the motor while sending data to the master arduino which then displaying the speed on the lcd; that will create only one master on the i2c bus.
I know this is a bit of an overkill but I’m also trying to implement a timer for the system, it will create too much workload for 1 arduino so I decided to follow this solution. I really want to know what you think of this solution and if there is any thoughts or suggestions, I would be extremely happy to hear. Thank you for reading.