Arduino Forum

Using Arduino => General Electronics => Topic started by: williamjcoates on Aug 15, 2015, 06:03 am

Title: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 15, 2015, 06:03 am
Hi,
I am new to arduino and need some direction.
I would like to output the position of my rotary encoder shaft to a lcd screen. The shaft position would start at 1 and terminate at 100, which would be 1 full revolution of the shaft. So if the shaft was turned  1/4 turn to the right the lcd readout would indicate 25.00. And a 1/2 turn would indicate 50.00 on the lcd readout. If the shaft was rotated to the left the lcd readout would indicate 75.00 or 50.00 if rotated 1/2 turn to left.
I have Arduino 1.6.5 installed on my computer.
I have a
Mega 2560 board
1620a lcd screen
Yumo-E6B2-CWZ3E Rotary encoder with a resolution 1024 P/R
I also have a basic adruino kit which includes a bread board, wires, resisters etc.
I have looked through tutorials and examples but havn't come across anything resembling this. Does anyone have any sample sketches and wiring diagrams that I could work with.
Bill

Title: Re: Rotary encoder output to lcd 1602a
Post by: CrossRoads on Aug 15, 2015, 06:48 am
Wow, 100 pulse/revolution rotary encoders are expensive!
http://www.digikey.com/product-search/en?pv395=4&FV=fff4001e%2Cfff80033&k=rotary+encoder&mnonly=0&newproducts=0&ColumnSort=0&page=1&stock=1&quantity=0&ptm=0&fid=0&pageSize=25

I don't see a datasheet for Yumo-E6B2-CWZ3E.
Counting encoder pulses and displaying them is pretty straightforward.
See the code here for counting them, change as needed for your display.
http://forum.arduino.cc/index.php?topic=318170.0


Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 15, 2015, 04:40 pm
hi,
Thanks for the reply. Really appreciate the help.
This is the encoder i'm using.

https://www.sparkfun.com/products/11102

I followed your link and used this code. I was able to hook everything up and have it output to serial. How can I calibrate or modify this sketch so that one revolution of the shaft would display 100.00. if I turn CCW 1/4 turn it would display 75.00. There would be a dial on the encoder shaft that would be marked out evenly 1 - 100. I also want to use the high resolution of this encoder to indicate  the dial position when it is between a number ie: 12.6572.

Once I can get it working and display it on the serial monitor I would like to have the encoder ouput to my lcd 1620a. I have no idea how to wire this to my adruino mega 2560 board, or how to include the lcd 1620a in the code.
Bill






/* Rotary encoder with attachInterrupt
Counts pulses from an incremental encoder and put the result in variable counter.
Taking also into account the direction and counts down when the rotor rotates in
the other direction.
This code is used attachInterrupt 0 and 1 which are pins 2 and 3 moust Arduino.
For more information about attachInterrupt see:
http://arduino.cc/en/Reference/AttachInterrupt
 
created 2014
by Ben-Tommy Eriksen
https://github.com/BenTommyE/BenRotaryEncoder
 
*/

// Encoder connect to digitalpin 2 and 3 on the Arduino.

volatile unsigned int counter = 0;  //This variable will increase or decrease depending on the rotation of encoder

void setup() {
  Serial.begin (9600);
  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);
 
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}

void loop() {
  // Send the value of counter
  Serial.println (counter);
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if(digitalRead(3)==LOW) {
    counter++;
  }else{
    counter--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if(digitalRead(2)==LOW) {
    counter--;
  }else{
    counter++;
  }
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: jcallen on Aug 15, 2015, 05:12 pm
Try:


Code: [Select]
Serial.println(counter * 100.0 / 1024);
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 15, 2015, 07:53 pm
Thanks  :)
I tried it and it moved the decimal place to 0.00.
Full rotation goes to 6400.00

Can't be that difficult but beyond me at the moment.
Title: Re: Rotary encoder output to lcd 1602a
Post by: Wawa on Aug 15, 2015, 11:36 pm
If a full rotation goes to 6400.00, divide it by another 64.

1024/64 = 16, so 100/16= 6.25

Serial.println(counter * 6.25); // default two decimal places

or

Serial.println(counter * 6.25, 3); // three decimal places

Leo..

Title: Re: Rotary encoder output to lcd 1602a
Post by: MarkT on Aug 16, 2015, 12:35 am
Wow, Sparkfun is so expensive!

http://www.ebay.com/itm/360P-R-Incremental-Rotary-Encoder-AB-phase-encoder-6mm-Shaft-W-coupling-New-/141686141372?hash=item20fd26f1bc (http://www.ebay.com/itm/360P-R-Incremental-Rotary-Encoder-AB-phase-encoder-6mm-Shaft-W-coupling-New-/141686141372?hash=item20fd26f1bc)
Title: Re: Rotary encoder output to lcd 1602a
Post by: free-bee on Aug 16, 2015, 03:13 am
Wow, Sparkfun is so expensive!

http://www.ebay.com/itm/360P-R-Incremental-Rotary-Encoder-AB-phase-encoder-6mm-Shaft-W-coupling-New-/141686141372?hash=item20fd26f1bc (http://www.ebay.com/itm/360P-R-Incremental-Rotary-Encoder-AB-phase-encoder-6mm-Shaft-W-coupling-New-/141686141372?hash=item20fd26f1bc)
Just wanna throw out that this (http://www.ebay.com/itm/Encoder-1000P-R-Incremental-Rotary-Encoder-AB-phase-encoder-6mm-Shaft-W-coupling-/231160065963) one is the closest one to what OP bought. OP's has almost three times the p/r of what you posted.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 16, 2015, 07:43 am
If a full rotation goes to 6400.00, divide it by another 64.

1024/64 = 16, so 100/16= 6.25

Serial.println(counter * 6.25); // default two decimal places

or

Serial.println(counter * 6.25, 3); // three decimal places

Leo..


hi Leo,
Thanks for the input. I tried your suggestion but no luck. I was also mistaken about the total value after 1 revolution. it showed 65535 in the serial monitor. I also noticed the display in the serial monitor was jumpy .
I guess this is because of the high resolution of the encoder 1024/pr. I wanted a high res encoder to track the movement of the shaft to something like 4 decimal places. so if the shaft stopped at 10 it would show 10.0000. The idea of this project is to be able to accurately measure the distance between the start and stop position of the encoder shaft. For now I would just take the start value displayed and subtract it from the stop value. In the future I would like to be able to display the results in a graph.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: TomGeorge on Aug 16, 2015, 08:50 am
Hi,
The  encoder you have is a chinese knock off of an Omron encoder.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Can you please post a copy of your sketch, using code tags?
They are made with the  </> icon in the reply Menu.
See section 7 http://forum.arduino.cc/index.php/topic,148850.0.html


Tom.... :)
Title: Re: Rotary encoder output to lcd 1602a
Post by: TomGeorge on Aug 16, 2015, 08:58 am
Hi,
That ebay one is a bit old too.
One of the notes in the spec says.

Quote
Notice:AB 2phase output must not be directly connected with VCC, otherwise, will burn the output triode, because different batches, and may not have the terminal
So if you use it you will have to wait for it to stop humming and warm up.
Also some batches have no terminals.

Tom.... :)
Title: Re: Rotary encoder output to lcd 1602a
Post by: Wawa on Aug 16, 2015, 09:04 am
I think if you want exactly 100 steps/rev, you should use an encoder that can produce 100 when divided by an integer.
e.g  1000 or 2000 steps, not 1024 steps.

Are you expecting a higher resolution than the encoder resolution?
Leo..
Title: Re: Rotary encoder output to lcd 1602a
Post by: TomGeorge on Aug 16, 2015, 09:41 am
Hi,
If you have 1024 steps per revolution and you want 100 steps with 1 step precision, it is not going  to happen.
1024/100 = 10.24 steps per needed step.
You cannot get  0.24 of a step input.

The OEM, Omron and the chinese mob, quote a 100 and a 2000 ppr model.
The 2000 model will give you 2000/100=20 step per needed step.
1/20= 0.05 resolution.

What is your application?

Tom.... :)
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 16, 2015, 04:37 pm
Thanks for replying,
With this project I want to use the rotary encoder to indicate the position of a dial. In this case a dial for a safe. Safe dials are numbered 0-100. By attaching the encoder to the dial i would be able to relay the exact position of the dial to an lcd readout. So if I set the safe dial at 0, turn on the adruino board and rotate the dial to the right and stop in the middle of 10-11 the encoder would relay the position and print to screen something like 10.56. If I rotate the dial to the left past zero and stop on 75, the encoder would read this and print to screen 75. I know I have a high resolution encoder but was hoping I could still make it work...
Maybe by using the map() function  with something like this
Code: [Select]
Serial.print(map(counter, 0, max_encoder_count, 0, 99))

My hardware setup is very basic at this point. the encoder is wired to my mega 2650 board this way
Encoder  Wire Black Out A to Digital Pin 2 Mega Board
Encoder  Wire White Out B to Digital Pin 3 Mega Board 
Encoder  Wire Brown 5V to 5V Mega Board
Encoder  Wire Blue OV(Common) to GND Mega Board
I have the Board Plugged into my laptop using the USB serial cable and view the results using the serial monitor in the adruino ide. I am using the following code example
Code: [Select]
/* Rotary encoder with attachInterrupt
Counts pulses from an incremental encoder and put the result in variable counter.
Taking also into account the direction and counts down when the rotor rotates in
the other direction.
This code is used attachInterrupt 0 and 1 which are pins 2 and 3 moust Arduino.
For more information about attachInterrupt see:
http://arduino.cc/en/Reference/AttachInterrupt
 
created 2014
by Ben-Tommy Eriksen
https://github.com/BenTommyE/BenRotaryEncoder
 
*/

// Encoder connect to digitalpin 2 and 3 on the Arduino.

volatile unsigned int counter = 0;  //This variable will increase or decrease depending on the rotation of encoder

void setup() {
  Serial.begin (9600);
  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);
 
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}

void loop() {
  // Send the value of counter
   // Serial.println (counter);
   Serial.print(map(counter, 0, max_encoder_count, 0, 99)).
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if(digitalRead(3)==LOW) {
    counter++;
  }else{
    counter--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if(digitalRead(2)==LOW) {
    counter--;
  }else{
    counter++;
  }
}

This code does not compile due to the "max_encoder_count" was not declared error.
Any help in pointing me in the right direction would be greatly appreciated
Bill
       
Title: Re: Rotary encoder output to lcd 1602a
Post by: MarkT on Aug 17, 2015, 12:29 am
hi,
Thanks for the reply. Really appreciate the help.
This is the encoder i'm using.

https://www.sparkfun.com/products/11102

I followed your link and used this code.
The code you quoted is not reliable as it samples only rising edges.

You have to sample rising and falling edges to get reliable quadrature decoding.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 17, 2015, 01:09 am
Hi MarkT,
Thanks For pointing that out. Do you have a link to some sample code that I could work with. Being very new to arduino I am not sure what would be better code. For now I just want to have the encoder output from 0 - 100 for one rotation to the serial monitor. But because the encoder is 1024 P/R there is no way to code the output to read 0-100? If not that would it be possible to measure in degrees of rotation?
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: MarkT on Aug 17, 2015, 01:12 am
Did you look at the playground?

http://playground.arduino.cc/Main/RotaryEncoders#Example3 (http://playground.arduino.cc/Main/RotaryEncoders#Example3)
Title: Re: Rotary encoder output to lcd 1602a
Post by: Wawa on Aug 17, 2015, 01:25 am
Not too much experience with encoders, but isn't OP's one outputting 3-bit Grey code.

I think 360 steps from a 1024 encoder would be as impossible as 100 steps.
Leo..
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 17, 2015, 02:56 am
Thanks MarkT,
I will have a look. I have been reading threads and going back over some as the coding becomes clearer. I did do this
Code: [Select]
void loop() {
  // Send the value of counter
   Serial.println (counter / 20.24);
   
}

And it goes up to 100.00 on a CW rotation but when i go CCW it starts at 3230.00. weird. The thing to remember is that I am using the rotary encoder as a means to measure the distance between two points on the dial. I then would take this value and put it on a graph. I am starting to get somewhere with this.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: TomGeorge on Aug 17, 2015, 04:31 am
Hi
Do you have to have exactly 100 steps per turn, do you have the encoder knob marked off in 1/100 divisions.

If not.
In other words a blank knob, you can have 1024/100= 10.24pulses per 1/100 of turn.
Who's to know that its not exact.
I gather you have the position readout on the display.

If you turn the knob 1 turn, how are you to know that its only 99 steps, a little turn more and it 100. the knob position has nothing to be referenced against. You only want the numbers to be displayed.
That is if you do not mark/calibrate the knob.

Tom... :)
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 17, 2015, 05:43 am
Hi,
Thats right. It would be nice if the numbers on the display matched the numbers on the actual dial that I would be measuring the movement on  but not critical. I think with more research I could get it worked out though. Its about taking the output of the encoder and filtering it into what I want in the display...I think anyway. Still very new to this stuff. Now i just started working on my lcd 1602 by soldering the pin header strip onto it. Going to try the hello world example. I would then like to output the encoder information to the lcd screen. Not sure on how to do this and if anyone can steer me in the right direction i would sure appreciate it.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: Wawa on Aug 17, 2015, 06:20 am
I think the first step is to make the encoder work.
1024 clicks per turn clockwise and 1024 clicks per turn anti-clockwise.
If that works reliably, then think of scaling it down to 100 click per turn.
Leo..
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 19, 2015, 07:26 pm
Hi Leo,
I did this
Code: [Select]
// Send the value of counter
  Serial.println (counter / 20.24);
It Gives me 100 on a full rotation CW and goes back down to 0 when I go CCW. If I start CCW however I get 6238.00 as the starting number and counts down from there. I'll figure it out sooner or later. Up until this point I have been using the serial monitor to view the output of the encoder. I now have a DF ROBOT LCD Keypad Shield Which I now have mounted on a arduino UNO board. I have done some tutorials with this setup and the lcd sheid works fine. Just had to change
Code: [Select]
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); to
Code: [Select]
LiquidCrystal lcd(8, 9, 5, 4, 6, 7);

I would now like to read the output of the rotary encoder on my lcd shield. Could someone show me how to go about this? Here is the sketch I am using now
Code: [Select]
/* Rotary encoder with attachInterrupt
Counts pulses from an incremental encoder and put the result in variable counter.
Taking also into account the direction and counts down when the rotor rotates in
the other direction.
This code is used attachInterrupt 0 and 1 which are pins 2 and 3 moust Arduino.
For more information about attachInterrupt see:
http://arduino.cc/en/Reference/AttachInterrupt
 
created 2014
by Ben-Tommy Eriksen
https://github.com/BenTommyE/BenRotaryEncoder
 
*/

// Encoder connect to digitalpin 2 and 3 on the Arduino.

volatile unsigned int counter = 0;  //This variable will increase or decrease depending on the rotation of encoder

void setup() {
  Serial.begin (9600);
  //Setting up interrupt
  //A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
  attachInterrupt(0, ai0, RISING);
 
  //B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
  attachInterrupt(1, ai1, RISING);
}

void loop() {
  // Send the value of counter
  Serial.println (counter / 20.24);
 
}

void ai0() {
  // ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
  // Check pin 3 to determine the direction
  if(digitalRead(3)==LOW) {
    counter++;
  }else{
    counter--;
  }
}

void ai1() {
  // ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
  // Check with pin 2 to determine the direction
  if(digitalRead(2)==LOW) {
    counter--;
  }else{
    counter++;
  }
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: Wawa on Aug 20, 2015, 03:55 am
Not a coder, so I might give you the wrong info.
What is the datatype of "counter".
Did you try "unsigned". e.g.  unsigned int counter = 0;

Printing to LCD is almost the same as printing to serial monitor.
Serial.println (counter / 20.24); becomes lcd.print (counter / 20.24);
https://www.arduino.cc/en/Reference/LiquidCrystal
Leo..

Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Aug 20, 2015, 04:20 am
Quote
I think the first step is to make the encoder work.
I agree with Wawa. You are clearly not reading the encoder properly. Based on the specific encoder reading  algorithm you should get 1024, 2048, or 4096 counts per revolution of an encoder with 1024 pulses per revolution. You can read 1,2, or 4 of the quadrature steps.

The code you are using reads two of the four and should produce 2048 counts per revolution. This certainly seems like enough resolution for your application, and should reliably indicate direction.

However, the code you are using is peculiar in that it reads rising edges on two interrupts and it is reading the first two pulses of the train of four instead of every other transition. To look at 2048 counts (instead of 4096,using the example #3 suggested by MarkT) a better algorithm is to trigger on one channel of the encoder CHANGE, and read the value of both channels in the ISR with digital read or faster alternatives. If both channels are high or low, it is going in one direction, if they are opposite, its going in the other.

It is basically the approach of the second example in the Arduino Playground Encoder tutorial, but be aware that the example in the tutorial uses Serial.print() in the ISR which is likely to fail.

Getting your information on the lcd is very simple so fix the encoder reading first. Your counts are not correct, the divisor should be 20.48, and  something is wrong with the direction. 
Quote
If I start CCW however I get 6238.00 as the starting number and counts down from there.
Quote
What is the datatype of "counter".
Did you try "unsigned". e.g.  unsigned int counter = 0;
Code: [Select]
volatile unsigned int counter=0; "Volatile" is correct for a value changed within an ISR. Depending upon how may revolutions you make in a direction it could be a volatile int since you only have 2048 counts per revolution. I do believe that you should be using a volatile int (or long) because if you start at 0 and go ccw you want it to start reading -1.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 20, 2015, 10:43 am
Hi,
I checked the code I have and it had the "Volatile" statement. So its time to scrap this code and try example 3. I think I tried this one before and received compile errors. Is this the code that Jurs supplied. I noticed later that I had to create a "Tab" named encoder.h. I tried doing this and it still wouldn't compile. I did up a new file and put the encoder code in it and named it encoder.h. the file ended up being called encoder.h.ino. i removed the last extension so it was named encoder.h and put it in the same directory as the sample code file.....So what did i do wrong?
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 20, 2015, 06:32 pm
I figured out how to get jurs code to work. Only question would be if this was example 3 that I should be looking at?
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Aug 20, 2015, 06:56 pm
Quote
I figured out how to get jurs code to work
I do not see where jurs has contributed to this thread, so I do not know what code you are talking about.

Example 3 in the Arduino Playground Encoder Tutorial does not use an additional header file encoder.h.

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 20, 2015, 07:05 pm
Hi cattledog, I went to a link that MarkT gave me.
Wow, 100 pulse/revolution rotary encoders are expensive!
http://www.digikey.com/product-search/en?pv395=4&FV=fff4001e%2Cfff80033&k=rotary+encoder&mnonly=0&newproducts=0&ColumnSort=0&page=1&stock=1&quantity=0&ptm=0&fid=0&pageSize=25

I don't see a datasheet for Yumo-E6B2-CWZ3E.
Counting encoder pulses and displaying them is pretty straightforward.
See the code here for counting them, change as needed for your display.
http://forum.arduino.cc/index.php?topic=318170.0



there was some examples there. I used the 3 one which Jurs had uploaded
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Aug 20, 2015, 07:31 pm
That reference was from Crossroads, not MarkT.

MarkT in reply #16 pointed you at http://playground.arduino.cc/Main/RotaryEncoders#Example3 (http://playground.arduino.cc/Main/RotaryEncoders#Example3)

I am sure that many variations of code reading an encoder will work for you. There are also libraries which require you to do nothing other than enter some pin numbers.

I would recommend that you find something you understand. Take a look at the quadrature square wave pattern produced by these encoders, and analyse how the code detects and processes the changes. I believe that understanding the fundamentals will help you in the end, and these encoders will seem simple and not mysterious.
 

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 20, 2015, 07:39 pm
thanks Cattledog,
My confusion
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 22, 2015, 06:11 am
Okay, I have been doing some reading and looking at how the code works. I am now using different code which is behaving better than the previous. Its not exactly what I want but it will work until i learn how to modify it better. I added a lcd keypad shield to my mega 2560 board and configured the lcd display for my sketch. It works  as shown here in the serial monitor.
Start
Counter value: 0
Counter value: 1
Counter value: 2
Counter value: 3
Counter value: 4
Counter value: 5
Counter value: 6
Counter value: 7
Counter value: 8
Counter value: 9
Counter value: 10
Counter value: 11
Counter value: 12
Counter value: 13
Counter value: 14
Counter value: 15
Counter value: 16
Counter value: 17
Counter value: 18
Counter value: 19
Counter value: 20
Counter value: 21
Counter value: 22
Counter value: 23
Counter value: 24
But in my lcd the numbers are all together on the same line. and would look like this.
1011121314151617181920
I only have the numbers showing on the lcd display. How can I configure the lcd to display "Counter value" on the first line and only one number on the second. I think I have to put in a statement that instructs the lcd.print to add the next variable to the next line/new line. Are there sample sketches showing how to do this.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: Paul__B on Aug 22, 2015, 12:56 pm
Three things:


Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Aug 22, 2015, 02:08 pm
Thanks Paul,
I will set the cursor to display the output more to the right. Will also work with the blank space to accommodate when the value decreases.
As for the Println(). Wasn't aware that was a bug. I left it in there to verify the output from the encoder when I was working on the lcd code and will remove it now.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 06, 2015, 12:03 am
Hi,
I have solved the problems I was having with the sketch  for my rotary encoder. The counter now outputs 99 for one CW revolution. Thanks for all the input. My next task is to take the value of the counter display on the lcd screen and save this to a file on a button click. I would then take that stored number and place it op a graph.  I have a mega 2560 board with a df robot lcd keypad shield attached. There are left, right and up, down buttons plus a select and reset button. I was thinking of using the left and right buttons to do this. Any ideas on how to go about this?
Bill

Here is my working code
Code: [Select]

#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
int16_t counter = 0;
const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() {
               Serial.begin(115200);
              //pinMode(2, INPUT_PULLUP);arduino uno
              //pinMode(3, INPUT_PULLUP);arduino uno
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
               

                //attachInterrupt(0, encoder_interrupt, CHANGE);arduino uno
                //attachInterrupt(1, encoder_interrupt, CHANGE);arduino uno
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

void loop() {
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Point:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
}
             void encoder_interrupt() {
             static uint8_t oldEncoderState = 0;
                      oldEncoderState <<= 2;
                      oldEncoderState |= ((PIND >> 2) & 0x03);
                      counter += encoderDirections[(oldEncoderState & 0x0F)];
                      if (counter < 0) counter = MAX_ENCODER_VALUE;
                      else if (counter > MAX_ENCODER_VALUE) counter = 0;
}








 
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 06, 2015, 12:55 am
You have made a lot of progress. There are a few modifications you should make to the code you currently have.

Code: [Select]
//int16_t counter = 0;
volatile int16_t counter = 0;


The value of counter is changed within the ISR, and declaring it volatile helps the compiler and program treat the variable correctly https://www.arduino.cc/en/Reference/Volatile (https://www.arduino.cc/en/Reference/Volatile)

You should also turn interrupts off to make a protected copy of count to ensure that it doesn't change when you are reading it. This is important for "non-atomic" variables (larger than 1 byte) since the value can change while you are reading the multiple bytes.
Code: [Select]
void loop() {
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Point:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     noInterrupts();
     int copyCounter = counter;
     interrupts();
    //lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     lcd.print(map(float(copyCounter), 0, MAX_ENCODER_VALUE, 0, 99));   
     
}


Quote
My next task is to take the value of the counter display on the lcd screen and save this to a file on a button click.
Do you presently know how to read button presses on the shield to do simple things like turn on an led or print a message on the screen. There is example code for these shields which should show you how to do that. That would be the first place to start. Learn how to display the value you want to save on the lcd or to Serial monitor with a button press.

You say you want to save this value to a file. Where? On an SD card? On your PC? On a webpage? What do do next will depend on the location of the file.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 06, 2015, 03:06 am
Hi Cattledog,
Thanks for getting back to me. I'll add your suggestions to my sketch. I just started searching about how to use the buttons on the shield, but haven't progressed very far as I wasn't sure how to word my search terms. Do you have the locations of these sample code that I could look at. As for where I want to save the encoder output. I think using a sd card module(shield) would work well. Don't know much about them either but am reading up on them.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 06, 2015, 07:50 am
Most lcd keypad shields are similar to this and there is a code example in the wiki.
http://www.dfrobot.com/wiki/index.php?title=Arduino_LCD_KeyPad_Shield_(SKU:_DFR0009) (http://www.dfrobot.com/wiki/index.php?title=Arduino_LCD_KeyPad_Shield_(SKU:_DFR0009))

Be aware that there is an issue with the backlight on many of the shields. Take a look at this sticky posting at the top of the "Displays" section of the forum, which is a warning about pin 10.
http://forum.arduino.cc/index.php?topic=96747.0 (http://forum.arduino.cc/index.php?topic=96747.0)

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 06, 2015, 04:47 pm
Thanks again Cattledog,
I uploaded the sample sketch for the button press and have it working on my board. I will look closer at the code and see what I can do to incorporate some of the functions into my sketch.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 07, 2015, 04:46 pm
Hi Cattledog,
Well I uploaded the sketch included in the link and it worked fine once i commented out the v1.1 and went with v1.0.
I then started to implement the button code into my sketch. Of course it is not working the way I wanted it to and I know this is my lack of understanding to how the buttons are defines for what ever function you want to complete.

This part of the code is confusing to me [code// For V1.0 comment the other threshold and use the one below:

 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnDOWN;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT;   ][/code]

I know if a certain condition is met the buttob selected will return what you define in the case statement.
Do you have any other examples that I could look at. I want to have the right or left button store the value of the encoder to file once depressed.
Bill




Code: [Select]
//Sample using LiquidCrystal library
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
const int numRows = 2;
const int numCols = 16;

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor
 // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
 // we add approx 50 to those values and check to see if we are close
 if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
 // For V1.1 us this threshold
 /*
 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 250)  return btnUP;
 if (adc_key_in < 450)  return btnDOWN;
 if (adc_key_in < 650)  return btnLEFT;
 if (adc_key_in < 850)  return btnSELECT; 
*/
 // For V1.0 comment the other threshold and use the one below:

 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnDOWN;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT;   



 return btnNONE;  // when all others fail, return this...
}




void setup()
{
 Serial.begin(115200);
              //pinMode(2, INPUT_PULLUP);arduino uno
              //pinMode(3, INPUT_PULLUP);arduino uno
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
               

                //attachInterrupt(0, encoder_interrupt, CHANGE);arduino uno
                //attachInterrupt(1, encoder_interrupt, CHANGE);arduino uno
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
}
 



void loop()
{

 lcd.setCursor(0, 0);
 
 noInterrupts();
 int copyCounter = counter;
 interrupts();
 
 
 lcd_key = read_LCD_buttons();  // read the buttons

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     lcd.print("RCP  ");
     lcd.setCursor(0,1);            // move to the begining of the second line
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99)); 
     break;
     }
     
   case btnLEFT:
     {
     lcd.print("LCP   ");
     lcd.setCursor(0,1);            // move to the begining of the second line
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99)); 
     break;
     }
     
   case btnUP:
     {
     lcd.print("UP    ");
     break;
     }
     
   case btnDOWN:
     {
     lcd.print("DOWN  ");
     break;
     }
     
   case btnSELECT:
     {
     lcd.print("SELECT");
     break;
     }
     
     case btnNONE:
     {
     lcd.print("NONE  ");
     break;
     }
   
 }

 

}
void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 08, 2015, 05:16 am
Quote
This part of the code is confusing to me
There is a network of resistors configured such that when a button is pushed a different and distinct value (0-1024) will be read at A0. There are evidently two versions of the board which produce different readings for the buttons.

You should experiment with your shield and determine the analogRead() value for each button on your shield. Write a simple sketch to read A0 and print it on your lcd, or use the AnalogReadSerial in the 01Basic Examples of the IDE. That will help you tune the values used to determine which button has been pushed.

Quote
Of course it is not working the way I wanted it to and I know this is my lack of understanding to how the buttons are defines for what ever function you want to complete.
What don't you understand?

The buttons select different resistance values which produce different analogRead() values at A0. You read those values, test them against limit values, and act accordingly. You don't need all the complete switch case statements if you are just using a subset of buttons and you don't need to put the analogRead() in a function with a returned value. For the left and right button you can certainly have simple code in the loop which looks like this
Code: [Select]
adc_key_in = analogRead(0);  // read the lcd shield buttons
if(adc_key_in < 50)
{ Do what you want when right button pressed}
if (adc_key_in <= 555 && adc_key_in >=380)
{ Do what you want when left button is pressed}


Can you currently print on the lcd or in the Serial monitor what you want to save when the left or right button is pressed? If so, its time to integrate the SD module.

It may matter if you use the Uno or the Mega when you integrate the SD card. There are potential problems with the lcd shield and the Uno due to the pin 10 used for the backlight and pin 10 settings for the SPI/SD libraries. You are better off using this shield with the Mega as was indicated in your last posted code.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 08, 2015, 05:43 pm
Thanks again cattledog,
I used this sketch here to give me the values for each button
Code: [Select]
/* Yu Hin Hau
 * DFRobot LCD Keypad Shield Tutorial
 * 7/29/2012
 */
 
//Initialize LCD
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
 
void setup()
{
//Set LCD Display Size
lcd.begin(16,2);
lcd.clear();
 

}
 
void loop()
{
 
 
  //Read Shield Button from Analog 0 Pin
  double button = analogRead(0);
 
  //Set LCD Display Settings
  lcd.setCursor(0,0);
  lcd.println("Analog 0 Value:  ");
 
  lcd.setCursor(0,1);
  lcd.print(button);
  lcd.println("                ");
 
}

and came up with these values
None -  1023.00
Select  - 640.00
Left-      409.00
Up-         99.00
Down-    256.00
Right-    0
I understand now what happens when a button on the shield is depressed. And how this behavior is defined in the read statement.
The next part for me is to define the action produced based on the button pressed. For the moment I would like the button press to print the lcd display to the serial monitor. So if I rotate the encoder and stop on 56. I would press the right button and "RCP: 56" would display in the serial monitor. Or if I pressed the left button "LCP: 56" would display in the serial  monitor. Once I have that working I would then want to save the lcd display to a text file on the sd card. I am going to pickup a sd card module, just not sure whether to go with the SD / TF Card Shield V1.0 Expansion Board Module, or a SD Card Reader Module for Arduino/ARM Read and Write.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 08, 2015, 06:15 pm
Quote
I am going to pickup a sd card module, just not sure whether to go with the SD / TF Card Shield V1.0 Expansion Board Module, or a SD Card Reader Module for Arduino/ARM Read and Write.
My advice on the SD card module is to make sure that whatever you get can run at 5v,  and that there is logic level shifting with a IC rather than a resistance network. 
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 10, 2015, 01:09 am
Hi Cattledog,
Well I have been working on the keypad/button and I have progressed a bit. In this sketch I was trying to print the value of the encoder when the left or right button was pressed to the serial monitor. I used the serial monitor so I could see if the action worked or not. However its not working. Could you point me in the right direction with my button setup. I also tried your suggestion on the button set up which didn't work. I assume because I am missing something.
Code: [Select]

#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnLEFT   3
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

 
 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 555)  return btnLEFT;
}

void setup() {
               Serial.begin(115200);
              //pinMode(2, INPUT_PULLUP);arduino uno
              //pinMode(3, INPUT_PULLUP);arduino uno
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
               

                //attachInterrupt(0, encoder_interrupt, CHANGE);arduino uno
                //attachInterrupt(1, encoder_interrupt, CHANGE);arduino uno
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

void loop() {

 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     Serial.println (map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     break;
     }
   case btnLEFT:
     {
     Serial.println (map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     break;
     }
 }


 
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     noInterrupts();
     int copyCounter = counter;
     interrupts();
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
}
      void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}



Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 10, 2015, 01:52 am
You are not calling the function int read_LCD_buttons() in the loop and assigning the return value of the function to the variable lcd_key which is used in the switch case tree.

This statement was in your earlier code, but does not appear in the latest version.

Code: [Select]
lcd_key = read_LCD_buttons();  // read the buttons

I may have confused you by suggesting code in a simplified snippet which did not have the analog read in a function or use a switch case on the return value, but rather had the analogRead and two conditional tests directly in the loop. It is a matter of style, and you should choose a path which makes the most sense for you and future uses of your code. For example, if you plan on implementing more buttons it my make more sense to maintain the structure of the original example code with the read_LCD_buttons() function, the return value, and the switch case.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 10, 2015, 02:41 am
Thanks Cattledog, That fixed it. Now I can read the encoder output on the lcd and then display the value on the serial monitor with a button press. You mentioned some characteristics I should look for when getting a sdcard module.  I am using the mega 2560 board with the dfrobot lcd keypad shield. Could you recommend a specific brand/ model that I could plug into the mega board and then have the lcd shield plug into that? Or would it better serve to hook up the module via a cable. And again what model/make.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 14, 2015, 08:36 pm
Quote
When I press the key now the output of the encoder is printed out to the serial monitor until I release the keypad. How can I modify the button code so that when I press the keypad only one line of data is sent to the serial monitor and the same value isn't repeated?
You are going to have to use something similar to the "state change detection" example found in the 02 digital examples section of the IDE. The following example from linksprite http://linksprite.com/wiki/index.php5?title=16_X_2_LCD_Keypad_Shield_for_Arduino (http://linksprite.com/wiki/index.php5?title=16_X_2_LCD_Keypad_Shield_for_Arduino) may be confusing because it is not following the format of your original key shield code but it is in effect the same and will give you some ideas. It also uses a library LCDKeypad.h but I don't see where it is used in the sketch and I think it should work without it.

Code: [Select]
#include <LiquidCrystal.h>
#include <LCDKeypad.h>
LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
char msgs[5][16] = {"Right Key OK ",
                    "Up Key OK    ",              
                    "Down Key OK  ",
                    "Left Key OK  ",
                    "Select Key OK" };
int adc_key_val[5] ={50, 200, 400, 600, 800 };
int NUM_KEYS = 5;
int adc_key_in;
int key=-1;
int oldkey=-1;
 
void setup()
{
  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("     helle! ");
  lcd.print("      welcome!");
  lcd.setCursor(0,1);
  lcd.print("   LinkSprite");
  lcd.print("    LCD Shield");
  delay(1000);
 
  lcd.setCursor(0,0);
  for (char k=0;k<26;k++)
  {
    lcd.scrollDisplayLeft();
    delay(400);
  }
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("ADC key testing");
}
void loop()
{
   adc_key_in = analogRead(0);    // read the value from the sensor
   key = get_key(adc_key_in);  // convert into key press
   if (key != oldkey)   // if keypress is detected
   {
     delay(50);  // wait for debounce time
     adc_key_in = analogRead(0);    // read the value from the sensor
     key = get_key(adc_key_in);    // convert into key press
     if (key != oldkey)    
     {  
       lcd.setCursor(0, 1);
       oldkey = key;
       if (key >=0)
       {
           lcd.print(msgs[key]);              
       }
     }
   }
   delay(100);
}
// Convert ADC value to key number
int get_key(unsigned int input)
{
    int k;
    for (k = 0; k < NUM_KEYS; k++)
    {
      if (input < adc_key_val[k])
      {
        return k;
      }
    }  
    if (k >= NUM_KEYS)k = -1;  // No valid key pressed
    return k;
}




Quote
I would also like to have it so that when I press the left button  and then the right button the data would appear in the same line like this in the serial monitor.
Your second question is easily solved with replacing the Serial.println()statement for button left with Serial.print() and then using the escape character  '\t' = tab  to control your formatting. You can do a google search on \t \n \r to learn about these escape characters.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 20, 2015, 01:21 am
Thanks for getting back to me cattledog. I would have replied sooner but I was away for the week. I will look into the code you supplied and see what I can do for the button press. I do have one question concerning the second part about having the the "LCP" and "RCP" value on the same line. If i press the left button I see LCP: 45 which is fine....How would I go about also printing the value of the right button which would be 0. so when I press left button I would get
"LCP: 45     RCP: 0" or if I pressed the right button I would get
"LCP: 0       RCP: 45"
So i guess i need to include in each button press statement the value of the other button which should be zero.
Sorry if this sounds confusing.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 24, 2015, 04:51 am
Hi All,
I didn't get to far on the problem of the output being repeated while holding down the button but figured it wouldn't be an issue. My end goal is to print the output to a sd card. I just recently bout a ethernet/sd card module and will be working with it soon. I have a couple of issues with my current sketch which I need to workout. When I press the left button I get the desired result "LCP:" plus the current output. As well I get "RCP:" plus the current output when pressing the right button. However I discovered that when I press either the up or down buttons I get the left button value"LCP:" plus the current output.? I haven't even initiated the up button. Why would this be happening?. My other question involves how to subtract the LCP: value from the RCP: value and display the result. I wanted to used the down button to initiate this and the display RESULT: plus the number. I started putting something together using some ideas from a sketch that added strings together but I didn't get very far.
Any ideas,,,
Bill





Code: [Select]

#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnLEFT   3
#define btnRESULT  2
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

 
 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 380)  return btnRESULT;
}

void setup() {
               Serial.begin(115200);
               result = String();
              //pinMode(2, INPUT_PULLUP);arduino uno
              //pinMode(3, INPUT_PULLUP);arduino uno
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
               

                //attachInterrupt(0, encoder_interrupt, CHANGE);arduino uno
                //attachInterrupt(1, encoder_interrupt, CHANGE);arduino uno
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

void loop() {
 lcd_key = read_LCD_buttons();  // read the buttons
 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     Serial.print("RCP  ");
     Serial.println (map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     break;
     }
   case btnLEFT:
     {
     Serial.print("LCP");
     Serial.print("\t");
     Serial.println(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     
     break;
     }

     case btnRESULT:
     {
     lcd.print("Result");
     break;
     }

     
 }


 
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     noInterrupts();
     int copyCounter = counter;
     interrupts();
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
}
      void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}








 
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 24, 2015, 05:16 pm
Up or down are less than 555 and trigger the left response. You need to run through the conditional test in order of increasing resistance.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Sep 24, 2015, 09:14 pm
Hi Cattledog,
That fixed it. Any ideas on how to subtract the "LCP output" from the "RCP output" Using the result button as the initiator? Basically I would rotate the encoder, click on the left button to display in the serial monitor, rotate the encoder and click on the right button to display in the serial monitor and then click on the result button to display the difference between the LCP and the RCP result.

Code: [Select]

#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

 
 if (adc_key_in < 50)   return btnRIGHT;
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnRESULT;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT; 
}

void setup() {
               Serial.begin(115200);
               result = String();
              //pinMode(2, INPUT_PULLUP);arduino uno
              //pinMode(3, INPUT_PULLUP);arduino uno
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
               

                //attachInterrupt(0, encoder_interrupt, CHANGE);arduino uno
                //attachInterrupt(1, encoder_interrupt, CHANGE);arduino uno
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

void loop() {
 lcd_key = read_LCD_buttons();  // read the buttons
 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     Serial.print("RCP  ");
     Serial.println (map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     break;
     }
   case btnLEFT:
     {
     Serial.print("LCP");
     Serial.print("\t");
     Serial.println(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
     
     break;
     }

     case btnRESULT:
     {
     Serial.println("Result:");
     break;
     }

     
 }


 
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     noInterrupts();
     int copyCounter = counter;
     interrupts();
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
}
      void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}








 
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Sep 27, 2015, 08:53 am
Rather than just printing out the values you need to assign them to variables and do the math with the variables.

Also, please take another look at reply #35. You are not using the transfer variable copyCounter, but instead are directly using counter.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 05, 2015, 12:10 am
Hi Cattledog,
Been working on my code. I now have the right and left buttons sending the encoder output to two separate txt files "dataRCP.txt, dataLCP.txt on a sd micro module. Still trying to implement the code that will reduce the multiple entries down to one when I press the button. If you have any other examples you could show me I'd appreciate it. As for subtracting the right button output from the left button output I have decided on a different approach. I will import the two .txt files i created into excel and use formulas and a the graphing utilities to achieve the final result. perhaps when I come more proficient in coding I will attempt to address the issue directing in arduino. If you could also look at what i have and see if there is anyway i could tweak what I have to run better i would appreciate this as well.
Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

 
 if (adc_key_in < 50)   return btnRIGHT;
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnRESULT;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT; 
}

void setup() {
               Serial.begin(9600);
               Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
             // see if the card is present and can be initialized:
            if (!SD.begin(chipSelect)) {
            Serial.println("Card failed, or not present");
           // don't do anything more:
            return;
            }
          Serial.println("card initialized.");
         
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
       
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

void loop() {
// make a string for assembling the data to log:
  String dataString = "";



 
 lcd_key = read_LCD_buttons();  // read the buttons
 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     {
   
    dataString =  String("RCP \t") + String(",") + String(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));       
   
    File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.
   
   
    if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
      dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
      dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
                          //likely o.k. and can be read with the computer.
     
      Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
    } 
  // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
    else {
      Serial.println("error opening dataRCP.txt");//in that case print an error message
    }
  }
     break;
     }

     
   case btnLEFT:
     {
{
   
    dataString =  String("LCP \t") + String(",") + String(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));     
    File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.
   
   
    if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
      dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
      dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
                          //likely o.k. and can be read with the computer.
     
      Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
    } 
  // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
    else {
      Serial.println("error opening dataLCP.txt");//in that case print an error message
    }
  }
     
   
     break;
     }

     case btnRESULT:
     {

     
   
 
     break;
     }

     
 }


 
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
     //lcd.print(map(counter, 0, 4095, 0, 99));
     noInterrupts();
     int copyCounter = counter;
     interrupts();
     lcd.print(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));
}
      void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}








Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 06, 2015, 06:06 am
A problem that I still see with your code, is that you do not actually use the protected copy of the encoder counts in your code. You indeed pull the counts into a variable which will not change during a reading, but you don't actually use it. Everywhere in your code you are directly accessing the variable "counter" in the mapped values.

Code: [Select]
noInterrupts();
     int copyCounter = counter;
     interrupts();


You could handle the use of the protected copy with a function like
Code: [Select]
int getCount ()
{  
     noInterrupts();
     int copyCounter = counter;
     interrupts();
     return copyCounter;
}


Then, everywhere in your code where you are using "counter", substitute the function getCount().

Code: [Select]

 dataString =  String("RCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
dataString =  String("LCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
 lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 07, 2015, 01:03 am
Thanks again Cattledog,
I went over my code and I think I have it right now......Do you have any more examples for the "State Change Detection" I just cant seem to get my head around what needs to be done here.
Bill

Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor

 
 if (adc_key_in < 50)   return btnRIGHT;
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnRESULT;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT; 
}

void setup() {
               Serial.begin(9600);
               Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
             // see if the card is present and can be initialized:
            if (!SD.begin(chipSelect)) {
            Serial.println("Card failed, or not present");
           // don't do anything more:
            return;
            }
          Serial.println("card initialized.");
         
              pinMode(18, INPUT_PULLUP);
              pinMode(19, INPUT_PULLUP);
             
               // set up the LCD's number of columns and rows:
                lcd.begin(numCols, numRows);
       
                attachInterrupt(4, encoder_interrupt, CHANGE);
                attachInterrupt(5, encoder_interrupt, CHANGE);
 
}

int getCount ()

     noInterrupts();
     int copyCounter = counter;
     interrupts();
     return copyCounter;
}

void loop() {
// make a string for assembling the data to log:
  String dataString = "";



 
 lcd_key = read_LCD_buttons();  // read the buttons
 switch (lcd_key)               // depending on which button was pushed, we perform an action
 {
   case btnRIGHT:
     {
     {
   
    dataString =  String("RCP \t") + String(",") + String(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));       
   
    File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.
   
   
    if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
      dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
      dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
                          //likely o.k. and can be read with the computer.
     
      Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
    } 
  // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
    else {
      Serial.println("error opening dataRCP.txt");//in that case print an error message
    }
  }
     break;
     }

     
   case btnLEFT:
     {
{
   
    dataString =  String("LCP \t") + String(",") + String(map(float(counter), 0, MAX_ENCODER_VALUE, 0, 99));     
    File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.
   
   
    if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
      dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
      dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
                          //likely o.k. and can be read with the computer.
     
      Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
    } 
  // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
    else {
      Serial.println("error opening dataLCP.txt");//in that case print an error message
    }
  }
     
   
     break;
     }

     case btnRESULT:
     {

     
   
 
     break;
     }

     
 }


 
   
     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
   
     noInterrupts();
     int copyCounter = getCount();
     interrupts();
     lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
}
      void encoder_interrupt() {
      static uint8_t oldEncoderState = 0;
      oldEncoderState <<= 2;
      oldEncoderState |= ((PIND >> 2) & 0x03);
      direction = encoderDirections[(oldEncoderState & 0x0F)];
      counter += direction;
      //counter += encoderDirections[(oldEncoderState & 0x0F)];
            if (counter < 0) counter = MAX_ENCODER_VALUE;
                  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}








Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 07, 2015, 02:51 am
Quote
I went over my code and I think I have it right now.....
No. I explicitly pointed out all the places constructing your Strings where you used the unprotected variable "counter" which needed to be replaced with the function getCount(). You have not done that.

Your code appears to work, so you have not adopted the coding practice which says that when you access a volatile variable bigger than a byte from an isr you need to ensure an interrupt can not change it while it is being read.

You can also clean up the lcd print portion of the code now that you have the getCount() function
Code: [Select]

     lcd.setCursor(0, 0);
     lcd.print("Contact Points:  ");
     lcd.setCursor(0, 1);
    
     //noInterrupts();
     //int copyCounter = getCount();
     //interrupts();
     lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
}


Here's one possibility on how to manage the multiple records on a button press. Your program will need to read a no button pressed before it can service a button again. Create a global variable (a byte will be fine) called Flag. Start off with it =1.  You can start the code in each active button with if (Flag ==0 ){//do what follows} At the end of the case, set Flag = 1.

Add btnNONE to the resistance list, and create the case for button NONE which sets the flag to 0.

Code: [Select]
case btnNONE:
      Flag = 0;
     break;
    


Here is some code. I could not follow your bracket arrangements, and I changed them. Be aware that the bracket arrangement in this untested code may not be correct.
Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  //noInterrupts();
  //int copyCounter = getCount();
  //interrupts();
  lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
  //counter += encoderDirections[(oldEncoderState & 0x0F)];
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 08, 2015, 12:39 am
Thanks Cattledog,
It works great now. I will study what you did and work on interfacing the sketch and excel using GOBETWINO which looks interesting. I am also going to work on producing some graphics representing the the rotation of the encoder. Thanks again for your help and patience. Really appreciate it.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 11, 2015, 12:25 am
Hi all,
I have been testing my sketch and have a couple of questions...
First off when I rotate the encoder clockwise(1 rotation) the lcd displays the count 1-99 fine. If i keep going clockwise the count should repeat 1-99. It does except for on exception. the second digit on the lcd display remains at 9 unti the count reaches 10.....so 1-20 looks like this
19,29,39,49,59,69,79,89,99,10,11,12,13,14,15,16,17,18,19,20. When I rotate the encoder CCW it reaches 10 and then the 0 remains like this count down from 20.
20,19,18,17,16,15,14,13,12,11,10,90,80,70,60,50,40,30,20,10. Anyone have an idea of why it would do this and how I could correct it. The other question involves refining the encoder output. I have included some pics of how am using the encoder which is mounted to a safe dial.(http://imgur.com/a/BuimE)
The safe dial is numbered 1-99 and my encoder measures 1-99 on 1 rotation. I would like to refine the measurement to includes 10ths. so when I turn the dial from 1 to 2 1 would get this on the display.
1.0,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0. It just a matter of changing the output resolution but I am not sure how to do it........ Here is my code.....Special thanks to cattle dog and Jaakko for helping me get to this point....
Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") + String(",") + String(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  //noInterrupts();
  //int copyCounter = getCount();
  //interrupts();
  lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 11, 2015, 01:22 am
You need to read the documentation on the map function https://www.arduino.cc/en/Reference/Map (https://www.arduino.cc/en/Reference/Map)
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged.

Given the integer nature of the map function, you should remove the cast to float of getCount().
Code: [Select]
//lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
lcd.print(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));


If you want to translate 0-4095 into 00.0 to 99.9 you are going to have to write your own function.

Regarding the management of the lcd print out, you were pointed at this in earlier posts #32 and #33
Quote
Will also work with the blank space to accommodate when the value decreases.
I would handle it this way
Code: [Select]
int value = map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99)
if (value <10)
  lcd.print("0");
lcd.print(value);


This should print a leading zero for values less than 10 on the way up and down.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 11, 2015, 04:04 am
Thanks Cattledog,
I tried adding this
Code: [Select]
int value = map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99)
if (value <10)
  lcd.print("0");
lcd.print(value);
and recieved this complile error
Code: [Select]
error: expected ',' or ';' before 'if'
error: 'lcd' does not name a type
expected ',' or ';' before 'if'



Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") + String(",") + String(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") + String(",") + String(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  //noInterrupts();
  //int copyCounter = getCount();
  //interrupts();
  //lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
lcd.print(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

int value = map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99)
if (value <10)
  lcd.print("0");
lcd.print(value);

int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 11, 2015, 06:05 am
You patched the code into the wrong place. It was supposed to be in the main loop where the lcd print was invoked.  I'll try not to provide code fragments in the future.

Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") + String(",") + String(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") + String(",") + String(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  int value = map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

  //noInterrupts();
  //int copyCounter = getCount();
  //interrupts();
  //lcd.print(map(float(getCount()), 0, MAX_ENCODER_VALUE, 0, 99));
//lcd.print(map(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 16, 2015, 02:42 am
Hi Cattledog,
Thanks for getting back to me. That did the trick. Also implemented another change to add to decimal places. I am ready to put my project to the test but have one little glitch. When i power up the mega board using the usb serial cable it works great. I tried removing the cable and using a 12v / 1amp power adapter but it doesn't work as expected. It powers up okay and I see the Contact Points: string on the Lcd, but the number digits seem to appear behind the Contact Points: string on the same line, and it doesn't look as if the output of the encoder is being read. i assume that I have hooked something up incorrectly. Any ideas?
Bill

Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named dataRCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         // Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named dataLCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

 

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 16, 2015, 05:24 am
Good work on the mapfloat function.

Quote
using a 12v / 1amp power adapter
What is that?

 
Is is something which plugs into mains power and puts out 12vdc (not ac) or is it some sort of battery pack? Is it plugged in to the barrel jack adaptor?

If everything was working on usb power and then went funny with your power supply, there are three things I can think off. It's not clear to me if things would work to the extent you see with any of these scenarios.

1) The end which plugs into the barrel jack needs to have center positive. Some power supplies can be center ground. You maybe applying reverse polarity.

2) Some "wall wart" power adaptors are unregulated, and can put out significantly higher voltage than the nameplate at low loads.  You can actually burn out the voltage regulator with them. the 12v supplies are particularly bad because they can be 18v at low load. These supplies often have a rated load to go with the voltage.  You want a regulated or "switching" power supply if using one of the plug in jobs.

3) Its a 12 volt ac adaptor.

There may also be some sort of grounding issue, and you want to make sure all the grounds are closely tied.

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 19, 2015, 12:03 am
Hi Cattledog,
Thanks for your reply. Upon reading it I replaced the power supply with a 9v battery adapter which plugs into the barrel jack. Still doing the same behavior. From what I can see, only the output string "Contact Points:" displays correctly. I noticed what appeared to be 00.00 underneath "Contact Points". I commented out the line
Code: [Select]
lcd.print("Contact Points:  "); and uploaded the sketch and sure enough at position 0,0 on the lcd screen 00.00 appeared. The encoder however wasn't functioning. Once I unplugged the 9v battery adapter from the barrel jack and plugged in the usb serial monitor cable the display worked correctly with 00.00 appearing on the lcd screen at 0,1 as it is supposed to and the encoder functioning again. I am somewhat bewildered as to what could be happening and wonder if the barrel jack connection on my arduino mega board 2560 might be faulty? The 9v adapter I am using came with my arduino kit and assume that it is wired correctly with the center pin being positive. Both the power light on the lcd shield and the on led on the mega board are light. Any ideas on what I could try to fix this. I have a arduino uno board which I will try with the lcd shield and encoder hooked up. with have to modify the sketch code to do this. I modified the sketch for the arduino uno board and get the same error now when the usb serial cable is plugged in as well as when I use the 9v adapter on the barrel jack.....confusing...ideas??????
Bill

Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

 // pinMode(18, INPUT_PULLUP);
  //pinMode(19, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  //attachInterrupt(4, encoder_interrupt, CHANGE);
  //attachInterrupt(5, encoder_interrupt, CHANGE);
  attachInterrupt(0, encoder_interrupt, CHANGE);
  attachInterrupt(1, encoder_interrupt, CHANGE);
}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named dataRCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         // Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named dataLCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

 

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 19, 2015, 02:55 am
Code: [Select]
const int chipSelect = 53;

If you are going to rewrite the sketch for a uno, I believe the CS pin will need to be changed. There may also be interactions with the backlight which is on pin 10, and also pin 4 is in use by the display. However, I doubt this is relevant to the major problems you are having.

I don't understand what might have happened when you hooked up to your first 12v lamp power supply but its possible something was damaged. The difference between the barrel jack and the usb power might indicate a problem with the voltage regulator. I've burned one out with an unregulated 12v supply. Look for that part on a schematic and see if you can see it damaged/burned.

Can you find more detail on what was connected to the barrel jack when things went bad? It could help in determining what happened.

I'm afraid you will have to go back to basic trouble shooting with simple sketches to see what it takes to get the lcd, the encoders, and the sd card working again. 

Quote
I modified the sketch for the arduino uno board and get the same error now when the usb serial cable is plugged in as well as when I use the 9v adapter on the barrel jack...
I'm with you, and do not understand this. Is the encoder not working or just the lcd on the uno? Unfortunately, all I can say is that you are going to have to take a step backward , but you at least know that you have working code waiting at the end when you figure out what happened with the hardware.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 20, 2015, 04:18 am
Well Cattledog i'm drawing a huge blank here. I switched out the lcd shield for another one and I am still getting the same behavior. I guess the lcd shield has issues with the barrel connector power supply.....Or even the way it is stacked on the arduino uno or mega board......
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 20, 2015, 06:31 am
Quote
I switched out the lcd shield for another one and I am still getting the same behavior.
That's useful information in that the internal controller chips on the 16x2 lcd which saw the lamp power supply are probably not damaged.

Can you run a simple "hello world" example sketch on either lcd shield with either the uno or the mega?
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 20, 2015, 12:05 pm
I uploaded the example sketch 'Hello, World' which includes the counter and it ran fine with the 9v adapter attached to the barrel jack. The lcd displayed "Hello, World" at 0,0 and the counter "0.0" at 0,1
So is it possible it is something in the way the LCD Display is handled in the sketch? Not sure how to proceed.
Bill


Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named dataRCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         // Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named dataLCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

 

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 20, 2015, 08:27 pm
Quote
So is it possible it is something in the way the LCD Display is handled in the sketch?
It was working before the power event, so it's not your lcd display code which looks fine.

Code: [Select]
lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);


If the first line of the lcd display "Contact Points:  " is unchanging, you can move it to set up. It will be stored in the lcd memory and you do not need to write it over and over in each loop.

Quote
Not sure how to proceed.
I'd next work on checking out the encoder and finding out why it is non responsive. As you go forward and describe your trouble shooting, please let me know if you are using the Mega which saw the power event, or the Uno which did not. Whether or not you are using the USB power or the 9V through the barrel jack, and what else is connected when you do the test. You have two arduinos, two means of power, and several pieces of hardware. You will need to move through all the combinations systematically and describe accurately and in detail what you have done.

Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 22, 2015, 05:46 am
Hi Cattledog....
I decided to try a a couple of different sketches using the lcd. With hello word...it worked fine on the dc battery adapter which I upgraded to a 16V DC 850ma.
I then tried an earlier sketch using the lcd and encoder and this also worked fine on the usb serial cable and using the power adapter on the barrel jack. the code below is what I used.
However. When I used the last modified code I now get the error where it will not work on the usb serial cable or with the power adapter on the barrel jack. I have not touched and wiring. I just uploaded the sketch. this makes me wonder if something in the code is causing this. I find it strange that it once worked with the serial cable but does not now, while the earlier sketch works fine . Below this sketch I have posted the last modified sketch that is having the problems...


Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named dataRCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") + String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named datalog.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

  

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}



Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 22, 2015, 08:30 am
Quote
I upgraded to a 16V DC 850ma.
The recommended input voltage is 7-12v. There may be a maximum rating of 20v. You will be creating alot of heat in the voltage regulator.  I don't think that a 16v supply is necessary or desireable.

I am very unclear as to what was the last working code, and what is the broken code.
 
Are you certain that there are no hardware issues from the power supply event? LCD, encoder, sd module and arduino all check out fine?

You are not providing me with the information to help you solve your problem.

Please post a working sketch and the hardware used. Then post the broken sketch and the hardware used. What did you change between the two versions?

Confirm that the working sketch is working and describe how the broken code is not. Explicity address the lcd, the encoder, and the sd card.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 22, 2015, 12:20 pm
Hi Cattledog,
Sorry this is the code that is not working correctly. I ran into a problem when I tried to use a power supply hooked up to the barrel jack. I then tried increasing the amount of power to rule out the problem being caused by insufficient power. At first this problem only occurred when I tried using the power supply hooked up to the  barrel jack connector with my latest code shown below...when i used the usb serial cable everything worked fine. However the code will not work now when I use either the usb serial cable or the power supply hooked to the barrel jack connector. The code I posted in the previous post does work though. And even works with the 9v battery hooked up to the barrel jack connector. This problem happen whether I am using the lcd shield with the arduino UNO or arduino Mega board. What I find weird is

1:how the code below would work with the usb serial cable before and not now
2:how the code in the above post works okay with either the 9v battery or usb serial cable.
3: For me I can rule out a hardware issue. Note: I have also switched LCD Shields and tried using both the arduino Uno and arduino mega board. I also tried different DC  power supplies to rule out insufficient power issues.


Code: [Select]
#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;

byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String result;
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnRESULT  2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnRESULT;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  Serial.begin(9600);
  Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
        dataString =  String("RCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));

        File dataFile = SD.open("dataRCP.txt", FILE_WRITE);//open a file named dataRCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         // Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }

        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataRCP.txt");//in that case print an error message
        }
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
        dataString =  String("LCP \t") +  String(mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
        File dataFile = SD.open("dataLCP.txt", FILE_WRITE);//open a file named dataLCP.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

          Serial.println(dataString);// print the string also to the serial port, so we can see what is going on.
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening dataLCP.txt");//in that case print an error message
        }
        Flag = 1;
      }

      break;

    case btnRESULT:
      break;

    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Contact Points:  ");
  lcd.setCursor(0, 1);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
    lcd.print("0");
  lcd.print(value);

 

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 22, 2015, 12:30 pm
I think my next plan will be to place the "Contact Points" string into setup as you suggested and start commenting out parts of code to see if I can find where the problem originates from
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: cattledog on Oct 22, 2015, 04:49 pm
I guess i am missing something. Can you please point out for me the exact differences between the two versions of posted code in post 71(not working) and 69(works OK).

What had you tried to modify when you changed the code. What problem with the working code were you trying to fix?

Please describe "not working".

Post #71
Quote
would work with the usb serial cable before and not now
At first this problem only occurred when I tried using the power supply hooked up to the  barrel jack connector with my latest code shown below...when i used the usb serial cable everything worked fine. However the code(post #71) will not work now when I use either the usb serial cable or the power supply hooked to the barrel jack connector.
Post #69
Quote
code in the above post (#69) works okay with either the 9v battery or usb serial cable.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 22, 2015, 07:05 pm
Hi Cattledog,
I apologize for not being clear with the problem. In post #64 I referred to a problem I had with the sketch when I tried hooking up a 9v battery to the barrel jack connector. The sketch worked great while the mega board was hooked up to the USB serial cable. But it did not function right using the barrel jack. The LCD displayed the string"Contact Points:" starting at 0,0 correctly. The output from the encoder is supposed to be displayed on LCD at 0,1. This is where the problem is.
1. The output is also displayed at 0,0
2. I commented out the "Contact Points: string and noticed the encoder is not working. I changed the power source to the 16V DC 850ma plugged into the barrel jack connector only to see if the problem was due to the board being under powered. But the problem was still there. When I plugged the board back into the USB serial cable the sketch worked as it should with no errors. I tried replacing the LCD shield but there was no change. I even tried replacing the mega board with a Arduino UNO board but it behaved the same way as the mega board reproducing the LCD display error. I then decided to test the LCD shield by uploading the hello world sketch. The sketch ran fine either booked up to the USB serial cable or using the power adapter hooked to the barrel jack. I then uploaded a previous sketch for the encoder. Post #34 this sketch read the output from the encoder and displayed it on the LCD screen no problem while hooked to the USB serial cable or to the power adapter. What I don't understand is how the sketch in post #69 worked okay with the serial cable and not with the power adapter. And now the program will not work with either the serial cable or the power adapter. I have changed nothing in the hardware. I hope I have explained better what's going on.
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 23, 2015, 03:05 am
I commented out the code
Code: [Select]
//lcd.setCursor(0, 0);
  //lcd.print("Contact Points:  ");
  //lcd.setCursor(0, 1);

Which comes after the switch statement for the buttons and this is what appeared on the lcd display starting at 0,0

00.0000.0000.00 The encoder is not working as well.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 24, 2015, 04:06 pm
Hi all,
I narrowed down the problem to the micro sd card module I am using. I removed all reference of it in the sketch and the sketch works fine using the 9v battery attached to the barrel jack. Not sure why this would be but I will look into it and see what I can come up with.
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Oct 31, 2015, 02:50 am
hi All,
Just another update. I solved the problem of the micro sd card malfunction. Turns out that the card didn't work properly when I had it powered off the 3v pin on my arduino mega board. Switched the power over to the 5v pin on the arduino board and everything works like a charm. Whether hooked to the usb serial cable or to the 9v battery plugged into the barrel jack. Thanks for your help and time  Cattledog in trying to figure this problem
Bill
Title: Re: Rotary encoder output to lcd 1602a
Post by: williamjcoates on Nov 12, 2015, 03:07 am
Been busy with modifying this sketch. When I click on the upBTN, I get the "result"
Code: [Select]
result = leftBtn - rightBtn; I also get the number of the button press
Code: [Select]
if(increaseA < 100)
   {
       increaseA++;
   }
   else increaseA = 0;
This represents the number on the safe dial I am testing. An example in my gap.txt would look like this.
0  00.00
1  06.13
2  07.45
and so on up to 99.
When I click on the down button I would like to do the same except I want to have the counter increment by 2.5. An example would look like this
0  00.00
2.5  07.12
5     06.34
and so on up to 97.5
At the moment I have it incrementing by 1.
My question is how can I make the counter increment by 2.5.
One other question is if I have done the following functions okay or is there a better way of writing the code.
Bill
Code: [Select]

#include <SD.h>
#include <SPI.h>
#include <LiquidCrystal.h>
#define MAX_ENCODER_VALUE 4095
const int chipSelect = 53;
const int8_t encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile int16_t counter = 0;
volatile int8_t direction = 0;
float rightBtn = 0;
float leftBtn = 0;
float result = 0;
int increaseA = 0;//add counter that will increment by 1 on each btnUP press
int increaseB = 0;//add counter that will  increment by 2.5 on each btnDOWN press..not working yet
byte Flag = 1;//add flag to control multiple records for same button press


const int numRows = 2;
const int numCols = 16;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP      1
#define btnDOWN    2
#define btnLEFT    3
#define btnSELECT  4
#define btnNONE    5
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor


  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  if (adc_key_in < 1024) return btnNONE;//add
}

void setup() {
  //Serial.begin(9600);
  //Serial.println("Initializing SD card...");
  pinMode(chipSelect, OUTPUT);//set chip select PIN as output.
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    //Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  //Serial.println("card initialized.");

  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);

  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);

  attachInterrupt(4, encoder_interrupt, CHANGE);
  attachInterrupt(5, encoder_interrupt, CHANGE);

}


void loop() {
  // make a string for assembling the data to log:
  String dataString = "";
 

  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
    case btnRIGHT:
      if (Flag == 0)
      {
       
        rightBtn = (mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
     
       
        Flag = 1;
      }
      break;

    case btnLEFT:
      if (Flag == 0)
      {
       
        leftBtn = (mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99));
       
       
        Flag = 1;
      }

      break;

    /**********************************************************************************/

      case btnUP:
      if (Flag == 0)
    {
   
result = leftBtn - rightBtn;
   
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      delay(10000);//Give time to read result before it clears off screen
      lcd.clear();
      if(increaseA < 100)
   {
       increaseA++;
   }
   else increaseA = 0;
     
    dataString =  String (increaseA) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("gap.txt", FILE_WRITE);//open a file named contactGap.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening gap.txt");//in that case print an error message
        }

     
 Flag = 1;
    }
      break;


/*************************************************************************************************************/

       case btnDOWN:
      if (Flag == 0)
    {
       Serial.println(increaseB);
result = leftBtn - rightBtn;
   
      lcd.setCursor(0, 1);
      lcd.print("Gap Dif:");
      lcd.setCursor(9, 1);
      lcd.print(result);
      delay(10000);
      lcd.clear();
      if(increaseB < 100)
   {
       increaseB++;
   }
   else increaseB = 0;
     
    dataString =  String (increaseB) + String("\t") + String("Contact Gap \t") +  String(result);
        File dataFile = SD.open("gap.txt", FILE_WRITE);//open a file named contactGap.txt.


        if (dataFile) {       // if the file is available, write to it ('datafile' is returned 1 if SD.open was successful.
          dataFile.println(dataString);//print the concatenated data string and finish the line with a carriage return (println adds the CR automatically after printing the string)
          dataFile.close();   //close the file. IT is a good idea to always open/close a file before and after writing to it. That way, if someone removes the card the file is most
          //likely o.k. and can be read with the computer.

         
        }
        // if SD.open is not successful it returns a 0, i.e. the else{} is executed if the file could not be opened/created successfully.
        else {
          Serial.println("error opening gap.txt");//in that case print an error message
        }

     
 Flag = 1;
    }
      break;
     


    case btnNONE:
      Flag = 0;
      break;

  }//closes switch


  lcd.setCursor(0, 0);
  lcd.print("Encoder:");
  lcd.setCursor(9, 0);

  float value = mapfloat(getCount(), 0, MAX_ENCODER_VALUE, 0, 99);
  if (value <10)
 
    lcd.print("0");
  lcd.print(value);

 

}//closes loop


void encoder_interrupt() {
  static uint8_t oldEncoderState = 0;
  oldEncoderState <<= 2;
  oldEncoderState |= ((PIND >> 2) & 0x03);
  direction = encoderDirections[(oldEncoderState & 0x0F)];
  counter += direction;
 
  if (counter < 0) counter = MAX_ENCODER_VALUE;
  else if (counter > MAX_ENCODER_VALUE) counter = 0;
}

float mapfloat(long x, long in_min, long in_max, long out_min, long out_max)
{
  return float((x - in_min) * float((out_max - out_min)) / (in_max - in_min) + out_min);
}


int getCount ()
{
  noInterrupts();
  int copyCounter = counter;
  interrupts();
  return copyCounter;
}