My first program

A place to discuss software and code that isn't automotive related. Free and open source preferred but not compulsory.
User avatar
longracing
LQFP112 - Up with the play
Posts: 140
Joined: Wed Jul 16, 2008 9:21 am
Location: NSW, Australia

My first program

Post by longracing »

I final made my first useful program last week.
I've been playing around with a PICKit-2 (USB programmer - about time) and the low pin count demo board that comes with a PIC16F690. I've been programming in Assembly and find myself able to understand most of what's going on :geek: ... either that or I'm starting to halucinate :D .

My first program was for a battery powered control box. It is a safety circuit to switch off the unit if the battery level gets too low via a transistor. It also uses a red LED, green LED and a piezo buzzer to indicate the battery level. The red LED flashes and buzzer sounds to give the operator about a minute warning that the unit is about to shutdown. That is so they can stop & save their video recording and get a DC power-supply or charger ready.
I still need to play with the levels that trigger the events but they will also depend on the voltage divider that I build into the final hardware. I tried porting it to an 8-pin PIC12F but have had a little bit of trouble with the outputs :( .

At work we have built control boxes with Lead-Acid batteries in the past but are building more with lithium cell packs for their reduced weight and size. With lithium cells there is a huge chance of a fire if they are allowed to fall below their minimum voltage level before recharge (do a search on youtube for lithium battery fires) and the fire cannot be extinguished!!!

In the future I might have a play with AVR's so I can use their free C compiler to learn that language.

If anyone is interested in the program let me know and I'll see if I can post it. Constructive critisism and useful tips would be welcome.
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: My first program

Post by Fred »

My only advice at 2am is to post it anyway and see what they say whether interested or not :-)

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
longracing
LQFP112 - Up with the play
Posts: 140
Joined: Wed Jul 16, 2008 9:21 am
Location: NSW, Australia

Re: My first program

Post by longracing »

Ok I'll have a go at posting it as it is only small.
Ultimately I'm working on using a MicroController to handle the charging, battery level indication and safety cut-off on the batt. powered control boxes at work.
Apparently plugging a charger in and pressing "Start" is asking too much of some people.

Here it is. Still very rough and the voltage check at the end of the shutdown loop isn't working properly.

Code: Select all

;**************************************************************
;         !!   Lithium Battery Safety Circuit   !!
;**************************************************************
;
; Date:		7 Jan 2009
; Author: 	S.L.
;
; Update History
; 
; Description: 	Messure Battery Voltage for LED indication
;				and Shutdown when Min. Voltage reached.
;				LED's & buzzer for level indication and
;				warning.
;
;
; Hardware Notes: PIC16F690
; 		10k ohm pot on RA0, var. from 5v to Gnd
;		for ADC input - voltage divider network in
;		working circuit.
;		PortC,0  	Power On
;		PortC,1		Green LED
;		PortC,2		Red LED
;		PortC,3		Buzzer
;
;*************************************************************


 #include <p16F690.inc>
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)

     cblock 0x20
Batt						; Battery value from ADC
dc1							; defines Delay counters
dc2
SDV							; define for Shutdown Value
BSDV						; define for Buzzer Shutdown
EndB						; define for end Buzzer
     endc


; !! This is the maths for the Voltages
;
; 	ResRat = 4700.0 / (4700.0 + 6800.0) 	; Res1 / (Res1 + Res2) 
;	       = 4700 / 11500
;		   = 0.4087
; Resistor divider network ratio
; Resistor divider used to bring input (batt) voltage
; down to compare with 5.0 Volts (Vdd).
;
; 	MinimumV = ResRat * 9.0						; ResRat * Minimum Voltage
;		     = 0.4087 * 9.0
;		     = 3.678
; Variable	MinV			; MinV = (MinimumV / Vdd) * 255
;			[=187]
;*******************************************************************
; 	Low Voltage = ResRat * 9.5						; ResRat * Low Voltage
; 		 		= 0.4087 * 9.5
;	     		= 3.883
; LowV			; LowV = (Low Voltage / Vdd) * 255
;			[=198]
;**********************************************************************
; 8-bit gives approx. 0.05 Volt resolution.



     org 0
Start:
    bsf		STATUS,RP0     	; select Register Page 1
	movlw	b'11110000'
	movwf	TRISC			; make C3,2,1,0 output
	movlw	b'00001111'	
	movwf	TRISB			; make B7,6,5,4 output
    movlw   0x10            ; A2D Clock Fosc/8
    movwf   ADCON1
    bcf     STATUS,RP0     	; back to Register Page 0
     bcf       STATUS,RP0   ; address Register Page 2
     bsf       STATUS,RP1     
     movlw     0xFF         ; all Port A pins Analoga
     movwf     ANSEL
     bcf       STATUS,RP0   ; address Register Page 0
     bcf       STATUS,RP1
     movlw     0x01
     movwf     ADCON0       ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module
	clrf	PORTB	
	clrf	PORTC 
	movlw	.105			; load value for shutdown
	movwf	SDV
	movlw	.020			; load value for buzzer shutdown
	movwf	BSDV

Main:
     nop                    ; wait 5uS for A2D amp to settle and capacitor to charge.
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     bsf       ADCON0,GO    ; start conversion
     btfss     ADCON0,GO    ; this bit will change to zero when the conversion is complete
     goto      $-1

; Check Batt above minimum voltage
	movf	ADRESH,w
	movwf	Batt			; put ADC in Batt
	bcf		STATUS,C		; prep for compare
	movlw	.187			; load variable for minimum Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= Minimum Voltage  						
	goto	Power_on		; goto Power_on if Voltage > MinV
	goto	Shutdown		

Power_on:
	bsf		PORTC,0			; turn on POWER
	movlw	.105			; load value for shutdown
	movwf	SDV
	movlw	.020			; load value for buzzer shutdown
	movwf	BSDV

; test if batt voltage is above "Low" level.
	bcf		STATUS,C		; prep for compare
	movlw	.198			; load variable for "Low" Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= Low Voltage 
	goto	Power_good		; goto Power_good if Voltage > LowV
	goto	Power_low

Power_good:
	movlw	b'00000011'		; Power ON, green LED ON, red LED OFF
	movwf	PORTC
	goto	Main

Power_low:
	movlw	b'00000101'		; Power ON, red LED ON, green LED OFF
	movwf	PORTC
	goto	Main

Shutdown:
	movlw	b'00001101'		; turn on Buzzer, Red LED and Power.
	movwf	PORTC
	call	Delay
	movlw	b'00000001'		; Power ON, turn off Buzzer & Red LED. 
	movwf	PORTC
	call	Delay
	call	Delay
	decfsz	BSDV			; test times shutdown has looped
	goto	Main
NoBuzzer
	movlw	b'00000101'		; turn off Buzzer, Red LED and Power ON.
	movwf	PORTC
	call	Delay
	movlw	b'00000001'		; Power ON, turn off Buzzer & Red LED. 
	movwf	PORTC
	call	Delay
	call	Delay
	decfsz	SDV				; test times shutdown has looped
	goto	NoBuzzer
; Check if power is still below minimum
     nop                    ; wait 5uS for A2D amp to settle and capacitor to charge.
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     bsf       ADCON0,GO    ; start conversion
     btfss     ADCON0,GO    ; this bit will change to zero when the conversion is complete
     goto      $-1

	movf	ADRESH,w
	movwf	Batt			; put ADC in Batt
	bcf		STATUS,C		; prep for compare
	movlw	.187			; load variable for minimum Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= Minimum Voltage  
	goto	Power_on
	clrf	PORTC			; Shutdown ALL
; Shutdown and buzzer for time.
	bsf		PORTC,3			; buzzer ON
	movlw	.008
	movwf	EndB			; load buzzer shutdown value
	call	Delay
	decfsz	EndB
	goto	$-2
	clrf	PORTC			; Shutdown ALL	
	goto	$				; Stop Here!!!!!!!!!!!!!!!!!!!!!!

Delay
; delay loops
; movlw .xxx value determines delay
  movlw	.065					
  movwf dc2					; puts value in delay2 counter
  clrf	dc1

delay1  					; loop 1
  nop
  decfsz 	dc1,f
  goto 		delay1
delay2  					; loop2
  nop
  decfsz	dc1,f
  goto		delay2
  decfsz	dc2,f
  goto		delay1
  return
	
 end
User avatar
longracing
LQFP112 - Up with the play
Posts: 140
Joined: Wed Jul 16, 2008 9:21 am
Location: NSW, Australia

Re: My first program

Post by longracing »

I've updated the program a bit.
Added an annoying beeping that doesn't stop until the unit is switched off. I did this because someone left a unit on at work and completely discharged the battery, now being a lithium battery it cannot be recharged without bursting into flames. Bit of an expensive paperweight.

I also had a play at porting it to a PIC12F again if anyone was interested but have had trouble programming it with a PIC-Kit 2.
I did do a circuit design for the PIC12F with PCB-Express, if anyone wants a look at let me know.

Here's the updated code,

Code: Select all

;**************************************************************
;         !!   Lithium Battery Safety Circuit   !!
;**************************************************************
;
; Date:		7 Jan 2009
; Author: 	S.Long
;
; Description: 	Messure Battery Voltage for LED indication
;				and Shutdown when Min. Voltage reached.
;				LED's & buzzer for level indication and
;				warning.
;
; Revision History:
;	22/01/09	Added time delay and beep loop at end of shutdown
;	27/01/09	Added test for DC power in beep loop. Program will
;				 go back to the start if DC power is connected or
;				 battery is charged.
;
;
; Hardware Notes: PIC16F690
; 		10k ohm pot on RA0, var. from 5v to Gnd
;		for ADC input - voltage divider network in
;		working circuit.
;		PortC,0  	Power On, transistor.
;		PortC,1		Green LED
;		PortC,2		Red LED
;		PortC,3		Buzzer
;
;*************************************************************


 #include <p16F690.inc>
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)

     cblock 0x20
Batt						; Battery value from ADC
dc1							; defines Delay counters
dc2
SDV							; define for Shutdown Value
BSDV						; define for Buzzer Shutdown
BLP							; define for Beep loop
     endc

; !! This is the maths for the Voltages - Needs adjusting
;
; 	ResRat = 4700.0 / (4700.0 + 6800.0) 	; Res1 / (Res1 + Res2) 
;	       = 4700 / 11500
;		   = 0.4087
; Resistor divider network ratio
; Resistor divider used to bring input (batt) voltage
; down to compare with 5.0 Volts (Vdd).
;*********************************************************************
; 	MinimumV = ResRat * 9.0					; ResRat * Minimum Voltage
;		     = 0.4087 * 9.0
;		     = 3.678
; Variable	MinV			; MinV = (MinimumV / Vdd) * 255
;			[=187]
;*********************************************************************
; 	Low Voltage = ResRat * 9.5				; ResRat * Low Voltage
; 		 		= 0.4087 * 9.5
;	     		= 3.883
; LowV			; LowV = (Low Voltage / Vdd) * 255
;			[=198]
;*********************************************************************
; 	getting_low Voltage = ResRat * 9.75				; ResRat * Low Voltage
; 		 				= 0.4087 * 9.75
;	     				= 3.985
; getting_lowV			; LowV = (getting_low Voltage / Vdd) * 255
;			[=203]
;*********************************************************************
; 8-bit gives approx. 0.05 Volt resolution.
;*********************************************************************


     org 0
Start:
    bsf		STATUS,RP0     	; select Register Page 1
	movlw	b'11110000'
	movwf	TRISC			; make C3,2,1,0 output
    movlw   0x10            ; A2D Clock Fosc/8
    movwf   ADCON1
    bcf     STATUS,RP0     	; back to Register Page 0
     bcf       STATUS,RP0   ; address Register Page 2
     bsf       STATUS,RP1     
     movlw     0xFF         ; all Port A pins Analoga
     movwf     ANSEL
     bcf       STATUS,RP0   ; address Register Page 0
     bcf       STATUS,RP1
     movlw     0x01
     movwf     ADCON0       ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module
	movlw	b'00000110'		; flash LEDs to show "Start"
	movwf	PORTC
	call	Delay	
	clrf	PORTC 			; initialise output setup
	movlw	.105			; load value for shutdown
	movwf	SDV
	movlw	.020			; load value for buzzer shutdown
	movwf	BSDV

Main:
     nop                    ; wait 5uS for A2D amp to settle and capacitor to charge.
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     nop                    ; wait 1uS
     bsf       ADCON0,GO    ; start conversion
     btfss     ADCON0,GO    ; this bit will change to zero when the conversion is complete
     goto      $-1

; Check Batt above minimum voltage
	movf	ADRESH,w
	movwf	Batt			; put ADC in Batt
	bcf		STATUS,C		; prep for compare
	movlw	.187				; load variable for minimum Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= Minimum Voltage  						
	goto	Power_on		; goto Power_on if Voltage > MinV
	goto	Shutdown		

Power_on:
	bsf		PORTC,0			; turn on POWER
	movlw	.105				; load value for shutdown
	movwf	SDV
	movlw	.020				; load value for buzzer shutdown
	movwf	BSDV

; test if batt voltage is above "Low" level.
	bcf		STATUS,C		; prep for compare
	movlw	.198				; load variable for "Low" Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= Low Voltage 
	goto	$+2				; goto $+2 if Voltage > LowV
	goto	Power_low

	nop
; test if batt voltage is above "getting_low" level.
	bcf		STATUS,C		; prep for compare
	movlw	.203			; load variable for "getting_low" Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= getting_lowow Voltage 
	goto	Power_good		; goto Power_good if Voltage > getting_lowV
	goto	Power_getting_low

Power_good:
	movlw	b'00000011'		; Power ON, green LED ON, red LED OFF
	movwf	PORTC
	goto	Main

Power_getting_low
	movlw	b'00000111'		; Power ON, green LED ON, red LED ON
	movwf	PORTC
	goto	Main

Power_low:
	movlw	b'00000101'		; Power ON, red LED ON, green LED OFF
	movwf	PORTC
	goto	Main

Shutdown:
	movlw	b'00001101'		; turn on Buzzer, Red LED and Power.
	movwf	PORTC
	call	Delay
	movlw	b'00000001'		; Power ON, turn off Buzzer & Red LED. 
	movwf	PORTC
	call	Delay
	call	Delay
	decfsz	BSDV			; test times shutdown has looped
	goto	Main
NoBuzzer
	movlw	b'00000101'		; turn off Buzzer. Red LED and Power ON.
	movwf	PORTC
	call	Delay
	movlw	b'00000001'		; Power ON, turn off Buzzer & Red LED. 
	movwf	PORTC
	call	Delay
	call	Delay
	decfsz	SDV				; test times shutdown has looped
	goto	NoBuzzer
	clrf	PORTC			; Shutdown ALL!!!!

; Added 22 Jan 2009 - Revision
; Shut all down, wait for time delay, Beep 4 times, then loop round
BeepLoop:
	call	BuzzOn
	call	BuzzOff
	call	BuzzOn
	call	BuzzOff
	call	BuzzOn
	call	BuzzOff
	call	BuzzOn
	call	BuzzOff
	call	Test_Pow		; test if DC power applied
	clrf	BLP	
	call	Delay
	decfsz	BLP	
	goto	$-2				; loop 255 times, approx. 1min delay
	goto	BeepLoop		; keep looping until unit is switched OFF!!!
	
	
BuzzOn
	bsf		PORTC,3			; turn buzzer ON
	call	Delay
  return
BuzzOff
	bcf		PORTC,3			; turn buzzer OFF
	call	Delay
  return

Test_Pow
; test if DC power has been applied, reset to main loop if it
; is above the required level.
  	nop						; allow for AD cap. to charge
  	nop
  	nop
  	nop 
  	nop
  	nop
  	nop
     bsf       ADCON0,GO    ; start conversion
     btfss     ADCON0,GO    ; this bit will change to zero when the conversion is complete
     goto      $-1
; Check Batt above required voltage
	movf	ADRESH,w
	movwf	Batt			; put ADC in Batt
	bcf		STATUS,C		; prep for compare
	movlw	.203			; load variable for required Voltage
	subwf	Batt,w
	btfsc	STATUS,C		; skip next if Batt <= required Voltage  						
	goto	Start			; goto Start if Battery Voltage > required
  return

Delay
; delay loops
; movlw .xxx value determines delay
  movlw	.065					
  movwf dc2					; puts value in delay2 counter
  clrf	dc1
delay1  					; loop 1
  nop
  decfsz 	dc1,f
  goto 		delay1
delay2  					; loop2
  nop
  decfsz	dc1,f
  goto		delay2
  decfsz	dc2,f
  goto		delay1
  return
	
 end
I've also attached a flowchart of the program.
Attachments
Lithium Safety Circuit.xls
A flowchart of the Lithium Safety Circuit program
(23 KiB) Downloaded 816 times
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: My first program

Post by Fred »

I've moved this to the new software part of the forum. I hope you don't mind.

Fred.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
longracing
LQFP112 - Up with the play
Posts: 140
Joined: Wed Jul 16, 2008 9:21 am
Location: NSW, Australia

Re: My first program

Post by longracing »

Well I have made a few boards with this code (updated a bit) and they seem to work quite well. I had to make a small voltage logger using the Arduino to profile the Lithium packs discharge curve, then I was able to set the trigger values at the best points.
Here's one I prepared early,
Image
PCB was made by PCB Express.

Now I'm using Kicad to combine it with another board & trying to rewrite the code in C & add a battery type select jumper &....
I finally got a C-code program working with the PIC uC, hopefully I can get to a good enough level to contribute to FreeEMS in the next couple of months.

Also made a PWM H-bridge motor controller using the Mini-Arduino, an SN754410, a 16x2 LCD and a Pot. Uses a pot or joystick to vary the motor speed in forward & reverse, has LCD display showing direction(fwd/rev), percentage throttle and a "Power bar". Hoping to develop this more with a different uC and MOSFETs to replace the current Robotic Controllers we build at work. That's another one for the long list of projects for work.
MotoFab
1N4001 - Signed up
Posts: 307
Joined: Thu May 29, 2008 1:23 am
Location: Long Beach CA

Re: My first program

Post by MotoFab »

Cool beans. I like coding in assembly, seems natural to me. Bit I do want to learn C. Did you by chance use this book? It's based on the PICkit development kit that you were using.

Beginner's Guide To Embedded C Programming: Using The Pic Microcontroller And The Hitech Picc-Lite C Compiler
By Chuck Hellebuyck
http://www.amazon.com/Beginners-Guide-E ... 115&sr=8-1
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: My first program

Post by Fred »

Keep up the good work, mate!
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
longracing
LQFP112 - Up with the play
Posts: 140
Joined: Wed Jul 16, 2008 9:21 am
Location: NSW, Australia

Re: My first program

Post by longracing »

It's slow going but making headway (as long as my brain doesn't fry first).

I started several months ago with "Programming and Customizing the PIC Microcontroller" by Mike Predko. He mainly deals with Assembly. About halfway through the book, when I got the PICKit-2 to play with, it all started to make sense.
Using the Arduino was a good starting point for learning 'C' and then I went back to the PIC uC. I had a lot of trouble until I figured out that the Hi-Tech examples were using an external MCLR pull up. When I changed the config statement it all started working (gave me a couple of months of frustration). I've got a few other books on C-code and other microcontrollers that I'm browsing as well. I got the UBW32 to play with but it needs the PICKit-3 to program (3.3V uC instead of 5V).

Here's a pic of some joystick testing I did with the Arduino and 16x2 LCD. Considering using something similar, different joysticks and a different microcontroller with more Inputs/Outputs for the robotic controller. You can see the Joystick outputs as "powerbars" or percentages on the LCD. I gutted the old RC transmitter and wired it with +5Volt & Gnd Rails, using a single wire for each pot output signal and the Trainer switch as the Reset.
Image


One last thing does anyone have any suggestions for changing the code for the safety circuit?
I have put #defines in but now I am trying to make a "battery type select" by a jumper. It uses one of the inputs with a weak pull-up being open or jumpered to ground. This is going to be used to change the battery values to a set for lithium type batteries or a set for SLA batteries as their voltage discharge profile are different.
User avatar
jharvey
1N4001 - Signed up
Posts: 1607
Joined: Tue Jun 10, 2008 5:17 pm

Re: My first program

Post by jharvey »

There are lots of techniques for making code more rugged. One technique is to fill the unused space with a jump command that jumps to a chunk of code that will log the error, perhaps then reset. Another is to build your system such that a reset or mild power supply pulse at any time will reboot to functioning code with out causing problems. Then have a forced reset every so often. This prevents issues with mild supply issues. I've also seen confirmations that when you set a pin high, it has another port that reads the pin to confirm it went high. This helps identify a blown port, ect. I've also seen a custom OS that divided tasks into several sections, and had a timer that would force a change from one set of code to another. One of the chunks of code was for error checking process verification.

Any how lots of potential options for ruggedizing code, any particular concerns of things that may go wrong?
Post Reply