Close

JVC part

A project log for JVC to Clio

I want to use a JVC car radio with Renault Clio's built-in steering wheel remote

Németh CsabaNémeth Csaba 11/26/2017 at 13:270 Comments

I have tried some version of JVC controller program I found on the Internet but only this one worked well.

Unfortunately I don't remember where I found it, but I will try to get the source URL and share it.

/*
#############
# Clio part #
#############
ISO 10487 defines a standard for connectors for the head unit to the car's electrical system, consisting of a system of four different connectors typically used in head units for car audio.
   Power (A)
     +-----------------+
     | |1  |3  |5  |7  |
    _|                 |
   |_  |2  |4  |6  |8  |
     +-----------------+
   
   A1 Speed signal  (pink)              *** Arduino INPUT
   A2 Phone mute    (not connected)     ---                      ---
   A3 Not connected (not connected)     ---                      ---
   A4 +12v battery  (red/pink)          ---                      *** JVC
   A5 Antenna motor (grey)                  Arduino ***          *** JVC
   A6 Illumination  (blue)              ---                      *** JVC
   A7 +12v switched (yellow/pink)       *** Arduino              *** JVC
   A8 Ground        (black)             *** Arduino              *** JVC


################
# Arduino part #
################

             +---+
      +------|USB|------+
      |[ ]J1 +---+      |
      |( )TX0     RAW( )|  RAW
      |( )RXI     GND( )|  GND
 GND  |( )GND     RST( )|  RESET
 GND  |( )GND     VCC( )|  VCC
      |( )2        A3( )|
INT0  |( )3   /\   A2( )|
      |(O)4  /  \  A1( )|
      |(O)5  \  /  A0( )|
      |(I)6   \/   15( )|  SCK
      |( )7        14( )|  MISO
      |( )8        16( )|  MOSI
      |(I)9        10( )|
      +-----------------+
           ProMicro
4 JVC_REMOTE_PIN
5 CLIO_DISPLAY_PIN
6 JVC_ANTENNA_PIN
9 CLIO_SPEEDSIGNAL_PIN
  
*/

// Define commands
#define VOLUP       0x04
#define VOLDOWN     0x05
#define SOURCE      0x08
#define EQUALIZER   0x0D
#define MUTE        0x0E
#define TRACKFORW   0x12
#define TRACKBACK   0x13
#define FOLDERFORW  0x14
#define FOLDERBACK  0x15
#define UNKNOWN1    0x37
#define UNKNOWN2    0x58
 
// Connect optocoupler input through a 1k resistor to this pin
#define JVC_REMOTE_PIN   4 // D8
 
// Pulse width in µs
#define PULSEWIDTH 527
 
// Address that the radio responds to
#define ADDRESS 0x47

int IncomingByte = 0; // Initialize Serial Buffer

void setup() {
  pinMode(JVC_REMOTE_PIN, OUTPUT); // Set pin to output
  digitalWrite(JVC_REMOTE_PIN, LOW);  // Output LOW to make sure optocoupler is off
  Serial.begin(9600);
  Serial.println("1 - Volume Up");
  Serial.println("2 - Volume Down");
  Serial.println("3 - Source");
  Serial.println("4 - Sound");
  Serial.println("5 - Mute");
  Serial.println("6 - Skip Fwd");
  Serial.println("7 - Skip Back");
  Serial.println("8 - Skip Fwd Hold");
  Serial.println("9 - Skip Back Hold");
}

void loop() { 
  if (Serial.available() > 0) {
    IncomingByte = Serial.read();
    
    switch (IncomingByte) {
      case '1':
        SendCommand(VOLUP);
        break;    
      case '2':
        SendCommand(VOLDOWN);
        break;    
      case '3':
        SendCommand(SOURCE);
        break;    
      case '4':
        SendCommand(EQUALIZER);
        break;    
      case '5':
        SendCommand(MUTE);
        break;    
      case '6':
        SendCommand(TRACKFORW);
        break;    
      case '7':
        SendCommand(TRACKBACK);
        break;    
      case '8':
        SendCommand(FOLDERFORW);
        break;    
      case '9':
        SendCommand(FOLDERBACK);
        break;    
        
      default:;
    }
  }
}

// Send a value (7 bits, LSB is sent first, value can be an address or command)
void SendValue(unsigned char value) {
  unsigned char i, tmp = 1;
  for (i = 0; i < sizeof(value) * 8 - 1; i++) {
    if (value & tmp)  // Do a bitwise AND on the value and tmp
      SendOne();
    else
      SendZero();
    tmp = tmp << 1; // Bitshift left by 1
  }
}

// Send a command to the radio, including the header, start bit, address and stop bits
void SendCommand(unsigned char value) {
      Serial.println("Sending");
  unsigned char i;
  Preamble();                         // Send signals to precede a command to the radio
  for (i = 0; i < 3; i++) {           // Repeat address, command and stop bits three times so radio will pick them up properly
    SendValue(ADDRESS);               // Send the address
    SendValue((unsigned char)value);  // Send the command
    Postamble();                      // Send signals to follow a command to the radio
  }
}
 
// Signals to transmit a '0' bit
void SendZero() {
//      Serial.println("zero");
  digitalWrite(JVC_REMOTE_PIN, HIGH);      // Output HIGH for 1 pulse width
  delayMicroseconds(PULSEWIDTH);
  digitalWrite(JVC_REMOTE_PIN, LOW);       // Output LOW for 1 pulse width
  delayMicroseconds(PULSEWIDTH);
}
 
// Signals to transmit a '1' bit
void SendOne() {
//        Serial.println("uno");
  digitalWrite(JVC_REMOTE_PIN, HIGH);      // Output HIGH for 1 pulse width
  delayMicroseconds(PULSEWIDTH);
  digitalWrite(JVC_REMOTE_PIN, LOW);       // Output LOW for 3 pulse widths
  delayMicroseconds(PULSEWIDTH * 3);
}
 
// Signals to precede a command to the radio
void Preamble() {
  // HEADER: always LOW (1 pulse width), HIGH (16 pulse widths), LOW (8 pulse widths)
  digitalWrite(JVC_REMOTE_PIN, LOW);       // Make sure output is LOW for 1 pulse width, so the header starts with a rising edge
  delayMicroseconds(PULSEWIDTH * 1);
  digitalWrite(JVC_REMOTE_PIN, HIGH);      // Start of header, output HIGH for 16 pulse widths
  delayMicroseconds(PULSEWIDTH * 16);
  digitalWrite(JVC_REMOTE_PIN, LOW);       // Second part of header, output LOW 8 pulse widths
  delayMicroseconds(PULSEWIDTH * 8);
 
  // START BIT: always 1
  SendOne();
}
 
// Signals to follow a command to the radio
void Postamble() {
  // STOP BITS: always 1
  SendOne();
  SendOne();
}

Discussions