Welcome to my Project page

A V8 Digital Cooling fan Controller

I am a Mature Student studying Electronic engineering at Exeter University.
For my project I have chosen to design and build a digital cooling fan controller with serial I/O.
The main feature of the project was to create a small and compact circuit which could fit inside a normal 12v vehicle relay .

The idea for this design came from the fact that during this summer of 2007, I transplanted a Range Rover V8 4L EFI engine into my LR Airportable and decided to leave the 2.25 L Radiator in place ( for asthetic reasons ) This has left a serious problem with OVER HEATING.

Rover V8 being removed from engine bay of a Range Rover.

Under normal running conditions the coolant temperature was stable but in traffic jams or very steep hills the coolant temperature would rise very quickly, in fact it was too fast for the factory fitted system to cope with.




Rover V8 fitted to my landrover

Because the MOT was due I was worried the engine would be left idling and OVERHEAT causing yet another stripdown !




I started with three basic points!
1) Digital design so temperature data could be shared with a computer
2) Accurate A/D convertor
3) Small simple circuit

The circuit I designed had four main areas.

1) PSU: 12V from the ignition circuit is fed into 'J2' which feeds the Relay coils and is then regulated to +5v via 'U1' which is a standard 7805 voltage regulator
2) PIC micro: This is a 12f675 4 Mhz with 10 bit A/D and 3 user pins (5, 6, and 7) A/D is read in on pin 6 and VREF is internal +5v. 10 bit A/D value is transmitted on SDA line pin 7 Relay drive is driven by pin 5.
3) RELAY: The relay is a simple 12v 30 Amp relay which is driven by two BC337 as a darlington pair. D1 provides protection from the relay coil.
4) THERMISTOR: This is a negative co-efficient type and forms a potential divider with R1, 100 Ohm 1/4 Watt when the engine as at normal running temperature the thermistor has a value of roughly 70 Ohms this produces a nominal voltage of 2 Volts. With R1 at 100 Ohms this limits current to 50 mA or 1/4 watt (should the terminal be shorted to earth)


This is the complete circuit Diagram.


Designing the code was simple, I decided to use pure Assembly language
and assemble with MPASM,
I used an easypic3 development board from Mikroelektronika
and chose a PIC12F675 as it had the following attributes.


1) Cheap
2) 10 bit A/D
3) A TTL port for communication
4) A TTL port for relay drive
5) Small 8 pin dil package
6) Had flash properties
7) No wastage of resources



The program listing ( Assembly file )
; V8 Relay controller for SOE2152
; Written by Graham Medland      gm236@ex.ac.uk
;
; RA0 = SDA LINE (serial data)
; RA1 = RELAY output
; RA2 = Analog in
; the rest are tied up internaly





;sda protocols
;
;search for 500 uS logic HIGH.
;wait for low transition (wait 10uS)
;now wait 25uS for center of sample point and read D0
;wait 50uS and read d1
;wait 50uS and read d2
; ---- --- --- --- ---
;wait 50uS and read d9
;this marks the end of the packed
;which consists of 10 bit a/d value 











;*************************************************************************
; MPASM
;*************************************************************************


    LIST p=12f675
    #include   ..\..\MPASM\p12ce674.inc

    __config _WDT_OFF &  _CP_OFF & _INTRC_OSC_NOCLKOUT


;*************************************************************************
; DATA
;*************************************************************************


 cblock 020
  gpio_pins                ; duplicate of port pins
  ad_val:2                 ; 10 bit ad value
  ad_val_t:2               ; copy of 10 bit ad value for data stream    
  l_bound:2                ; lower bound voltage  2 byte
  u_bound:2                ; upper bound voltage  2 byte
  tmr:2                    ; lsb=initial value : msb=the counter
  temp                     ; temporary dump for variables
  eocp                     ; end of code page (linear store of data)
 endc


;*************************************************************************
; CODE
;*************************************************************************
; Initialise the A/D 
; setup variables
; this gets done on a POR
 

  movlw 0
  movwf gpio_pins          ; fan is off initialy

  movlw 091
  movwf l_bound
  movlw 01
  movwf l_bound+1          ; 70 Ohms cut off point, fan comes on if any lower

  movlw 0A0
  movwf u_bound
  movlw 01
  movwf u_bound+1          ; 75 Ohms cut off point, fan switches off 

  bcf 03,6
  bsf 03,5                 ; bank 1
  movlw 04                 ; RA0,1 = OUTPUT     RA2 = INPUT
  movwf 05                 ; trisa
  movlw 0
  movwf 01                 ; option
  movwf 0b                 ; no interupts
  movlw 014                ; an2 = analog, rest are digital,fosc/8 with 4mhz internal osc = 2us
  movwf 01f                ; ANSEL
  bcf 03,5                 ; bank 0
  movlw 089                ; right justified,vref vdd, AN2, 0 , 1
  movwf 01f                ; ADCON0
  goto main                ; all setup so go do main loop for ever !!!!!









;**************************
; Start the main sequence
; check A/D and switch
; the Fan On/Off

main:
  call do_pins             ; output the pins
  call get_ad              ; read ad, value in w
  call test_lower          ; test for upper bound
  andlw 0ff                ; -1 or zero ?
  btfsc 03,2
  goto fan_on              ; if here adval < lower bound ( < 70 ohms)
  call test_upper          ; test lower bound
  andlw 0ff                ; -1 or zero ?
  btfss 03,2
  goto fan_off             ; if here adval > upper bound( > 75 ohms)
  goto main


;**************************
; Upper and Lower bounds
; for A/D values

test_lower:
  movf ad_val+1,w          ; get high bit
  subwf l_bound+1,w
  btfss 03,0               ; skip if positive
  retlw 0ff                ; oh dear high bit no good
  btfss 03,2                     
  retlw 0                  ; definately high no point checking low
  movf ad_val,w            ; get low bit
  subwf l_bound,w
  btfss 03,0               ; skip if positive
  retlw 0ff                ; oh dear high equal and low bit bit no good
  retlw 0                  ; high bit equal and low bit ok !!!!!  yeah !


test_upper:
  movf ad_val+1,w          ; get high bit
  subwf u_bound+1,w
  btfss 03,0               ; skip if positive
  retlw 0ff                ; oh dear high bit no good
  btfss 03,2                    
  retlw 0                  ; definately high no point checking low
  movf ad_val,w            ; get low bit
  subwf u_bound,w
  btfss 03,0               ; skip if positive
  retlw 0ff                ; oh dear high equal and low bit bit no good
  retlw 0                  ; high bit equal and low bit ok !!!!!  yeah !


;**************************
; Virtual to Real
; Outputs the pins


do_pins:
  movf gpio_pins,w
  movwf 05                  ; Real output to pins
  retlw 0


fan_on:                      ; Virtual output to pins
  movlw 02
  iorwf gpio_pins,f
  goto main


fan_off:
  movlw 0fd                
  andwf gpio_pins,f
  goto main


dta_high:
  movlw 01
  iorwf gpio_pins,w
  movwf 05
  movwf gpio_pins  
  return


dta_low:
  movlw 0fe                
  andwf gpio_pins,w
  movwf 05
  movwf gpio_pins
  return


;**************************
; on exit
;   ad_val   = d7-d0 ad value
;   ad_val+1 = d9-d8

get_ad:
  movlw 2                  ; mask for DONE/GO 
  iorwf 01f,f              ; start conversion
  call send_data           ; go do data bit stream while a/d is being done
  bsf 03,5                 ; bank 1
  movf 01e,w
  bcf 03,5
  movwf ad_val             ; save d7-d0
  bcf 03,5                 ; bank 0
  movf 01e,w
  movwf ad_val+1           ; save
  return                   ; ret true


;**************************
;serial data routines



send_data:                 ;                                  fosc=0
  call dta_high            ; start initial high
  clrf tmr                 ; longest possible wait state
  call wait_state          ; long high (porch)
  movf ad_val,w
  movwf ad_val_t           ; copy lsb   movf ad_val+1,w
  movf ad_val+1,w
  movwf ad_val_t+1         ; copy msb
  movlw 0a                 ; 10 bits of a/d to send
  movwf temp               ; use temp as it is available      fosc=0314
  call dta_low             ; this is the trigger for BIT 0    fosc=031c

send_data1:             
  bcf 03,0
  rrf ad_val_t+1,f         ; finger in a woodpeckers hole
  rrf ad_val_t,f           ; all ten bits shifted,c=1 for high, c=0 for low
  btfsc 03,0               ; test the carry flag
  goto send_data_H         ; send a high
  goto send_data_L         ; send data low
  goto 0                   ; this never gets done,

send_data2:
  decfsz temp,f            ; done all 10 bits ?
  goto send_data1          ; if not then keep going
  return                   ; else return (1 packet sent)


send_data_L:               ; output a logic low fosc=039         
  call dta_low
  movlw 0a
  movwf tmr
  call wait_state
  goto send_data2


send_data_H:               ; output a logic high fosc=039
  call dta_high
  movlw 0a
  movwf tmr
  call wait_state
  goto send_data2



;*******************************
;delay routine to stretch signal

wait_state:
  movf tmr,w                ; get the start counter
  movwf tmr+1               ; copy to the timer

wait_state1:
  decfsz tmr+1,f            ; decrement and repeat  
  goto wait_state1
  return                    ; else return





;******************************************************************************

 END







The assembly program was debugged using my own simulator PICDEBUG which can be found here And runs in a windows DOS box





Screen shot of debugging. (Note the symbols which have been imported from the Bytecraft .COD file






The program was Assembled using MPASM which created the following HEX file









The HEX file was loaded into the PIC12F675 using the EASYPIC3 software





Screen shot of hardware debugging. (Note the scope probes and signal generator leads for simulating the engine




This processs was repeated until I was happy with both the software and hardware configuration.





Screen shot of hardware and Software development process. (Note that the device being programmed stays STATIC in the board and can be programmed while it is in circuit. The whole process of Assembling and programming the pic can be done in under 30 seconds.




With the hardware working I then injected an analog signal into the A/D pin simulating the rise and fall of engine temperature.




Frequency of 0.232 Hz or 1/4 Hz
Actual frequency from Engine
temperature is about 1/160 Hz
With only 35 Seconds from
good to overheating
Volts Peak to Peak of 2v
This gives a nice 1 Volt up/down
about the mean voltage
triggering the fan on/off
about the peaks



DC Offset voltage of 2.1v
this is the MEAN value of temperature
during normal running of engine.








please view the video footage by clicking Here where you can see
the analog signal (bottom trace)
and the TTL output for the fan control (top trace)




With the hardware working
I then took a standard car indicator relay
removed the components except the relay and free wheeling diode
then mounted the componts where I could (utilising the old tracks left behind) .





Screen shot of Relay packed with the components. (Note the PIC micro glued vertically in anh 8 pin dil socket which is just above the 7805 regulator.
Here it is with the case going on !




This unit was fitted to the land rover and is still working very well !!
I then wrote a small demo routine
in x86 assembly language to decode the 10bit serial data





Here is the laptop coupled to the pic
it is nice to see the bargraph and serial bit stream on the laptop screen change as the engine warms
Here is an osciloscope trace
taken from the pic SDA pin
showing an alternating
bit pattern representing
the value 01_0101_0101
or 0155 Hex






Here is the x86 listing which requires my favourite assembler and is targeted for MSDOS under a windows dos box or real mode




The program listing ( Assembly file )
; V8 Relay controller for SOE2152 ; Written by Graham Medland gm236@ex.ac.uk ; use A386/D386 to assemble ; MSDOS application to extract 10 bit A/D ; from 12f675. and runs in v86 or real mode ; for the intel x86 processor mov ax,040 push ax pop fs fs mov dx,w[08] mov al,0ff ; all data high inc dx ; get EPP port mov ax,013 int 010 start: call draw_data ; draw the bit stream in al,060 cmp al,03d ; until F3 is pressed jnz start mov ax,0 int 016 start1: call draw_data ; draw the bit stream call draw_sp1 ; mark the ten sample points under track in al,060 cmp al,01c ; until RET is pressed jnz start1 mov ax,0 int 016 call vga_cls start2: call draw_data ; draw the bit stream call draw_sp2 ; mark the ten sample points over track in al,060 cmp al,03d ; until F1 is pressed jnz start2 mov ax,0 int 016 call vga_cls start3: call draw_data ; draw the bit stream call draw_sp ; mark the ten sample points over track in al,060 cmp al,01C ; until F1 is pressed jnz start3 mov ax,0 int 016 call vga_cls start4: call get_bar_graph ; draw a bar garaph in al,060 cmp al,03d ; until F1 is pressed jnz start4 mov ax,0 int 016 start5: call draw_data ; draw the bit stream call draw_sp ; mark the ten sample points over track call get_bar_graph ; draw a bar garaph call draw_bar_graph in al,060 cmp al,01c ; until F1 is pressed jnz start5 mov ax,03 int 010 mov ax,0 int 016 mov ax,04c00 int 021 ;----------------------------- draw_data: mov es,0a000 mov di,16000 mov cx,320 get_porch: ; on exit we have bit 0 transmitted in al,dx in al,dx in al,dx in al,dx cmp al,07f ; is it a high ? jz get_porch_1 ; if it is do the count mov ebp,0 ; if not then reset the counter get_porch_1: inc ebp ; increment the counter >300 is the porch cmp ebp,070 jb get_porch get_porch_2: ; wait for high/low transition in al,dx cmp al,03f ; is it low ? jnz get_porch_2 ; keep repeating get_porch_3: in al,dx in al,dx xor al,040 stosb loop get_porch_3 ret ;------------------------------------------------------------ draw_sp: mov di,16971 mov cx,10 ;10 bits of data draw_spa: es mov w[di],0ffff es mov w[di+320],0ffff add di,17 push cx and cx,1 add di,cx ; fudge factor for linear tracking of bit stream pop cx loop draw_spa ret ;------------------------------------------------------------ draw_sp1: mov di,16971 mov cx,10 ;10 bits of data draw_sp1a: es mov w[di],0ffff es mov w[di+320],0ffff add di,17 loop draw_sp1a ret ;------------------------------------------------------------ draw_sp2: mov di,16971 mov cx,10 ;10 bits of data draw_sp2a: es mov w[di],0ffff es mov w[di+320],0ffff add di,18 loop draw_sp2a ret vga_cls: mov di,16971 mov cx,320 mov ax,0 rep stosw ;clear the line ret ;------------------------------------------------------------ get_bar_graph: mov di,16011 ; point to center of data bit 0 mov cx,10 ; 10 bits of data mov bx,0 ; bx will hold the 10 data bits get_bar_graph1: es mov al,b[di] es mov b[di],0ff es mov b[di+320],0ff es mov b[di-320],0ff sal al,2 rcr bx,1 add di,17 push cx and cx,1 add di,cx ; fudge factor for linear tracking of bit stream pop cx loop get_bar_graph1 not bx ; 1s complement shr bx,6 ; 10 bit allign and bx,03ff cs mov w[082],bx shr bx,2 ; 0-255 for bar graph, 10bit to 8bit cs mov w[080],bx ret ;------------------------------------------------------------- draw_bar_graph: ; draws both bargraphs cld cs mov cx,w[080] ; draw scaled line (0-3ff) ---> 0-0ff or cx,1 mov al,0ff mov di,3200 rep stosb mov al,0 mov cx,320 rep stosb cs mov cx,w[082] cmp cx,01a0 ; upper bound ja ret cmp cx,0191 ; lower bound jb ret sub cx,0190 ; draw magnified line mov ax,0ffff mov di,6480 rep stosw mov al,0 mov cx,128 rep stosb ret




With everything working as it should
I started creating the PCB





Original artwork with very thin tracks
Sorry ROGER
Final artwork
Actual PCB
Populated PCB
with connections.




After the wires have been pushed into the sockets on the PCB
the whole circuit will be potted with just the colour coded wires
poking out of the box
Allowing easy connections to any rover v8 cooling system





Now that the Landrover no-longer overheats Everyone is HAPPY and my kids think it is COOL




If you have any questions or comments please email me me
It would be nice to hear from you

gm236@ex.ac.uk




THEEND