Interfacing to circuit which grounds the input

I'm want to interface to a circuit which grounds the input.
What it expects is the arduino to hold the line at 5V, and then it has a transistor or similar to ground that 5V signal to give a percentage of speed.

It's drawn as attached - the transistor at the top (ECU) takes the 5V held high signal and grounds it proportionally to the speed it wants to drive the two fans at.

My intent is to remove the fan controller, but obviously maintain interaction with the ECU for it's desired fan control.
To do that based on the image, common the grounds between the two controllers, hold the line high at 5V with a resistor sized to limit current (say 5mA) - 160ohm or so. Then the ECU will ground that signal and so vary the reading the arduino sees on the analog pin - right?

So by design, if the arduino ADC Is then reading 4096 - it's expecting 0% fan output. If it's reading 0, then 100% fan output - or have I got the circuit concept wrong?
When I metered V on it today, with the fan controller unplugged it read 0.03V, and as it reached higher temps and wanted cooling, the V dropped to -0.01V.

Looks like you forgot to add the attachment.

Bugger, I exported it and forgot!

If the output from the ECU is an open collector NPN transistor as you have shown it, then it isn't an analog signal, it's a PWM digital signal. There are two ways you can read this on an Arduino:

  1. Use a resistor to +5V and then an RC smoothing network to convert the PWM signal into an analog signal, which you can read using an analog input.

  2. Feed it to a digital pin, time the HIGH and LOW intervals, then calculate the ratio of HIGH to HIGH+LOW. Easiest way is probably to use a resistor to +5V, feed it into a pin that supports interrupts, attach an ISR to that pin using mode CHANGE, and do the timing in the ISR.

I would use method (1) if the PWM frequency is more than about 1KHz, and (2) if it is lower.

btw:

(1) analog input readings on the Arduino go from 0 to 1023 (not 4096) because it is a 10-bit ADC

(2) a 160 ohm pullup resistor would give almost 5/0.16 = 31.25mA, not 5mA. A 1K pullup would give 5mA.

Ahh and that timing could indeed be critical to operation.
This would mean that to take it over correctly, I must first monitor it's current operation.

I can get data from it using the diagnostics port, but the information I get there is simply the duty cycle ("128 = 50%").

To monitor the signal (with no oscilloscope) and time the interrupts to get the true time base for the PWM - can I join two signals to the one ECU output?
i.e. Arduino pin 2, held high with a resistor (1k !) to 5V, on from there to the ECU pin.

And then both the arduino and fan controller get the PWM signal?

While you are leaving the fan connected as well, just connect the ECU output to the Arduino input through a 10K resistor. The fan controller already has a pullup resistor in it. The 10K resistor is to protect the Arduino in case the voltages are a bit different.

I monitored the output and tested some knowns. When I run the A/C compressor this runs the fans at 50% from previous tests.

I tried to monitor the PWM signal using this line:
value = pulseIn(pulsepin, HIGH, 1000000);

I got values such as 229, or 99.
What happens tho is when I turn the A/C compressor on, it reads 0!
Not believing that - I metered it and saw 4.9V.

I need a way of doing it such that I can differentiate between line idling high, and line remaining low and allowed to go high.
I know that when the fans are not needed, the wire reads 0V (so I think the ECU continually drives it to 0V when it wants no fan - which makes sense, wiring harness gets damaged then it should remain '5V'...

I like '1' better - any thoughts on a circuit for that design (i.e. smooth the pwm to a voltage and feed to analog in).. This would give me great proportional control.

Instead of using pulseIn, do a number of digitalRead calls at regular intervals over a period much larger than the PWM period, and compute the ratio of HIGH reading to total readings.

What I'm concerned about is if the frequency is too fast, then I won't catch the transition I need to.
i.e. if I loop 20 times, reading the pin and for those 20 times I read that the input is low, but what happens is between the read for read 2, and read 3, it transitions and back again i'll potentially miss it?

How do I know what PWM period is to read 'larger' than it?
I think PWM period is a important bit of info - i.e. if the PWM signal was 10%, and the period was 10 seconds, the first 1 second would be low. I don't know what that PWM period is.

You could connect the input to one of the pins that supports attachInterrupt, set the interrupt mode to CHANGE, and time the low and high periods in the ISR. If you find that you haven't received any interrupts recently, then just read whether the pin is high or low.

I set it up the first way, that is to continuously count the number of times the pin is high out of a fixed number (3000). This appeared to work really good and smooth out any problems!

It works better than pulseIn, as the time interval is dependant on knowing the timebase, whereas merely counting the number of times in a fixed number gives you a good percentage.
Thanks heaps for that tip - worked really well.

What size pull up resistor ? I'm thinking 1k.. (just enough to hold it high so the ECU gnds it)