; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.

; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.

; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

; Panteltje hcs-0.2
; copyright Jan Panteltje 2007-always
; integer and floating point math copyright Microchip, some other routines copyright others, my part is GPL.
;
;
; I have written a small temperature controller for PIC16F690
; It uses LM135 or similar Kelvin sensors.
; It is quite universal as it also displays voltage.
; It has a real time clock (as long as it has power), runs             
; from the PIC internal 8MHz oscillator, and seems quite accurate,
; The soft has a serial 19200 Baud, 8 bits no parity interface, and accepts
; the following commands:
;
; unnENTER	sets hour
; mnnENTER    sets minute
; tnnnENTER   sets temperature set point in Celsius, is saved in EEPROM
; annENTER    displays AD channel nn count
; vnnENTER    displays AD channel nn converted to voltage
; cnnENTER    displays AD channel nn converted to Celsius
; s           displays temp set point
; GnnnENTER   sets clock calibration, timer1 reload low byte, use 175 for nominal, is saved in EEPROM
; g           displays clock calibration (timer1 reload low byte)
; I			  calibrate inside temp sensor, use 17 as default, 16 is one degree Celcius higher, 18 one lower, value is saved in EEPROM
; i           print inside calibration value
; O			  calibrate outside temp sensor, use 17 as default, 16 is one degree Celcius higher, 18 one lower, value is saved in EEPROM
; o           print outside calibration value
;                 * AFTER FIRST POWER ON type:  G175ENTER, I17ENTER, O17ENTER, t21ENTER to program the EEPROM, then H to start the control loop again *
; The above commands exit the control loop (control loop is on by default on power on).
;
;
; H           starts control loop (again)
; h           help message tells you to read README, there is no README yet :-)
; F           loops as fast as ADC can be read (for test).
; f           ADC is read once per minute, this is the default.
;
; Very precise control of room temperature is achieved by doing an test against set point
; every 60 seconds, this is ONLY intended to switch an electric heater (via a triac optocoupler),
; probably too fast for something that runs on oil or gas.
;
; There is a LED output 'frost alarm' (so you can tap the water if needed).
;
; This control is a bit more pleasant then the normal bi-metal thermostats in the electric
; heaters, those have an hysteresis of several degrees C, this less then one.
; I have enabled 2 analog channels here only, AN5 and AN7.
; If you need more analog inputs you need to set the related bits in TRISA / TRISB / TRISC,
; and ANSEL and ANSELH (about line 902 in the code).
; There are too many banksel instructions, and I likely forgot some.
; The math is done in integer, the floating point lib (copyright Microchip) is defined out.



; CODE IS FOR GPASM, may work on MPLAB too.


; set this to your supply voltage (use LM317 for example, ADC uses supply as reference).
; Vdd PIC measured 5.06V
; #define VREF	5060	; mV
#define VREF_H	D'19'	; high byte
#define VREF_L	D'196'	; low byte


TRUE    equ     1
FALSE   equ     0
MSB		equ		7
Mode16  equ     TRUE            ; Change this to FALSE if a 32 bit product is desired for F_mpy routine.
SIGNED  equ     FALSE           ; Set This To 'TRUE' if the routines
;                               ; for Multiplication & Division needs
;                               ; to be assembled as Signed Integer
;                               ; Routines. If 'FALSE' the above two
;                               ; routines ( D_mpy & D_div ) use
;                               ; unsigned arithmetic.



; NOTE : If one needs to get a 32 bit product( & an 8 bit exponent ),
;        re assemble the program after changing the line " Mode16 equ TRUE"
;        to " Mode16  equ  FALSE ".                                        
;        If this option is chosen, then the 32 bit result is returned in
;        ( ACCbHI, ACCbLO, ACCcHI, ACCcLO ) and the 8 bit exponent in EXPb.
;        This method ( with " Mode16 equ FALSE " ) is NOT Recommended.


; for second jump table, commands with numeric arguments.
#define COMMAND_OFF									D'0'
#define COMMAND_READ_ADC							D'1'
#define COMMAND_TEMP_SETPOINT						D'2'
#define COMMAND_PRINT_SETPOINT						D'3'
#define COMMAND_SET_PWM								D'4'
#define COMMAND_PRINT_MILLIVOLTS					D'5'
#define COMMAND_PRINT_TEMPERATURE					D'6'
#define COMMAND_HCS									D'7'					
#define COMMAND_SET_MINUTES							D'8'
#define COMMAND_SET_HOURS							D'9'
#define COMMAND_FAST_MODE							D'10'
#define COMMAND_SLOW_MODE							D'11'
#define COMMAND_CALIBRATE_CLOCK						D'12'
#define COMMAND_PRINT_CLOCK_CALIBRATION				D'13'
#define COMMAND_OUTSIDE_TEMP_CALIBRATION			D'14'
#define COMMAND_PRINT_OUTSIDE_TEMP_CALIBRATION		D'15'
#define COMMAND_INSIDE_TEMP_CALIBRATION				D'16'
#define COMMAND_PRINT_INSIDE_TEMP_CALIBRATION		D'17'


#define MODE_OFF									D'0'
#define MODE_READ_ADC								D'1'
#define MODE_PRINT_SETPOINT							D'2'
#define MODE_PRINT_MILLIVOLTS						D'3'
#define MODE_PRINT_TEMPERATURE						D'4'
#define MODE_HCS									D'5'
#define MODE_CALIBRATE_CLOCK						D'6'
#define	MODE_PRINT_CLOCK_CALIBRATION				D'7'
#define MODE_PRINT_OUTSIDE_TEMP_CALIBRATION			D'8'
#define MODE_PRINT_INSIDE_TEMP_CALIBRATION			D'9'

; ** NOTE:                                                                            **

; define config fuses
; IF YOU WANT TO RUN VERIFY, BETTER HAVE COPY PROTECTION OFF ;-)
; Internal OSC, OSC clock output on pin 3 (RA4,AN3,T1G,OSC2,CLKOUT).
	__CONFIG  _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTOSC

; when !MRCLRE is asserted in INTOSC or RC mode, the internal clock oscillator is disabled.


; include PIC register definitions, and some macros
	PROCESSOR	p16f690
	include	<p16f690.inc>
;	include	"picmac.h"

; IO pin bit assignment PORTA, PORTB, PORTC
; PORTA


; PORTB

; PORTC
HEATER_OUT		equ	0			; PORTC RC0 pin 16			heater control, 0 is active
OUTSIDE_TEMP	equ 1			; PORTC RC1 pin 15	AN5 	outside temperature LM135
FROST_ALARM		equ	2			; PORTC RC2 pin 14			frost alarm LED, 0 is on
INSIDE_TEMP		equ 3			; PORTC RC3 pin 7	AN7		inside temperature LM135
;				equ	4			; PORTC RC4 pin 6	
;				equ	5			; PORTC RC5 pin 5
;				equ	6			; PORTC RC6 pin 8
;				equ	7			; PORTC RC7 pin 9

; define register file variables
; start at 0x20 hex, 32 dec, total 256 bytes

; 0x20 - 0x7f in bank 0						;  32 - 127
; 0x70 - 0x7f in each bank the same			; 112 - 127
; 0xa0 - 0xef in bank 1						; 160 - 239
; 0x120 - 0x16f in bank 2					; 288 - 376


flags						equ	D'32'			; flags
delay_count1				equ	D'33'			; 1ms delay
delay_count2				equ	D'34'
RESULTLO					equ	D'35'
RESULTHI					equ	D'36'
tx_timeout					equ D'37'
flags1						equ	D'38'
temp1						equ	D'39'
count						equ	D'40'
temp_h						equ	D'41'
temp_l						equ	D'42'
temp						equ D'43'		; temp for binary to BCD
bin							equ	D'44'
H_byte						equ D'44'		; bin 16 in for binary to BCD
L_byte						equ D'45'		; bin 16 in for binary to BCD	
bcd							equ	D'46'
R0							equ D'46'		; BCD digit 5 right justified
R1							equ D'47'		; BCD digit 4 and 3
R2							equ D'48'		; BCD digit 2 and 1
ii							equ	D'49'
timer1_reload_l				equ	D'50'		; saved in EEPROM clock calibration
outside_temp_calibration	equ	D'51'
inside_temp_calibration		equ	D'52'
temp_correction				equ	D'53'

;pti						equ	D'50'
;pto						equ	D'51'
;temp_w						equ	D'52'
;temp_s						equ	D'53'
;temp2						equ	D'54'

status_display_timer		equ	D'55'
command						equ	D'56'
digit_in					equ	D'57'
digit_cnt					equ	D'58'
temp3						equ	D'59'
value						equ	D'60'
flags2						equ D'61'
flags3						equ	D'62'
pwm_pulse_width				equ	D'63'
analog_select				equ	D'64'
minutes						equ	D'65'
seconds_5					equ	D'66'
seconds						equ	D'67'
ana0_h						equ	D'68'
ana0_l						equ	D'69'
ana1_h						equ	D'70'
ana1_l						equ	D'71'
ana2_h						equ	D'72'
ana2_l						equ	D'73'
ana3_h						equ	D'74'
ana3_l						equ	D'75'
ana4_h						equ	D'76'
ana4_l						equ	D'77'
ana5_h						equ	D'78'
ana5_l						equ	D'79'
ana6_h						equ	D'80'
ana6_l						equ	D'81'
ana7_h						equ	D'82'
ana7_l						equ	D'83'
ana8_h						equ	D'84'
ana8_l						equ	D'85'
ana9_h						equ	D'86'
ana9_l						equ	D'87'
ana10_h						equ	D'88'
ana10_l						equ	D'89'
ana11_h						equ	D'90'
ana11_l						equ	D'91'
pri_h						equ	D'92'
pri_l						equ	D'93'
pri_cnt						equ	D'94'
fsr_save					equ	D'95'
fsr_save2					equ	D'96'
mode						equ	D'97'
ad_h						equ	D'98'
ad_l						equ	D'99'
celcius_h					equ	D'100'
celcius_l					equ	D'101'
temp_s_h					equ	D'102'
temp_s_l					equ	D'103'
vref_h						equ	D'104'				; to be saved in EEPROM
vref_l						equ	D'105'				; to be saved in EEPROM
millivolt_h					equ	D'106'
millivolt_l					equ	D'107'
kelvin_h					equ	D'108'
kelvin_l					equ	D'109'
temp_int					equ	D'110'
hours						equ	D'111'

; SAME IN ALL BANKS 112 - 127
temp_setpoint				equ	D'112'				; to be saved in EEPROM
eeprom_address				equ	D'113'
eeprom_data					equ	D'114'

ACCaLO						equ	D'115'
ACCaHI						equ	D'116'
ACCbLO						equ	D'117'
ACCbHI						equ	D'118'
ACCcLO						equ	D'119'
ACCcHI						equ	D'120'
ACCdLO						equ	D'121'
ACCdHI						equ	D'122'
sign						equ	D'123'
s_pclath					equ	D'124'

;EXPa						equ	D'124'
;EXPb						equ	D'125'

offset						equ	D'125'
temp_w						equ	D'126'
temp_s						equ	D'127'


; define flags
FAST_MODE_FLAG				equ	D'1'


; define  flags1
ONE_MINUTE_FLAG				equ	D'0'
NEGATIVE_TEMPERATURE_FLAG	equ	D'1'	
FIRST_ZERO_SUPPRESSED_FLAG  equ D'2'
HAVE_INTERRUPT_FLAG			equ	D'4'
EEPROM_WRITE_ERROR_FLAG     equ D'5'
TEST_LED_ON_FLAG			equ	D'6'
ONE_SECOND_FLAG				equ	D'7'

; define flags

; macros to save and restore W and status register in interrupt.
save_w_stat macro
	movwf   temp_w
	swapf   STATUS,W
	clrf	STATUS			; extra force bank 0 clears IRP, RP1, RP0
	movwf   temp_s
	movfw	PCLATH
	movwf	s_pclath
	endm

restore_w_stat macro
	movfw	s_pclath
	movwf	PCLATH
	swapf   temp_s,W
	movwf   STATUS
	swapf   temp_w,F
	swapf   temp_w,W
	endm

; code start
	org	0
	goto	reset_entry

	org	4
; interrupt entry point
; 8 MHz internal OSC
; OPTION_REG is 0xff at power up!

; do interrupt processing here

	save_w_stat					; save W and status

	banksel	0

; what interrupt?
; test for timer 1 interrupt
test_timer1_interrupt:
;	banksel	PIR1				; bank 0
	btfss	PIR1, TMR1IF
	goto	test_rx_interrupt	

; decrement seconds / 5, if 0 reload 5, decrement seconds.
	bcf	flags1, ONE_SECOND_FLAG
	decfsz	seconds_5
	goto	in_5

	bsf	flags1, ONE_SECOND_FLAG
	movlw	D'5'
	movwf	seconds_5

; increment seconds
	incf	seconds
; test 60 seconds	
	movlw	D'60'
	subwf	seconds, w
	btfss	STATUS, Z
	goto	in_5

; one minute

#ifdef TEST_LED
; test led toggle
	btfsc	flags1, TEST_LED_ON_FLAG
	goto	test_led_off
	bcf	PORTC, FROST_ALARM				; test LED on
	bsf	flags1, TEST_LED_ON_FLAG

	goto one_minute

test_led_off:
	bsf	PORTC, FROST_ALARM				; test LED off
	bcf	flags1,	TEST_LED_ON_FLAG
; end test led toggle
#endif
		; TEST_LED

one_minute:
	clrf	seconds	
	incf	minutes

	bsf	flags1, ONE_MINUTE_FLAG			; to be checked and cleared in main
; test 60 minutes
	movlw	D'60'
	subwf	minutes,	w
	btfss	STATUS,	Z	
	goto	in_5

	clrf	minutes
	incf	hours
; test 24 hours
	movlw	D'24'
	subwf	hours,	w
	btfss	STATUS, Z
	goto	in_5

	clrf	hours

in_5:

; reload 65535 - 50000 makes 5Hz = 200mS

; Calibrate clock speed here
;	banksel	TMR1H				; bank 0 65535 - 50000 = 15535 reload (upcounter int on overflow), makes 60 175
	movlw	D'60'
	movwf	TMR1H

;	movlw	D'175'
	movfw	timer1_reload_l
	movwf	TMR1L

;	banksel	T1CON				; in bank 0
	bsf	T1CON,	T1CKPS1			; 11 = 1:8 prescaler 
	bsf	T1CON,	T1CKPS0			; 

;	banksel	0
;	goto	int_end
	
test_rx_interrupt:
;	banksel	PIR1
;	btfss	PIR1, RCIF	
;	goto	int_end


; read rx status	
; test framing error
	banksel	RCSTA
	btfss	RCSTA,	FERR
	goto	test_overrun
; framing error
	goto	reset_rx_circuit

test_overrun:
	btfss	RCSTA,	OERR
	goto	get_rx_char
; overrun error

reset_rx_circuit:
; clear error flags
	bcf	RCSTA,	FERR
	bcf	RCSTA,	OERR
; restart rx
	bcf	RCSTA,	CREN
	bsf	RCSTA,	CREN
;	goto	int_end					; discard character

; send Bell audio signal immediatly
	movlw	D'7'					; ring bell
	call	tx_w
	goto	int_end

get_rx_char:
; test_serial_port_interrupt
	btfss	PIR1,	RCIF				; test if serial port interrupt
	goto	int_end

; have serial char in RCREG
;	movfw	RCREG
; TEST echo for TEST	
;	call tx_w


	movlw	D'13'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	cr_command

	movlw	'a'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	read_adc_command

	movlw	'c'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_temperature_command

	movlw	'F'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	fast_mode_command

	movlw	'f'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	slow_mode_command

	movlw	'g'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_clock_calibration_command

	movlw	'G'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	calibrate_clock_command

	movlw	'H'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	hcs_command

	movlw	'h'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_help

	movlw	'I'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	inside_temp_calibration_command

	movlw	'i'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_inside_temp_calibration

	movlw	'm'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	set_minutes_command

	movlw	'O'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	outside_temp_calibration_command

	movlw	'o'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_outside_temp_calibration

	movlw	'p'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	set_pwm_command

	movlw	's'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_setpoint_command

	movlw	't'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	temp_setpoint_command

	movlw	'u'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	set_hours_command

	movlw	'v'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	print_millivolts_command

	movlw	'0'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'1'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'2'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'3'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'4'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'5'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'6'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'7'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'8'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	movlw	'9'
	subwf	RCREG,	W
	btfsc	STATUS, Z
	goto	process_digits_command

	goto	int_end


cr_command:
; If zero digits were entered, do nothing

	movlw	COMMAND_OFF
	subwf	digit_cnt,	W
	btfsc	STATUS,	Z						; if zero digits do nothing
	goto	int_end				

	movlw	COMMAND_READ_ADC
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_read_adc_command

	movlw	COMMAND_TEMP_SETPOINT
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_temp_setpoint_command

	movlw	COMMAND_SET_PWM
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_pwm_command

	movlw	COMMAND_PRINT_MILLIVOLTS
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_print_millivolts_command

	movlw	COMMAND_PRINT_TEMPERATURE
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_print_temperature_command
	
	movlw	COMMAND_SET_MINUTES
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_set_minutes_command

	movlw	COMMAND_SET_HOURS
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_set_hours_command

	movlw	COMMAND_CALIBRATE_CLOCK
	subwf	command,	W
	btfsc	STATUS, Z
	goto	end_calibrate_clock_command

	movlw	COMMAND_OUTSIDE_TEMP_CALIBRATION
	subwf	command,	W
	btfsc	STATUS,	Z
	goto	end_outside_temp_calibration_command

	movlw	COMMAND_INSIDE_TEMP_CALIBRATION
	subwf	command,	W
	btfsc	STATUS,	Z
	goto	end_inside_temp_calibration_command


	goto	int_end


; these commands have no numeric argument
print_help:
	call	help_pri
	goto	int_end_clr

print_setpoint_command:
	movlw	COMMAND_PRINT_SETPOINT
	movwf	command
	movlw	MODE_PRINT_SETPOINT
	movwf	mode
	goto	int_end_clr

hcs_command:
	movlw	COMMAND_HCS
	movwf	command
	movlw	MODE_HCS
	movwf	mode
	goto	int_end_clr

slow_mode_command:
	bcf		flags, FAST_MODE_FLAG
	goto	int_end_clr

fast_mode_command:
	bsf		flags,	FAST_MODE_FLAG
	goto	int_end_clr

print_clock_calibration_command:
	movlw	COMMAND_PRINT_CLOCK_CALIBRATION
	movwf	command
	movlw	MODE_PRINT_CLOCK_CALIBRATION
	movwf	mode
	goto	int_end_clr

print_inside_temp_calibration:
	movlw	COMMAND_PRINT_INSIDE_TEMP_CALIBRATION
	movwf	command
	movlw	MODE_PRINT_INSIDE_TEMP_CALIBRATION
	movwf	mode
	goto	int_end_clr

print_outside_temp_calibration:
	movlw	COMMAND_PRINT_OUTSIDE_TEMP_CALIBRATION
	movwf	command
	movlw	MODE_PRINT_OUTSIDE_TEMP_CALIBRATION
	movwf	mode
	goto	int_end_clr


; these commands have a numeric argument
set_pwm_command:
	movlw	COMMAND_SET_PWM
	movwf	command
	goto	command_end

read_adc_command:
	movlw	COMMAND_READ_ADC
	movwf	command
	goto	command_end

temp_setpoint_command:
	movlw	COMMAND_TEMP_SETPOINT
	movwf	command
	goto	command_end

print_millivolts_command:
	movlw	COMMAND_PRINT_MILLIVOLTS
	movwf	command
	goto	command_end

print_temperature_command:
	movlw	COMMAND_PRINT_TEMPERATURE
	movwf	command
	goto	command_end

set_minutes_command:
	movlw	COMMAND_SET_MINUTES
	movwf	command
	goto	command_end

set_hours_command:
	movlw	COMMAND_SET_HOURS
	movwf	command
	goto	command_end

calibrate_clock_command:
	movlw	COMMAND_CALIBRATE_CLOCK
	movwf	command
	goto	command_end

inside_temp_calibration_command:
	movlw	COMMAND_INSIDE_TEMP_CALIBRATION
	movwf	command
	goto	command_end

outside_temp_calibration_command:
	movlw	COMMAND_OUTSIDE_TEMP_CALIBRATION
	movwf	command
	goto	command_end


; final processing of commands with numeric arguments, we have the number in 'value' now.
end_pwm_command:
	movfw	value
	movwf	pwm_pulse_width
	goto	command_end_status

end_read_adc_command:
	movfw	value
	movwf	analog_select
	movlw	MODE_READ_ADC
	movwf	mode
	goto	command_end_status

end_temp_setpoint_command:
	movfw	value
	movwf	temp_setpoint
	call	save_settings
	goto	command_end_status

end_print_millivolts_command:
	movfw	value
	movwf	analog_select
	movlw	MODE_PRINT_MILLIVOLTS
	movwf	mode
	goto	command_end_status

end_print_temperature_command:
	movfw	value
	movwf	analog_select
	movlw	MODE_PRINT_TEMPERATURE
	movwf	mode
	goto	command_end_status

end_set_minutes_command:
	movfw	value
	movwf	minutes
	goto	command_end_status

end_set_hours_command:
	movfw	value
	movwf	hours
	goto	command_end_status

end_calibrate_clock_command:
	movfw	value
	movwf	timer1_reload_l
	call	save_settings
	goto	command_end_status

end_inside_temp_calibration_command:
	movfw	value
	movwf	inside_temp_calibration
	call	save_settings
	goto	command_end_status
	
end_outside_temp_calibration_command:
	movfw	value
	movwf	outside_temp_calibration
	call	save_settings
	goto	command_end_status

process_digits_command:
 	movlw	D'48'
	subwf	RCREG,	W			; digit now in W

	movwf	digit_in

; value = value * 10
; value += RCREG

	movfw	value				; W = original value
; look, I know about rlf, but we have 4096 words available.
	addwf	value				; value * 2
	addwf	value				; value * 3
	addwf	value				; value * 4
	addwf	value				; value * 5
	addwf	value				; value * 6
	addwf	value				; value * 7
	addwf	value				; value * 8
	addwf	value				; value * 9
	addwf	value				; value * 10

	movfw	digit_in			; input digit in W
	addwf	value				; add W to value

	incf	digit_cnt
	goto	int_end

; end of interrupt routines
command_end_status:
	banksel	0
	clrf	status_display_timer

command_end:
; reset the value, so we can continue for x, y, f, or z with 200ENTER
	banksel	0
	clrf	value
	clrf	digit_cnt
	goto	int_end

int_end_clr:					; for non numeric commands, no digits expected.
	banksel	0
	clrf	status_display_timer
	clrf	command

int_end:
	banksel	0
;	OLD IF COMPARATOR movf	CMCON,	W			; read CMCON to end mismatch because of comparator output change
; INTCON:  GIE PEIE T0IE INTE RABIE T0IF INTF RABIF
	bcf INTCON,	GIE
;	bcf	INTCON,	PEIE
	bcf INTCON,	T0IE
	bcf INTCON,	INTE
	bcf INTCON,	RABIE
	bcf	INTCON,	T0IF			; timer 0 overflow interrupt flag
	bcf	INTCON,	INTF			; GP2/INT
	bcf	INTCON,	RABIF			; port change interrupt flag bit

; PIR1   --   ADIF RCIF TXIF  SSPIF CCP1IF TMR2IF TMR1IF
	bcf	PIR1,	ADIF
	bcf	PIR1,	RCIF
	bcf	PIR1,	TXIF
	bcf	PIR1,	SSPIF
	bcf	PIR1,	CCP1IF
	bcf	PIR1,	TMR2IF
	bcf	PIR1,	TMR1IF

; PIR2  OSFIF C2IF C1IF EEIF   --     --     --     --
	bcf	PIR2,	OSFIF
	bcf	PIR2,	C2IF
	bcf	PIR2,	C1IF
	bcf	PIR2,	EEIF

	restore_w_stat				; get back W and status
	retfie


reset_entry:

; set internal OSC speed, the output on pin 3 (OSC2) is this clock / 4. 
; SELECT BANK
	banksel OSCCON
;	crlf OSCCON			; all zero
;	bcf	OSCCON, 7		; bit 7  not implemented

	bsf	OSCCON, 6		; bit 6 osc speed  111=8 MHz, 110=4MHz (default), 101=2MHz, 100=1MHz, 011=500kHz, 010=250kHz, 001=125kHz, 000=32kHz (LFINTOSC) 
	bsf	OSCCON, 5		; bit 5 osc speed
	bsf	OSCCON, 4		; bit 4 osc speed

	bcf	OSCCON, 3		; bit 3, HTS 0 = internal OSC, 1 = external

;	bcf	OSCCON, 2		; bit 2, HTS HFINTOSC status, 1 = stable
;	bcf	OSCCON, 1		; bit 1, LTS  LFINTOSC status, 1 = stable

	bcf	OSCCON, 0		; bit 0, SCS 0 = clock source defined by FOSC<2:0> of the CONFIG register, 1 = internal osc used for system clock


; initialize IO output latches

	banksel	0

; GPIO bank 0, address 0x05
	clrf	PORTA				; init all output latches to zero
	clrf	PORTB
	clrf	PORTC


; portb init (4 to 7)
	banksel	0

	CLRF  PORTB      		; Init PORTB

	banksel TRISB
	MOVLW 00h				; Set RB<7:4> as outputs
	MOVWF TRISB

;	banksel	0

; init async serial out 
;12.1.1.6        Asynchronous Transmission Set-up:
;1.  Initialize the SPBRGH, SPBRG register pair and
;    the BRGH and BRG16 bits to achieve the desired
;    baud rate (see Section 12.3 "EUSART Baud
;    Rate Generator (BRG)").
;2.  Enable the asynchronous serial port by clearing
;    the SYNC bit and setting the SPEN bit.
;3.  If 9-bit transmission is desired, set the TX9 con-
;    trol bit. A set ninth data bit will indicate that the 8
;    Least Significant data bits are an address when
;    the receiver is set for address detection.
;4.  Enable the transmission by setting the TXEN
;    control bit. This will cause the TXIF interrupt bit
;    to be set.
;5.  If interrupts are desired, set the TXIE interrupt
;    enable bit. An interrupt will occur immediately
;    provided that the GIE and PEIE bits of the
;    INTCON register are also set.
;6.  If 9-bit transmission is selected, the ninth bit
;    should be loaded into the TX9D data bit.
;7.  Load 8-bit data into the TXREG register. This
;    will start the transmission.

; 8 bit async
; SYNC = 0, BRG16 = 0, BRGH=1, at 8MHz: 19231 Baud, 0.16% for SPBRG=25
;	banksel TRISB
;	bcf TRISB, TRISB7			; pin 10 (RB7,TX,CK) output	

	banksel SPBRG
	movlw	D'25'
	movwf	SPBRG

;	default 8 bit mode, SPBRGH not used
;	banksel SPBRGH
	
	banksel BAUDCTL
	bcf	BAUDCTL, BRG16

	banksel TXSTA
	bsf TXSTA, BRGH
	bcf TXSTA, SYNC

	banksel RCSTA
	bsf RCSTA, SPEN
	
	banksel TXSTA
	bsf TXSTA, TXEN


;12.1.2.8        Asynchronous Reception Set-up:
;1.  Initialize the SPBRGH, SPBRG register pair and
;    the BRGH and BRG16 bits to achieve the
;    desired baud rate (see Section 12.3 "EUSART
;    Baud Rate Generator (BRG)").
;2.  Enable the serial port by setting the SPEN bit.
;    The SYNC bit must be clear for asynchronous
;    operation.
;3.  If interrupts are desired, set the RCIE interrupt
;    enable bit and set the GIE and PEIE bits of the
;    INTCON register.
;4.  If 9-bit reception is desired, set the RX9 bit.
;5.  Enable reception by setting the CREN bit.
;6.  The RCIF interrupt flag bit will be set when a
;    character is transferred from the receive shift
;    register to the receive buffer. An interrupt will be
;    generated if the RCIE interrupt enable bit was
;    also set.
;7.  Read the RCSTA register to get the error flags
;    and, if 9-bit data reception is enabled, the ninth
;    data bit.
;8.  Get the received 8 Least Significant data bits
;    from the receive buffer by reading the RCREG
;    register.
;9.  If an overrun occurred, clear the OERR flag by
;    clearing the CREN receiver enable bit.


	banksel RCSTA
	bsf	RCSTA, CREN
; SYNC and SPEN already done.	


; Load 5 Hz ticck
	movlw	D'5'
	movwf	seconds_5

; clock to 00:00
	clrf	seconds
	clrf	minutes
	clrf	hours


;This code block configures the ADC
;for polling, Vdd reference, Frc clock
;and AN0 input.
;
;Conversion start & polling for completion
; are included.
;
	BANKSEL   ADCON1       ;
	MOVLW     B'00100000'	; not used, :32, 
							; bit 7	not used, zero
							; bit 6 clock speed
							; bit 5 clock speed
							; bit 4 clock speed
							; bit 3 not used
							; bit 2 not used
							; bit 1 not used
							; bit 0 not used
	MOVWF     ADCON1


;	BANKSEL   TRISC
;	BSF       TRISC, 1     ; Set RC1 as input
	banksel TRISC
; 1 = input, 0 = output
	movlw	B'11111010'			; io port direction
						; bit 7 AN7	outside temperature
						; bit 6			not used
						; bit 5
						; bit 4
						; bit 3	
						; bit 2	RC2 FROST out
						; bit 1 AN5 in inside temperature
						; bit 0 RC0 HEATER out
	movwf	TRISC

; select which port c pins are analog inputs
	BANKSEL   ANSEL			; default is 1111 1111
	bcf	ANSEL, 0			; ASN 0
	bcf	ANSEL, 1			; ASN 1
	bcf	ANSEL, 2			; ASN 2
	bcf	ANSEL, 3			; ASN 3
	bcf	ANSEL, 4			; ASN 4
	bsf	ANSEL, 5			; ASN 5 	pin 15	analog in AN5		outside temperature
	bcf	ANSEL, 6			; ASN 6
	bsf	ANSEL, 7			; ASN 7		pin 7	analog in AN7		outside temperature

	BANKSEL   ANSELH		; default is 1111
	bcf	ANSELH, 0			; ASN 8
	bcf	ANSELH, 1			; ASN 9
	bcf	ANSELH, 2;			; ASN 10
	bcf	ANSELH, 3			; ASN 11	UART RX
							; only lower 4 bits used	
; right justify analog result
	BANKSEL   ADCON0
	clrf ADCON0
	bsf ADCON0, ADFM		; ADFM right justified	
	bcf ADCON0, VCFG		; Vdd reference		

; select an analog channel for the ADC
	bcf	ADCON0, 5			; 0   0101= AN5
	bsf	ADCON0, 4			; 1
	bcf	ADCON0, 3			; 0
	bsf	ADCON0, 2			; 1

; bit 1 is A/D conversion status bit	
; start the ADC
	bsf ADCON0,	ADON		; AD on

; OPTION_REG bank 1, address 0x81
; !GPPU INTEDG T0CS T0SE PSA PS2 PS1 PS0

; serial com init
	banksel OPTION_REG
	movlw	B'00000001'			; prescaler 1
	movwf	OPTION_REG
;	bsf	OPTION_REG,	NOT_GPPU	; no pullups 

; serial in interrupt enable
	banksel	PIE1
	clrf	PIE1
	bsf PIE1,   RCIE            ; USART receive interrupt enable
;	bsf	PIE1,	ADIE			; AD converter interrupt enable (12F675 only)
	bsf	PIE1,	TMR1IE			; timer 1 overflow interrupt enable
;	bsf	PIE1,	CMIE			; comparator interrupt enable

; PIE2: OSFIE C2IE C1IE EEIE -- -- -- --
	banksel	PIE2
	bcf	PIE2,	EEIE			; EEPROM write complete interrupt enable
	
	banksel	PORTC
; set ouputs high (not active)
	bsf	PORTC, HEATER_OUT
	bsf	PORTC, FROST_ALARM

; flags to zero
	clrf 	flags
	clrf	flags1

; OPTION_REG bank 1, address 0x81
; !GPPU INTEDG T0CS T0SE PSA PS2 PS1 PS0

	banksel OPTION_REG
	movlw	B'00000001'			; prescaler 1
	movwf	OPTION_REG
;	bsf	OPTION_REG,	NOT_GPPU	; no pullups 

; timer 1  :4 clock = 2MHz, :8 prescaler=250000 Hz, :50000 reload=5Hz interrupt 
; T1CON:	T1GINV TMR1GE T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON
	banksel T1CON
	bcf	T1CON,	T1GINV			; non invert
	bcf	T1CON,	TMR1GE			; no gate enable
	bsf	T1CON,	T1CKPS1			; 11 = 1:8 prescaler 
	bsf	T1CON,	T1CKPS0			; 
	bcf	T1CON,	T1OSCEN			; no external clock
	bcf	T1CON,	NOT_T1SYNC		; no sync
	bcf	T1CON,	TMR1CS			; select :4 internal osc = 2MHz	
	bsf	T1CON,	TMR1ON			; timer 1 on

; set timer 1 reload 0, and clear TMR1IF as on page 88 pdf	
	movlw	D'0'
	banksel	TMR1H			; 50000 reload
	movwf	TMR1H
	banksel	TMR1L
	movwf	TMR1L
; reset timer 1 interrupt flag	
	banksel PIR1
	bcf	PIR1,	TMR1IF

	banksel 0

; enable gobal and peripheral interrupt
	banksel	INTCON
	clrf	INTCON
	bsf	INTCON,	PEIE			; peripheral interrupts enable
;	bsf	INTCON,	T0IE			; timer 0 overflow interrupt enable
;	bsf	INTCON,	INTE			; GP2/INT interrupt enable
;	bsf	INTCON,	GPIE			; port change interrupt enable
	bsf	INTCON,	GIE				; global interrupt enable

	banksel	0

; print ID 
	call	print_id

; load settings from eeprom 0
	banksel	0
	call	load_settings			; this sets flags1

;	clrf	mode
	movlw	MODE_HCS				; HCS by default
	movwf	mode
main_loop:
	banksel	0
	movlw	MODE_HCS
	subwf	mode, w
	btfss	STATUS,	Z
	goto	test_read_adc
	
; start hcs
	btfsc	flags, FAST_MODE_FLAG
	goto	clear_one_minute_flag	

	btfss	flags1, ONE_MINUTE_FLAG
	goto	main_loop

; one_minute
clear_one_minute_flag:
	bcf	flags1, ONE_MINUTE_FLAG			; assume we do all im main within one minute

; print time
	call	print_time	

	banksel 0

	movlw	' '
	call	tx_w

; outside temperature processing, if below zero set FROST_ALARM
; say outside
	movlw	'o'
	call	tx_w
	movlw	'u'
	call	tx_w
	movlw	't'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'i'
	call	tx_w
	movlw	'd'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	' '
	call	tx_w

; read adc 5
	movlw	D'5'
	movwf	analog_select
	call	read_adc				; value in ad_h ad_l

	banksel	0
; print adc 5
	call	print_adc

	banksel	0
; print space
	movlw	' '
	call	tx_w
	
; convert adc5 to millivolts
	call	ad_to_millivolts		; ad_h ad_l to millivilt_h millivolt_l

	banksel	0
; convert millivolts to Celcius and Kelvin
;	movlw	D'17'					; DEFAULT 17   degrees Kelvin low byte from 273, +2
	movfw	outside_temp_calibration
	movwf	temp_correction
	call	millivolts_to_temp		; millivolt_h millivolt_l to kelvin_h kelvin_l, celcisu_h celcius_l and NEGATIVE_TEMPERATURE_FLAG

	banksel	0
; print adc 5 millivolts
	call	print_millivolts

	banksel	0
; print space
	movlw	' '
	call	tx_w

; print adc5 Celcius	
	call	print_celcius

; print space
	movlw	' '
	call	tx_w

;	call	tx_crlf

; compare temp
; if temperature negative then frost alarm 
	btfss	flags1, NEGATIVE_TEMPERATURE_FLAG
	goto	no_frost

; frost
	bcf	PORTC, FROST_ALARM
	goto	process_inside_temperature			; WAS compare_temp_to_setpoint

no_frost:
	bsf	PORTC,	FROST_ALARM

process_inside_temperature:
; inside temperature procesing, if below setpoint set HEATER_OUT
; say 'inside '
	movlw	'i'
	call	tx_w
	movlw	'n'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'i'
	call	tx_w
	movlw	'd'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	' '
	call	tx_w

; read adc 7
	movlw	D'7'
	movwf	analog_select
	call	read_adc				; value in ad_h ad_l

	banksel	0
; print adc 7
	call	print_adc

	banksel	0

; print space
	movlw	' '
	call	tx_w
	
; convert adc7 to millivolts
	call	ad_to_millivolts		; ad_h ad_l to millivilt_h millivolt_l

	banksel	0
; convert millivolts to Celcius and Kelvin
;	movlw	D'17'					; degrees Kelvin low byte from 273
	movfw	inside_temp_calibration
	movwf	temp_correction
	call	millivolts_to_temp		; millivolt_h millivolt_l to kelvin_h kelvin_l, celcisu_h celcius_l and NEGATIVE_TEMPERATURE_FLAG

	banksel	0
; print adc 7 millivolts
	call	print_millivolts

	banksel	0
; print space
	movlw	' '
	call	tx_w

; print adc7 Celcius	
	call	print_celcius

; print space
;	movlw	' '
;	call	tx_w

	call	tx_crlf

compare_temp_to_setpoint:
; add 273 to centigrade setpoint to get kelvin	
	movlw	D'0'
	movwf	ACCbHI
	movfw	temp_setpoint
	movwf	ACCbLO

	movlw	D'1'
	movwf	ACCaHI
	movlw	D'17'
	movwf	ACCaLO				; add 273

	call	D_add				; Double Precision  Addition ( ACCb + ACCa -> ACCb )

; setpoint in kelvin now in ACCb, always positive (minimum 273)
; save in temp
	movfw	ACCbHI
	movwf	temp
	movfw	ACCbLO
	movwf	temp1

; temperature to ACCa
	movfw	kelvin_h
	movwf	ACCbHI				; get temperature in kelvin 
	movfw	kelvin_l
	movwf	ACCbLO

; setpoint to ACCa	
	movfw	temp
	movwf	ACCaHI
	movfw	temp1
	movwf	ACCaLO

	call	D_sub				; Double Precision Subtraction ( ACCb - ACCa -> ACCb )

; ACCb	now temperature - setpoint
; if msb Hi is set then temperature was higher then setpoint, heater on 
	banksel	0

	btfss	ACCbHI, 7
	goto	heater_off

; heater on
    bcf PORTC, HEATER_OUT			; heater on set switch output to zero (hcs heater on)

	goto	main_loop		

heater_off:
	bsf	PORTC, HEATER_OUT			; heater off
; do not reset mode, we stay in hcs loop by default on power on, or when requested, and only exit if other command requested				
	goto	main_loop

test_read_adc:
	movlw	MODE_READ_ADC
	subwf	mode, w
	btfss	STATUS, Z
	goto	test_print_temperature

	call	read_adc

	banksel	0

	call	print_adc

	banksel	0

	call	tx_crlf

	goto	main_end

test_print_temperature:
	banksel	0
	movlw	MODE_PRINT_TEMPERATURE
	subwf	mode, w
	btfss	STATUS, Z
	goto	test_print_millivolts
	
	call	read_adc

	call	ad_to_millivolts
	
	call	millivolts_to_temp

	call	print_celcius

	call	tx_crlf

	goto	main_end

test_print_millivolts:
	banksel	0
	movlw	MODE_PRINT_MILLIVOLTS
	subwf	mode, w
	btfss	STATUS, Z
	goto	test_setpoint_pri

	call	read_adc

	call	ad_to_millivolts

	call	millivolts_to_temp

	call	print_millivolts

	call	tx_crlf

	banksel	0

	goto	main_end

test_setpoint_pri:
	banksel	0
	movlw	MODE_PRINT_SETPOINT		
	subwf	mode, w
	btfss	STATUS, Z
	goto	test_print_clock_calibration

	call	setpoint_pri
	
	banksel	0

	call	tx_crlf

	goto	main_end

test_print_clock_calibration:
	banksel	0
	movlw	MODE_PRINT_CLOCK_CALIBRATION
	subwf	mode,	w
	btfss	STATUS, Z
	goto	test_inside_temp_calibration

	call	clock_calibration_pri	
	
	banksel	0

	call	tx_crlf	

	goto	main_end


test_inside_temp_calibration:
	banksel	0
	movlw	MODE_PRINT_INSIDE_TEMP_CALIBRATION
	subwf	mode,	w
	btfss	STATUS, Z
	goto	test_outside_temp_calibration

	call	inside_temp_calibration_pri	
	
	banksel	0

	call	tx_crlf	

	goto	main_end


test_outside_temp_calibration:
	banksel	0
	movlw	MODE_PRINT_OUTSIDE_TEMP_CALIBRATION
	subwf	mode,	w
	btfss	STATUS, Z
	goto	main_loop					; IF NOT, ONLY CLEAR mode if something found.

	call	outside_temp_calibration_pri	
	
	banksel	0

	call	tx_crlf	

	goto	main_end


main_end:
	banksel	0
	clrf	mode
	goto	main_loop

; ***************** subroutines ********************

read_adc:									; value for AD channel analog_select to ad_h and ad_l
	banksel	0
	movfw	analog_select

; TRISC or other ports must be set for input if used for ADC
; ANSEL and ANSELH must have bits set for analog input

; select an analog channel for the ADC

; set bit<5-2> in ADCONO for the selected input number
; mask out lowest 4 bits
	andlw	D'15'
	movwf	temp3

; to position
; RLF: carry to LSB, MSB to carry	
; clear carry	
	bcf	STATUS, C				; x 2
	rlf	temp3, 1
; clear carry	
	bcf	STATUS, C
	rlf	temp3, 1				; x 4

; to ADCON0
	movfw	temp3

	BANKSEL   ADCON0
	clrf	ADCON0
	movwf	ADCON0

; select an analog channel for the ADC
;	bcf	ADCON0, 5				; 0   0101= AN5
;	bsf	ADCON0, 4				; 1
;	bcf	ADCON0, 3				; 0
;	bsf	ADCON0, 2				; 1

	bsf ADCON0, ADFM			; ADFM right justified		bit 7
	bcf ADCON0, VCFG			; Vdd reference				bit 6

; bit 1 is A/D conversion status bit	
; start the ADC
	bsf ADCON0,	ADON		; AD on							bit	0

; sample time delay
	movlw	D'255'
	movwf	delay_count1	
adc_sample_delay:
	decfsz	delay_count1, F
	goto	adc_sample_delay

; set ADCON0 GO / !DONE bit to start the conversion
	BSF		ADCON0, GO			; Start conversion			bit	1

	BTFSC	ADCON0, GO			; Is conversion done?
	GOTO	$-1					; No, test again

	BANKSEL	ADRESH
	MOVF	ADRESH, W			; Read upper 2 bits

	banksel	0
	MOVWF	ad_h				; store in GPR space
	
	BANKSEL	ADRESL
	MOVF	ADRESL, W			; Read lower 8 bits

	banksel	0
	MOVWF	ad_l				; Store in GPR space

	return


delay10us:						; delays W * 10 us 
	movlw	D'6'				; 10 us
	movwf	delay_count1
delay_loop1:
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	decf	delay_count1,f
	btfss	STATUS,	Z		
	goto	delay_loop1		

	return


delay_1ms:
;	movlw	D'100'				; 100 x 10 us = 1 ms
	movwf	delay_count2
delay_loop2:

	call	delay10us

	decf	delay_count2,f
	btfss	STATUS,	Z		
	goto	delay_loop2		
	return

; send byte in W
tx_digit_in_w:
	banksel	TXREG

	addlw	'0'				; zero
tx_w:
	movwf	TXREG
;	call	wait_tx_empty
; inline
	banksel	0
; make sure we have a timeout
	movlw	D'255'	
	movwf	tx_timeout
test_tx_empty:
	decfsz	tx_timeout,	1
	goto	test_txsta
	goto	tx_has_timed_out

test_txsta:
	btfss	TXSTA,	TRMT	
	goto	test_tx_empty

tx_has_timed_out:
	banksel	0

	return


print_w_ascii_dec:				; prints register W in ASCII decimal
	bsf	flags1,	FIRST_ZERO_SUPPRESSED_FLAG
	movwf	temp1
	clrf	count				; number of hundreds found
loop_hundreds:
	movlw	D'100'
	subwf	temp1
	btfss	STATUS,	C			; if no carry flag, no more hundreds, go count tenth		
	goto	count10				; substraction failed
	incf	count	
	goto	loop_hundreds
count10:
	movlw	D'0'
	subwf	count,	W
	btfsc	STATUS,	Z
	goto	suppress_first_zero

	bcf	flags1,	FIRST_ZERO_SUPPRESSED_FLAG

	movfw	count
	call	tx_digit_in_w			; print hundreds

suppress_first_zero:
	movlw	D'100'				; restore temp1 from one substract to many
	addwf	temp1	

	clrf	count				; number of tenth found
loop_tenth:
	movlw	D'10'
	subwf	temp1
	btfss	STATUS,	C			; if no carry flag no more tenth, only units left	
	goto	count1		
	incf	count
	goto	loop_tenth
count1:
	movlw	D'0'
	subwf	count,	W
	btfss	STATUS,	Z
	goto	print_tenth			; tenth not zero

; tenth zero
; test if zero supression was active in hundreds (first digit)
	btfsc	flags1,	FIRST_ZERO_SUPPRESSED_FLAG
	goto	print_units			; if first digit was not zero, print this zero	

print_tenth:
	movfw	count
	call	tx_digit_in_w			; print tenth

print_units:
	movlw	D'10'				; restore temp1 from 1 substract to many
	addwf	temp1

; units
	movfw	temp1
	call	tx_digit_in_w			; print units

	return



print_16_ascii_dec:				; prints 16 bit value in registers Hi_byte and LO_byte in ASCII decimal
	call	b2bcd

; suppress leading zeros
	bsf		flags1,	FIRST_ZERO_SUPPRESSED_FLAG

	movfw	bcd
	call	print_bcd_in_w_decimal_2_digits

	movfw	bcd+1
	call	print_bcd_in_w_decimal_2_digits

	movfw	bcd+2
	call	print_bcd_in_w_decimal_2_digits

; if the zero suppress flag is still set we had zero, so print zero
	btfss	flags1, FIRST_ZERO_SUPPRESSED_FLAG
	return

	movlw	D'0'
	call	tx_digit_in_w

	return


; Convert 32-bit binary number at <bin> into a bcd number
; at <bcd>. Uses Mike Keitz's procedure for handling bcd 
; adjust; Modified Microchip AN526 for 32-bits.
b2bcd:
	bcf		STATUS, C
	movlw	D'16'			; 32 for 32-bits
	movwf	ii				; make cycle counter
	clrf	bcd				; clear result area
	clrf	bcd+1
	clrf	bcd+2
;	clrf	bcd+3
;	clrf	bcd+4
	
b2bcd2:
	movlw	bcd				; make pointer
	movwf	FSR
	movlw	3				; was 5
	movwf	count

; Mike's routine:
b2bcd3:
	movlw	0x33		
	addwf	INDF, f			; add to both nybbles
	btfsc	INDF, 3			; test if low result > 7
	andlw	0xf0			; low result >7 so take the 3 out
	btfsc	INDF, 7			; test if high result > 7
	andlw	0x0f			; high result > 7 so ok
	subwf	INDF, f			; any results <= 7, subtract back
	incf	FSR, f			; point to next
	decfsz	count
	goto	b2bcd3
	
;	rlf	bin+3,f				; get another bit
;	rlf	bin+2,f
	rlf	bin+1,f
	rlf	bin+0,f

;	rlf	bcd+4,f				; put it into bcd
;	rlf	bcd+3,f
	rlf	bcd+2,f
	rlf	bcd+1,f
	rlf	bcd+0,f	
	decfsz	ii,f			; all done?
	goto	b2bcd2			; no, loop

	movlw	0
	movwf	bcd

	return


print_bcd_in_w_decimal_2_digits:

;	high digit first	
	movwf	temp				; save w
	swapf	temp, w
	andlw	0x0f
; test if zero
	btfss	STATUS, Z
; if not zero print it	
	goto	print_high_nibble	

test_lead_zero:
; test if leading zero suppress flag set
	btfsc	flags1, FIRST_ZERO_SUPPRESSED_FLAG
	goto	low_nibble		

print_high_nibble:
	bcf		flags1, FIRST_ZERO_SUPPRESSED_FLAG
	call    tx_digit_in_w

low_nibble:
; low digit second
	movfw	temp				; get w
	andlw	0x0f
; test if zero
	btfss	STATUS, Z
; if not zero print it
	goto print_low_nibble

; test if leading zero suppress flag is set
	btfsc	flags1, FIRST_ZERO_SUPPRESSED_FLAG
; return if n ozero print
	return	

print_low_nibble
	bcf		flags1, FIRST_ZERO_SUPPRESSED_FLAG
	call	tx_digit_in_w

	return


tx_crlf:
	movlw	D'13'
	call	tx_w				; CR
	movlw	D'10'				; LF
	call	tx_w
	return


;id_text:
;	DT	"panteltje hcs_pic-0.1"	; generates RETLW instructions
print_id:
	movlw	'P'
	call	tx_w
	movlw	'a'
	call	tx_w
	movlw	'n'
	call	tx_w
	movlw	't'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	'l'
	call	tx_w
	movlw	't'
	call	tx_w
	movlw	'j'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	'h'
	call	tx_w
	movlw	'c'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'-'
	call	tx_w
	movlw	'0'
	call	tx_w
	movlw	'.'
	call	tx_w
	movlw	'2'
	call	tx_w
	call tx_crlf
	return


help_pri:
	movlw	'F'
	call	tx_w
	movlw	'o'
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	'h'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	'l'
	call	tx_w
	movlw	'p'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	'R'
	call	tx_w
	movlw	'E'
	call	tx_w
	movlw	'A'
	call	tx_w
	movlw	'D'
	call	tx_w
	movlw	'M'
	call	tx_w
	movlw	'E'
	call	tx_w
	call	tx_crlf
	return


eeprom_write:
	banksel INTCON
	bcf	INTCON,	GIE				; disable interrupts

	BANKSEL EEADR				;
	MOVF    eeprom_address, W	;
	MOVWF   EEADR				; Data Memory Address to write
	MOVF    eeprom_data, W		;
	MOVWF   EEDAT				; Data Memory Value to write
	BANKSEL EECON1				;
	BCF     EECON1, EEPGD		; Point to DATA memory
	BSF     EECON1, WREN		; Enable writes
	BCF     INTCON, GIE			; Disable INTs.
	BTFSC   INTCON, GIE			; SEE AN576
	GOTO    $-2
	MOVLW   0x55				;
	MOVWF   EECON2				; Write 55h
	MOVLW   0xAA				;
	MOVWF   EECON2				; Write AAh
	BSF     EECON1, WR			; Set WR bit to begin write
	BSF     INTCON, GIE			; Enable INTs.
eeprom_poll_write_complete_loop:
    banksel EECON1
    btfsc   EECON1, WR
    goto    eeprom_poll_write_complete_loop

	BCF     EECON1, WREN		; Disable writes
	BANKSEL 0					; Bank 0

	call	eeprom_verify

	return


eeprom_verify:					; data at EEDADR against eeprom_data
	call eeprom_read			; EEDATA in w

	banksel	0
	bcf	flags1,	EEPROM_WRITE_ERROR_FLAG

	movfw	eeprom_data

	banksel	EEDATA
	subwf	EEDATA,	W			; compare to requested
	btfss	STATUS,	Z			; skip if no error

	goto	eeprom_write_error

	banksel	0

	return


eeprom_write_error:
	call	eeprom_report

	banksel	0
	bsf	flags1,	EEPROM_WRITE_ERROR_FLAG

	return


eeprom_report:
; eeprom write result
	banksel	0
	movlw	'e'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	'p'
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'o'
	call	tx_w
	movlw	'm'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	'w'
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'i'
	call	tx_w
	movlw	't'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	' '
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'u'
	call	tx_w
	movlw	'l'
	call	tx_w
	movlw	't'
	call	tx_w
	movlw	' '
; address=nnn	
	call	tx_w
	movlw	'a'
	call	tx_w
	movlw	'd'
	call	tx_w
	movlw	'd'
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	's'
	call	tx_w
	movlw	'='
	call	tx_w
	movfw	eeprom_address
	call	print_w_ascii_dec
	movlw	' '
	call	tx_w
; original=nnn
	movlw	'o'
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'i'
	call	tx_w
	movlw	'g'
	call	tx_w
	movlw	'i'
	call	tx_w
	movlw	'n'
	call	tx_w
	movlw	'a'
	call	tx_w
	movlw	'l'
	call	tx_w
	movlw	'='
	call	tx_w
	movfw	eeprom_data
	call	print_w_ascii_dec
	movlw	' '
; read=nnn
	call	tx_w
	movlw	'r'
	call	tx_w
	movlw	'e'
	call	tx_w
	movlw	'a'
	call	tx_w
	movlw	'd'
	call	tx_w
	movlw	'='
	call	tx_w
; read eeprom	
	call	eeprom_read

	banksel	0
	call	print_w_ascii_dec	
	call	tx_crlf
	return

eeprom_read:					; address in eeprom_address, returns data in W
	banksel 0
	movfw	eeprom_address

	banksel	EEADR
	movwf	EEADR	

	banksel EECON1
	bcf	EECON1, EEPGD			; access data memory	
	bsf	EECON1,	RD

	banksel EEDATA
	movfw	EEDATA
; return data in w
	return

save_settings:
	banksel	0
; temp_setpoint
	movlw	D'0'
	movwf	eeprom_address			; 0
	movfw	temp_setpoint
	movwf	eeprom_data
	call	eeprom_write
; clock_calibration
	banksel	0
	incf	eeprom_address			; 1
	movfw	timer1_reload_l
	movwf	eeprom_data
	call	eeprom_write	
; inside temp calibration
	banksel	0
	incf	eeprom_address			; 2
	movfw	inside_temp_calibration
	movwf	eeprom_data
	call	eeprom_write	
; outside temp calibration
	banksel	0
	incf	eeprom_address			; 3
	movfw	outside_temp_calibration
	movwf	eeprom_data
	call	eeprom_write	

	return

load_settings:
	banksel	0
; temp setpoint
	movlw	D'0'
	movwf	eeprom_address			; 0
	call	eeprom_read				; returns data in w
	banksel	0
	movwf	temp_setpoint
; clock calibration
	incf	eeprom_address			; 1
	call	eeprom_read				; returns data in w
	banksel	0
	movwf	timer1_reload_l
; inside temp calibration	
	incf	eeprom_address			; 2
	call	eeprom_read				; returns data in w
	banksel	0
	movwf	inside_temp_calibration
; outside temp calibration
	incf	eeprom_address			; 3
	call	eeprom_read				; returns data in w
	banksel	0
	movwf	outside_temp_calibration

	return

setpoint_pri:
; print temperature setpoint
	banksel	0

	movfw	temp_setpoint
	call	print_w_ascii_dec

	call	tx_crlf

	return


clock_calibration_pri:
; print timer1_reload_l
	banksel	0

	movfw	timer1_reload_l
	call	print_w_ascii_dec

	call	tx_crlf

	return


inside_temp_calibration_pri:
; print inside_temp_calibration
	banksel	0

	movfw	inside_temp_calibration
	call	print_w_ascii_dec

	call	tx_crlf

	return


outside_temp_calibration_pri:
; print outside_temp_calibration
	banksel	0

	movfw	outside_temp_calibration
	call	print_w_ascii_dec

	call	tx_crlf

	return


neg_A
	comf    ACCaLO, F       ; negate ACCa ( -ACCa -> ACCa )
	incf    ACCaLO, F
	btfsc	STATUS, Z
	decf    ACCaHI, F
	comf    ACCaHI, F
	retlw   0


; Double Precision Subtraction ( ACCb - ACCa -> ACCb )
D_sub
;	 call    neg_A           ; At first negate ACCa; Then add
; inline
	comf    ACCaLO, F       ; negate ACCa ( -ACCa -> ACCa )
	incf    ACCaLO, F
	btfsc	STATUS, Z
	decf    ACCaHI, F
	comf    ACCaHI, F

; Double Precision  Addition ( ACCb + ACCa -> ACCb )
D_add
	movf    ACCaLO, W
	addwf   ACCbLO, F		; add lsb
	btfsc   STATUS, C		; add in carry
	incf    ACCbHI, F
	movf    ACCaHI,	W
	addwf   ACCbHI, F		; add msb
	retlw   0


;       division macro
;
divMac  MACRO
	LOCAL   NOCHK
	LOCAL   NOGO
;
	bcf     STATUS, C
	rlf     ACCdLO, F
	rlf     ACCdHI, F
	rlf     ACCcLO, F
	rlf     ACCcHI, F
	movf    ACCaHI, W
	subwf   ACCcHI, W          ;check if a>c
	btfss   STATUS, Z
	goto    NOCHK
	movf    ACCaLO, W
	subwf   ACCcLO, W        ;if msb equal then check lsb
NOCHK
	btfss   STATUS,C        ;carry set if c>a
	goto    NOGO
	movf    ACCaLO, W        ;c-a into c
	subwf   ACCcLO, F
	btfss   STATUS, C
	decf    ACCcHI, F
	movf    ACCaHI, W
	subwf   ACCcHI, F
	bsf     STATUS, C        ;shift a 1 into b (result)
NOGO
	rlf     ACCbLO, F
	rlf     ACCbHI, F
;
	ENDM


;       Double Precision Divide ( 16/16 -> 16 )
;
;         ( ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output
; with Quotiont in ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO).
;
;   NOTE  :  Before calling this routine, the user should make sure that
;            the Numerator(ACCb) is greater than Denominator(ACCa). If
;            the case is not true, the user should scale either Numerator
;            or Denominator or both such that Numerator is greater than
;            the Denominator.
;
;
setup
	movlw	.16					; for 16 shifts
	movwf	temp
	movf	ACCbHI, W			; move ACCb to ACCd
	movwf	ACCdHI
	movf	ACCbLO, W
	movwf	ACCdLO
	clrf	ACCbHI
	clrf	ACCbLO
	retlw	0
;
D_divF
;
     IF   SIGNED
     CALL    S_SIGN
     ENDIF
;
	call    setup
	clrf    ACCcHI
	clrf    ACCcLO
;
; use the divMac macro 16 times
;
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
	divMac
;
    IF    SIGNED
	btfss   sign,MSB        ; check sign if negative
	retlw   0
	goto    neg_B          ; negate ACCa ( -ACCa -> ACCa )
    ELSE
	retlw   0
    ENDIF

;  Assemble this section only if Signed Arithmetic Needed
;
     IF    SIGNED
;
S_SIGN  movf    ACCaHI,W
	xorwf   ACCbHI,W
	movwf   sign
	btfss   ACCbHI,MSB        ; if MSB set go & negate ACCb
	goto    chek_A
;
	comf    ACCbLO          ; negate ACCb
	incf    ACCbLO
	btfsc   STATUS,Z
	decf    ACCbHI
	comf    ACCbHI
;
chek_A  btfss   ACCaHI,MSB        ; if MSB set go & negate ACCa
	retlw   0
	goto    neg_A
;
     ENDIF
;


;               Double Precision Multiply ( 16x16 -> 32 )
;         ( ACCb*ACCa -> ACCb,ACCc ) : 32 bit output with high word
;  in ACCb ( ACCbHI,ACCbLO ) and low word in ACCc ( ACCcHI,ACCcLO ).
;
D_mpyS                           ;results in ACCb(16 msb's) and ACCc(16 lsb's)
;
     IF   SIGNED
     CALL    S_SIGN
     ENDIF
;
	call    setup
mloop   rrf     ACCdHI, F       ;rotate d right
	rrf     ACCdLO, F
	btfsc   STATUS,C    ;need to add?
	call    D_add
	rrf     ACCbHI, F
	rrf     ACCbLO, F
	rrf     ACCcHI, F
	rrf     ACCcLO, F
	decfsz  temp, F         ;loop until all bits checked
	goto    mloop
;
    IF    SIGNED
	btfss   sign,MSB
	retlw   0
	comf    ACCcLO, F       ; negate ACCa ( -ACCa -> ACCa )
	incf    ACCcLO, F
	btfsc   STATUS,Z
	decf    ACCcHI, F
	comf    ACCcHI, F
	btfsc   STATUS,Z
neg_B   comf    ACCbLO, F       ; negate ACCb
	incf    ACCbLO, F
	btfsc   STATUS,Z
	decf    ACCbHI, F
	comf    ACCbHI, F
	retlw   0
    ELSE
	retlw   0
    ENDIF


#ifdef USE_BINARY_FLOATS

;       multiplication macro
;
mulMac  MACRO
	LOCAL   NO_ADD
;
	rrf		ACCdHI, F			; rotate d right
	rrf		ACCdLO, F
	btfss	STATUS, C			; need to add?
	goto	NO_ADD				; no addition necessary
	movf	ACCaLO, W			; Addition ( ACCb + ACCa -> ACCb )
	addwf	ACCbLO, F			; add lsb
	btfsc	STATUS, C			; add in carry
	incf	ACCbHI, F
	movf	ACCaHI, W
	addwf	ACCbHI, F			; add msb
NO_ADD
	rrf		ACCbHI, F
	rrf		ACCbLO, F
	rrf		ACCcHI, F
	rrf		ACCcLO, F
;
	ENDM


;               Double Precision Multiply ( 16x16 -> 32 )
;         ( ACCb*ACCa -> ACCb,ACCc ) : 32 bit output with high word
;  in ACCb ( ACCbHI,ACCbLO ) and low word in ACCc ( ACCcHI,ACCcLO ).
;
D_mpyF                          ;results in ACCb(16 msb's) and ACCc(16 lsb's)
;
     IF   SIGNED
     CALL    S_SIGN
     ENDIF
;
	call    setup
;
; use the mulMac macro 16 times
;
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
	mulMac
;
    IF    SIGNED
	btfss   sign,MSB
	retlw   0
	comf    ACCcLO          ; negate ACCa ( -ACCa -> ACCa )
	incf    ACCcLO
	btfsc   STATUS,Z
	decf    ACCcHI
	comf    ACCcHI
	btfsc   STATUS,Z
neg_B   comf    ACCbLO          ; negate ACCb
	incf    ACCbLO
	btfsc   STATUS,Z
	decf    ACCbHI
	comf    ACCbHI
	retlw   0
    ELSE
	retlw   0
    ENDIF

     IF    SIGNED
;
S_SIGN  movf    ACCaHI,W
	xorwf   ACCbHI,W
	movwf   sign
	btfss   ACCbHI,MSB        ; if MSB set go & negate ACCb
	goto    chek_A
;
	comf    ACCbLO          ; negate ACCb
	incf    ACCbLO
	btfsc   STATUS,Z
	decf    ACCbHI
	comf    ACCbHI
;
chek_A  btfss   ACCaHI,MSB        ; if MSB set go & negate ACCa
	retlw   0
	goto    neg_A
;
     ENDIF
;

;       Floating Point Subtraction  ( ACCb - ACCa -> ACCb )
;
F_sub
	call    neg_A           ; At first negate ACCa; Then add
;
F_add
	movf    EXPa,W          ; scale mantissas
	subwf   EXPb,W          ; find the greater exponent
	btfsc   STATUS,Z
	goto    padd            ; exponents are equal
	btfsc   STATUS,C    ;
	call    F_swap          ; if A > B then swap ( A<->B )
	movf    EXPa,W
	subwf   EXPb, F
scloop  call    shftSR
	incfsz  EXPb, F
	goto    scloop
	movf    EXPa,W
	movwf   EXPb
padd    movf    ACCaHI,W
	iorwf   ACCbHI,W
	movwf   sign
	call    D_add           ; compute double precision integer add
	btfss   sign,MSB
	btfss   ACCbHI,MSB
	retlw   0
	bcf     STATUS,C
	incf    EXPb, F
	goto    shftR


shftSR
	bcf     STATUS,C
	btfsc   ACCbHI,MSB
	bsf     STATUS,C            ; set carry if < 0
shftR
	rrf     ACCbHI, F
	rrf     ACCbLO, F
	retlw   0
;
shftSL
	bcf     STATUS,C
;
	if   Mode16
	rlf     ACCcLO, F
	rlf     ACCcHI, F
	endif
;
	rlf     ACCbLO, F
	rlf     ACCbHI, F
	bcf     ACCbHI,MSB
	btfsc   STATUS,C
	bsf     ACCbHI,MSB
	retlw   0


;   Binary Floating Point Multiplication :
;   ACCb(16 bits)EXP(b) * ACCa(16 bits)EXPa -> ACCb(16 bits)EXPb
;
F_mpy
	call    S_SIGN
	call    setup
mloop
	bcf     STATUS,C    ; clear carry bit       ??????????
	rrf     ACCdHI, F       ;rotate d right
	rrf     ACCdLO, F
	btfsc   STATUS,C    ;need to add?
	call    D_add
	rrf     ACCbHI, F
	rrf     ACCbLO, F
	rrf     ACCcHI, F
	rrf     ACCcLO, F
	decfsz  temp, F         ;loop until all bits checked
	goto    mloop
;
	movf    EXPa,W
	addwf   EXPb, F
;
	IF   Mode16
	movf    ACCbHI, F
	btfss   STATUS,Z
	goto    finup           ; if ACCbHI != 0
	movf    ACCbLO, F
	btfss   STATUS,Z
	goto    Shft08          ; if ACCbLO != 0 && ACCbHI == 0
;
	movf    ACCcHI,W
	movwf   ACCbHI          ; if ACCb == 0, then move ACCc to ACCb
	movf    ACCcLO,W
	movwf   ACCbLO
	movlw   .16
	addwf   EXPb, F
	goto    finup
;
Shft08  movf    ACCbLO,W
	movwf   ACCbHI
	movf    ACCcHI,W
	movwf   ACCbLO
	movlw   .8
	addwf   EXPb, F
;
	ENDIF                   ; matching endif for IF Mode16
;
finup   btfss   sign,MSB
	goto    F_norm
;
	decf    ACCcLO, F       ; negate ACCc
	comf    ACCcLO, F
	btfsc   STATUS,Z
	decf    ACCcHI, F
	comf    ACCcHI, F
	btfsc   STATUS,Z
;
neg_B   decf    ACCbLO, F       ; negate ACCb
	comf    ACCbLO, F
	btfsc   STATUS,Z
	decf    ACCbHI, F
	comf    ACCbHI, F
;
	goto    F_norm

;   Floating Point Division :
;   ACCb(16 bits)EXP(b) / ACCa(16 bits)EXPa -> ACCb(16 bits)EXPb , with
;                               remainder in ACCc ( 16 bits ).
;
F_div   call    S_SIGN
	call    setup
	clrf    ACCcHI
	clrf    ACCcLO
dloop   bcf     STATUS,C     ;????????
	rlf     ACCdLO, F
	rlf     ACCdHI, F
	rlf     ACCcLO, F
	rlf     ACCcHI, F
	movf    ACCaHI,W        ; check if ACCa > ACCb
	subwf   ACCcHI,W
	btfss   STATUS,Z
	goto    nochk
	movf    ACCaLO,W
	subwf   ACCcLO,W        ;if msb equal then check lsb
nochk   btfss   STATUS,C    ;carry set if c>a
	goto    nogo
	movf    ACCaLO,W        ;c-a into c
	subwf   ACCcLO, F
	btfss   STATUS,C
	decf    ACCcHI, F
	movf    ACCaHI,W
	subwf   ACCcHI, F
	bsf     STATUS,C    ;shift a 1 into b (result)
nogo    rlf     ACCbLO, F
	rlf     ACCbHI, F
	decfsz  temp, F         ;loop untill all bits checked
	goto    dloop
	movf    EXPa,W
	subwf   EXPb, F
	btfss   sign,MSB
	goto    F_norm
	decf    ACCbLO, F       ; negate ACCb
	comf    ACCbLO, F
	btfsc   STATUS,Z
	decf    ACCbHI, F
	comf    ACCbHI, F
	goto    F_norm

S_SIGN
	movf    ACCaHI,W
	xorwf   ACCbHI,W
	movwf   sign
	btfss   ACCbHI,MSB        ; if MSB set go & negate ACCb
	goto    chek_A
;
	comf    ACCbLO, F        ; negate ACCb
	incf    ACCbLO, F
	btfsc   STATUS,Z
	decf    ACCbHI, F
	comf    ACCbHI, F
;
chek_A
	btfss   ACCaHI,MSB        ; if MSB set go & negate ACCa
	retlw   0
	goto    neg_A

;      Normalize Routine
; Normalizes ACCb for use in floating point calculations.
; Call this routine as often as possible to minimize the loss
; of precission. This routine normalizes ACCb so that the
; mantissa is maximized and the exponent minimized.
;
;
;
F_norm  movf    ACCbHI, F
	btfss   STATUS,Z
	goto    C_norm
	movf    ACCbLO, F
	btfsc   STATUS,Z
	retlw   0
C_norm  btfsc   ACCbHI,6
	retlw   0
	call    shftSL
	decf    EXPb, F
	goto    C_norm


;  Swap ACCa & ACCb   [ (ACCa,EXPa) <--> (ACCb,EXPb) ]
;
F_swap
	movf    ACCaHI,W
	movwf   temp
	movf    ACCbHI,W        ;ACCaHI <--> ACCbHI
	movwf   ACCaHI
	movf    temp,W
	movwf   ACCbHI
;
	movf    ACCaLO,W
	movwf   temp
	movf    ACCbLO,W        ;ACCaLO <--> ACCbLO
	movwf   ACCaLO
	movf    temp,W
	movwf   ACCbLO
;
	movf    EXPa,W
	movwf   temp
	movf    EXPb,W          ;EXPa <--> EXPb
	movwf   EXPa
	movf    temp,W
	movwf   EXPb
;
	retlw   0
;

#endif
		; USE_BINARY_FLOATS

millivolts_to_temp:					; converts millivolts in millivolt_h and millivolt_l to temperature in degrees Centigrade in celcius_h and celcius_l, and Kelvin in kelvin_h and kelvin_l,
									; sets NEGATIVE_TEMPERATURE_FLAG, assuming LM135 kelvin sensors.
; math:
; temp Celcius = 25 + 100 x (voltage - 2.982) (National handbook LM135) (range -273.2 to 226.8)		signed 16 bit
; temp Kelvin = celcius + 273

; Celcius = 25 +  ( (millivolts - 2982) / 10 )

; LM135:  temperature coefficient of 10mV/K. The nominal output voltage is therefore 2.73V at 0°C, and 3.73V at  100°C.

; so 0 K is 0 mV, 0 C = 273 K = 273 x 10 = 2730 mV
; so Kelvin is mV / 10

	movfw	millivolt_h
	movwf	ACCbHI

	movfw	millivolt_l			; millivolts in ACCb
	movwf	ACCbLO

	movlw	D'0'
	movwf	ACCaHI

	movlw	D'10'				; 10 in ACCa
	movwf	ACCaLO

	call	D_divF				; ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output

; Kelvin = mV / 10 in ACCb

; millivolts - 2982 in ACCb
	banksel	0
	
	movfw	ACCbHI
	movwf	kelvin_h

	movfw	ACCbLO
	movwf	kelvin_l

; Celcius = Kelvin - 273

	movlw	D'1'
	movwf	ACCaHI

;	movlw	D'17'
	movfw	temp_correction
	movwf	ACCaLO				; 273 in ACCa

	call	D_sub				; Double Precision Subtraction ( ACCb - ACCa -> ACCb )

	banksel	0

	movfw	ACCbHI
	movwf	celcius_h

	movfw	ACCbLO
	movwf	celcius_l			
	
	bcf	flags1,	NEGATIVE_TEMPERATURE_FLAG	
	
; if msb Hi is set, then temperature is negative.
	banksel	0
	btfss	ACCbHI,	7

	return
	
; temp negative, subtract the other way around:
; -Celcius = 273 - Kelvin 
	bsf	flags1,	NEGATIVE_TEMPERATURE_FLAG

	movfw	kelvin_h
	movwf	ACCaHI

	movfw	kelvin_l
	movwf	ACCaLO
	
	movlw	D'1'
	movwf	ACCbHI

;	movlw	D'17'
	movfw	temp_correction
	movwf	ACCbLO				; 273 in ACCb

	call	D_sub				; ACCb - ACCa -> ACCb 

	banksel	0

	movfw	ACCbHI
	movwf	celcius_h

	movfw	ACCbLO
	movwf	celcius_l

	return


print_celcius:
	banksel	0
	btfss	flags1, NEGATIVE_TEMPERATURE_FLAG
	goto	print_celcius_positive
; negative	
; print '-' sign
	movlw	'-'
	call	tx_w

print_celcius_positive:
	movfw	celcius_h
	movwf	bin 

	movfw	celcius_l
	movwf	bin+1

	call	print_16_ascii_dec

	banksel	0

	movlw	'°'
	call	tx_w
	movlw	'C'
	call	tx_w

	return	


print_millivolts:
	banksel	0
	movfw	millivolt_h
	movwf	bin 

	movfw	millivolt_l
	movwf	bin+1

	call	print_16_ascii_dec

	banksel	0

	movlw	'm'
	call	tx_w
	movlw	'V'
	call	tx_w

	return	


print_adc:
	banksel	0
	movfw	ad_h
	movwf	bin 

	movfw	ad_l
	movwf	bin+1

	call	print_16_ascii_dec

	banksel	0

	return	


ad_to_millivolts:					; converts AD reading in ad_h and ad_l to millivolts in volts_h and volts_l.
; math:
; Vref = 5070 mV 	
; voltage = (AD / 1023) x Vref (range 0 to Vref)											use signed 16 bit
; voltage = AD * (5.07 /  1023) = AD * 4.956 mV is aprox  AD * 5 mV 	

; AD * 49 / 10

; Vref in milli volts
	movlw	VREF_H				; D'19'
	movwf	ACCaHI
	movlw	VREF_L				; D'206'				; Vref in mV,  5070 
	movwf	ACCaLO

	movfw	ad_h
	movwf	ACCbHI
	movfw	ad_l
	movwf	ACCbLO

	call	D_mpyS         		; Double Precision Multiply ( 16 x 16 -> 32 ( ACCb * ACCa -> ACCb, ACCc ) : 32 bit output with high word, results in ACCb(16 msb's) and ACCc(16 lsb's)

; AD * 5000 in ACCb - ACCc range 0 to 5115000 for 5V Vref (32 bits)
; now divide by 1023 to get mV

; if we divide by 1024 we can use simple shifts and throw low bits away.	
; sr 1 = :2, sr 2 = :4, sr 3 = :8, sr 4 = :16, sr 5 = :32, sr 6 = :64 , sr 7 = :128 , sr 8 = :256, sr 9 = :512, sh 10 = :1024
; 1024 makes 1 byte plus 2 bits.
;  result ACCbHI, ACCbLO, ACCcHI, ACCcLO
; after 1 byte shift:
; result ACCbHI, ACCbLO, ACCcHI
; we know never more then about 5000, this fits in 2 bytes, throw away ACCbHI.
; now 16 bits divide by 4.
	movfw	ACCbLO
	movwf	ACCbHI				; overwrites ACCbHI
	movfw	ACCcHI
	movwf	ACCbLO

; divid by 4
	movlw	D'0'
	movwf	ACCaHI
	movlw	D'4'
	movwf	ACCaLO		

	call	D_divF				; Double Precision Divide ( 16/16 -> 16 )  ( ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output with Quotiont in ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO).

; milli volts now in ACCb
	banksel	0

	movfw	ACCbHI
	movwf	bin 
	movwf	millivolt_h

	movfw	ACCbLO
	movwf	bin+1
	movwf	millivolt_l

	return


print_time:
	movfw	hours
	call	print_w_ascii_dec
	
	movlw	':'
	call	tx_w

	movfw	minutes
	call	print_w_ascii_dec

	return



	end

