Mercurial > public > hwos_code
view src/adc_lightsensor.asm @ 601:08a0162d3ca1
Fix false CNS readings in logbook
author | heinrichsweikamp |
---|---|
date | Tue, 14 Aug 2018 11:01:47 +0200 |
parents | b455b31ce022 |
children | 00b24fb4324d |
line wrap: on
line source
;============================================================================= ; ; File adc.asm V2.98 ; ; ; Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved. ;============================================================================= ; HISTORY ; 2011-08-08 : [mH] moving from OSTC code #include "hwos.inc" #include "math.inc" #include "wait.inc" #include "eeprom_rs232.inc" #include "i2c.inc" extern reset_battery_internal_only sensors CODE ;============================================================================= wait_adc: movwf ADCON0 nop bsf ADCON0,1 ; start ADC wait_adc2: btfsc ADCON0,1 ; Wait... bra wait_adc2 return global get_battery_voltage get_battery_voltage: ; starts ADC and waits until finished btfss battery_gauge_available bra get_battery_voltage1 ; Normal ostc3 hardware call lt2942_get_accumulated_charge call lt2942_get_voltage tstfsz batt_voltage+1 ; <256mV? bra get_battery_voltage_noretry ; No ; Retry call lt2942_get_accumulated_charge call lt2942_get_voltage get_battery_voltage_noretry: btfsc divemode return ; Not in divemode bcf cv_active bcf cc_active bcf LEDr bcf TRISJ,2 ; Chrg-Out output bsf CHRG_OUT btfss CHRG_IN bra charge_cc_active bcf CHRG_OUT bsf TRISJ,2 ; Chrg-Out high impedance WAITMS d'1' btfsc CHRG_IN return ;cv_active: decfsz get_bat_volt_counter,F return movlw .15 cpfsgt batt_voltage+1 ; Batt Voltage >= 16*256mV (4,096V)? bra charge_cc_active ; No bsf cc_active bsf cv_active bsf LEDr ; Indicate charging call lt2942_charge_done ; Reset accumulating registers to 0xFFFF WAITMS d'10' bcf LEDr ; Indicate charging bsf get_bat_volt_counter,0 ; =1 return charge_cc_active: bsf cc_active bsf LEDr ; Indicate charging bcf CHRG_OUT bsf TRISJ,2 ; Chrg-Out high impedance movlw .10 movwf get_bat_volt_counter return get_battery_voltage1: bsf adc_running ; =1: The ADC is in use movlw b'00100000' ; 2.048V Vref+ -> 1LSB = 500µV movwf ADCON1 movlw b'00011001' ; power on ADC, select AN6 rcall wait_adc movff ADRESH,batt_voltage+1 ; store value movff ADRESL,batt_voltage+0 ; store value bcf ADCON0,0 ; power off ADC ; Multiply with 2,006 to be exact here... ; bcf STATUS,C ; rlcf xA+0,F ; ; rlcf xA+1,F ; x2 ; movff xA+0,batt_voltage+0 ; store value ; movff xA+1,batt_voltage+1 movlw LOW lithium_36v_low movwf sub_a+0 movlw HIGH lithium_36v_low movwf sub_a+1 movff batt_voltage+0,sub_b+0 movff batt_voltage+1,sub_b+1 call subU16 ; sub_c = sub_a - sub_b ; Battery is 3,6V (>lithium_36v_low?) btfss neg_flag bra get_battery_voltage4 ; No, use 1,5V bsf battery_is_36v ; Yes, set flag (Cleared in power-on reset only!) ; Check if the battery is near-dead already movlw LOW lithium_36v_empty movwf sub_a+0 movlw HIGH lithium_36v_empty movwf sub_a+1 call subU16 ; sub_c = sub_a - sub_b ; Battery is not dead yet (>lithium_36v_empty?) btfsc neg_flag bra get_battery_voltage2 ; Yes, battery is still ok ; Battery is probably dead very soon ; Set ">=24Ah used" into battery gauge registers movlw .128 movff WREG,battery_gauge+5 get_battery_voltage2: ; Use 3,6V battery gauging mode movff battery_gauge+5,xC+3 movff battery_gauge+4,xC+2 movff battery_gauge+3,xC+1 movff battery_gauge+2,xC+0 ; battery_gauge:6 is nAs ; devide through 65536 ; devide through battery_capacity:2 ; Result is in percent movff internal_battery_capacity+0,xB+0 movff internal_battery_capacity+1,xB+1 call div32x16 ; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder movff xC+0,lo ; Limit to 100 movlw .100 cpfslt lo movwf lo ; lo will be between 0 (Full) and 100 (empty) movf lo,W sublw .100 movwf lo get_battery_voltage3: movlw .100 cpfslt lo movwf lo ; lo will be between 100 (Full) and 0 (empty) ; use 3,6V battery sensing based on 50mA load ; 75% movff batt_voltage+0,sub_b+0 movff batt_voltage+1,sub_b+1 movlw LOW lithium_36v_75 movwf sub_a+0 movlw HIGH lithium_36v_75 movwf sub_a+1 call subU16 ; sub_c = sub_a - sub_b btfsc neg_flag bra get_battery_voltage3a movlw .75 movwf lo get_battery_voltage3a: ; 50% movlw LOW lithium_36v_50 movwf sub_a+0 movlw HIGH lithium_36v_50 movwf sub_a+1 call subU16 ; sub_c = sub_a - sub_b btfsc neg_flag bra get_battery_voltage3b movlw .50 movwf lo get_battery_voltage3b: ; 25% movlw LOW lithium_36v_25 movwf sub_a+0 movlw HIGH lithium_36v_25 movwf sub_a+1 call subU16 ; sub_c = sub_a - sub_b btfsc neg_flag bra get_battery_voltage3c movlw .25 movwf lo get_battery_voltage3c: ; 10% movlw LOW lithium_36v_10 movwf sub_a+0 movlw HIGH lithium_36v_10 movwf sub_a+1 call subU16 ; sub_c = sub_a - sub_b btfsc neg_flag bra get_battery_voltage3d movlw .10 movwf lo get_battery_voltage3d: movlw .100 cpfslt lo movwf lo ; lo will be between 100 (Full) and 0 (empty) movf batt_percent,W cpfsgt lo ; keep batt_percent on the lowest value found movff lo,batt_percent ; store value btfsc battery_is_36v ; but always use computed value for 3,6V battery movff lo,batt_percent ; store value bcf adc_running ; =1: The ADC is in use return get_battery_voltage4: ; Use 1,5V battery voltage mode ; Use approximation (batt_voltage:2-aa_15v_low)/4 = lo movff batt_voltage+0,sub_a+0 movff batt_voltage+1,sub_a+1 movlw LOW aa_15v_low movwf sub_b+0 movlw HIGH aa_15v_low movwf sub_b+1 call subU16 ; sub_c = sub_a - sub_b bcf STATUS,C rrcf sub_c+1 rrcf sub_c+0 ; /2 bcf STATUS,C rrcf sub_c+1 rrcf sub_c+0 ; /4 movff sub_c+0,lo bra get_battery_voltage3d ; Check limits and return global get_ambient_level get_ambient_level: ; starts ADC and waits until finished btfsc adc_running ; ADC in use? return ; Yes, return btfsc ambient_sensor bra get_ambient_level1 ; Normal ostc3 hardware banksel isr_backup ; Back to Bank0 ISR data movff opt_brightness,isr1_temp incf isr1_temp,F ; adjust 0-2 to 1-3 movlw ambient_light_max_high_cr ; cR and 2 hardware brightest setting dcfsnz isr1_temp,F movlw ambient_light_max_eco ; brightest setting dcfsnz isr1_temp,F movlw ambient_light_max_medium ; brightest setting movff WREG,ambient_light+0 ; Set to max. movff ambient_light+0,max_CCPR1L ; Store value for dimming in TMR7 interrupt return get_ambient_level1: movlw b'00000000' ; Vref+ = Vdd movwf ADCON1 movlw b'00011101' ; power on ADC, select AN7 rcall wait_adc movff ADRESH,ambient_light+1 movff ADRESL,ambient_light+0 bcf ADCON0,0 ; power off ADC ; ambient_light:2 is between 4096 (direct sunlight) and about 200 (darkness) ; First: Divide by 16 banksel ambient_light bcf STATUS,C rrcf ambient_light+1 rrcf ambient_light+0 bcf STATUS,C rrcf ambient_light+1 rrcf ambient_light+0 bcf STATUS,C rrcf ambient_light+1 rrcf ambient_light+0 bcf STATUS,C rrcf ambient_light+1 rrcf ambient_light+0 ; Result: ambient_light:2/16 ; Now, make sure to have value between ambient_light_low and ambient_light_max movlw .254 tstfsz ambient_light+1 ; >255? movwf ambient_light+0 ; avoid ADC clipping incfsz ambient_light+0,W ; =255? bra get_ambient_level2 ; No, continue movlw .254 movwf ambient_light+0 ; avoid ADC clipping get_ambient_level2: ; movlw .10 ; subwf ambient_light+0,F ; Subtract 10 (ADC Offset) ; btfsc STATUS,N ; movwf ambient_light+0 ; avoid clipping banksel isr_backup ; Back to Bank0 ISR data movff opt_brightness,isr1_temp btfsc RCSTA1,7 ; UART module on? clrf isr1_temp ; Yes, set temporally to eco mode incf isr1_temp,F ; adjust 0-2 to 1-3 banksel common ; flag is in bank1 movlw ambient_light_max_high_cr ; cR and 2 hardware brightest setting btfss battery_gauge_available movlw ambient_light_max_high_15V ; 1,5V battery brightest setting btfsc battery_is_36v ; 3,6V battery in use? movlw ambient_light_max_high_36V ; 3,6V battery brightest setting banksel isr_backup ; Back to Bank0 ISR data dcfsnz isr1_temp,F movlw ambient_light_max_eco ; brightest setting dcfsnz isr1_temp,F movlw ambient_light_max_medium ; brightest setting banksel ambient_light incf ambient_light+0,F ; +1 cpfslt ambient_light+0 ; smaller then WREG? movwf ambient_light+0 ; No, set to max. banksel isr_backup ; Back to Bank0 ISR data movff opt_brightness,isr1_temp incf isr1_temp,F ; adjust 0-2 to 1-3 movlw ambient_light_min_high ; darkest setting dcfsnz isr1_temp,F movlw ambient_light_min_eco ; darkest setting dcfsnz isr1_temp,F movlw ambient_light_min_medium ; darkest setting dcfsnz isr1_temp,F movlw ambient_light_min_high ; darkest setting banksel ambient_light cpfsgt ambient_light+0 ; bigger then WREG? movwf ambient_light+0 ; No, set to min banksel common movff ambient_light+0,max_CCPR1L ; Store value for dimming in TMR7 interrupt return global get_analog_inputs get_analog_inputs: ; starts ADC and waits until finished bsf adc_running ; =1: The ADC is in use btfsc TFT_PWM bra get_analog_inputs ; Wait for PWM low movlw b'00100000' ; 2.048V Vref+ -> 1LSB = 500µV movwf ADCON1 movlw b'00100001' ; power on ADC, select AN8 rcall wait_adc bcf STATUS,C rrcf ADRESH,F ; /2 rrcf ADRESL,W ; add to o2_mv_sensor1:2 addwf o2_mv_sensor1+0,F movf ADRESH,W addwfc o2_mv_sensor1+1,F ; Devide by 2 bcf STATUS,C rrcf o2_mv_sensor1+1,F ; /2 rrcf o2_mv_sensor1+0,F movlw HIGH ignore_mv cpfsgt o2_mv_sensor1+1 ; >ignore_mv? bra get_analog_inputs2a ; No ; Yes, ignore this reading clrf o2_mv_sensor1+1 clrf o2_mv_sensor1+0 get_analog_inputs2a: ; Ignore 1,9mV noise for not-connected inputs tstfsz o2_mv_sensor1+1 ; >25,5mV? bra get_analog_inputs2 ; Yes, skip here movlw .19 cpfsgt o2_mv_sensor1+0 ; >1,9mV? clrf o2_mv_sensor1+0 ; no, clear result get_analog_inputs2: movlw b'00100101' ; power on ADC, select AN9 rcall wait_adc bcf STATUS,C rrcf ADRESH,F ; /2 rrcf ADRESL,W ; add to o2_mv_sensor2:2 addwf o2_mv_sensor2+0,F movf ADRESH,W addwfc o2_mv_sensor2+1,F ; Devide by 2 bcf STATUS,C rrcf o2_mv_sensor2+1,F ; /2 rrcf o2_mv_sensor2+0,F movlw HIGH ignore_mv cpfsgt o2_mv_sensor2+1 ; >ignore_mv? bra get_analog_inputs3a ; No ; Yes, ignore this reading clrf o2_mv_sensor2+1 clrf o2_mv_sensor2+0 get_analog_inputs3a: ; Ignore 1,9mV noise for not-connected inputs tstfsz o2_mv_sensor2+1 ; >25,5mV? bra get_analog_inputs3 ; Yes, skip here movlw .19 cpfsgt o2_mv_sensor2+0 ; >1,9mV? clrf o2_mv_sensor2+0 ; no, clear result get_analog_inputs3: movlw b'00101001' ; power on ADC, select AN10 rcall wait_adc bcf STATUS,C rrcf ADRESH,F ; /2 rrcf ADRESL,W ; add to o2_mv_sensor3:2 addwf o2_mv_sensor3+0,F movf ADRESH,W addwfc o2_mv_sensor3+1,F ; Devide by 2 bcf STATUS,C rrcf o2_mv_sensor3+1,F ; /2 rrcf o2_mv_sensor3+0,F movlw HIGH ignore_mv cpfsgt o2_mv_sensor3+1 ; >ignore_mv? bra get_analog_inputs4a ; No ; Yes, ignore this reading clrf o2_mv_sensor3+1 clrf o2_mv_sensor3+0 get_analog_inputs4a: ; Ignore 1,9mV noise for not-connected inputs tstfsz o2_mv_sensor3+1 ; >25,5mV? bra get_analog_inputs4 ; Yes, skip here movlw .19 cpfsgt o2_mv_sensor3+0 ; >1,9mV? clrf o2_mv_sensor3+0 ; no, clear result get_analog_inputs4: bcf ADCON0,0 ; power off ADC bcf adc_running ; =1: The ADC is in use return global piezo_config ; sets up piezo sensitivity of heinrichs weikamp piezo buttons (~30ms) piezo_config: ; Settings between 20 and 200 clrf TMR5H clrf TMR5L ; ~2sec bcf PIR5,TMR5IF ; Clear flag bcf switch_right bcf switch_left piezo_config0: btfsc switch_right bra piezo_config btfsc switch_left bra piezo_config ; Restart on button press btfss PIR5,TMR5IF bra piezo_config0 ; Wait loop bcf INTCON,GIE movff opt_cR_button_right,WREG ; right button btfsc flip_screen ; 180° rotation ? movff opt_cR_button_left,WREG ; Yes, left button rcall piezo_config_tx movff opt_cR_button_left,WREG ; left button btfsc flip_screen ; 180° rotation ? movff opt_cR_button_right,WREG ; Yes, right button rcall piezo_config_tx movlw .20 ; reserved rcall piezo_config_tx movlw .20 ; reserved rcall piezo_config_tx bsf INTCON,GIE return piezo_config_tx: ; send one byte movwf lo ; store byte movlw .8 movwf hi ; bit counter bcf TX3_PIEZO_CFG ; start bit rcall piezo_config_wait_bit piezo_config_tx_loop: btfss lo,0 ; LSB first bcf TX3_PIEZO_CFG btfsc lo,0 ; LSB first bsf TX3_PIEZO_CFG rcall piezo_config_wait_bit rrncf lo,F decfsz hi,F bra piezo_config_tx_loop bsf TX3_PIEZO_CFG ; stop bit rcall piezo_config_wait_bit return piezo_config_wait_bit: setf TMR5H movlw .255-.26 ; 26 x 31,5µs = 819us movwf TMR5L bcf PIR5,TMR5IF ; Clear flag piezo_config_wait_bit3: btfss PIR5,TMR5IF bra piezo_config_wait_bit3 ; Wait loop return global reset_battery_pointer reset_battery_pointer: ; Resets battery pointer 0x07-0x0C and battery_gauge:5 extern lt2942_charge_done btfsc battery_gauge_available ; Something to reset? call lt2942_charge_done ; Yes, reset accumulating registers to 0xFFFF goto reset_battery_internal_only ; and return global get_analog_switches get_analog_switches: ; starts ADC and waits until finished btfsc analog_switches bra get_analog_switches2 ; no analog switches bcf analog_sw2_pressed bcf analog_sw1_pressed return ; Done. get_analog_switches2: btfsc adc_running ; ADC in use? return ; Yes, return movlw b'00001001' ; left justified movwf ADCON2 ; movlw b'00000000' ; Vref+ = Vdd clrf ADCON1 movlw b'00100101' ; power on ADC, select AN9 rcall wait_adc banksel analog_counter movff ADRESH,WREG addwf analog_sw2_raw+0 movlw .0 addwfc analog_sw2_raw+1 decfsz analog_counter,F ; continue averaging? bra get_analog_switches2a ; Yes ; Done. Compute average bcf STATUS,C rrcf analog_sw2_raw+1 rrcf analog_sw2_raw+0 ; /2 bcf STATUS,C rrcf analog_sw2_raw+1 rrcf analog_sw2_raw+0 ; /4 bcf STATUS,C rrcf analog_sw2_raw+1 rrcf analog_sw2_raw+0 ; /8 bcf STATUS,C rrcf analog_sw2_raw+1 rrcf analog_sw2_raw+0 ; /16 movff analog_sw2_raw+0,analog_sw2 clrf analog_sw2_raw+1 clrf analog_sw2_raw+0 ; Reset average registers ; movlw .16 ; movwf analog_counter ; only once... get_analog_switches2a: banksel common bcf analog_sw2_pressed movff opt_cR_button_left,WREG ;20-100 bcf STATUS,C rrcf WREG ;/2 -> 10-50 bcf STATUS,C rrcf WREG ;/2 -> 5-25 decf WREG,W ;-1 decf WREG,W ;-1 decf WREG,W ;-1 -> 2-22 banksel analog_sw2 btfss button_polarity,1 ;(1= normal, 0=inverted) bra sw2_inverted addwf analog_sw2,W ; average (~128) cpfsgt ADRESH bra get_analog_sw1 banksel common bsf analog_sw2_pressed ; Left button normal bra get_analog_sw1 sw2_inverted: subwf analog_sw2,W ; average (~128) cpfslt ADRESH bra get_analog_sw1 banksel common bsf analog_sw2_pressed ; Left button inverted get_analog_sw1: banksel common movlw b'00101001' ; power on ADC, select AN10 rcall wait_adc banksel analog_counter movff ADRESH,WREG addwf analog_sw1_raw+0 movlw .0 addwfc analog_sw1_raw+1 tstfsz analog_counter ; continue averaging? bra get_analog_switches1a ; Yes ; Done. Compute average bcf STATUS,C rrcf analog_sw1_raw+1 rrcf analog_sw1_raw+0 ; /2 bcf STATUS,C rrcf analog_sw1_raw+1 rrcf analog_sw1_raw+0 ; /4 bcf STATUS,C rrcf analog_sw1_raw+1 rrcf analog_sw1_raw+0 ; /8 bcf STATUS,C rrcf analog_sw1_raw+1 rrcf analog_sw1_raw+0 ; /16 movff analog_sw1_raw+0,analog_sw1 clrf analog_sw1_raw+1 clrf analog_sw1_raw+0 ; Reset average registers movlw .16 movwf analog_counter ; only once... get_analog_switches1a: banksel common bcf analog_sw1_pressed movff opt_cR_button_right,WREG ;20-100 bcf STATUS,C rrcf WREG ;/2 -> 10-50 bcf STATUS,C rrcf WREG ;/2 -> 5-25 decf WREG,W ;-1 decf WREG,W ;-1 decf WREG,W ;-1 -> 2-22 banksel analog_sw1 btfss button_polarity,0 ;(1= normal, 0=inverted) bra sw1_inverted addwf analog_sw1,W ; average (~128) cpfsgt ADRESH bra get_analog_sw_done banksel common bsf analog_sw1_pressed ; right button normal bra get_analog_sw_done sw1_inverted: subwf analog_sw1,W ; average (~128) cpfslt ADRESH bra get_analog_sw_done banksel common bsf analog_sw1_pressed ; right button inverted get_analog_sw_done: banksel common movlw b'10001101' ; Restore to right justified movwf ADCON2 btfsc analog_sw1_pressed return btfsc analog_sw2_pressed return setf TMR1H ; No button pressed, enhance timer1 to overflow quickly return END