Fun with Arduino 36 Store Data in EEPROM

The turntable application of video 35 expects to first run the ‘find zero’ routine after startup in order to have a reference position from where step counting starts. Suppose after every move we could store our current position in non volatile memory? At startup we can now read the stored position out of memory and we know where we are … we are at the last position we moved to before power was switched off.

This would be convenient. We can start to move to other positions without the hassle of having to find zero first. And the good news is … the Arduino has 1024 bytes of EEPROM built in. Data that we write to this EEPROM will stay available even after power off.

We still keep the ‘find zero’ routine at the push of a button. If the application somehow went out of position we can still find zero again. This can happen when for instance power was switched off while the motor was running, or when there was a mechanical issue which made the motor lose steps. Also, of course, the very first time the software is used we have to run the ‘find zero’ routine because the EEPROM does not yet contain valid data.

Read on below the video …

To use the EEPROM we have to include the library:

#include <EEPROM.h>

Now we can write and read, one byte at a time, with these instructions …

… where address is an integer ranging from 0 – 1023, representing the EEPROM storage location and where value is a byte stored in that address.

We can now enhance the turntable application. With every change of position we write the new position into EEPROM. We’ll use address 0. In the setup() routine we read address 0 and we will know where we are … that’s it.

#define NUM_POSITIONS     3 // How many positions to move to
#define MOTOR_PIN_1      A1
#define MOTOR_PIN_2      A2
#define MOTOR_PIN_3      A3
#define MOTOR_PIN_4      A4
#define POTM_PIN         A5
#define POS_1_PIN         9 // LOW = go to pos 1
#define POS_2_PIN         8 // LOW = go to pos 2
#define POS_3_PIN        12 // LOW = go to pos 3
#define ZERO_PIN          6 // Start zero find routine
#define ZERO_FOUND_PIN    7 // End switch to find zero position
#define ONOFF_LED_PIN     5 // Motor running LED
#define PULSES_PER_REV 2048 // Pulses per revolution of blue/metal toy motor
// Define number of positions, and steps from zero to each position
unsigned long tt_position[NUM_POSITIONS + 1] = {0,100,612,1124};

byte dir, current_pos, new_pos, rpm, rpm_old, stepnr;
unsigned long timeoflaststep;

#include <EEPROM.h>

void find_zero() {
Serial.println("Finding zero sensor");
dir = 0;
while(digitalRead(ZERO_FOUND_PIN) == HIGH) {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
do_one_step();
}
}
motor_idle();
current_pos = 0;
new_pos = 1; // move to pos 1 after finding zero
Serial.println("Zero sensor found");
Serial.println();
}

unsigned long stepinterval() { // calculates step timing based on potmeter input
rpm = map(analogRead(POTM_PIN), 0, 1024, 1, 13); // max 12 rpm, else pulses get lost
if(rpm != rpm_old) {
Serial.print("RPM: ");
Serial.println(rpm);
rpm_old = rpm;
}
return 60000000UL / PULSES_PER_REV / rpm;
}

void rotate(unsigned long numsteps) {
digitalWrite(ONOFF_LED_PIN, HIGH);
Serial.print("To pos ");
Serial.print(new_pos);
Serial.print(", ");
Serial.print(numsteps);
Serial.print(" steps, dir = ");
Serial.println(dir);
while(numsteps > 0) {
if ((micros() - timeoflaststep) > stepinterval()) {
timeoflaststep = micros();
do_one_step();
numsteps--;
}
}
motor_idle();
}

void motor_idle() {
digitalWrite(MOTOR_PIN_1,   LOW);
digitalWrite(MOTOR_PIN_2,   LOW);
digitalWrite(MOTOR_PIN_3,   LOW);
digitalWrite(MOTOR_PIN_4,   LOW);
digitalWrite(ONOFF_LED_PIN, LOW);
}

void do_one_step() {
if(dir == 0) stepnr--;
else stepnr++;
stepnr = stepnr%4;

switch (stepnr) { // remembers in which of the 4 phases the motor is
case 0:
digitalWrite(MOTOR_PIN_1, HIGH);
digitalWrite(MOTOR_PIN_2, LOW);
digitalWrite(MOTOR_PIN_3, LOW);
digitalWrite(MOTOR_PIN_4, LOW);
break;
case 1:
digitalWrite(MOTOR_PIN_1, LOW);
digitalWrite(MOTOR_PIN_2, HIGH);
digitalWrite(MOTOR_PIN_3, LOW);
digitalWrite(MOTOR_PIN_4, LOW);
break;
case 2:
digitalWrite(MOTOR_PIN_1, LOW);
digitalWrite(MOTOR_PIN_2, LOW);
digitalWrite(MOTOR_PIN_3, HIGH);
digitalWrite(MOTOR_PIN_4, LOW);
break;
case 3:
digitalWrite(MOTOR_PIN_1, LOW);
digitalWrite(MOTOR_PIN_2, LOW);
digitalWrite(MOTOR_PIN_3, LOW);
digitalWrite(MOTOR_PIN_4, HIGH);
break;
}
}

void setup() {
pinMode(POS_1_PIN,     INPUT_PULLUP);
pinMode(POS_2_PIN,     INPUT_PULLUP);
pinMode(POS_3_PIN,     INPUT_PULLUP);
pinMode(ZERO_PIN,      INPUT_PULLUP);
pinMode(ZERO_FOUND_PIN,INPUT_PULLUP);
pinMode(MOTOR_PIN_1,   OUTPUT);
pinMode(MOTOR_PIN_2,   OUTPUT);
pinMode(MOTOR_PIN_3,   OUTPUT);
pinMode(MOTOR_PIN_4,   OUTPUT);
pinMode(ONOFF_LED_PIN, OUTPUT);
if(current_pos > NUM_POSITIONS) {
currnet_pos = 1;
EEPROM.write(0,1);
}
new_pos = current_pos;
Serial.begin(9600);
Serial.println();
Serial.print("Current memory position = ");
Serial.println(current_pos);
Serial.println();
Serial.println("If memory position is NOT according");
Serial.println("to reality, then find zero first!");
Serial.println();
}

void loop() {

stepinterval(); // read speed and show RPM on serial monitor

if(digitalRead(ZERO_PIN) == 0) find_zero();
if(digitalRead(POS_1_PIN) == 0) new_pos = 1;
if(digitalRead(POS_2_PIN) == 0) new_pos = 2;
if(digitalRead(POS_3_PIN) == 0) new_pos = 3;

if(new_pos != current_pos) {
if(new_pos > current_pos) {
dir = 1;
rotate(tt_position[new_pos] - tt_position[current_pos]);
}
else {
dir = 0;
rotate(tt_position[current_pos] - tt_position[new_pos]);
}
current_pos = new_pos;
EEPROM.write(0, current_pos);
}
}

Test … first move to say positions 2. Then power off the Arduino and power it back on. We see that it knows where it is and we can immediately move to other positions, without finding zero first. Great.

So far we have used a \$2,- toy stepper motor. It works well, but it does not have the strength to reliably drive an application that has some mass or friction. In the next video we’ll have a look at a nema-17 motor, connected to a driver that can deliver more power.

— 0 —