I'm fairly new to this and I apologize in advance for what might seem a series of "dumb" questions.
Find attached my current code!
I'm using an Arduino Nano to monitor a rotary encoder of a motor and display a count of said encoder on an LCD. The nano has been chosen because of its small size factor as the final product will be a compact box with a 20x4 LCD on top.
Encoder info:
2000 counts per rev
differential pairs (A, not A, B and not B and index - one pulse per revolution)
Because of the "lack" of pins on the nano, the screen is being driven using I2C.
I have only managed to get so far with this code thanks to the help of the forum however I seem to find myself stuck when it comes to the following:
the counts will sometimes show correctly and display roughly 2000 per rev however other times it isn't accurate and displays less than the correct number, i.e 100 to 200 less.
I have set a refresh rate to the screen so it only updates once every second but it still doesn't work as intended. However, when the rate is changed to once every 5 seconds, it works great so I'm guessing it's something to do with it losing time writing to the screen.
volatile int aPlusVal = 0;
volatile int aMinusVal = 0;
volatile int bPlusVal = 0;
volatile int bMinusVal = 0;
volatile int indexPlusVal = 0;
volatile int indexMinusVal = 0;
volatile int encoderCount = 0;
volatile int indexCount = 0;
Whenever you access these values in loop(), you MUST make sure that an interrupt can't happen during that access.
I can somewhat see what you mean but unfortunately, my knowledge does not expand far enough to be able to fix it. Would you be able to expand a little on your comment so I can try to find a way to access the values whilst the interrupts are happening?
The pins are being accessed so I can print their values live to the LCD.
I'm unsure to why pins 2 and 3 were not set as input_pullups but I have rectified that now.
First, check your Arduino libraries and find the Rotary subdirectory (e.g., Arduino1.8.9/libraries/Rotary) and look at the examples that are provided. A good library that I've used before is by Brian Low, which you can download from here. Get a sample working first so you gain some understanding of how the encoder works, and then use the code as a model for your own sketch. Here's an example from that library:
/*
Rotary Encoder - Interrupt Example
The circuit:
* encoder pin A to Arduino pin 2
* encoder pin B to Arduino pin 3
* encoder ground pin to ground (GND)
*/
#include <Rotary.h> // Download from here: https://github.com/brianlow/Rotary
Rotary r = Rotary(2, 3);
void setup() {
Serial.begin(9600);
r.begin();
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
}
void loop() {
}
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_NONE) {
// do nothing
}
else if (result == DIR_CW) {
Serial.println("ClockWise");
}
else if (result == DIR_CCW) {
Serial.println("CounterClockWise");
}
}
Anytime I use a library that is not part of the original Arduino distribution, I add a comment that has the URL where it can be downloaded, as shown above.
differential pairs (A, not A, B and not B and index - one pulse per revolution)
How fast will the motor be rotating?
With 2000 (or is it 4000) pulses per rev a motor rotating at 1200 RPM or 20 RPS would produce 40,000 or 80,000 pulses per second. That means an interval between pulses of only 25 or 12.5 microsecs. That doesn't really leave any time for the Arduino to do other work.
Firstly thank you econjack, I will have a look into that.
Robin, the purpose of this project is just to test the encoder's functionality before the motor is fitted to the final product. The motor will be turned by hand so it will not be spinning fast at all but even by doing so, my current code still misses a few counts whilst it's busy doing other things so all I'm trying to achieve is a more efficient way of still displaying info on the LCD and not miss important counts.
I'm pretty certain it is 2000 pulses per rev.
Or was there another reason you mentioned "Good for testing but unsuitable for a real program." @MorganS
I agree it is best for testing. I expect whoever uses the counter code wouldn't try to spit it out the serial port at such high rates
Serial.print uses interrupts as well so they don't play nicely together at higher rates. this was my attempt to not spam the serial output so much as to lock up the UNO. I use a 400 step encoder per revolution and this code can handle it well.
Z
Once again thanks for the replies, they have given me some ideas on how to improve the code.
I am fairly worried that as the complexity of the code increases, I will end up missing more counts.
I have stumbled across a device that does all the counting outside the arduino and reports back via SPI. It uses the famous LS7366R Quadrature encoder counter chip so I might give that a try.