Charging · 9 min
Reading the pilot with an Arduino — the actual circuit
You wired CP to A0 because a tutorial said read the PWM. The pin is 5 V. The pilot is ±12 V. Load it, then scale it, before a sketch means anything.
You wired CP to A0 because a tutorial said “read the PWM.” The pin is 5 V. The pilot is ±12 V. Sometimes the Arduino dies. Sometimes it lives and the number you print is garbage, and you spend a weekend chasing firmware while the wall box sits there refusing to close. A DC meter on CP says 9 V. The station still will not give you AC, because the negative half never made it to −12 V and the diode check failed. That is the pile this note is for.
The Arduino is not the inlet. Two jobs have to exist in hardware before a sketch means anything: you have to load the pilot so the EVSE thinks a vehicle is there, and you have to scale ±12 V so a 5 V (or 3.3 V) pin can see the wave without dying or lying. A bare GPIO does neither.
This is not a new schematic. The voltages and the vehicle resistors are already on pilot, proximity, and PWM. This page is the front-end people skip.
You are the car, not the wall
The EVSE writes the 1 kHz ±12 V square wave. The vehicle leans on it. If you bought a board that generates PWM, you bought a wall box. Leave it on the building. That mismatch is why off-the-shelf J1772 controllers often do not fit.
A conversion Arduino (or any MCU behind an inlet) has to do the vehicle half.
Load the pilot so the station sees a car
IEC 61851 / SAE J1772 vehicle network, same numbers as the PWM note:
- About 2.74 kΩ (builders often use 2.7 kΩ) from CP to PE, through a series diode, is State B. Connected, not asking.
- Switch 1.3 kΩ in parallel (~882 Ω) and you are State C. Ready.
- Optional extra ~330 Ω is State D, ventilation required. Rare on a conversion.
- The EVSE’s source impedance is about 1 kΩ. That is why those loads become ~9 V and ~6 V on the positive pulse.
The diode is not decoration. It lets the EVSE see that the negative half of the PWM still sits at −12 V. Resistor-only CP looks fine on a DC meter and still fails the check. A lot of stations will not close.
Craig Peacock’s Beyondlogic EVCC is the clearest published vehicle front-end. D2 + R7 (2.74 kΩ) is the connected load. A second resistor (1.3 kΩ) switches in for ready. D2 rectifies so only the positive pulse is loaded — that is the diode check, the puddle-versus-car test. D3 is a TVS that clamps stray voltage to about 16 V. His MCU is a dsPIC33, not an Arduino. The inlet network is still the one you copy.
Nick Sayer’s J1772 EV Simulator writes the same vehicle end in plain language: 2.7 kΩ + diode CP to GND for +9 V; +1.3 kΩ in parallel for +6 V; optional +330 Ω for +3 V. Same 1 kΩ EVSE source.
Do not invent a third set of resistors. Use the standard network or a published board that already did.
Then scale the wave so the Arduino can see it
±12 V on a 5 V ADC pin is how you let the smoke out. Even if the clamp saves the pin, a raw GPIO still cannot tell you duty cycle honestly.
Three published ways people actually read this wave:
Divider, then a buffer, then the ADC. Sayer’s simulator rescales −12…+12 V to 0–5 V with a resistor divider. The divider looking into the pin is about 200 kΩ. An AVR ADC wants the source at or under 10 kΩ. Without a unity-gain op-amp in front of the analog pin, the sample-and-hold capacitor drags the scaled voltage around for a few microseconds on every conversion — on the order of half a volt. Brief, and enough to wreck a duty-cycle read. He also feeds the analog comparator a voltage that represents about 0 V on the pilot (10 kΩ / 12 kΩ on a 5 V rail, about 2.71 V) and times the edges in an ISR. That is how you get frequency and duty without trusting a slow ADC sample of a 1 kHz edge.
A comparator, not a GPIO. Beyondlogic does not hang the dsPIC I/O on CP. A TL331 on 3.3 V (the part’s input can stand 38 V) turns the wave into a clean logic edge for duty. The MCU never eats ±12 V. If you are on an Arduino and you only need duty, this is the safer half of the problem.
A published EVSE still has to scale the same volts. OpenEVSE generates the wave, so it does not need to discover duty the way a car does. It still has to look at CP to see vehicle state and a missing diode. Their theory of operation feeds the pilot back to ADC1. On the DIY 30 A board the read-back divider is 200 kΩ, 100 kΩ, and 56 kΩ (R5 / R6 / R7), meant to put −12 V near 0 and +12 V near 5 V on an ATmega328P. Older write-ups mention a three-transistor scale into the same ADC. Copy those values only if you are building their station. Do not bolt the generate half into the car.
A lot of “Arduino J1772” pages skip the buffer, skip the diode, and treat analogRead() of a raw divider as a current command. That is how you get a sketch that prints 30 A while the station is still in State B.
What the sketch is allowed to do
Once the front-end is honest:
- Voltage of the positive pulse is state (12 / 9 / 6 / 3). That is the load you presented, plus whatever the EVSE is sourcing.
- Duty cycle of the 1 kHz wave is the amp advertisement. Formulas live on the PWM note. Cap the onboard charger to that number. Do not draw more.
- The negative pulse is the diode check. If it does not sit near −12 V (after your scale), the station may never close. Fix the diode before you rewrite the ISR.
PP is a different pin. Latch, not PWM. Do not scope it looking for 1 kHz, and this page does not reprint an ohm-to-amp table.
Do not generate ±12 V from the Arduino and call that an inlet. Writing the wave is the EVSE. Reading it is the car.
What people get wrong
Hooking CP to a GPIO “just to see.”
Using a DC meter, seeing 9 V, and declaring the inlet finished.
Copying an EVSE-generate schematic (op-amp driven from ±12 V, TI EVSE apps, OpenEVSE’s drive half) into the frunk.
A high-Z divider straight into analogRead(), then blaming the sketch when duty jitters.
Forgetting S2. The Arduino can print a beautiful duty cycle all day in State B. The contactor on the wall will not close until you pull CP to 6 V.
Building this from a napkin instead of a published front-end. Start from Beyondlogic’s vehicle network, or Sayer’s simulator read path, and keep the numbers.
Sources
- J1772 pilot, proximity, and PWM — states, duty formulas, PP vs CP
- IEC61851 / J1772 Electric Vehicle Charge Controller — Craig Peacock. Vehicle 2.74 k / 1.3 k, diode, TVS ~16 V, TL331 duty
- J1772 EV Simulator — Nick Sayer. 2.7 k / 1.3 k / diode load; 200 kΩ divider; unity-gain buffer; comparator vs ~0 V
- OpenEVSE theory of operation — EVSE generates ±12 V, reads state and diode on ADC1
- OpenEVSE DIY 30 A read-back divider 200 k / 100 k / 56 k — Chris on the OpenEVSE list