Hi All,
I have a MEGA connected to a TB6600 stepper motor driver. I send pulses to the driver every 33 microseconds (using 1/16 step driver mode). This motor drives a linear actuator that moves outward 87mm and back 87mm at a speed of about 40mm/sec. I've been asked to provide a LCD screen showing the current position of the actuator slider. And, YES, I know that it's impossible to see the LCD screen updates from 00 to 40 in one second and have explained such (and even demoed it), but never the less, it has been deemed required for this project.
It seems that the LCD screen (16x2 LCD Screen) updates are way too slow; ranging from around 2000 microseconds to 25000 microseconds from the research I've done on this forum and others. Every 640 pulses of the stepper motor equates to 1mm of linear slider travel. So, I only need to update the 2 LCD characters (from 00 to 87) every 640 pulses, which is 21,120 microseconds.
Here is where my issue develops: I can't do two things at once. I have to keep the motor running and update the LCD screen, which the Mega can't do (at least I don't know how it could do this as a single processor board). So, to get around this, I simply output another pulse signal (different pin) when I send the motor pulse signal. Then, with a 2nd board (UNO instead of Mega), I capture through an interrupt the pulse and count to 640. I then update the LCD screen. While this allows the motor to keep running on the Mega and the LCD screen to be updated at the same time, the motor pulses from the Mega get ignored by the UNO during the LCD screen update process. So, I end up missing about 30+ pulses for every LCD screen update.
I decided to create an off-line demo using two UNOs so I could experiment more.
Below is the code for the "Master" stepper motor driver UNO.
byte directionPin = 4;
byte stepPin = 3;
byte mega_uno_send_pin = 7;
byte startbuttonPin = 9;
byte bluebuttonPin = 8;
byte stopbuttonPin = 2;
int microsbetweenSteps = 65;
unsigned long Motor_Pulse_Counter = 0;
unsigned long curMicros;
unsigned long prevStepMicros = 0;
int Motor_Rotation_Direction = 0;
int emergencyStopFlag = 0;
void setup() {
Serial.begin(9600);
pinMode(directionPin, OUTPUT);
pinMode(stepPin, OUTPUT);
digitalWrite(directionPin, HIGH);
// From Mega to Uno motor pulse pin
pinMode(mega_uno_send_pin, OUTPUT);
digitalWrite(mega_uno_send_pin, HIGH);
// Stop button interrupt setup
pinMode(stopbuttonPin, INPUT_PULLUP);
// Start button pin
pinMode(startbuttonPin, INPUT_PULLUP);
pinMode(bluebuttonPin, INPUT_PULLUP);
delay(300);
// Wait for start button to be pressed
while (digitalRead(stopbuttonPin) == HIGH && digitalRead(startbuttonPin) == HIGH)
{
if (digitalRead(startbuttonPin) == LOW)
{
microsbetweenSteps = 65;
}
if (digitalRead(stopbuttonPin) == LOW)
{
microsbetweenSteps = 300;
}
}
// Stop button interrupt setup
attachInterrupt(digitalPinToInterrupt(stopbuttonPin), emergency_stop_flag, RISING);
}
void loop() {
// Check if emergency stop button has been pressed.
if (emergencyStopFlag == 1)
{
while (digitalRead(stopbuttonPin) == LOW)
{
}
emergencyStopFlag = 0;
}
// Nema 17 stepper motor control in microseconds (this program only works with 1/16 microstepping).
curMicros = micros();
singleStep();
}
// <<<<<<<<<<<<<<<<<<<< Pulse motor 1 time (1/16 step) >>>>>>>>>>>>>>>>>>>>
void singleStep() {
// Provide 1 pulse to the motor after microsBetweenSteps microseconds have elapsed.
if (curMicros - prevStepMicros >= microsbetweenSteps)
{
// Designed lead screw travel = 83mm from HOME offset position (4mm from HOME position)
// For 1/16 microsteps, and at 1.8Β° per step motor, there are 3200 pulses per shaft revolution.
// For a lead screw pitch = 5mm, this gives 16.6 shaft rotations for 83mm travel. This is 53120 motor pulses for the 83mm travel.
Motor_Pulse_Counter = Motor_Pulse_Counter + 1;
prevStepMicros = curMicros;
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
digitalWrite(mega_uno_send_pin, HIGH);
digitalWrite(mega_uno_send_pin, LOW);
// Change motor direction at end of travel.
if (Motor_Pulse_Counter == 55680)
{
Motor_Pulse_Counter = 0;
if (Motor_Rotation_Direction == 0)
{
Motor_Rotation_Direction = 1;
digitalWrite(directionPin, LOW);
}
else
{
Motor_Rotation_Direction = 0;
digitalWrite(directionPin, HIGH);
}
}
}
}
// *******************************************************************************************
// <<<<<<<<<<<<<<<<<<<< Emergency stop button pressed (interrupt routine) >>>>>>>>>>>>>>>>>>>>
void emergency_stop_flag() {
emergencyStopFlag = 1;
}
// *******************************************************************************************
Below is the code for the "Slave" LCD Screen Update UNO.
/*
LiquidCrystal Library
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
library works with all LCD displays that are compatible with the
Hitachi HD44780 driver. There are many of them out there, and you
can usually tell them by the 16-pin interface.
The circuit:
* LCD RS pin to digital pin 7
* LCD Enable pin to digital pin 8
* LCD D4 pin to digital pin 9
* LCD D5 pin to digital pin 10
* LCD D6 pin to digital pin 11
* LCD D7 pin to digital pin 12
* LCD R/W pin to ground
* LCD VSS pin to ground
* LCD VCC pin to 5V
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
byte mega_receive_pin = 3;
// For 1/16 step and lead screw = 5mm: slider position 1mm movement for every 640 pulses.
unsigned long Motor_Pulse_Counter = 0;
int slider_position = 0;
int slider_position_previous = 0;
int direction_switch = 0;
// Slider direction: 0 = right, 1 = left.
int slider_direction = 0;
int arrow_location = 1;
int arrow_counter = 0;
void setup() {
pinMode(mega_receive_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(mega_receive_pin), mega_pulse_counter, LOW);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Absolute Encoder");
lcd.setCursor(0, 1);
lcd.print(slider_position);
lcd.print(" ");
lcd.setCursor(10,1);
lcd.print("--->");
}
void loop() {
if (slider_position != slider_position_previous)
{
if (slider_position < 10)
{
lcd.setCursor(0, 1);
lcd.print(slider_position);
lcd.print(" ");
}
else
{
lcd.setCursor(0, 1);
lcd.print(slider_position);
}
}
if (direction_switch == 1)
{
if (slider_direction == 0)
{
lcd.setCursor(10,1);
lcd.print("--->");
}
else
{
lcd.setCursor(10,1);
lcd.print("<---");
}
direction_switch = 0;
}
}
void pulse_counter()
{
if (slider_direction == 0)
{
Motor_Pulse_Counter = Motor_Pulse_Counter + 1;
slider_position = Motor_Pulse_Counter / 640;
}
else
{
Motor_Pulse_Counter = Motor_Pulse_Counter + 1;
slider_position = 87 - (Motor_Pulse_Counter / 640);
}
// Serial.println((String)"Motor Pulse Counter = " + Motor_Pulse_Counter);
if (Motor_Pulse_Counter == 55680)
{
Motor_Pulse_Counter = 0;
direction_switch = 1;
if (slider_direction == 0)
{
slider_direction = 1;
}
else
{
slider_direction = 0;
}
}
}
void mega_pulse_counter()
{
slider_position_previous = slider_position;
pulse_counter();
}
I have been researching dual core processors to see if this could solve my challenges. I looked at the Giga and thought might work until I read that the transfer of data between the two cores is by a serial port. This will not work for me as the speed of the pulses is 33 microseconds - way to fast for any serial port. So, I'm still hunting for an Arduino solution as I really don't want to have to go to another platform and completely redo all my Mega code that is over 500 lines.
I would be grateful for the communities thoughts.
Thank you.
Robert