Вы находитесь на странице: 1из 8

/*

Take old style steering controls and convert to JVC car audio infra red based
signals over wire
Early Land Rover Discovery base and mid line radios used simple press button f
unctions on the steering control (not resistor based),
so this just detects a button push and build the appopriate RC signal - if you
want to change to resistor based then amend the code between the ########### co
mments
The code allows each button to have four functions, single click, double click
, long press and very long press, though I cant find an effective use for very l
ong press, perhaps power off)
It is assumed that only one button at a time is to be processed, simultaneous
pressing of different buttons gives odd effects, usually as a double click on t
he last button pressed.
I scanned the wire for all available codes and found some to do Bluetooth Call
functions and some other odd ones that do testing/diagnostics. I have coded all
the functions that came up except the test ones
and not allocated every one to a button press.
Also kept only volume related functions on the volume control buttons so that
you don't accidently blast your eardrums when wanting to change a music station
etc.
Vol
Vol
Vol
Vol

+
+
+
+

Single click - Step volume up


Double click - Step volume up 3 levels
Hold - no function
Very Long Hold - no function

Vol
Vol
Vol
Vol

Single click - Step volume down


Double click - Mute
Hold - power off
Very Long Hold - no function

Waveband
Waveband
Waveband
Waveband
Tune
Tune
Tune
Tune

control
control
control
control

control
control
control
control

Single click Double click Hold - Make BT


Very Long Hold

Change Source
Answer BT call
call
- no function

Single click - Next station pre-select, track or USB song


Double click - Previous station pre-select, track or USB song
Hold - scan for next station
Very Long Hold - no function

Connections
Pin 4: + from vol + control
Pin 5: - from vol - control
Pin 6: + from Waveband control
Pin 7: + from Tune control
Pin 8: to circuit controlling blue remote wire
GND - common ground from steering controls
I used an Optocoupler to seperate the 5v and 12v circiuits
Note that you do NOT feed power to the radio remote steering wire but rather g
round it to generate a signal
pin 8 to the feed of the coupler, and ground to the Arduino on the input side
Collector to blue/yellow wire
Emmiter to radio common ground 12V
To use this you need a 12v to 5v power converter to power the arduino, it make
s life easier if you use the female equivalent connector of the Land rover steer
ing controls

Thanks are due to:


The multi button class: Original code by Jeff Saltzman // http://jmsarduino.bl
ogspot.com/2009/10/4-way-button-click-double-click-hold.html
Most of the JVC codes and sending interface by Dan Guerra (deguerra98@yahoo.co
m)
The rest by Rob Lloyd (rob.remove.lloyd@sibaya.co.uk) March 5 2013
*/
#define
#define
#define
#define

_0 OUTPUT
_1 INPUT
jvc 2
dataDelay 537

int BPVirt = 0;
int adddouble = 4;
le click event
int addhold = 8;
event
int VolUB = 4;
int VolDB = 5;
int WaveB = 6;
int TuneB = 7;
int ConOut = 1;
int PINO = 8;
int Length = 537;
int IncomingByte = 0;
int Reps = 3;
int b = 0;
etected
int buttonPin= 0;
to 7)
int i = 0;

// Virtual event number, used in case selection


// number to be bumped to pin number to identify doub
// number to be bumped to pin number to identify hold
//
//
//
//
//
//
//
//
//
//

// the input pin, coresponds to one of 4 real pins (4


// count for IR send loop

// Button timing variables


int debounce = 20;
//
sing or releasing the button,
int DCgap = 250;
//
fault 250
int holdTime = 1000;
//
ent
int longHoldTime = 3000; //
ld event
int event = 0;
//
//

Input pin 4 corresponds to volume up switch


Input pin 5 corresponds to volume down switch
Input pin 6 corresponds to wave switch
Input pin 7 corresponds to Tune switch
by default no output to console
Digital IO pin connected to base of transistor
Length in Microseconds
Initialize Serial Buffer
Number of times to repeat each transmission
detected event number i.e. what button action is d

ms debounce period to prevent flickering when pres


default 20
max ms between clicks for a double click event, de
ms hold period: how long to wait for press+hold ev
ms long hold period: how long to wait for press+ho
event number

Initialisation

void setup() {
pinMode(PINO, OUTPUT);
pinMode(VolUB, INPUT);
pinMode(VolDB, INPUT);
pinMode(WaveB, INPUT);
pinMode(TuneB, INPUT);
digitalWrite(PINO, LOW); // Make PIN low to shut off transistor
Serial.begin(9600);
Serial.println("1 - Volume Up");

Serial.println("2
Serial.println("3
Serial.println("4
Serial.println("5
Serial.println("6
Serial.println("7
Serial.println("8
Serial.println("9
}
//

Volume Down");
Source");
Sound");
Mute");
Skip Fwd");
Skip Back");
Skip Fwd Hold");
Skip Back Hold");

Process loop, if serial interface is active send outputs to console too

void loop() {
if (Serial.available() > 0) {
ConOut = 1;
}
BPVirt = 0;
// check if and which button has been pressed #####################
if (digitalRead(VolUB) == HIGH) {
buttonPin = 4;
digitalWrite(buttonPin, HIGH );
}
if (digitalRead(VolDB) == HIGH) {
buttonPin = 5;
digitalWrite(buttonPin, HIGH );
}
if (digitalRead(WaveB) == HIGH) {
buttonPin = 6;
digitalWrite(buttonPin, HIGH);
}
if (digitalRead(TuneB) == HIGH) {
buttonPin = 7;
digitalWrite(buttonPin, HIGH );
}
// end of button check
####################
if (buttonPin !=0) {
b = checkButton();
if (b == 1) clickEvent();
if (b == 2) doubleClickEvent();
if (b == 3) holdEvent();
if (b == 4) longHoldEvent();
}
b = 0;
switch (BPVirt) {
case 4: // vol up, single click
AGC();
sendCommand(0x04, 1);
break;
case 5: //vol down, single click
AGC();
sendCommand(0x05, 1);
break;
case 6: //source select, single click
AGC();
sendCommand(0x08, 1);
break;
case 7: //next, single click
AGC();

sendCommand(0x12, 1);
break;
case 8: // vol up, double click
AGC();
sendCommand(0x04, 0);
sendCommand(0x04, 0);
sendCommand(0x04, 1);
break;
case 9: //vol down, double click
AGC();
sendCommand(0x06, 1);
break;
case 10: //EQ select, double click
AGC();
sendCommand(0x0C, 1);
break;
case 11: //next, double click
AGC();
sendCommand(0x13, 1);
break;
case 12: // vol up, hold
break;
case 13: //vol down, hold
AGC();
sendCommand(0x00, 1);
break;
case 14: //source select, hold
break;
case 15:
break;
default:;
}
BPVirt = 0;
/* For testing - check if input from console (bypass buttons), if so send
output to console too */
/*if (Serial.available() > 0) {
IncomingByte = Serial.read();
ConOut = 1;
switch (IncomingByte) {
case '1':
JVCVolUp();
break;
case '2':
JVCVolDn();
break;
case '3':
JVCSource();
break;
case '4':
JVCSound();
break;
case '5':
JVCMute();
break;
case '6':

JVCSkipFwd();
break;
case '7':
JVCSkipBack();
break;
case '8':
JVCSkipFwdHold();
break;
case '9':
JVCSkipBackHold();
break;
default:;
}*/
}
//

Type of button event detected


void clickEvent()
{
Serial.println(" ");
Serial.print(" Click on ");
Serial.print(buttonPin);
BPVirt = buttonPin ;
}
void doubleClickEvent()
{
Serial.println(" ");
Serial.print(" Double click on ");
Serial.print(buttonPin);
BPVirt = buttonPin + adddouble;
}
void holdEvent()
{
Serial.println(" ");
Serial.print(" Short hold on ");
Serial.print(buttonPin);
BPVirt = buttonPin + addhold;
}
void longHoldEvent()
{
Serial.println(" ");
Serial.print(" Long hold on ");
Serial.print(buttonPin);
BPVirt = buttonPin + addhold;
}

// IR codes for each JVC function


void sendCommand(byte data, bool stopBit){
//Start
sendBit(1);
//Address
byte buffer = 0x47;
for(int d; d < 7; d++){
bool dataBit = (buffer&0x01);
sendBit(dataBit);
}
//Command
buffer = data;
for(int d; d < 7; d++){

bool dataBit = (buffer&0x01);


sendBit(dataBit);
}
//Stop 1
sendBit(1);
//End of stream if high
if(stopBit){
sendBit(1);
}
}
void sendBit(bool data){
//This encodes the bit
pinMode(PINO, _0);
delayMicroseconds(dataDelay);
pinMode(PINO, _1);
if(data){
delayMicroseconds(dataDelay);
}
}
void AGC(){
//AGC
pinMode(PINO, _0);
delay(dataDelay * 16);
pinMode(PINO, _1);
delay(dataDelay * 8);
}
/*
MULTI-CLICK: One Button, Multiple Events
Oct 12, 2009
Run checkButton() to retrieve a button event:
Click
Double-Click
Hold
Long Hold
*/
// Other button variables
boolean buttonVal = LOW; // value read from button
boolean buttonLast = LOW; // buffered value of the button's previous state
boolean DCwaiting = false; // whether we're waiting for a double click (down)
boolean DConUp = false; // whether to register a double click on next release,
or whether to wait and click
boolean singleOK = true; // whether it's OK to do a single click
long downTime = -1; // time the button was pressed down
long upTime = -1; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the
click+hold was triggered
boolean waitForUp = false; // when held, whether to wait for the up event
boolean holdEventPast = false; // whether or not the hold event happened alrea
dy
boolean longHoldEventPast = false;// whether or not the long hold event happen
ed already

int checkButton()
{

/* int event = 0; */
event = 0;
// Read the state of the button
buttonVal = digitalRead(buttonPin);
// Button pressed down
if (buttonVal == HIGH && buttonLast == LOW && (millis() - upTime) > debounce) {
downTime = millis();
ignoreUp = false;
waitForUp = false;
singleOK = true;
holdEventPast = false;
longHoldEventPast = false;
if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp =
true;
else DConUp = false;
DCwaiting = false;
}
// Button released
else if (buttonVal == LOW && buttonLast == HIGH && (millis() - downTime) > debou
nce) {
if (not ignoreUp) {
upTime = millis();
if (DConUp == false) DCwaiting = true;
else {
event = 2;
DConUp = false;
DCwaiting = false;
singleOK = false;
}
}
}
// Test for normal click event: DCgap expired
if ( buttonVal == LOW && (millis()-upTime) >= DCgap && DCwaiting == true && DCon
Up == false && singleOK == true) {
event = 1;
DCwaiting = false;
}
// Test for hold
if (buttonVal == HIGH && (millis() - downTime) >= holdTime) {
// Trigger "normal" hold
if (not holdEventPast) {
event = 3;
waitForUp = true;
ignoreUp = true;
DConUp = false;
DCwaiting = false;
//downTime = millis();
holdEventPast = true;
}
// Trigger "long" hold
if ((millis() - downTime) >= longHoldTime) {
if (not longHoldEventPast) {
event = 4;
longHoldEventPast = true;
}
}
}
buttonLast = buttonVal;
return event;
}