I am trying to improve some existing code that did not work very well with a no-detent encoder. I have removed that code completely and replaced it with the code mentioned here:Rotary encoder decode for Arduino
Here is the code I have in an encoders() function
void encoders () {
static long encoder_pos = 0, last_encoder_pos = 0, encoder_change; // will hold state of pins last time encoder was read, will hold any movement deduced from comparing old and new pins states from an encoder
//These two lines are for the other two encoders
static long encoder2_pos = 0, last_encoder2_pos = 0; long encoder2_change;
static long encoder3_pos = 0, last_encoder3_pos = 0; long encoder3_change;
unsigned long long old_freq;
encoder_pos = (digitalRead(enc1pinA)<<1|digitalRead(enc1pinB));
if (encoder_pos != last_encoder_pos) {
Serial.print(last_encoder_pos); Serial.println(encoder_pos);
encoder_change = RotaryDecodeTable[last_encoder_pos][encoder_pos]; // used RotaryDecodeTable to decide movement, if any
last_encoder_pos = encoder_pos;
if (encoder_change == B01){ // if combined transitions result was move right (CW), increment counter
counter++; }
if (encoder_change == B10){ // if combined transitions result was move left (anti-CW), decrement counter
counter--; }
delay(10); // wait generous debounce period before next read
/// Other code here
}
This is the output I get from the code when I turn the encoder.
The counter (temp variable for now) is supposed to be the frequency to be displayed and possibly other calculations, however with this code counter seems to count up/down slower than expected.
What would be the best way to improve the speed to ensure that the transitions that are happening increment/decrement the counter variable correctly.
If I turn the encoder too quickly, I get the following
If you have your serial port at 9600 that can slow it down. Increase the serial port to 115200. If the serial buffer fills the print calls block until buffer space becomes available. At 9600 it takes about 1ms to print a character.
You might even consider buffering the counters and only printing them when the encoder is not moving. That will give a more accurate picture. With a 10ms delay you will never capture more than 100 increments per second.
I've been at it for some time now, and modified the matrix to a single line
The new code is here
void encoders () {
static long encoder_pos = 0, last_encoder_pos = 0, encoder_change=0; // will hold state of pins last time encoder was read, will hold any movement deduced from comparing old and new pins states from an encoder
//These two lines are for the other two encoders
static long encoder2_pos = 0, last_encoder2_pos = 0; long encoder2_change;
static long encoder3_pos = 0, last_encoder3_pos = 0; long encoder3_change;
unsigned long long old_freq;
last_encoder_pos = encoder_pos;
encoder_pos = (digitalRead(enc1pinA)*2 + digitalRead(enc1pinB));
if (encoder_pos != last_encoder_pos) {
encoder_change = RotaryDecodeTable[last_encoder_pos * 4 + encoder_pos]; // used RotaryDecodeTable to decide movement, if any
if (encoder_change == 1){ // if combined transitions result was move right (CW), increment counter
encoder_change = 4 * encoder_change;
}
else if (encoder_change == -1){ // if combined transitions result was move left (anti-CW), decrement counter
encoder_change = 4 * encoder_change;
}
delay(1); // wait generous debounce period before next read
/// Other code here
}
I'm still getting false readings, I'm thinking since I'm using a non-detent encoder may be that is cause?
i used an interrupt triggered on the RISING edge of one encoder input and simply checked the other encoder input to increment or decrement a count. doesn't count every encoder event and doesn't increment or decrement on opposite events.
but i've also had problems where knowing rotation was in a constant direction, i saw interrupts occurring earlier than expected and the "other" encoder input indicating motion in the opposite direction. my workaround was to ignore events occurring much sooner (< half) than the previous event.
i think, but haven't tested, that adding hysterisis may correct (?) the problem. I hope to try passing each encoder output through the trigger/threshold of a 555.
Integration with the main section of the code that consists of a number of DSP stuff and screen refreshes did not go too well.
There was a considerable and severe lag on turning the tuning knob which for some reason would only update the counter upwards, CCW turns had no effect. The original code was very responsive in CW and CCW.
I made the follow change to the line
if (state==0xfff0){
to
if (state > 0xf03c && state < 0xffff){
.
Any reduction to the lower value F03C automatically started the frequency count to increment.
Any ideas would be appreciated, I would really like to get the tuning sorted, especially to get it to be responsive as the original code.
Both snippets of code works fine if it is just being used as a test, but if I add it to the main program, the large amount of code that is running in a loop() maybe causes a delay and does not give a correct response.
So far you have posted enough code for me to tell what pins or Arduino board you're using. Complete code and board specification should have been in your very first post.
But, it only works on pins that support external interrupts. On an Uno, that would be 2 & 3. Again, that's why it's important to know what board you're using.
Hi,
Yes, Sorry. I should have said what the environment was about. I did not realise that the large DSP code would affect the running of the tuning encoder.
I am using the Arduino environment to modify the Teensy code (I'm using Teensy 3.6), so I came here for help. I'm using pins 16 and 17 on the Teensy 3.6 for the encoder.
Apologies if this was the incorrect forum or if I did not post enough about the environment, I should have done so.
There are 2 other encoders that are detent-ed and those work fine since they control a limited set of functions, but I might try and work on them if this seemingly works well.
That's a fairly complex project. How well do you understand the code to be attempting to modify it? It already uses the PJRC Encoder library which will be interrupt driven on a T3.6 as all its GPIO pins are interrupt-capable. I see no reason why it wouldn't work with your particular encoder. I'd dig into that anomaly before trying to role your own encoder handler.
The library at the GitHub link I posted will also work. But, I wouldn't use it at the same time as the PJRC library. Since its method calls are different, you'd have to change the handling of all 3 encoders.
I've done PIC programming and I have a decent knowledge of C, so I guess I should be ok.
On the modification of the code, I guess I have to edit the encoders() section only, which I have done and I have removed the code for the Tuning encoder and used automaton.h
I have therefore included the 2 or 3 lines to drive just this encoder using the .OnChange line and have managed to insert the +4/-4 that the code requires to calculate the correct frequency.
The encoder works well and is fully responsive in CW and CCW directions, the frequency is also being updated correctly based on the step value.
I have kept the other two encoders as-is since they are working fine with the existing code (these are both detent-ed ones).
With all the earlier code that I used the tuning encoder was failing on CCW and was causing the frequency to jump large steps in the other (CW) direction.
Using the code from Rotary encoder decode for Arduino , or anything else caused the encoder to jump when used in the full version, however the sample code would work well in a test program where just the encoder snippet was used.
I've now tried to spin the tuning as fast as possible both CW and CCW and it works fine.
Maybe some further investigation on why the earlier snippets of code was not working with the same encoder is something that I must look into.