PIC PROJECTS / PROGRAMMING PAGE

 

A Smart Charger (under development)

by ZS2R and members of the Port Elizabeth Amateur Radio  Society

23 May 2011

This project is firstly developed as a PIC controlled interface between solar panels,  a battery and a load. Later this can be futher developed to be an interface between a power supply and a battery to become a versatile unit - a smart charger.

The files included will be updated from time to time so watch this space. ZS2R will be available on the 2m East Cape network  to answer questions, accept suggestions and advice most evenings after 20H30 local time.

A number of PEARS ( Port Elizabeth Amateur Radio  Society) members have PIC programers but have not got down to using them. I have included the asm file which will grow with the project. You can watch what is added and if you build the unit see the results of the additional code. The circuit has been assembled on vereoboard so the unit can be build up in short while. There is no need to unplug the PIC for programing,  the in circuit serial programing  pins have been brought out on a separate plug.

 

The Prototype PIC-based Smart Charger

The first prototype has facilities to:-

1)  measure battery voltage.

2)  measure solar panel current.

3)  measure load current

4)  drive a LCD display (any type from the junk box !)

5)  switch the solar panel on/off .

6)  switch the load on/off

7)  generate a log of any of the measured quantities.

The main idea is to switch the solar panel on to the battery, monitor the battery potential and switch off the solar panel when the battery is fully charged. The PIC will monitor the battery continually and switch on the solar panel when neccessary or disconnect the load should the battery potential drop below a predetermined value. The unit will also monitor the charging current and load current.

In the picture of the assembled board notice that decoupling  capacitors have been added. This was neccessary because the 5V supply  is used as a reference voltage for the A to D converter and  needs to be as stable as possible.

The shunt resistor in this unit is  0,01 ohm. As the unit was only intended to measure currents up to 5 amperes this resistor needs to be of the order of 0,25 watt.

I made the shunt by silver soldering two beads on a piece of nichrome wire and then soldering heavy copper wires onto the beads to act as connecting terminals. Measure the potential across the shunt while passing a current of say 2 A. This should be 0,02 V. File away some of the wire until this value is obtained.  Plan your actions because filling can only reduce the resistance and if you file away to much you will have to start again.  Suitable resistance wire can be sourced from an old resistor - see picture. 

SHUNT construction

 

Old resistor used for nichrome wire

 

The software to date will only measure and display the battery potential. (23 May 2011).

 

Smart Charger update  (26 June 2011)

 

Discussions  by members of PEARS members since the last posting has reveiled two main short commings of the unit as detailed to date.

Firstly software must make provision for the posibility of the battery being fully charged by say 11 am, and the load must then be supplied  by the solar  panel and not the battery for as long as possible or some technique devised to continuously  supplement the battery with energy equal to that drawn by the load. This could make for some interresting software solutions. Ideas will be welcome !

Secondly it seems that a safety precausion should be included. This to isolate the load should the the voltage at the load rise above a predetermined value. This switching  to be as fast as possible  and so the use of an interrupt  via one of the 16F685's comparators would be the best option. If we op to use comparator 1, then pin 18 can be used  as the input so constructors must insert a link between pin 17 and 18. Software to do the rest.

Discussions around the use of the shunts in the low side of the solar  panel and load  generated quite a bit of interest. An alternative way of making shunts was given by Lionel, ZS2DD. Use a strip of copper plate, drill holes in the strip and file them out untill you get the required resistance. Proportions being applied to match the current rating.

The updated  asm file now measures the currents and voltages and switches the load and battery.

 

 

Smart Charger update  (16 February 2012)  

The charger has now been completed ready for installation. Some comments and corrections to the original unit.

1) . The accuracy of the current monitoring circuit is not satisfatory, being greater than 20% over the full range.Using a small pot in place of R7 and R13 will allow adjustments that improve matters somewhat. When this unit is redone four op amps will be used to enable the shunts to be placed in the positive line. A greater value of shunt resistance and less gain on the op-amps should improve the accuracy.Also lower value resistors to set the gain (less noise) and more bypassing capacitors.

2) The solar panel will be switched in when the battery potential drops to 13.5 volts and switched out when the battery potential reaches 14 volts.

3) The load will be disconnected when the battery potential drops to 11 volts and reconnected when the battery potential reaches 12 volts.

4) The values quoted in 2 and 3 above can easily be changed in software.

5) CORRECTION : The FETs shown on the circuit diagram must have their source and drain interchanged. They are P channel power fets and I used an IRF9630 for FET1 but could not find a second one in my shack so I used a small relay instead.

6) The diode D1 has been ommitted because solar panel will not allow reverse current even in the dark.

7) A driving transistor and relay have been added to switch an external device. Software to control the switching.

8) For safety reasons, a fuse has been added to the battery positive line . The value to be determined by the user.

 

Completed unit

 

Smart Charger update  (25 May 2014)  

Allan sent us an updated .ASm file, which can be downloaded by clicking on the link below.

 

 

PCB Layouts (pdf format):

Circuit diagram

Component side

Solder side top

Solder side bottom

All layers

 

ASM Source code:  (click here for the file itself)

;**********************************************************************
; This file is a basic code template for assembly code generation *
; on the PIC16F685. This file contains the basic code *
; building blocks to build upon. * 
; *
; Refer to the MPASM User's Guide for additional information on *
; features of the assembler (Document DS33014). *
; *
; Refer to the respective PIC data sheet for additional *
; information on the instruction set. *
; *
;**********************************************************************
; *
; Filename: WIFi_charger_cntrl.asm *
; Date: 2012/01/04 *
; File Version:3 *
; revision date 2/1/2013 *
; Author:zs2r *
; Company: *
; * 
; *
;**********************************************************************
; *
; Files Required: P16F685.INC *
; *
;**********************************************************************
; Notes: *
; Pinout:-1,Vdd, +5V *
; 2,RA5, N/C *
; 3,RA4, N/C * 
; 4,RA3, serial programmer *
; 5,RC5, load connect/disconnect *
; 6,RC4, solar panel connect/disconnect *
; 7,RC3, V in scale to load current *
; 8,RC6, push button *
; 9,RC7, push button *
; 10,RB7, LCD data d3 *
; 11,RB6, LCD data d2 * 
; 12,RB5, LCD data d1 *
; 13,RB4, LCD data d0 * 
; 14,RC2, LCD enable * 
; 15,RC1, LCD RS *
; 16,RC0, V in scale to solar panel current value * 
; 17,RA2, V in scale to battery pd * 
; 18,RA1, serial programmer clock *
; 19,RA0, serial programmer data *
; 20,Vss ground *
; *
; * 
;**********************************************************************
;Configuration notes
;_FCMEN_ON EQU H'3FFF' failsafe clock monitor on
;_FCMEN_OFF EQU H'37FF' failsafe clock monitor off
;_IESO_ON EQU H'3FFF' Internal/External Switchover bit (Two-Speed Startup mode enabled).on
;_IESO_OFF EQU H'3BFF' Internal/External Switchover bit (Two-Speed Startup mode enabled).off
;_BOR_ON EQU H'3FFF' Brown out reset on
;_BOR_NSLEEP EQU H'3EFF'
;_BOR_SBODEN EQU H'3DFF'
;_BOR_OFF EQU H'3CFF' Brown out reset off
;_CPD_ON EQU H'3F7F' code protection data on
;_CPD_OFF EQU H'3FFF' code protection data off
;_CP_ON EQU H'3FBF' code protection on
;_CP_OFF EQU H'3FFF' code protection off
;_MCLRE_ON EQU H'3FFF' master clear on pin on
;_MCLRE_OFF EQU H'3FDF' MCLRE pin now input
;_PWRTE_OFF EQU H'3FFF' power up timer off
;_PWRTE_ON EQU H'3FEF' power up timer
;_WDT_ON EQU H'3FFF' watchdog timer on
;_WDT_OFF EQU H'3FF7' watchdog timer off
;_LP_OSC EQU H'3FF8' low freq osc.+/- 32kHz low gain amp
;_XT_OSC EQU H'3FF9' medium gain resonators
;_HS_OSC EQU H'3FFA' high speed oscillator
;_EC_OSC EQU H'3FFB' external clock
;_INTRC_OSC_NOCLKOUT EQU H'3FFC'
;_INTRC_OSC_CLKOUT EQU H'3FFD'
;_EXTRC_OSC_NOCLKOUT EQU H'3FFE'
;_EXTRC_OSC_CLKOUT EQU H'3FFF'
;_INTOSCIO EQU H'3FFC' internal osc
;_INTOSC EQU H'3FFD' internal osc
;_EXTRCIO EQU H'3FFE' external RC with IO on osc2/clockout
;_EXTRC EQU H'3FFF' external RC
;
;*******************************************************************************************************************************

list p=16f685 ; list directive to define processor
#include <P16F685.inc> ; processor specific variable definitions

__CONFIG _CP_OFF & _CPD_OFF & _BOR_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _FCMEN_OFF & _IESO_OFF


; '__CONFIG' directive is used to embed configuration data within .asm file.
; The labels following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.






;***** VARIABLE DEFINITIONS
w_temp EQU 0x7D ; variable used for context saving
status_temp EQU 0x7E ; variable used for context saving
pclath_temp EQU 0x7F ; variable used for context saving

inside equ H'0020' ;general delay
insidev equ H'0021' ;general delay
middle equ H'0022' ;general delay
middlev equ H'0023' ;general delay
outside equ H'0024' ;general delay
outsidev equ H'0025' ;general delay
time equ H'0026' ;general delay
timeo equ H'0027' ;general delay
timev equ H'0028' ;general delay 
atod equ H'0029' ;A to D result 
flags equ H'0030'
battV equ H'0031'
currentS equ H'0032' ;current from solar panel 
V_tens equ H'0033' ;battV in decimal 
V_units equ H'0034'
V_tenths equ H'0035'
I_units equ H'0036' ;I in decimal
I_tenths equ H'0037'
I_hths equ H'0038'
temp1 equ H'0039' 
offset equ H'0040' ;displaycount
dispadd equ H'0041'
datafile equ H'0042'
counter equ H'0043' ;setup 
counter1 equ H'0044'
currentL equ H'0045' ;current to load 



#define charge_flag flags,0
#define load_flag flags,1
#define iflag flags,2
#define writeflag flags,3

#define dispe PORTC,2
#define regselect PORTC,1
;**********************************************************************
ORG 0x000 ; processor reset vector
goto initialise ; go to beginning of program


ORG 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
movf PCLATH,w ; move pclath register into W register
movwf pclath_temp ; save off contents of PCLATH register


; isr code can go here or be located as a call subroutine elsewhere

movf pclath_temp,w ; retrieve copy of PCLATH register
movwf PCLATH ; restore pre-isr PCLATH register contents 
movf status_temp,w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
retfie ; return from interrupt






initialise
;setup set/clear all neccessary special function bits

banksel TRISA
movlw b'00111111' 
movwf TRISA ;ra0(19), ra1(18),ra3(4) inputs,reserved for programing,ra2(17)is analogue input
movlw b'00000000'
movwf TRISB ;rb output data to LCD 
movlw b'11001001'
movwf TRISC ;rc0,3,6 & rc7 inputs others output.
clrf INTCON ; global interrupts disabled
movlw b'10000000'
movwf OPTION_REG ;porta&b pull ups disabled

banksel ANSEL
movlw b'00010100'
movwf ANSEL ;ra2(17), rc0(16) now set for analogue input
clrf ANSELH 
banksel counter
; use 4MHz internal clock i.e. default setting
banksel OSCCON
movlw b'01100001'
movwf OSCCON
banksel counter ;back to bank 0

clrf flags


;Initialise the LCD display and put it in 4 bit data transfer mode.pin read/write wired low 
movlw .3
movwf counter
bcf regselect 
;bcf readnotw 
bcf dispe
bsf writeflag
displaysetup

call delay15ms
movlw b'00110000' ;8bit mode
movwf datafile
call writeinstr
decfsz counter,f
goto displaysetup ;send 8 bit command at least 3 times
movlw b'00100000' ;This instruction puts it in 4 bit mode
movwf datafile
call writeinstr
bcf writeflag
movlw b'00101000' ;select 2 lines 5x7 dots
movwf datafile
call writeinstr
bcf writeflag
call cleardisp ;now display is in 4 bit mode, 2 lines and 5x7 
movlw b'00001100' ;characters display on, cursor & blink off
movwf datafile
call writeinstr
bcf writeflag
movlw b'00000110' ;incr.cursor automatically although invisible
movwf datafile
call writeinstr
bcf writeflag
clrf dispadd
call setadd
;display is now ready and character memory set
;to first character on line 1


main 



call find_V
call set_flags
btfsc charge_flag
call charger_on
btfss charge_flag
call charger_off
btfsc load_flag
call load_on
btfss load_flag
call load_off
btfss PORTC,6
call send_log
btfss PORTC,7
call set_display ;will alternate display current charging/load 
call show ;battery volts on top line,charging/load current bottom line.
goto main

;############################################################################################################## 
;find V for battery and current
find_V
;set a/d converter
;hardware set to put 1/4 of battery pd (voltage) on pin17, RA2, so have 0 -20V voltmeter

banksel ADCON1
movlw b'00010000' ;a/d conversion clock = clock /8
movwf ADCON1
banksel ADCON0
movlw b'00001011' ;left justify,Vdd as ref V,an2 (ra2) as input, a/d turned on
movwf ADCON0
call delayd1s ;acquisition time .1s arbitary but sure to be long enough R source < 10k
bsf ADCON0,GO ;start conversion
btfsc ADCON0,GO ;is conversion done?
goto $-1 ;no! test again
banksel ADRESH ;ADRESH is in bank0
movf ADRESH,w
movwf battV ;will only use 8 most sig bits, ignore ADRESL

;V for current from solar panel

;hardware set to put 0 - 5V on pin16, RC0, to represent a current of 0 - 5 amperes.

banksel ADCON1
movlw b'00010000' ;a/d conversion clock = clock /8
movwf ADCON1
banksel ADCON0
movlw b'00010011' ;left justify,Vdd as ref V,an4 (rc0) as input, a/d turned on
movwf ADCON0
call delayd1s ;acquisition time .1s arbitary but sure to be long enough R source < 10k
bsf ADCON0,GO ;start conversion
btfsc ADCON0,GO ;is conversion done?
goto $-1 ;no! test again
banksel ADRESH ;ADRESH is in bank0
movf ADRESH,w
movwf currentS ;will only use 8 most sig bits, ignore ADRESL




;V for current to load
;hardware set to put 0 - 5V on pin16, RC3, to represent a current of 0 - 5 amperes.

banksel ADCON1
movlw b'00010000' ;a/d conversion clock = clock /8
movwf ADCON1
banksel ADCON0
movlw b'00011111' ;left justify,Vdd as ref V,an7 (rc3) as input, a/d turned on
movwf ADCON0
call delayd1s ;acquisition time .1s arbitary but sure to be long enough R source < 10k
bsf ADCON0,GO ;start conversion
btfsc ADCON0,GO ;is conversion done?
goto $-1 ;no! test again
banksel ADRESH ;ADRESH is in bank0
movf ADRESH,w
movwf currentL ;will only use 8 most sig bits, ignore ADRESL


return


delayd1s ;4MHz clock
movlw .7
movwf outside
movlw .14
movwf middle
movlw .254
movwf inside
call delay
return
;##########################################################################################################


set_flags


movlw .135
subwf battV,0
btfss STATUS,C ;is battV < 13.5V
bsf charge_flag ;yes 
btfss STATUS,C ;no, check again
goto $+5 ;yes to load check 
movlw .140
subwf battV,0
btfsc STATUS,C ;is battV > = 14V
bcf charge_flag ;yes
nop ;no


movlw .120
subwf battV,0
btfsc STATUS,C ;is battV >= 12,0V
bsf load_flag ;yes
btfsc STATUS,C ;no
goto $+5
movlw .110
subwf battV,0
btfss STATUS,C ;is battV < 11,0V
bcf load_flag ;yes
nop ;no

return

;##########################################################################################################
;will alternate the state of the iflag each this routine is called
set_display

btfsc iflag
goto ciflag
bsf iflag
return
ciflag
bcf iflag
return

;##########################################################################################################


charger_on
btfsc PORTC,4
return
bsf PORTC,4
return

;############################################################################################################


charger_off
btfss PORTC,4
return
bcf PORTC,4
return

;###########################################################################################################


load_on
btfsc PORTC,5
return
bsf PORTC,5
return

;############################################################################################################3

load_off
btfss PORTC,5
return
bcf PORTC,5
return 

;############################################################################################################
; For voltmeter display 0 to 25.5 volts. A to D file (battV) 0 to 255 so each increment of 1 is 0.1V on display.
; For the ammeter display 0 to 5.1 amps. A to D file (current) 0 to 255 so each increment of 1 is 0.02A on display

show
; modify battV to get 3 digits V_tens,V_units and V_tenths
clrf V_tens
clrf V_units
clrf V_tenths
movf battV,w


tens movwf temp1
bcf STATUS,C
movlw .100
subwf temp1,0
btfsc STATUS,C ;a/d value <100?
incf V_tens,f ;no
btfsc STATUS,C ;yes
goto tens ;no
movf temp1,w ;yes


units movwf temp1 
bcf STATUS,C
movlw .10
subwf temp1,0 
btfsc STATUS,C ;a/d value <10?
incf V_units,f ;no
btfsc STATUS,C ;yes
goto units ;no
movf temp1,w ;yes

tenths movwf temp1
bcf STATUS,C
movlw .1
subwf temp1,0 
btfsc STATUS,C ;a/d value < 1?
incf V_tenths,f ;no
btfsc STATUS,C ;yes
goto tenths ;no
movf temp1,w ;yes

;now batt_V in 3 digits V_tens,V_units and V_tenths max 25.5V
clrf dispadd
call setadd

movf V_tens,w
call displaynumber
movf V_units,w
call displaynumber
movlw '.'
movwf datafile
call writedata
bcf writeflag
movf V_tenths,w
call displaynumber

movlw 'V'
movwf datafile 
call writedata
bcf writeflag


;modify current to give 3 digits 0 to 5.10A in increments of .02A file 0 to 255




clrf I_units
clrf I_tenths
clrf I_hths
btfsc iflag
goto $+3
movf currentS,w
goto $+2
movf currentL,w
;subwf
;subtracts W register from register f. If d is 
;0, the result is stored in the W
;register. If d is 1, the result is
;stored back in register f.
;C = 0 W > f
;C = 1 W = f


I_u movwf temp1
bcf STATUS,C
movlw .50
subwf temp1,0
btfsc STATUS,C ;battV>=50 ? (ie 1.00A) , 
incf I_units,f ;yes C= 1 if battV >=50
btfsc STATUS,C ;no C = 0 if battV<50
goto I_u
movf temp1,w

I_t movwf temp1 
bcf STATUS,C
movlw .5
subwf temp1,0
btfsc STATUS,C ;>10
incf I_tenths,f ;yes
btfsc STATUS,C ;no
goto I_t
movf temp1,w

I_h movwf temp1
bcf STATUS,C
movlw .1
subwf temp1,0
btfsc STATUS,C
incf I_hths,f
btfsc STATUS,C
goto I_h
rlf I_hths,f ; now in increments of .02


movlw .40 ;now on line 2 of display
movwf dispadd
call setadd

movf I_units,w
call displaynumber
movlw '.'
movwf datafile
call writedata
bcf writeflag
movf I_tenths,w
call displaynumber 
movf I_hths,w
call displaynumber
movlw 'A'
movwf datafile
call writedata
bcf writeflag
movlw ' '
movwf datafile
call writedata
bcf writeflag
movlw ' '
movwf datafile
call writedata
bcf writeflag
btfsc iflag
goto write_s
movlw 'S'
movwf datafile
call writedata
bcf writeflag
return
write_s
movlw 'L'
movwf datafile
call writedata
bcf writeflag
return
;####################################################################################################

displaynumber 
movwf offset ;move the value from w to 'offset' (w normally contains 
incf offset,f ;the digit value as loaded in above)
movlw low display ;for use in the look-up table to convert 
addwf offset,f ;from binary to ASCII. This method used allow
movlw high display ;crossing of memory page
btfsc STATUS,C
addlw .1
movwf PCLATH
movf offset,w
call display ;call the look up table
movwf datafile
call writedata ;write ASCII to the display. Remember display
bcf writeflag ;automatically steps to next character as set up

return
;###################################################################################################
;sets the lcd character address to the value in dispadd 
setadd 
movf dispadd,w
movwf datafile
bsf datafile,7
call writeinstr
bcf writeflag
return




;##############################################################################
;get ascii code for numbers
;ASCII look up table for numbers 
display 
movwf PCL
retlw b'00110000'
retlw b'00110001'
retlw b'00110010'
retlw b'00110011'
retlw b'00110100'
retlw b'00110101'
retlw b'00110110'
retlw b'00110111'
retlw b'00111000'
retlw b'00111001'
retlw '.'
retlw ' '
retlw '?'
retlw '?'
retlw '?'


writedata ;to the LCD

bsf regselect
;bcf readnotw
bsf dispe
movf datafile,w
movwf PORTB
nop
nop
nop
nop
bcf dispe 
call delay15ms ;this delay is a little longer than in the original(2,2,12)
btfsc writeflag
return
swapf datafile,f
bsf writeflag
goto writedata


writeinstr ;instruction to the LCD
bcf regselect
;bcf readnotw
bsf dispe
movf datafile,w
movwf PORTB
nop
nop
nop
nop
bcf dispe 
call delay15ms ;see note under write data
btfsc writeflag
return
swapf datafile,f
bsf writeflag
goto writeinstr

;#########################################################################################################
;name says it all
cleardisp
movlw b'00000001' ;clear display
movwf datafile
call writeinstr
bcf writeflag
call delay15ms
return 
;###############################################################################################################
delay1s
movlw .14
movwf outside
movlw .17
movwf middle
movlw .247
movwf inside
call delay
return


;#############################################################################################################

;General purpose delay routine. Pass to it parameters inside, middle and 
;outside to alter the delay
delay
movf outside,w
movwf outsidev
outsideloop
movf middle,w
movwf middlev
middleloop
movf inside,w
movwf insidev
insideloop
clrwdt
decfsz insidev,f
goto insideloop
decfsz middlev,f
goto middleloop
decfsz outsidev,f
goto outsideloop
return
;##############################################################################################################

delay15ms
;4MHz clock
movlw .3
movwf outside
movlw .6
movwf middle
movlw .207
movwf inside
call delay
return


;##############################################################################################################3


send_log

nop
return
;##############################################################################################################


ORG 0x2100 ; data EEPROM location
DE 1,2,3,4 ; define first four EEPROM locations as 1, 2, 3, and 4




END ; directive 'end of program'

 

 

 

 

 

BACK TO PEARS HOME PAGE