Hello to everyone,
I've recently started with arduino and programming, and i did some project already;
I would like to modify and extend the project i realized:
The project is a steering wheel remote control of my car that converts the button pressed for my JVC headunit (that's already working fine).
i want to add a bluetooth audio board that has 3 switches (play/pause, vol+ / Netx, Vol - / Back); The switches shorts the pin to ground when pressed, and some functions are available with short/long press.
I would like to use one of the buttons (for example MODE button) to switch between headunit or bluetooth board control.
The actual sketch read wich button has ben pressed and start to send the signal to the headunit with a precise pulse width and you will find it below.
// 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
// Renault Twingo / Clio steering wheel remote wire functions
// pin_cycle_current 1 0 2
// OUTPUTS BLUE GREEN YELLOW
// INPUTS PIN# 3 5 6
// BLACK 2 MUTE TOP RIGHT BTN TOP LEFT BTN
// RED 4 VOL+ BOTTOM BTN VOL-
// HIGH HIGH LOW SCROLL UP (CCW)
// BROWN 7 HIGH LOW HIGH SCROLLWHEEL
// LOW HIGH HIGH SCROLL DN (CW)
// Outputs are set LOW one at a time (the other outputs will be HIGH). Inputs (with internal pull-up) are then evaluated.
// If an input is being pulled LOW this means a button is being pressed. Taking into account which output is currently LOW
// we know which button this is. For example, is output pin 3 (Blue wire) is currently LOW and we also read LOW on
// input pin 2 (Black) we know the MUTE button is being pressed.
// For the scrollwheel we must take into account its last known position in order to determine if there has been a change.
// We can determine the direction based on which pins are being pulled LOW.
// Connect Renault Twingo / Clio steering wheel remote wires to these pins
#define BLACKPIN 2 // D2
#define BLUEPIN 3 // D3
#define REDPIN 4 // D4
#define GREENPIN 5 // D5
#define YELLOWPIN 6 // D6
#define BROWNPIN 7 // D7
// Connect optocoupler input through a 1k resistor to this pin
#define OUTPUTPIN 8 // D8
// On-board LED, useful for debugging
#define LEDPIN 13 // D13
// Pulse width in µs
#define PULSEWIDTH 527
// Address that the radio responds to
#define ADDRESS 0x47
// Set number of output pins and put those pins in an array to cycle through when polling the input pins
#define OUT_PINS 3
unsigned char out_pins[OUT_PINS] = {GREENPIN, BLUEPIN, YELLOWPIN};
void setup() {
pinMode(OUTPUTPIN, OUTPUT); // Set the proper pin as output
digitalWrite(OUTPUTPIN, LOW); // Output LOW to make sure optocoupler is off
// Set the pins connected to the steering wheel remote as input / output
pinMode(BLACKPIN, INPUT_PULLUP);
pinMode(BLUEPIN, OUTPUT);
pinMode(REDPIN, INPUT_PULLUP);
pinMode(GREENPIN, OUTPUT);
pinMode(YELLOWPIN, OUTPUT);
pinMode(BROWNPIN, INPUT_PULLUP);
pinMode(LEDPIN, OUTPUT); // Set pin connected to on-board LED as output...
digitalWrite(LEDPIN, LOW); // ...and turn LED off
for (unsigned char i = 0; i <= 7; i++) { // Flash on-board LED a few times so it's easy to see when the Arduino is ready
delay(100);
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
}
delay(100);
digitalWrite(LEDPIN, LOW); // Make sure LED ends up being off
}
// The steering wheel remote has 6 buttons and a scrollwheel, interfaced via 6 wires.
// This function will cycle through the output pins, setting one pin LOW at a time.
// It will then poll the input pins to see which input pins - if any - are pulled LOW.
unsigned char GetInput(void) {
static unsigned char pin_cycle_current = 0; // To keep track of which output pin is currently LOW
static unsigned char pin_cycle_stored; // To store the last known scrollwheel position
static boolean first_run = true; // After booting, there is no known last position for the scrollwheel
// So on the first poll of the scrollwheel just store the current position and don't send a command
unsigned char i;
if (++pin_cycle_current > (OUT_PINS - 1)) pin_cycle_current = 0; // Reset pin_cycle_current counter after last pin
for (i = 0; i < OUT_PINS; i++) { // Cycle through the output pins, setting one of them LOW and the rest HIGH
if (i == pin_cycle_current)
digitalWrite(out_pins[i], LOW);
else
digitalWrite(out_pins[i], HIGH);
}
if (!digitalRead(BROWNPIN)) { // We're only interested if this pin is being pulled LOW
if (pin_cycle_current != pin_cycle_stored) { // If the output that's currently LOW is different from the one that was LOW the last time
// we came through here, then the scrollwheel has changed position
signed char scrollwheel_current = pin_cycle_current - pin_cycle_stored; // Result of this calculation can range from -2 to 2
pin_cycle_stored = pin_cycle_current; // Store which output pin is currently LOW
if (first_run) { // If this is the first run, don't send a command
first_run = false; // (since there was no previously known scrollwheel position)
return 0;
}
if ((scrollwheel_current == 1) || (scrollwheel_current == -2)) { // If above calculation resulted in 1 or -2 the scrollwheel was rotated up (ccw)
return FOLDERBACK;
}else { // If above calculation resulted in anything else the scrollwheel was rotated down (cw)
return FOLDERFORW;
}
}
}
if (!digitalRead(REDPIN)) { // We're only interested if this pin is being pulled LOW
switch(pin_cycle_current) {
case 0: // RED (input) is LOW while GREEN (output) is LOW: bottom button pressed
return SOURCE;
case 1: // RED (input) is LOW while BLUE (output) is LOW: volume + button pressed
return VOLUP;
case 2: // RED (input) is LOW while YELLOW (output) is LOW: volume - button pressed
return VOLDOWN;
}
}
if (!digitalRead(BLACKPIN)) { // We're only interested if this pin is being pulled LOW
switch(pin_cycle_current) {
case 0: // BLACK (input) is LOW while GREEN (output) is LOW: top right button is pressed
return TRACKFORW;
case 1: // BLACK (input) is LOW while BLUE (output) is LOW: mute button is pressed
return MUTE;
case 2: // BLACK (input) is LOW while YELLOW (output) is LOW: top left button is pressed
return TRACKBACK;
}
}
return 0;
}
void loop() {
unsigned char Key = GetInput(); // If any buttons are being pressed the GetInput() function will return the appropriate command code
if (Key) { // If no buttons are being pressed the function will have returned 0 and no command will be sent
SendCommand(Key);
}
}
// 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) {
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() {
digitalWrite(OUTPUTPIN, HIGH); // Output HIGH for 1 pulse width
digitalWrite(LEDPIN, HIGH); // Turn on on-board LED
delayMicroseconds(PULSEWIDTH);
digitalWrite(OUTPUTPIN, LOW); // Output LOW for 1 pulse width
digitalWrite(LEDPIN, LOW); // Turn off on-board LED
delayMicroseconds(PULSEWIDTH);
}
// Signals to transmit a '1' bit
void SendOne() {
digitalWrite(OUTPUTPIN, HIGH); // Output HIGH for 1 pulse width
digitalWrite(LEDPIN, HIGH); // Turn on on-board LED
delayMicroseconds(PULSEWIDTH);
digitalWrite(OUTPUTPIN, LOW); // Output LOW for 3 pulse widths
digitalWrite(LEDPIN, LOW); // Turn off on-board LED
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(OUTPUTPIN, LOW); // Make sure output is LOW for 1 pulse width, so the header starts with a rising edge
digitalWrite(LEDPIN, LOW); // Turn off on-board LED
delayMicroseconds(PULSEWIDTH * 1);
digitalWrite(OUTPUTPIN, HIGH); // Start of header, output HIGH for 16 pulse widths
digitalWrite(LEDPIN, HIGH); // Turn on on-board LED
delayMicroseconds(PULSEWIDTH * 16);
digitalWrite(OUTPUTPIN, LOW); // Second part of header, output LOW 8 pulse widths
digitalWrite(LEDPIN, LOW); // Turn off on-board LED
delayMicroseconds(PULSEWIDTH * 8);
// START BIT: always 1
SendOne();
}
// Signals to follow a command to the radio
void Postamble() {
// STOP BITS: always 1
SendOne();
SendOne();
}
Can somebody have some advice about it?
Thanks