Project tutorial
JeePioneer Radio Control

JeePioneer Radio Control © LGPL

Control your Chrysler car's aftermarket radio with only cruise control buttons, thanks to Arduino

  • 1,698 views
  • 2 comments
  • 5 respects

Components and supplies

Necessary tools and machines

Jeep

About this project

Most cars you drive today will have radio controls on the steering wheel. The added safety of keeping both hands on the wheel as often as possible can’t be overstated. Since one of my vehicles didn’t have that feature I decided to add it. The cost could be less than $20.  

http://www.speedlimit88.com/arduino/jeepioneer-radio-control/

You could build this with an Arduino UNO, some wire, and an IR LED. You could also solder up your own on some protoboard. I used the UNO to test the idea and later I made a board for it to leave in the car. Here is a simple schematic of what is going on. 

On the left you see the main processor (U2) with the analog signal coming in from the steering wheel. The voltage regulator (top right) takes in the 12V battery supply from the car and keeps it at 5V for the processor and the IR LED. The regulator is already built into the UNO. The IR LED circuit (bottom right) has a transistor controlled by the processor to activate it. The 56 ohm resistor and 300 ohm resistor are approximate and could be setup differently, but this is what is working for me. I was worried about writing code that might leave the LED on accidentally and burn it out quickly, so that is why I have the 56 ohm. 

Above is what my setup looks like. The cigarette lighter plug was for quick install testing. It was later hardwired into the fuse panel. The blue banana jack was used so that the box could be unplugged from the car if it needed to be. I added a switch that disconnects the steering wheel input from the device. All of that stuff is optional, so I didn’t include it in my cost. It was all left over equipment I had from other projects anyways. The circuit board that everything is soldered to was nice to have. A couple years ago I had these printed so that I could easily solder small UNO projects like this. It makes the job quicker and lets me fit it in a nice case with room to spare. Again, that was not necessary either.  


Installation

Once you have the box built, installing it is easy. On the driver’s side of the dash is the fuse panel. Simply remove the cover, plug the positive power supply into the right side of the 10 amp fuse for the radio (fuse number 21). To do this, take out the fuse, slide the wire into the fuse holder, and then plug the fuse back in. Be careful not to have any stray wires short the fuse. Doing this will make the fuse useless and could later damage wiring in the car if there is a short circuit. For the ground you can wrap the wire around any bolt you can find in the chassis of the car.

Under the radio/HVAC controls, just behind the center console there is a lot of space behind the carpet. I just set the box there. The wires for the LED were tucked under the center console and then ran up near the E-brake handle. That was the only place I could find to install the light that would stay in place without any drilling or cutting.

The wire for the analog input from the steering wheel is all violet in color and is the 6th pin of a 6 pin connector under the steering wheel (2005 year). To make sure you have the right wire you can try measuring the voltage as you press the buttons with key on. Do not tamper with any of the yellow connectors because they are for the air bags! Also, when you install this, it is a good idea to disconnect the battery first.

Click here to download the complete software 

Click here to see a detailed parts list with prices 

Code

JeePioneerC/C++
Here is the Arduino code (.ino)
/*******************************
* Chrysler/Jeep Cruise Control to Pioneer Radio Control Adapter
* July 14 2015
* Aruido Uno tested, built on breadboard later
* Created by: Speedlimit88.com - Mcgavinz26
* Version 1_0 Working in Jeep with UNO and breadboard
*******************************/
/*
INTRODUCTION:
This program was tested on a 2005 Jeep Liberty with only cruise control buttons on the steering wheel.
The radio was a Pioneer DEH-X6600BT.  The infrared(IR) LED commands have been the same on many Pioneer
radios for a while.  This should work with most other Pioneers. Cruise control can still work if it is 
turned on, but the radio commands will also happen.  Don't be an idiot.  By trying to reproduce this 
device you are automatically saying, "If I do something stupid like trying to work radio controller and 
accidentally doing something bad with the cruise control while driving, then I take full responsibility 
for my own actions ... and I am an idiot."

TESTING NOTES:
Loose wire test results in car with wire twisted, not soldered, grounded to cigarette lighter
Analog read of pin 6, violet, under steering wheel
With the engine off, the analog reading was very stable (analog read +/-1 bit tolerance)
With the engine on, the tolerance was not so stable (analog read +/-15)
But even though it was unstable, the average seemed similar to what was read engine off.
Sketch uses 5,256 bytes (16%) of program storage space. Maximum is 32,256 bytes.
Global variables use 373 bytes (18%) of dynamic memory, leaving 1,675 bytes for local variables. 
*/

int RESpin = A4; //analog voltage read in from the steering wheel
int IRpin = 7;   //This pin is for infrared control output to mute/unmute a radio

unsigned long ButtonV = 1023;      //This is where the button pressed value is stored as it is read
unsigned long TotalButtonV = 0;    //This is the button pressed total value as it is added up for averaging
int NoPressV = 880;                //when no buttons pressed, voltage above at least this nubmer (925 was actual reading)
unsigned long ButPresCounter = 0;  //counts through the while loop while a button is pressed
int ButWhileDelay = 1100;          //counts in while loop before average is calculated
unsigned long AveButtonV = 0;      //the average value of the button voltage when pressed
int AnalogTolerance = 20;          //this the tolerance in the analog values read in (bits)
int ButtonDebounceCount = 0;       //counter to help debounce button presses, avoid double press
int VoltBitsOffset = 10;           //Use this to tweak the voltage offset if necessary on all buttons

//Button mapping: Name of button on steering wheel and its 10-bit analog voltage value
int RES_ACCEL     = 823;
int CANCEL        = 365;
int DECEL         = 561;
int SET           = 686;
int SET_CANCEL    = 320;
int SET_RES_ACCEL = 628;
int SET_DECEL     = 463;

//Connect a Pioneer radio command to a button name from above plus an offset if necessary
int VolumeUp = RES_ACCEL + VoltBitsOffset;
int PrestFwd = CANCEL + VoltBitsOffset;
int VolumeDn = DECEL + VoltBitsOffset;
int SourceSl = SET_RES_ACCEL + VoltBitsOffset;
int TrackFwd = SET_CANCEL + VoltBitsOffset;
int TrackBck = SET_DECEL + VoltBitsOffset;

//Create a high and a low range for each radio control used
int VolumeUp_ = VolumeUp + AnalogTolerance;
int _VolumeUp = VolumeUp - AnalogTolerance;
int PrestFwd_ = PrestFwd + AnalogTolerance;
int _PrestFwd = PrestFwd - AnalogTolerance;
int VolumeDn_ = VolumeDn + AnalogTolerance;
int _VolumeDn = VolumeDn - AnalogTolerance;
int SourceSl_ = SourceSl + AnalogTolerance;
int _SourceSl = SourceSl - AnalogTolerance;
int TrackFwd_ = TrackFwd + AnalogTolerance;
int _TrackFwd = TrackFwd - AnalogTolerance;
int TrackBck_ = TrackBck + AnalogTolerance;
int _TrackBck = TrackBck - AnalogTolerance;
int _SET = SET + VoltBitsOffset - 30;     //if the SET button is press, these values are used to stop averaging because
int SET_ = SET + VoltBitsOffset + 30;     // the math gets screwed up coming in and out of combo button presses

boolean SETisPressed = 0;   //this will equal 1 if the SET steering wheel button is pressed
int HoldButtonDelay = 500;  //time in milliseconds that the button is delayed after first press
int _AveButtonLast = 0;     //this is needed to know if the same button is being pressed as last time
int AveButtonLast_ = 0;

//These commands are used when pulsing the infrared LED
int TheFirstPulse = 335;
int TheFirstDelay = 4200;
int A_Dot = 500;
int A_Dash = 1525;
int IRPulses = 21;
int x = 0;

void setup(){
  pinMode(IRpin, OUTPUT); 
  digitalWrite(IRpin, HIGH); 
  Serial.begin(9600);   //only used in development for debugging
}

void loop(){
  ////Read the button voltage
  ButtonV = analogRead(RESpin);  
  
  //if only the SET button is pressed, then make use of that to avoid doing the button average calculation
  if (ButtonV > _SET && ButtonV < SET_) SETisPressed = 1;
  else SETisPressed = 0;
  
  //Button average calculation:
  while (ButtonV < NoPressV && SETisPressed == 0){    //while the voltage is low enough to indicate its pressed
    ButtonV = analogRead(RESpin);      //start adding up the voltages read
    TotalButtonV += ButtonV;
    ButPresCounter++;                  //count the times through this loop
    if (ButPresCounter > ButWhileDelay){
      AveButtonV = TotalButtonV/ButPresCounter;   //Average the voltage
      ButtonV = 1023;                  //this will kick you out of the while loop
    }
    if (ButtonV > _SET && ButtonV < SET_) SETisPressed = 1;
    else SETisPressed = 0; //this will also kick you out of the loop, helpful for multi buttons pressed
  }
  
  //this tracks how long a button is held down to avoid unintended double taps
  if (AveButtonV > _AveButtonLast && AveButtonV < AveButtonLast_){
      ButtonDebounceCount++;
    }
  else ButtonDebounceCount = 0;
  
  //if the same button was pressed as the last time a button was pressed, delay for some time
  if (ButtonDebounceCount == 1) delay(HoldButtonDelay);
  
  ///////Call an IR light command/////////////////////////////////////////
  if (AveButtonV > _VolumeUp && AveButtonV < VolumeUp_) {
    Serial.println("Volume UP");
    PioneerVolumeUp();
  }
  
  if (AveButtonV > _PrestFwd && AveButtonV < PrestFwd_) {
    Serial.println("Preset Forward");
    PioneerPrestFwd();
  }
  
  if (AveButtonV > _VolumeDn && AveButtonV < VolumeDn_) {
    Serial.println("Volume DOWN");
    PioneerVolumeDn();
  }
  
  if (AveButtonV > _SourceSl && AveButtonV < SourceSl_) {
    Serial.println("Source");
    PioneerSource();
  }
  
  if (AveButtonV > _TrackFwd && AveButtonV < TrackFwd_) {
    Serial.println("Track Forward");
    PioneerTrackFwd();
  }
   
  if (AveButtonV > _TrackBck && AveButtonV < TrackBck_) {
    Serial.println("Track Back");
    PioneerTrackBack();
  }

  //put a high and low tolerance on the analog average of the button pressed
  AveButtonLast_ = AveButtonV + AnalogTolerance;
  _AveButtonLast = AveButtonV - AnalogTolerance;
  ///Reset Counters//
  ButPresCounter = 0;
  TotalButtonV = 0;
  AveButtonV = 1023;
}

//This will pulse the IR LED a specific way that is common at the beginning of all the IR commands
//Look for it used later in all of the Pioneer commands below
void TheFirstIRsignal(){
  for (x = 0; x < TheFirstPulse; x++) {
    digitalWrite(IRpin, LOW);
    delayMicroseconds(8);
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(9);
  } 
  delayMicroseconds(TheFirstDelay);
  for (x = 0; x < IRPulses; x++) {
    digitalWrite(IRpin, LOW);
    delayMicroseconds(8);
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(9);
  } 
 return;
}

//This will delay the IR LED signal a short time and then send a short IR signal
void Dot(){
  delayMicroseconds(A_Dot);
  for (x = 0; x < IRPulses; x++) {
    digitalWrite(IRpin, LOW);
    delayMicroseconds(8);
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(9);
  }   
 return;
}

//This will delay the IR LED signala longer time and then send a short IR signal
void Dash(){
  delayMicroseconds(A_Dash);
  for (x = 0; x < IRPulses; x++) {
    digitalWrite(IRpin, LOW);
    delayMicroseconds(8);
    digitalWrite(IRpin, HIGH);
    delayMicroseconds(9);
  }   
 return;
}

void PioneerVolumeUp(){
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();
  return;
}
  
void PioneerVolumeDn(){
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();
  return;
}

void PioneerTrackFwd(){
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();
  Dot();
  Dash();
  return;
}

void PioneerPrestFwd(){
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();
  Dash();
  Dash();
  Dot();
  Dash();
  return;
}

void PioneerMute(){ 
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dash();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dash();
  Dot();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();  
  return;
}

void PioneerSource(){ 
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dash();
  Dash();  
  return; 
}

void PioneerTrackBack(){ 
  TheFirstIRsignal();
  Dash();
  Dot();
  Dash();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dot();
  Dash();
  Dot();
  Dot();
  Dot();
  Dot();
  Dash();
  Dot();
  Dash();
  Dot();
  Dash();
  Dash();
  Dash();
  Dash();
  Dot();
  Dash();
  return;
}

Schematics

JeePioneer_Schematic.png
Jeepioneer schematic

Comments

Similar projects you might like

Control Your Computer With A Remote Control

Project tutorial by Arduino_Scuola

  • 5,942 views
  • 1 comment
  • 8 respects

Servo Control with TV Remote Control

Project showcase by eldo85

  • 5,628 views
  • 5 comments
  • 17 respects

Control an LED with the Remote Control

Project showcase by Nicholas_N

  • 3,192 views
  • 2 comments
  • 9 respects

Control your light system with your voice

Project tutorial by Maha Raafat

  • 33,108 views
  • 22 comments
  • 147 respects

PS3 Controller Control Servo Wireless

Project tutorial by Youssef Sabaa

  • 19,881 views
  • 2 comments
  • 12 respects
Add projectSign up / Login