Want to emulate a rotary encoder, have a couple of questions.

Hi, I'm rather new to Arduino and C++ programming. I've spent the past several days reading about rotary encoders and using them as an input with the Arduino. I seem to grasp how they work as a sensor, but I want to do something a little different.

I have a signal processor for my car called an Audison Bit One. I am using it to interface with my factory stereo head unit.
Many newer cars have built in, volume sensitive equalization in them that essentially cuts the bass output as volume goes up.
Normally you would set your output level from the head unit to it's maximum unclipped level, and leave it there and use the speaker level signal from the radio to feed the BitOne. Then you would use the volume control on the processor to adjust volume.

My car has steering wheel controls, and I am attempting to interface the Arduino with them. Ideally, when it sees the Volume Up or Volume Down buttons, I would like it to (obviously) turn the volume up or down on the BitOne while leaving the setting on the factory radio alone; essentially functioning as my master volume control.

My idea was to read the input voltage for the steering wheel controls with an AnalogRead(), and compare it to certain values. If it sees Volume up, Volume Dn, or Mode it does one thing, otherwise it uses a Digitalwrite() on a PWM output pin to allow the other functions to work normally.

I had thought about using a continuous rotation servo to control the knob, which seems easy enough to control with a PWM output. But if I could avoid using a noisy mechanical piece, that would be better, as that may cost me points in car stereo competitions. Also, I'd like to keep the entire package as small as possible, as I may attempt to integrate it into a HUD at some point.

Where I feel I may run into a problem is that the rotary encoder pins (2 pins, high or low on each one) stay set depending on position....so I would need to continuously send a signal to the board (on the BitOne controller). If I set an output to HIGH or LOW, does it stay set, or does it only stay set for a short period of time?

I plan to use interrupt pins to read the input from the steering wheel, and even if I used a loop to continuously write the proper values, when the interrupt gets called it would screw up the timing and may turn the volume up or down unintentionally.

I haven't yet written the code for it, but I ran some simple coding, and got my voltage values (0-1023) for each button by reading inputs and sending the outputs to the serial monitor. I also used my multimeter and got actual voltages for each button.

I plan to desolder the rotary encoder and remove it from the board if possible, since I don't believe it would work with the RE still attached.

I'm using an Arduino Uno, btw.

Thanks.

Jay

You should look into finding out if your car sends its steering wheel controls (volume up, etc.) through the car's OBD-II system.

They do not. I have the schematic for the system. The radio has 2 wires, a ground and a 5 volt feed that go through a resistor ladder. Typically German cars and Chryslers are the ones that most commonly do that. I have a Kia.

Finding the signal from the car isn't the problem, I need to make an aftermarket piece of equipment think a knob is spinning.

Jay

JayinMI:
Where I feel I may run into a problem is that the rotary encoder pins (2 pins, high or low on each one) stay set depending on position....so I would need to continuously send a signal to the board (on the BitOne controller). If I set an output to HIGH or LOW, does it stay set, or does it only stay set for a short period of time?

The type of encoders commonly used in things like computer mice have two outputs that each cycle high and low as the encoder moves - the phasing is determined by which way the encoder is moving. Just imagine two sets of slotted discs which are half a slot out of alignment and you will get the idea.

Once you know what sequence of highs and lows you need to generate on the two pins to simulate the encoder disc moving, outputting those on the Arduino would be very simple. The outputs will stay in whatever state you put them until you change them, so your sketch doesn't need to do anything unless it needs to simulate the encoder moving, and then it just needs to toggle the output pins up and down in the right order the right number of times. The only thing there I can see that you'd need to be careful about is getting the voltage levels right - if the device reading the 'encoder' uses the same voltage levels as your Arduino it should be OK, but otherwise you would need to add a small circuit to convert the Arduino's voltage to whatever the other device needs.

To have a arduino simulate a quadrature encoder you would simply take two output pins, call them A and B for now and you would just set them HIGH or LOW in either of the two sequences shown in the picture depending on what direction of rotation you want to go at any given time. Note that there is a change of one or the other outputs every 'half pulse time' or 90 degrees phase change. Your program would determine how fast or slow the sequence goes by the time delays you use between each sequence change. Stopping is OK at any state just like with a real quad encoder.

http://digital.ni.com/public.nsf/ad0f282819902a1986256f79005462b1/c6c6632a54dba7dd86256275005e18e2/$FILE/encoder-phase.gif

Lefty

Do you have the remote that sit's on the dash of the car

For the radio? No. It's a factory radio. I have the wired remote control/display unit.

Jay

PeterH:

JayinMI:
Where I feel I may run into a problem is that the rotary encoder pins (2 pins, high or low on each one) stay set depending on position....so I would need to continuously send a signal to the board (on the BitOne controller). If I set an output to HIGH or LOW, does it stay set, or does it only stay set for a short period of time?

The outputs will stay in whatever state you put them until you change them, so your sketch doesn't need to do anything unless it needs to simulate the encoder moving,

That's what I needed to know.

and then it just needs to toggle the output pins up and down in the right order the right number of times. The only thing there I can see that you'd need to be careful about is getting the voltage levels right - if the device reading the 'encoder' uses the same voltage levels as your Arduino it should be OK, but otherwise you would need to add a small circuit to convert the Arduino's voltage to whatever the other device needs.

They both work on a 5 volt reference, so as long as I power the arduino off car power (through a 7812 regulator, perhaps) and use the 5 volt output from the arduino in place of the 5 volt output from the radio, I should be fine. The only issue with using a 7812 is that I will only be bale to feed it 13.8 volts or so...so it seems like it will make slightly less than 12 volts, but that should be fine as long as it is above 7 volts or so.

Jay

OK. So, to make sure I understand how things work, I wanted to read my encoder, just to check and make sure it works the way I thought it should. So, I soldered wires to the 3 terminals. One is common (connected to ground), and the other two are the encoder pins. Problem I'm running into is that I've been attempting this with various programs from various sources which are supposed to read the encoder. Only thing is, they aren't. I've verified that the pins change when the shaft is turned (with my multimeter), but they don't seem to have any effect on ANY of the programs I've attempted to use. I'm using an Arduino Uno. I've tried using interrupt driven programs and non-interrupt programs.
Any ideas?

Thanks.

Jay

JayinMI:
I've verified that the pins change when the shaft is turned (with my multimeter), but they don't seem to have any effect on ANY of the programs I've attempted to use. I'm using an Arduino Uno. I've tried using interrupt driven programs and non-interrupt programs.
Any ideas?

I guess there is something wrong with your programs.

Had I written them myself, I would think that would be true. But I'm simply copy and pasting examples I've found on other sites, the playground and the reference area.

Jay

Well, if the Arduino input pins change as you expect and the Arduino does not respond to that correctly, that implies that the sketch is wrong.

Of course this isn't a very helpful diagnosis, but I was hoping that you'd work out for yourself that you need to post details of what sketch you ran, and what inputs you applied, and what the sketch actually did, in order to enable a more detailed analysis.

OK. I decided to start simply. I copied and pasted an example that simply reads a button and turns on the onboard LED when pressed. It utilizes digital pin 2 via INPUT_PULLUP. If I simply jump a wire from the ground pin to pin 2, it functions as it's supposed to (simulating the closing of the switch.) But, as soon as I connect the output of the switch to pin 2 (with the ground side of the switch connected to ground), it acts like the switch is on and does not respond. I am getting about 4.5-4.8 Megohms of resistance between the ground and switch, and a straight ground when pressed, according to my DMM. I figured once I verified that the inputs were working properly, I could narrow down where my problem is....

Just as a detail, the buttons I have (there are 5, plus the output I get from pushing down on the rotary encoder) and the rotary encoder common pin are all tied to a common ground point, and are still on the board of the piece I am trying to integrate with. I don't expect that to be an issue, but figured it might help?

I am getting 4.8-4.9V between pin 2 and ground (with the button disconnected). When I check from pin 2 to the button, I get about 4.5V and it goes up to about 4.76V when I press the button. Weird.

Jay

PeterH:
Well, if the Arduino input pins change as you expect and the Arduino does not respond to that correctly, that implies that the sketch is wrong.

Of course this isn't a very helpful diagnosis, but I was hoping that you'd work out for yourself that you need to post details of what sketch you ran, and what inputs you applied, and what the sketch actually did, in order to enable a more detailed analysis.

Wow. You're right. I'm an idiot, I just read the post about what to do before posting. :blush:

/*
 Input Pullup Serial
 
 This example demonstrates the use of pinMode(INPUT_PULLUP). It reads a
 digital input on pin 2 and prints the results to the serial monitor.
 
 The circuit:
 * Momentary switch attached from pin 2 to ground
 * Built-in LED on pin 13
 
 Unlike pinMode(INPUT), there is no pull-down resistor necessary. An internal
 20K-ohm resistor is pulled to 5V. This configuration causes the input to
 read HIGH when the switch is open, and LOW when it is closed.
 
 created 14 March 2012
 by Scott Fitzgerald
 
 http://www.arduino.cc/en/Tutorial/InputPullupSerial
 
 This example code is in the public domain
 
 */

void setup(){
  //start serial connection
  Serial.begin(9600);
  //configure pin2 as an input and enable the internal pull-up resistor
  pinMode(2, INPUT_PULLUP);
  pinMode(13, OUTPUT);

}

void loop(){
  //read the pushbutton value into a variable
  int sensorVal = digitalRead(2);
  //print out the value of the pushbutton
  Serial.println(sensorVal);
 
  // Keep in mind the pullup means the pushbutton's
  // logic is inverted. It goes HIGH when it's open,
  // and LOW when it's pressed. Turn on pin 13 when the
  // button's pressed, and off when it's not:
  if (sensorVal == HIGH) {
    digitalWrite(13, LOW);
  }
  else {
    digitalWrite(13, HIGH);
  }
}

That is the code I'm currently working with.
I have verified that my Arduino board is working, and the code seems to be working properly, but I feel like the issue is with my interfacing.

Thanks!

Jay

The code you posted looks like it is for a push button.

Code to read a rotary encoder is a lot different.

Check out this tutorial I found: http://www.circuitsathome.com/mcu/programming/reading-rotary-encoder-on-arduino

It IS for a push button. I was attempting to make sure the inputs were working properly on the Arduino Uno. I figured it would be simpler with a push button that a rotary encoder. Once I figure out what I need to get the results I'm looking for with the button, then I can move up to testing with the RE.

Jay

Try this modified version of the Debounce example found with the Arduino IDE.
Tell us what it prints when you activate the button.

Also, a piece of wire from GND to pin 2 "the button pin" can also be used to simulate a switch. Just insert the wire and remove it back and forth.

/* 
 Debounce
 
 Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
 press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
 a minimum delay between toggles to debounce the circuit (i.e. to ignore
 noise).  
 
 The circuit:
 * LED attached from pin 13 to ground
 * pushbutton attached from pin 2 to +5V
 * 10K resistor attached from pin 2 to ground
 
 * Note: On most Arduino boards, there is already an LED on the board
 connected to pin 13, so you don't need any extra components for this example.
 
 
 created 21 November 2006
 by David A. Mellis
 modified 30 Aug 2011
 by Limor Fried
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Debounce
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  //start serial connection
  Serial.begin(9600);
  //configure pin2 as an input and enable the internal pull-up resistor
  pinMode(2, INPUT);
  digitalWrite(2, HIGH); //enables pull-up resitor
  pinMode(13, OUTPUT);
}

void loop() {
  // read the state of the switch into a local variable:
  int sensorVal = digitalRead(2);
  Serial.println(sensorVal);
  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (sensorVal != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the sensorVal is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = sensorVal;
  }

  // set the LED using the state of the button:
  digitalWrite(13, buttonState);

  // save the sensorVal.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = sensorVal;
}

Unfortunately, I can't use that one. I need to use a ground for the button. Since it's still mounted on a very expensive piece of equipment, and it is referenced to ground there. I don't want to try and shoot 5v into all the grounds. I'm beginning to wonder if I damaged my pullup resistors...at one point while testing something for another part of this project, I got a message saying I exceeded the current capacity of my USB port and it shut it down...unfortunately, being Thanksgiving, Radio Shack won't be open for me to pick up some resistors to test with.

I was simply jumping the wire back and forth w/o the switch, and that was how I determined the inputs/sketch seemed to be working as they should. I even tried adding a diode inline on the switch/pin 2 side to see if it had any effect, and it didn't.

Jay