Another Nub in Trouble !!

I'm a nub and i'm stuck...
I want to control a relay (I have the relay board already that requires a +5 volt input to energize the relay) with a Mega.. I wish to enter a numeric value via a 4X4 keypad and have the relay energize until that value is reached by the rotary encoder I have attached to the arduino Mega..

I have a Mega, 4x4 keypad, Relay Board (not Shield) and an Automation direct TRD-NH2500-RZVWD rotary Encoder..

I have started to write some code using different sketches but have totally buried myself with lack of knowledge..

Is there a sketch already available to do this or do I need to piece it together on my own??

Any help is appreciated..

Dave :frowning:

How do you eat an elephant? One bite at a time. :slight_smile:

I'd suggest break down your tasks into the following:

  • controlling the relay from arduino
  • making the keypad work
  • learning how to work with rotary encoders

Write small sketches that deal with each of the above so you learn how to make that one particular task work (or prove to yourself that your code works.) Check out the playground for sample code (for ex: the rotary encoder sketch).

Then once you can make each of your hardware works, then it's just a matter of assembling all the code together, with the necessary flow logic in place to glue them all together.

Hello and welcome aboard nub :slight_smile:

One thing at a time, learn how to use each parts separately, only then you will be able to mix them all together. I suggest you start by learning how to use your rotary encoder, if you have problems with this first part then post your code :slight_smile:

Edit: Yeah, what Vasquo said, but I like to start with the hardest part so that list is upside down for me :wink:

Is there a sketch already available to do this

Very unlikely.

do I need to piece it together on my own?

Probably.

It really isn't that difficult.

Break the program into sections. In loop, call a function to get a number. That function should return true if the value is available, and false if it isn't. Available or not will depend on some sort of "enter" key being defined (typically the # or the *). Since that function will be called very often, it must mot block. It simply sees if there is a key being pressed, and adds it to an array if so. Dealing with the backspace key (pick one to mean backspace) earns you bonus points. Keeping the array NULL terminated does not; that is mandatory.

Whether that function, or loop(), converts the array to an int isn't really important. The atoi() function does all the work, in either case.

Now that you have a target, you can deal with turning a pin on or off.

Then, read the encoder. How depends on the number of steps per revolution. If it is a small value, polling will be sufficient. If it is a large value, interrupts will be necessary.

Once you can get a target value and an actual value, its time to put everything together. Turn the pin on when the enter key is pressed, and turn it off when the actual value matches the target value.

@Paul S..I have the encoder talking to the arduino.. It is a 2500 (yes 2500ppm) model so I need to scale it down as the arduino only wants to see 1024 counts.. As for the keypad, I havent attempted it yet as I am stuck on scaling the encoder input..
Here is my code so far>> I didn't write the original, I have edited to try to accomplish my task. I added PIN 15 to try to use a push button to reset the encoder count to 0. I didn't know where to go after defining the pin..My train of thought is this. If I can get the encoder scaled to be accepted by the arduino and I can print to the LCD, then I will work on the reset button.I can only get a count to 1023 on my LCD..

#include <LiquidCrystal.h>
#define encoder0PinA 3
#define encoder0PinB 2
#define analogOutPin 5
#define analogInPin 15
LiquidCrystal lcd(12,11,7,6,5,4);
volatile unsigned int encoder0Pos = 0;
unsigned int tmp = 0;
unsigned int Aold = 0;
unsigned int Bnew = 0;

void setup() {
pinMode(encoder0PinA, INPUT);
pinMode(encoder0PinB, INPUT);

// encoder A on interrupt 1 (pin 3)
attachInterrupt(1, doEncoderA, CHANGE);
// encoder B on interrupt 0 (pin 2)
attachInterrupt(0, doEncoderB, CHANGE);

}

void loop(){
//if position has changed, display it on LCD
if (tmp != encoder0Pos) {
tmp = encoder0Pos;
//for (int loopCnt = 0; loopCnt < (tmp / 2500) +1 ; loopCnt++1);
}
lcd.begin(16,1);
lcd.setCursor(5,0);
lcd.print(tmp);
delay(170);
}

// Interrupt on A changing state
void doEncoderA(){
// if Bnew = Aold, increment, otherwise decrement
Bnew^Aold ? encoder0Pos++:encoder0Pos--;
Aold=digitalRead(encoder0PinA);
// check for underflow (< 0)
if (bitRead(encoder0Pos, 150) == 1) encoder0Pos = 0;
// check for overflow (> 1023)
if (bitRead(encoder0Pos, 100) == 1) encoder0Pos = 1023;
constrain(encoder0Pos, 0, 1023);
}

// Interrupt on B changing state
void doEncoderB(){
Bnew=digitalRead(encoder0PinB);
// if Bnew = Aold, increment, otherwise decrement
Bnew^Aold ? encoder0Pos++:encoder0Pos--;
// check for underflow (< 0)
if (bitRead(encoder0Pos, 15) == 1) encoder0Pos = 0;
// check for overflow (> 1023)
if (bitRead(encoder0Pos, 10) == 1) encoder0Pos = 1023;
}

loopCnt++1

Never seen that construct before.

Once you have copied the encoder position, in loop, shouldn't you reset the encoder position to 0? Shouldn't you be adding the current encoder position to tmp, rather then replacing tmp?

Do you suppose the inability to count over 1023 has anything to do with this:

  // check for overflow (> 1023)
  if (bitRead(encoder0Pos, 10) == 1) encoder0Pos = 1023;

I have to admit, I am a newbie and as such, I'm not fluent in Arduino !!.. Can you give me an example of how to reset the encoder position? and adding the position to TMP.. The If statement doesn't make sense to my infantile knowledge.

Help Please !!

@AWOL... That line was left in from the Bar Graph display that was in the original sketch.. It apparently was to add 1 to the loop.. It's remarked out..

Can you give me an example of how to reset the encoder position?

encoder0Pos = 0;

and adding the position to TMP

tmp += encoder0Pos;

The If statement doesn't make sense to my infantile knowledge.

There is a comment before it. If you don't think that 1023 is an overflow condition, then you don't need to check for it. Delete that statement, and the comment.

What is the purpose of the keypad? You said you want to enter a value with the keypad and now rotary encoder is doing that. Do you intend to have both of them as inputs? Understood this part better now.

BTW, the program you have there for the rotary encoders doesn't debounce the encoders.

You probably also mixed up ppm and ppr. 2500ppm means 2500 parts per million. Totally nonsense for rotary encoders. 2500ppr is likely pulse per revolution, meaning very accurate measurement of rotation, at 0.14 degree resolution, as indicated here: "2500 pulses per revolution, 8mm hollow shaft, 50mm diameter body, 5VDC"

Get into the habit of posting data sheets.

Your device is pretty expensive. If possible, get a cheap one to play with before you try and break the expensive one.

One more question: will the actual rotation be restricted within one revolution or will it go beyond one revolution? Your current program discards anything beyond a full revolution. You borrowed code and didn't tell us what you want.

@ Liudr.. The rotary encoder will only move from 0 degrees to approx 190 degrees.. Never all the way around.. OOPs I meant pulses per revolution not parts per million..

I did in fact borrow code that was for counting the PPR from a rotary encoder and display it on an LCD as a bar graph and print it serially to the terminal as Decimal..I modified it to read the PPR and display it on the LCD as Decimal only.. For me thats a great accomplishment..LOL !!

I want to enter a decimal # via a 4X4 keypad, have it display on an LCD display, then have an analog output go HI until the PPR equals the entered keypad value. I need to use a second LCD to display the pulse count from the rotary encoder.At the "matched" value, the analog output would go low. As an added feature, I would like to clear the rotary encoders count to 0 by pushing a button.

I'm trying to scale the PPR or at least have the Arduino display a count over 1023.. After that I will work on the reset via a pushbutton..

Again, any help or guidance is appreciated...

P.S the automation direct part # for my encoder is: TRD-NH2500_RZVWD.. I am using the A+ and A- leads as well as the +5vdc and Ground (0 V)

Can someone explain what these lines are doing..And how?.. I understand they are looking at the rotary encoders movements but how?..
Help please !!!

// Interrupt on A changing state
void doEncoderA(){
// if Bnew = Aold, increment, otherwise decrement
Bnew^Aold ? encoder0Pos++:encoder0Pos--;
Aold=digitalRead(encoder0PinA);
// check for underflow (< 0)
if (bitRead(encoder0Pos, 150) == 1) encoder0Pos = 0;
// check for overflow (> 1023)
if (bitRead(encoder0Pos, 100) == 1) encoder0Pos = -10023;
constrain(encoder0Pos, 0, 10023);
}

// Interrupt on B changing state
void doEncoderB(){
Bnew=digitalRead(encoder0PinB);
// if Bnew = Aold, increment, otherwise decrement
Bnew^Aold ? encoder0Pos++:encoder0Pos--;
// check for underflow (< 0)
if (bitRead(encoder0Pos, 15) == 1) encoder0Pos = 0;
// check for overflow (> 1023)
if (bitRead(encoder0Pos, 10) == 1) encoder0Pos = 10023;
}

OK, the A- lead only gives your the negated A+ value. You need to use A+ and B+ for channel A and B (did I misunderstand what you are using?).

If you replace all 1023 by 2499, then you will be able to count from 0 to 2499, plenty for your 190 degree rotation. The number entry part can be done with two separate libraries, the liquidcrystal and keypad or phi_interfaces. You essentially capture all key presses until the enter (maybe use * or #) and turn the input into number.

This part can be programmed separately from counting encoders. I recommend you try this separately. Also, instead of LCD, use the serial as input and output. Just type in 1200# and send in to arduino via serial monitor will test your code's ability to recognize 1200 as input number. Once that part is good, replace serial monitor with LCD :wink:

  if (bitRead(encoder0Pos, 100) == 1) encoder0Pos = -10023;

Can anyone explain this?

@AWOL.. That was me trying to get the counter to go above 1023.. My Bad !!.. I have changed it back to 1023..until I can get this code into my head and make sense of it..
Thanks