This can be tricky to get a gear shift reading from. I've created the circuit and code below to interface with this shifter. This works well on my project.
Note that this setup uses a digital input for the left/right position, I have chosen resistor values to trigger a high<>low transition on a 3.3V MCU (ATSAM3x8E) at the "70% to the right" point. This may vary with other setups, and definitely will for 5V MCUs. I recommend using an analog input for this if available (or even better, two inputs to give a comparison).
I do not have the wiring diagram/pinout for this shifter, I normally make a note of things like this but can't find anything. I recall it being pretty straightforward. I just have the attached drawings. I commoned the two GNDs, and the 5V/B+ inputs (I used 5V for everything).
This is based on the shifter from a 2017 Auris. Other shifters will work fine, they may need some tweaking to the code or resistor values.
In this code and diagrams, "shifter pos" is for up/down, and "shifter sel" is for left/right.
Code: Select all
//2017 Auris shifter
//Returns prnd_gear when shifter moves back to left hand side
//Regen available using the "B" position when in "Drive"
//This code is snippets only to insert into your project.
//park_notify is intended to trigger a light, beep, dash message, etc.
//E&OE. Use at your own risk.
//gears
#define GEAR_NONE 0
#define GEAR_PARK 1
#define GEAR_REVERSE 2
#define GEAR_NEUTRAL 3
#define GEAR_D_HIGH 4
#define GEAR_DRIVE 5
#define GEAR_SHIFTING 6
//shifter positions
#define SHIFT_L 0 //side to side on the shifter
#define SHIFT_R 1
#define SHIFT_REVERSE 270 //pass this point to be considered in gear
#define SHIFT_DRIVE 820 //pass this point to be considered in gear
#define SHIFT_NEUTRAL 534 //centre point
#define SHIFT_REGEN 878
#define SHIFT_MIN 120
#define SHIFT_MAX 1000
#define SHIFT_DELTA 50
#define SHIFT_HYST 40
#define REGEN_DEADZONE 80
#define PARK_DELAY 900
//pins
#define pin_shift_sel 41
#define pin_shift_pos1 A1
#define pin_shift_pos2 A2
bool shift_sel = 0; //side to side on the shifter
short shift_pos1 = 0, shift_pos2 = 0, shift_pos = 0, shiftcheck = 0; //forward and back on the shifter
byte nextgear = GEAR_NONE, prnd_gear = GEAR_PARK, shiftgood = 0;
short regen_level = 0;
unsigned long park_timer = 0;
bool park_timer_on = 1;
bool park_notify = 0; //show alert that park timer is reached
void setup()
{
pinMode(pin_shift_sel, INPUT);
pinMode(pin_shift_pos1, INPUT);
pinMode(pin_shift_pos2, INPUT);
}
void get_prnd()
{
//do something to not allow us to leave park if we aren't in DRIVE state
// if (pcm_state != PCM_STATE_DRIVE)
// {
// prnd_gear = GEAR_PARK;
// return;
// }
shift_sel = digitalRead(pin_shift_sel);
shift_pos1 = analogRead(pin_shift_pos1);
shift_pos2 = analogRead(pin_shift_pos2);
shiftcheck = shift_pos1 - shift_pos2;
if ((shiftcheck >= -SHIFT_DELTA) && (shiftcheck <= SHIFT_DELTA) && (shift_pos1 >= SHIFT_MIN) && (shift_pos1 <= SHIFT_MAX) && (shift_pos2 >= SHIFT_MIN) && (shift_pos2 <= SHIFT_MAX)) //normal
{
shiftgood = 3;
shift_pos = shift_pos1;
}
else if ((shift_pos1 >= SHIFT_MIN) && (shift_pos1 <= SHIFT_MAX)) //1 stil valid
{
shiftgood = 1;
shift_pos = shift_pos1;
}
else if ((shift_pos2 >= SHIFT_MIN) && (shift_pos2 <= SHIFT_MAX)) //2 still valid
{
shiftgood = 2;
shift_pos = shift_pos2;
}
else //cant use regen
{
shiftgood = 0;
shift_pos = shift_pos1;
}
switch (shift_sel)
{
case SHIFT_L:
switch (nextgear)
{
case GEAR_NONE: //regen mode
if (prnd_gear == GEAR_DRIVE && shiftgood != 0)
{
regen_level = map(shift_pos, SHIFT_NEUTRAL + REGEN_DEADZONE, SHIFT_REGEN, 0, 255);
if (regen_level < 0)regen_level = 0;
if (regen_level > 255)regen_level = 255;
}
else regen_level = 0;
break;
case GEAR_REVERSE:
prnd_gear = GEAR_REVERSE;
nextgear = GEAR_NONE;
break;
case GEAR_DRIVE:
prnd_gear = GEAR_DRIVE;
nextgear = GEAR_NONE;
break;
case GEAR_NEUTRAL:
prnd_gear = GEAR_NEUTRAL;
nextgear = GEAR_NONE;
break;
case GEAR_PARK:
prnd_gear = GEAR_PARK;
nextgear = GEAR_NONE;
break;
default:
break;
}
nextgear = GEAR_NONE;
park_timer_on = 0;
break;
case SHIFT_R:
regen_level = 0;
if (nextgear == GEAR_DRIVE || nextgear == GEAR_REVERSE)break;
else if (shift_pos >= SHIFT_DRIVE + SHIFT_HYST)
{
nextgear = GEAR_DRIVE;
park_timer_on = 0;
break;
}
else if (shift_pos <= SHIFT_REVERSE - SHIFT_HYST)
{
nextgear = GEAR_REVERSE;
park_timer_on = 0;
break;
}
else
{
if (park_timer_on == 0)
{
nextgear = GEAR_NEUTRAL;
park_timer = millis();
park_timer_on = 1;
break;
}
else
{
if (millis() - park_timer > PARK_DELAY)
{
nextgear = GEAR_PARK;
break;
}
}
}
break;
default:
break;
}
if (nextgear == GEAR_PARK && prnd_gear != GEAR_PARK)park_notify = 1; else park_notify = 0;
}
void diag_shifter()
{
Serial.print("Shifter: \t1: "); Serial.print(shift_pos1); Serial.print("\t2: "); Serial.print(shift_pos2); Serial.print("\tSel: "); Serial.println(shift_sel ? "Right" : "Left");
Serial.print("\t\tCheck: "); Serial.print(shiftcheck);
Serial.print(" - ");
switch (shiftgood)
{
case 3: Serial.print("Normal"); break;
case 1: Serial.print("Limp-Pos1"); break;
case 2: Serial.print("Limp-Pos2"); break;
case 0: Serial.print("Bad"); break;
default: Serial.print("ERROR"); break;
}
Serial.print("\nNext Gear: ");
switch (nextgear)
{
case GEAR_PARK: Serial.print("Park"); break;
case GEAR_REVERSE: Serial.print("Reverse"); break;
case GEAR_NEUTRAL: Serial.print("Neutral"); break;
case GEAR_DRIVE: Serial.print("Drive"); break;
case GEAR_NONE: Serial.print("None"); break;
default: Serial.print("Error"); break;
}
Serial.print("\nSelected Gear: ");
switch (prnd_gear)
{
case GEAR_PARK: Serial.print("Park"); break;
case GEAR_REVERSE: Serial.print("Reverse"); break;
case GEAR_NEUTRAL: Serial.print("Neutral"); break;
case GEAR_DRIVE: Serial.print("Drive"); break;
case GEAR_NONE: Serial.print("None"); break;
default: Serial.print("Error"); break;
}
Serial.print("\nRegen level: "); Serial.print(regen_level);
Serial.print("\nPark Notify: "); Serial.print(park_notify ? "On" : "Off"); Serial.print("\tTimer: "); Serial.print(park_timer_on ? "On - " : "Off"); if (park_timer_on)Serial.println(millis() - park_timer);
Serial.println();
}