Help needed please. I am a new recruit to Arduino and learning slowly. I have adopted oled display routines to show the height of a laser nozzle above the bed using a rotary encoder attatched to the up/down leadscrew.
Works a treat except that it forgets its position when turned off and leaving it on leads to display burn in. I want to use EEPROM.update to save the position. This works but reading it back on boot up doesn`t. I suspect its to do with the interrupt routine (borrowed off the net) not being called so not updating. Any help appreciated.
/**************************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/category/63_98
This example is for a 128x32 pixel display using I2C to communicate
3 pins are required to interface (two I2C and one reset).
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source
hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries,
with contributions from the open source community.
BSD license, check license.txt for more information
All text above, and the splash screen below must be
included in any redistribution.
**************************************************************************/
// Rotary encoder oled flipped using interrupt routines. I want it to save the current rotary value to eeprom as an update and read it back after reset
// Thus remembering the current position after reset.
#include <SPI.h>
#include <Wire.h>
#include <RotaryEncoder.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
Adafruit_SSD1306 display(4);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
float z=0.0;// set up floating point variable
// Setup a RotaryEncoder for pins A2 and A3 on encoder output A and B use A2 andA3
RotaryEncoder encoder(A2, A3);
void setup()
{
int value;
int newPos;
value = EEPROM.read(0); //read position from eeprom
if(value != 0) // test if there was a reset and if so use this value
{
newPos = value;
}
// Serial.begin(9600); //for monitoring output debugging
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.setRotation(2); //rotate screen 180 degrees optional
// You may have to modify the next 2 lines if using other pins than A2 and A3
PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
}
// The Interrupt Service Routine for Pin Change Interrupt 1
// This routine will only be called on any signal change on A2 and A3: exactly where we need to check.
ISR(PCINT1_vect) {
encoder.tick(); // just call tick() to check the state.
}
// Read the current position of the encoder and print out when changed
void loop()
{
static int pos = 0;
display.display();
int newPos = encoder.getPosition();
if (pos != newPos) {
Serial.print(newPos);
display.clearDisplay();
Serial.println();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE);
display.setCursor(4,1);
display.println("Laser Focus Distance");
display.setTextSize(2);
display.setCursor(15, 14);
float(z)=newPos/5.0;// scalefactor is 5.0 for my 4mm pitch leadscrew
display.println(float(z)); // display height as 2 dec places
display.setCursor(80, 14);
display.println("mm");
// Serial.println(float(z));
display.display(); //finalises and displays changes
pos = newPos;
EEPROM.update(0,pos);
}
}
// The End
More suspect would be that you do not have a home position for the lead screw and a switch to tell the Arduino when it gets there and the code to find the home position when power is applied.
Paul. Once the laser focus is set, by dropping the nozzle onto the bed, the display shows height relative to this zero. I agree that I need to add a button to clear the eeprom and reset to zero when say changing the lens and that is my next step once I sort the save and load eeprom routine out. I don't want to have to zero it on startup as there would be no need.
**Here is my solution I arrived at after much thought. It works well for positive integers 0 to 255. Next I would like to extend it to larger than 8 bit numbers so that Iit works for more turns of the leadscrew and so that I can save negative numbers as well. Thats the next task. **
/**************************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/category/63_98
This example is for a 128x32 pixel display using I2C to communicate
3 pins are required to interface (two I2C and one reset).
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source
hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries,
with contributions from the open source community.
BSD license, check license.txt for more information
All text above, and the splash screen below must be
included in any redistribution.
**************************************************************************/
// Rotary encoder oled flipped using interrupt routines. I want it to save the current rotary value to eeprom as an update and read it back after reset
// Thus remembering the current position after reset. Works well for positive integers 0 to 255. Would like to extend this to 16 bit numbers giving
// more scope for larger numbers I could split to give negative numbers also.
#include <SPI.h>
#include <Wire.h>
#include <RotaryEncoder.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
Adafruit_SSD1306 display(4);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
float z=0.0;// set up floating point variable
// Setup a RotaryEncoder for pins A2 and A3 on encoder output A and B use A2 andA3
RotaryEncoder encoder(A2, A3);
int count=0;
int value;
int total;
void setup()
{
int newPos;
// Serial.begin(9600); //for monitoring output debugging
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.setRotation(2); //rotate screen 180 degrees optional
// You may have to modify the next 2 lines if using other pins than A2 and A3
PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
}
// The Interrupt Service Routine for Pin Change Interrupt 1
// This routine will only be called on any signal change on A2 and A3: exactly where we need to check.
ISR(PCINT1_vect) {
encoder.tick(); // just call tick() to check the state.
}
// Read the current position of the encoder and print out when changed
void loop()
{
static int pos = 0;
int newPos = encoder.getPosition();
if (pos != newPos) {
if (count == 0){
value = EEPROM.read(0);
newPos = newPos + value;
count++;
}
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE);
display.setCursor(4,1);
display.println("Laser Focus Distance");
display.setTextSize(2);
display.setCursor(15, 14);
newPos = newPos + value;
float(z) = newPos/5.0;// scalefactor is 5.0 for my 4mm pitch leadscrew
display.println(float(z)); // display height as 2 dec places
display.setCursor(80, 14);
display.println("mm");
display.display(); //finalises and displays changes
pos = newPos;
EEPROM.update(0,pos);
}
}
// The End
Hi John I looked at the option of sleeping the oled but wanted a simple method where when I turned the laser off the Arduino and oled display would also be off. I have now managed to just about sort it and used 16 bit variables so I don’t run out of travel. It loads the old distance when reset. Only problem left is how it deals with negative integers if I move the head up from zero it rolls over. Looking at splitting the 16 bit integer and fiddling with the numbers to make negative readings. Could also just not save to Eeprom if it goes past zero. Technically I could bring the bed up to zero after a lens clean and drop the lens holder onto the bed to set its start point. New code below.
/**************************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/category/63_98
This example is for a 128x32 pixel display using I2C to communicate
3 pins are required to interface (two I2C and one reset).
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source
hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries,
with contributions from the open source community.
BSD license, check license.txt for more information
All text above, and the splash screen below must be
included in any redistribution.
**************************************************************************/
// Rotary encoder oled flipped using interrupt routines. I want it to save the current rotary value to eeprom as an update and read it back after reset
// Thus remembering the current position after reset. Works well for positive integers 0 to 255. Would like to extend this to 16 bit numbers giving
// more scope for larger numbers I could split to give negative numbers also.
#include <SPI.h>
#include <Wire.h>
#include <RotaryEncoder.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
Adafruit_SSD1306 display(4);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
float z=0.0;// set up floating point variable
// Setup a RotaryEncoder for pins A2 and A3 on encoder output A and B use A2 andA3
RotaryEncoder encoder(A2, A3);
uint16_t count=0;
uint16_t lastValueRecorded;
int lsByte;
int msByte;
void setup()
{
//pinMode(7,INPUT_PULLUP);
int newPos;
Serial.begin(9600); //for monitoring output debugging
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.setRotation(2); //rotate screen 180 degrees optional
display.clearDisplay();
display.display();
// You may have to modify the next 2 lines if using other pins than A2 and A3
PCICR |= (1 << PCIE1); // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
PCMSK1 |= (1 << PCINT10) | (1 << PCINT11); // This enables the interrupt for pin 2 and 3 of Port C.
}
// The Interrupt Service Routine for Pin Change Interrupt 1
// This routine will only be called on any signal change on A2 and A3: exactly where we need to check.
ISR(PCINT1_vect) {
encoder.tick(); // just call tick() to check the state.
}
// Read the current position of the encoder and print out when changed
void loop()
{
static uint16_t pos = 0;
uint16_t newPos = encoder.getPosition(); //need 16 bit integers
if (pos != newPos) { // has rotor moved
if (count == 0){ // if true then this was after a cold reset
lsByte = EEPROM.read(0);// after cold reset load the last save values back
msByte = EEPROM.read(1);
lastValueRecorded = lsByte + (256 * msByte);// join the lsbyte and msbyte to make 16 bit integer
count++; // after this eeprom will not be read again till cold reset
}
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE);
display.setCursor(4,1);
display.println("Laser Focus Distance");
display.setTextSize(2);
display.setCursor(15, 14);
newPos = newPos + lastValueRecorded; //new movement value is added to value from eeprom to get absolute value
float(z) = newPos/5.0;// scalefactor is 5.0 for my 4mm pitch leadscrew
display.println(float(z)); // display height as 2 dec places
display.setCursor(90, 14);
display.println("mm");
display.display(); //finalises and displays changes
pos = newPos;
lsByte=lowByte(pos);// split 16 bit integer into 2 bytes most significant and least significant
msByte=highByte(pos);
EEPROM.update(0,lsByte);//save to eeprom each byte in locations 0 and 1
EEPROM.update(1,msByte);
}
}
// The End