Arduino code suddenly stopped working after clicking the reset button [SOLVED] - Page 1
Forum section: electronics / general

author: ZeTeX
author_rank: Frequent Contributor
timestamp: December 28, 2016, 10:23:30 pm
content: Hi,I have the following library installed and the following code flashed onto the arduino:https://github.com/buxtronix/arduino/tree/master/libraries/RotaryCode:/** Example using the Rotary library, dumping integers to the serial* port. The integers increment or decrement depending on the direction* of rotation.** This example uses interrupts rather than polling.*/#include <Rotary.h>// Rotary encoder is wired with the common to ground and the two// outputs to pins 2 and 3.Rotary rotary = Rotary(2, 3);// Counter that will be incremented or decremented by rotation.int counter = 0;void setup() {Serial.begin(57600);attachInterrupt(0, rotate, CHANGE);attachInterrupt(1, rotate, CHANGE);}void loop() {}// rotate is called anytime the rotary inputs change state.void rotate() {unsigned char result = rotary.process();if (result == DIR_CW) {counter++;Serial.println(counter);} else if (result == DIR_CCW) {counter--;Serial.println(counter);}}This code worked great for reading the encoder, but I tried clicking on the reset button on the arduino and the code just stopped working even after I recompiled and flashed it, so I've tried other rotary encoder library that I found on google and it worked great so it is something about the code that has f*cked.I've also tried re-downloading the library and installing it, I tried random examples from the arduino software and they all worked, I tried connecting the encoder directly to the arduino pins without the breadboard, I'm out of ideas.What could be the problem?

author: rstofer
author_rank: Super Contributor
timestamp: December 30, 2016, 04:29:16 pm
content: It seems to me that rotate() is some kind of interrupt handler. If so, I wouldn't be putting Serial.Print statements inside the handler. Get in, do as little as possible and get out. Leave the printing for loop(). Your interrupt routine should just update the count.

author: ZeTeX
author_rank: Frequent Contributor
timestamp: December 30, 2016, 10:35:04 pm
content: Quote from: rstofer on December 30, 2016, 04:29:16 pmOK, I moved Serial.print to void loop, and removed it from void rotary.Code looks like this now :Code:/** Example using the Rotary library, dumping integers to the serial* port. The integers increment or decrement depending on the direction* of rotation.** This example uses interrupts rather than polling.*/#include <Rotary.h>// Rotary encoder is wired with the common to ground and the two// outputs to pins 2 and 3.Rotary rotary = Rotary(2, 3);// Counter that will be incremented or decremented by rotation.int counter = 0;void setup() {Serial.begin(57600);attachInterrupt(0, rotate, CHANGE);attachInterrupt(1, rotate, CHANGE);}// rotate is called anytime the rotary inputs change state.void rotate() {unsigned char result = rotary.process();if (result == DIR_CW) {counter++;} else if (result == DIR_CCW) {counter--;}}void loop() {Serial.println(counter);}But still, same result, the counter doesn't update at all. the serial monitor just spams 0 over and over again like it should.problem here is that the code worked before, but suddenly it doesn't, how can you debug something like that?

author: retrolefty
author_rank: Super Contributor
timestamp: December 30, 2016, 10:52:18 pm
content: Unless you have wired external pull-up resistors for the two encoder signals you should use pinMode function to enable internal pull-ups for pins 2 and 3 in your setup fuction.

author: ZeTeX
author_rank: Frequent Contributor
timestamp: December 30, 2016, 11:14:02 pm
content: Quote from: retrolefty on December 30, 2016, 10:52:18 pmI have tried with external 10k pull ups. nothing changes.

author: MickM
author_rank: Regular Contributor
timestamp: December 31, 2016, 12:49:27 am
content: Where do the interrupts get enabled?Move the call to rotary.process() into loop().

author: linux-works
author_rank: Super Contributor
timestamp: December 31, 2016, 12:58:52 am
content: like others have said, so nearly no work inside the ISR.in fact, I suggest you abandon the isr and just poll. there are examples for this including the use of a lookup table for faster if/then logic.I'm using a high res (400ppr) opto rotary and just polling for it and I nearly never drop events and definitely never count backwards by mistake (which often happens if you lose an event and dont' have a full state table implemented).

author: MarkF
author_rank: Super Contributor
timestamp: December 31, 2016, 04:23:19 am
content: This is a wonderful example of why I avoid using unknown libraries from the web and write my own at all costs. (35 years of experience doing code development here.)Having a print statement to the console will kill any kind of execution rate you're trying to achieve.See attached file for reading an encoder without a lookup table or a bunch of "if" statements. I use an ISR to provide my polling rate and NOT to detect knob movement. One more thing is to USE the recommended filter and pullup configuration in the data sheet.Linux-works, what polling rate do you use?

author: obiwanjacobi
author_rank: Super Contributor
timestamp: December 31, 2016, 07:16:59 am
content: From the couch:Code:/** Example using the Rotary library, dumping integers to the serial* port. The integers increment or decrement depending on the direction* of rotation.** This example uses interrupts rather than polling.*/#include <Rotary.h>// Rotary encoder is wired with the common to ground and the two// outputs to pins 2 and 3.Rotary rotary = Rotary(2, 3);// Counter that will be incremented or decremented by rotation.//int counter = 0;// var shared between interrupt handler and common code must be volatile!volatile int counter = 0; // <=========void setup() {Serial.begin(57600);attachInterrupt(0, rotate, CHANGE);attachInterrupt(1, rotate, CHANGE);// turn on interruptsinterupts(); // <============}// rotate is called anytime the rotary inputs change state.void rotate() {unsigned char result = rotary.process();if (result == DIR_CW) {counter++;} else { // if (result == DIR_CCW) { <== maybe the return value is something else?counter--;}}void loop() {Serial.println(counter);}

author: ZeTeX
author_rank: Frequent Contributor
timestamp: December 31, 2016, 10:49:42 am
content: Quote from: obiwanjacobi on December 31, 2016, 07:16:59 amThis code kinda works, but it doesn't jump by 1 in the counter but more like 2+. also you can only move the encoder in 1 direction.there is also a polling example:Code:/** Example using the Rotary library, dumping integers to the serial* port. The integers increment or decrement depending on the direction* of rotation.** This example uses polling rather than interrupts.*/#include <Rotary.h>// Rotary encoder is wired with the common to ground and the two// outputs to pins 5 and 6.Rotary rotary = Rotary(5, 6);// Counter that will be incremented or decremented by rotation.volatile int counter = 0;void setup() {Serial.begin(57600);}void loop() {unsigned char result = rotary.process();if (result == DIR_CW) {counter++;} else if (result == DIR_CCW) {counter--;}Serial.println(counter);}that's also doesn't work.I took the original code from here:http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

author: obiwanjacobi
author_rank: Super Contributor
timestamp: December 31, 2016, 11:24:10 am
content: Quote from: ZeTeX on December 31, 2016, 10:49:42 amThat means the switches in the decoder are bouncing. That library should have some way to set the bounce-timeout... (I hope).Try printing the 'result' var, perhaps with a switch to translate to text...

author: chris_leyson
author_rank: Super Contributor
timestamp: December 31, 2016, 01:17:42 pm
content: Some time ago I was looking for a reliable and simple method for decoding quadrature signals from a rotary encoder and I found this really nice solution thanks to Oleg Mazurov,https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/. It's an elegant solution using a state table and doesn't need debouncing harware but I added 10n caps across the encoder switches just to clean up the edges a little bit, pullups were 4k7.I used two encoders, TE Connectivity DPL12 24 pulse per revolution, encoder 1 wired to RB0,RB1 and encoder 2 wired to RB2,RB3 and PIC interrupt on change to call an ISR. I should point out that the technique works best if the encoders are wired to consecutive port pins. Relavent code snippets posted below.Code:int encval_1 = 0;int encval_2 = 0;int count_1 = 0;int count_2 = 0;unsigned int old_state_1 = 0xffff;unsigned int old_state_2 = 0xffff;// Change notice interrupt:- Incremental encodersvoid __attribute__((__interrupt__, no_auto_psv)) _CNInterrupt(void){static int enc_state[] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0};old_state_1 = old_state_1 << 2;old_state_1 |= (PORTB & 0x0003);encval_1 = encval_1 + (enc_state[old_state_1 & 0x0f]);if(encval_1 > 3){ count_1++; encval_1 = 0;}else if(encval_1 < -3){ count_1--; encval_1 = 0;}// because old_state_2 bit pairs are swapped over// encstate has opposite signold_state_2 = old_state_2 >> 2;old_state_2 |= (PORTB & 0x000c);encval_2 = encval_2 - (enc_state[old_state_2 & 0x0f]);if(encval_2 > 3){ count_2++; encval_2 = 0;}else if(encval_2 < -3){ count_2--; encval_2 = 0;}IFS1bits.CNIF = 0;}Because encoder 2 needs a right shift instead of a left shift then the two bit pairs that make up the 4-bit table address, old state<<2 and old state which is actually the new state are swapped over and this can be fixed by changing the sign of enc_state. It might look a bit cryptic but once you work through Oleg's description it's not to difficult to see how it works. The encoders increment or decrement a pair of signed 2-bit counters encval1 and encval2 and when they overflow or underflow the counters count_1 and count_2 are incremented or decremented. Because of a little bit of remaining switch bounce the variable encval might jitter by +/- one count but the technique automatically recovers and no matter how fast you spin the encoders they never missed a count.Chris

author: linux-works
author_rank: Super Contributor
timestamp: December 31, 2016, 04:07:06 pm
content: that last post is using the code that I also found online a few years ago. its the fastest I could find and the lookup table and statefulness of it is brilliant.just use that and poll.as for polling rate, every spare cycle, I poll, in my main loop. don't know the rate, though.

author: ZeTeX
author_rank: Frequent Contributor
timestamp: December 31, 2016, 05:04:20 pm
content: Quote from: chris_leyson on December 31, 2016, 01:17:42 pmI've used this code from the site:QuoteBut it doesn't work that well for me, I've defined the encoder like that:Quoteand connected it to pin 8 and 9.but at the serial monitor I get:Quotefor about each step, so if I move the encoder 3 steps it will be like this:QuoteWhat is really annoying is that the code I posted at the start of the topic did work but suddenly it stopped, how can you explain that?

author: rstofer
author_rank: Super Contributor
timestamp: December 31, 2016, 05:28:43 pm
content: Quote from: ZeTeX on December 31, 2016, 05:04:20 pmWell, the answer is obvious but not likely satisfying: Your code changed between the first and second evolutions. Somewhere, somehow, you changed something. Just a lilttle 'clean up', 'I don't need this...' or something like that. It happens all the time. A little brain fade and things don't work anymore.I don't have a way to replicate your problem so I don't know if your posted code works or not. Libraries, written by others, are always suspect!

author: MarkF
author_rank: Super Contributor
timestamp: January 01, 2017, 06:03:06 am
content: Here is a code snippet I use to read an encoder with a push switch:Code:// PORTCbits.RC0 = encoder switch// PORTCbits.RC1 = encoder phase 0// PORTCbits.RC2 = encoder phase 1uint8_t currP0; // encoder phase 0 (current value)uint8_t lastP0; // encoder phase 0 (last value)uint8_t lastSw0; // encoder switch (last value)int8_t en0; // encoder value (0=no change, (-)=CCW count, (+)=CW count)uint8_t sw0; // encodeeer switch;// Main entryvoid main(void){uint8_t count;// Initialize encoder variablesen0=0;sw0=0;lastP0=PORTCbits.RC1;lastSw0=PORTCbits.RC0;// Setup interrupt here// (Recommend 50Hz or greater polling rate)// Enter main loopwhile (1) {// Encoder knob processingif (en0 != 0) {count=en0; // save counten0=0; // reset encoder value quickly// so we don't miss any changes// DO SOMETHING WITH ENCODER COUNT}// Encoder switch processingif (sw0 != 0) {sw0=0; // reset enocder switch state quickly// so we don't miss any presses// DO SOMETHING WITH ENCODER SWITCH PRESS}// DO OTHER PERIODIC PROCESSING}}// Interrupt service entryvoid isr(void){uint8_t pin;// Read encoder knobcurrP0=PORTCbits.RC1; // encoder phase 0if (lastP0 == 0 && currP0 == 1) {if (PORTCbits.RC2 == 1) // encoder phase 1en0--; // increment CCW count for main loopelseen0++; // increment CW count for main loop}lastP0=currP0; // save current phase 0// Read encoder switchpin=PORTCbits.RC0; // get current switch stateif (lastSw0 == 0 && pin == 1)sw0=1; // set switch state for main looplastSw0=pin; // save switch state}

author: ZeTeX
author_rank: Frequent Contributor
timestamp: January 06, 2017, 11:40:17 pm
content: QuoteDoes anybody knows how to change:Counter value: 0Counter value: 1every step, to a counter that just adds 1 in cc or cw rotation or remove 1 in cow or cc rotation?I'm desperate, no code other then the really simple one basically work for me, its like something happened to the arduino!

author: rstofer
author_rank: Super Contributor
timestamp: January 07, 2017, 12:23:08 am
content: Debugging is something of an art...When you read the pins, immediately send them to a pair of LEDs. That way you will know what was read.I didn't work through your state tables but it might be worth your time to walk through a typical set of transitions.

author: ZeTeX
author_rank: Frequent Contributor
timestamp: January 07, 2017, 04:41:36 pm
content: I FOUND THE PROBLEM! FINALLY!and it is not the code, the problem was that I made a small encoder module because last time I just soldered pin headers to the encoder the encoder pins just broke, and somehow there was not a good soldering connection (which is weird because by eye it looks perfect) so I have just re-soldered it and and it works great, ISR or just polling. "never assume anything in electronics" - I assumed the problem was the code and not the encoder, silly me.Thanks @rstofer, I connected a resistor and a led to see if the led would light up the way it should (00, 01, 11, 11) and I noticed only 1 led was on, the other one just didn't light up, measured continuity and found the problem. 2minutes fix, 6 hours+ troubleshooting a code that works.