jockmack Newbie
Joined: 17/03/2024 Location: AustraliaPosts: 5 |
Posted: 04:09am 20 Mar 2024 |
Copy link to clipboard |
Print this post |
|
Hello to everyone, I am new to the group but have a problem with a project I am unsure of how to solve.
I recently built the SC project "Battery multi logger". Its based on micromite type design using PIC32MX170, it uses AD7192 four channel 24 bit ADC with SPI interface. A pic 16F1455 also provide USB to serial interface.
The problem is it works but I am unable to calibrate the current settings for the inputs. I have included some photos to show the interface on the LCD touchscreen ILI9341.
I was able to calibrate the volts OK and it is working fine but when trying to save any of the current values it appears to lock up the display. I don't believe the PIC is locked up as when the display is frozen I can still access the PIC and interrogate it via the USB port and Tera term. Only a power cycle will clear the display.
I have reloaded the hex image as per Silicon Chip download but the behaviour was the same. The images are in sequence, when you accept the value entered another OK Cancel buttons are displayed below the original OK Cancel buttons.Selecting OK locks up but Cancel will take you back to the calibration selection display.
The original basic code is as below.
I would expect there is no bugs as SC would have tested and I haven't seen any errata or notes regarding this project.
One other anomaly I noticed was when initially setting up the touch screen (2.8"v1.2)buttons were mirror imaged as to the touch sensor, I did a GUI calibrate and it flipped the touch sensor but it did complain it with Warning: inaccurate calibration 0, 3937, 3855, -904, -544. original setting was 0, 192, 230, 908, 687.as per SC provided PIC32MX170.
If someone could point me to where I should look I would be grateful.
Thanks
Jock
OPTION EXPLICIT OPTION BASE 0 OPTION AUTORUN ON CONST BG_COL = RGB(BLACK) CONST FG_COL = RGB(WHITE) CONST FADE_COL = RGB(128,128,128) CONST BUTTON_COL = RGB(CYAN) CONST ERROR_COLOUR = RGB(RED) CONST HL_COLOUR = RGB(BLACK) CONST AXIS_COLOUR = RGB(128,128,128) CONST AXIS_LEFT = 34 CONST AXIS_RIGHT = 286 CONST AXIS_TOP = 36 CONST AXIS_BOTTOM = 190 CONST V_COLOUR = RGB(RED) CONST I1_COLOUR = RGB(YELLOW) CONST I2_COLOUR = RGB(GREEN) CONST I3_COLOUR = RGB(CYAN) CONST I4_COLOUR = RGB(BLUE) ''using Micromite % units Dim Integer ON_BL Dim Integer IDLE_BL Dim Integer MN_TMOUT CONST IDLE_TIMEOUT = 5000 DIM INTEGER DISPLAY_TIMEOUT ON_BL = 70 IDLE_BL = 5 MN_TMOUT = 55000 '' AD7192 interface '' using HW SPI on 3/25/14 (MOSI/SCK/MISO) '' ~5MHz max frequency '' full scale = 2^24 (16777216) '' 2.5V reference with 39/1 divider => FS=100V '' nominal value of Vx_CAL is 100/16777216 '' 15m# shunts for current const ADC_CS=24 DIM FLOAT V_CAL(5) 'four multipliers by raw 24bit ADC value V_CAL(1)=100/16777216 ''nominal 100V/24bit full scale V_CAL(2)=V_CAL(1) V_CAL(3)=V_CAL(1) V_CAL(4)=V_CAL(1) 'DIM FLOAT V_ACT(5),V_SAMPLE(5) 'four readings SETPIN ADC_CS,DOUT ''this stays on at all times to keep CS high pin(ADC_CS)=1 CONST ADC_TIMEOUT = 1200 ''allows four samples/five seconds, typically takes 850ms/sample '' analog read on pin 4 for buck reg current shunt CONST SHUNT_ADC=4 SETPIN SHUNT_ADC,AIN DIM FLOAT I_CAL(5) I_CAL(1) = -1/(100*0.1) '0.1# shunt with x100 gain same as 10# resistor. 1V => 100mA, result in A I_CAL(2) = -1/0.015 'nominal 15m# shunt I_CAL(3) = -1/0.015 'nominal 15m# shunt I_CAL(4) = -1/0.015 'nominal 15m# shunt DIM FLOAT I_RATIO(5) ''used in alternate calibration, are ratio of I dividers to main V divider ''calculated on each sample ready for calibration, so V_CAL(2)=I_RATIO(2)*V_CAL(1) etc I_RATIO(2)=1 I_RATIO(3)=1 I_RATIO(4)=1 ' globals used by Sub DrawButton CONST BUTTON_COUNT = 30 Dim Integer key_coord(BUTTON_COUNT, 5) Dim String key_caption(BUTTON_COUNT) DIM INTEGER BUTTON_PRESS CONST SMOOTHING_FACTOR = 0 'number of samples over which data is exponentially smoothed ((OLD * SF)+ NEW)/(SF+1) 0=> no smoothing ''globals used as statics within subs ''sampling plan: ''channels take about a second each, so say 5s per scan, gives 12/min, 720/hr (hourly good for long term) ~2 days ''5 variables: Voltage and 4 currents DIM FLOAT NEW_RAW(10) 'for processing and smoothing NEW_RAW(0)=0 NEW_RAW(1)=-1 NEW_RAW(2)=0 NEW_RAW(3)=0 NEW_RAW(4)=0 NEW_RAW(5)=0 NEW_RAW(6)=0 NEW_RAW(7)=0 NEW_RAW(8)=0 NEW_RAW(9)=0 DIM INTEGER RAW_ACTUAL(6) 'raw smoothed ADC results RAW_ACTUAL(0)=0 'ignore 0 index RAW_ACTUAL(1)=-1 'voltage, set as error to flag at startup RAW_ACTUAL(2)=0 'current 1 RAW_ACTUAL(3)=0 'current 2 RAW_ACTUAL(4)=0 'current 3 RAW_ACTUAL(5)=0 'current 4 ''actual now values, in units of volts/amps- all floats are these units DIM FLOAT ACTUAL(6) ACTUAL(0)=0 'ignore 0 index ACTUAL(1)=0 'voltage ACTUAL(2)=0 'current 1 ACTUAL(3)=0 'current 2 ACTUAL(4)=0 'current 3 ACTUAL(5)=0 'current 4 ''for capacity checking DIM FLOAT V_FULL,V_EMPTY,I_SCALE,V_SHUTDOWN ''defaults for 12V V_FULL=14.4 V_EMPTY=11.0 V_SHUTDOWN=10.5 I_SCALE=20 ''usage tracking DIM FLOAT AH_SINCEF, AH_SINCEE, WH_SINCEF, WH_SINCEE DIM INTEGER USAGE_STATE AH_SINCEF=0 AH_SINCEE=0 WH_SINCEF=0 WH_SINCEE=0 USAGE_STATE=0 ' +1= min reached, +2=max reached => 3=data complete ''these are at the limit of VAR SAVE CONST S_COUNT = 720 CONST H_COUNT = 48 CONST D_COUNT = 17 DIM INTEGER SAMPLE_STATE, SAMPLE_PTR SAMPLE_STATE=0 SAMPLE_PTR=0 ''(is index into 720 below) ''these arrays are filled from the start and then 'scrolled' DIM INTEGER D_START, D_PTR ''what is day of first item in D_SAMP (format?), pointer into D_SAMP array DIM INTEGER H_START, H_PTR ''what is day of first item in H_SAMP (format?), pointer into H_SAMP array D_PTR=0 H_PTR=0 ''to be set by RTC or when needed D_START=0 H_START=0 DIM FLOAT SAMPLES(5,S_COUNT) ''an hour of samples, this takes 17k of RAM, not saved DIM FLOAT H_SAMP(5,H_COUNT) ''2 days of hourly samples (takes 1189 bytes in VAR SAVE) DIM FLOAT D_SAMP(5,D_COUNT) ''32 days of daily samples (takes 709 bytes) ''loop counters etc DIM I AS INTEGER ''mark values as invalid ''currents can be +/- so use V as flag FOR I = 0 to S_COUNT-1 SAMPLES(0,I)=-1 SAMPLES(1,I)=0 SAMPLES(2,I)=0 SAMPLES(3,I)=0 SAMPLES(4,I)=0 NEXT I FOR I = 0 to H_COUNT-1 H_SAMP(0,I)=-1 H_SAMP(1,I)=0 H_SAMP(2,I)=0 H_SAMP(3,I)=0 H_SAMP(4,I)=0 NEXT I FOR I = 0 to D_COUNT-1 D_SAMP(0,I)=-1 D_SAMP(1,I)=0 D_SAMP(2,I)=0 D_SAMP(3,I)=0 D_SAMP(4,I)=0 NEXT I ''display state management DIM INTEGER DISPLAYSTATE DISPLAYSTATE=2 'on ''temp for calculation and display DIM INTEGER DISP_NUM ''SETUP VAR RESTORE VAR SAVE H_SAMP(),D_SAMP(),D_START, D_PTR,H_START, H_PTR, V_CAL(), I_CAL(),ON_BL,IDLE_BL,MN_TMOUT,V_EMPTY,V_FULL,AH_SINCEF, AH_SINCEE, WH_SINCEF, WH_SINCEE,I_SCALE,V_SHUTDOWN LCD_ON ''turn on LCD CLS(BG_COL) SET_BACKLIGHT(ON_BL) ''check RTC, ignore errors ON ERROR IGNORE RTC GETTIME ON ERROR ABORT DISPLAY_TIMEOUT=TIMER ''this is used to monitor our display timeout DRAW_MAIN DO ''main loop, calls other routines as needed, they should DRAW_MAIN before returning SAMPLE_MANAGER ''check sampling SAMPLE_MANAGER ''do this twice as every second event happens quickly ''minute skipper for testing ''IF val(mid$(TIME$,4,2))<59 and val(mid$(TIME$,7,2))> 10 THEN SET_RTC(4,59):SET_RTC(5,45) ''if minutes =1 , change to 59,so we can scroll through time quickly ''check buttons if DISPLAYSTATE>0 THEN 'debug data for display timeout TEXT 315,0,right$(" "+str$(INT(((MN_TMOUT+IDLE_TIMEOUT)-(TIMER-DISPLAY_TIMEOUT))\1000)),8),RT,1,1,FG_COL,BG_COL 'debug data for full/empty state 3=both states reached 'TEXT 0,0,right$(" "+str$(USAGE_STATE),3),LT,1,1,FG_COL,BG_COL IF CHECK_SCREEN_TOUCH()=1 THEN DISPLAY_TIMEOUT=TIMER ''counts time awake, reset if screen touched IF DISPLAYSTATE<2 THEN DISPLAYSTATE=2 SET_BACKLIGHT(ON_BL) ENDIF ENDIF BUTTON_PRESS=CheckButtonPress(0, 2) IF BUTTON_PRESS >= 0 THEN ''wake up/set full backlight on button press in case we missed it DISPLAYSTATE=2 SET_BACKLIGHT(ON_BL) if BUTTON_PRESS=0 THEN CheckButtonRelease(0) DATA_MENU ENDIF if BUTTON_PRESS=1 THEN CheckButtonRelease(0) SETTINGS_MENU ENDIF if BUTTON_PRESS=2 THEN CheckButtonRelease(0) CALIBRATE_MENU ENDIF ENDIF ''display voltages etc on idle screen TEXT 160,68," "+DATE$+" "+TIME$+" ",CT,1,1,FG_COL,BG_COL IF RAW_ACTUAL(1)<0 THEN ''sampling error TEXT 45,84,"ERROR",CT,1,1,ERROR_COLOUR,BG_COL ELSE TEXT 45,84," OK ",CT,1,1,FG_COL,BG_COL ENDIF TEXT 4,100,"V="+STR$(ACTUAL(1), 5, 2)+"V",LT,1,1,FG_COL,BG_COL TEXT 4,116,"I1="+STR$(ACTUAL(2), 4, 2)+"A",LT,1,1,FG_COL,BG_COL TEXT 4,132,"I2="+STR$(ACTUAL(3), 4, 2)+"A",LT,1,1,FG_COL,BG_COL TEXT 4,148,"I3="+STR$(ACTUAL(4), 4, 2)+"A",LT,1,1,FG_COL,BG_COL TEXT 4,164,"I4="+STR$(ACTUAL(5), 4, 2)+"A",LT,1,1,FG_COL,BG_COL IF V_FULL - V_EMPTY > 0.1 THEN DISP_NUM = ((ACTUAL(1)-V_EMPTY)*100)/(V_FULL - V_EMPTY) if DISP_NUM<0 THEN DISP_NUM=0 IF DISP_NUM>100 THEN DISP_NUM=100 TEXT 112,84,"CHGv="+STR$(DISP_NUM, 3, 0)+"%",LT,1,1,FG_COL,BG_COL ELSE TEXT 112,84,"CHGv=---%",LT,1,1,ERROR_COLOUR,BG_COL ENDIF TEXT 112,116,"Ah since full= "+STR$(AH_SINCEF, 6, 1)+"Ah",LT,1,1,FG_COL,BG_COL TEXT 112,132,"Ah since empty="+STR$(AH_SINCEE, 6, 1)+"Ah",LT,1,1,FG_COL,BG_COL TEXT 112,148,"Wh since full= "+STR$(WH_SINCEF, 6, 1)+"Wh",LT,1,1,FG_COL,BG_COL TEXT 112,164,"Wh since empty="+STR$(WH_SINCEE, 6, 1)+"Wh",LT,1,1,FG_COL,BG_COL DISP_NUM=0 'use this one to display capacity based on AH 'IF (AH_SINCEF-AH_SINCEE)>0.1 THEN DISP_NUM = (-AH_SINCEE*100)/(AH_SINCEF-AH_SINCEE) 'use this one to display capacity based on WH IF (WH_SINCEF-WH_SINCEE)>0.1 THEN DISP_NUM = (-WH_SINCEE*100)/(WH_SINCEF-WH_SINCEE) if DISP_NUM<0 THEN DISP_NUM=0 IF DISP_NUM>100 THEN DISP_NUM=100 IF USAGE_STATE>2 THEN TEXT 200,84,"CAP="+STR$(AH_SINCEF-AH_SINCEE, 6, 1)+"Ah",LT,1,1,FG_COL,BG_COL TEXT 200,100,"CAP="+STR$(WH_SINCEF-WH_SINCEE, 6, 1)+"Wh",LT,1,1,FG_COL,BG_COL TEXT 112,100,"CHGm="+STR$(DISP_NUM, 3, 0)+"%",LT,1,1,FG_COL,BG_COL ELSE TEXT 200,84,"CAP="+STR$(AH_SINCEF-AH_SINCEE, 6, 1)+"Ah",LT,1,1,FADE_COL,BG_COL TEXT 200,100,"CAP="+STR$(WH_SINCEF-WH_SINCEE, 6, 1)+"Wh",LT,1,1,FADE_COL,BG_COL TEXT 112,100,"CHGm="+STR$(DISP_NUM, 3, 0)+"%",LT,1,1,FADE_COL,BG_COL ENDIF ''update brightness and dim as needed ''fade IF (DISPLAYSTATE > 1) and ((TIMER-DISPLAY_TIMEOUT)>MN_TMOUT) THEN DISPLAYSTATE=1 SET_BACKLIGHT(IDLE_BL) ENDIF ''off IF ((TIMER-DISPLAY_TIMEOUT)>MN_TMOUT+IDLE_TIMEOUT) THEN DISPLAYSTATE=0 SET_BACKLIGHT(0) LCD_OFF ENDIF PAUSE 50 ''wait a little between updates ELSE ''wait for touches and reset IF ACTUAL(1)> V_SHUTDOWN THEN CPU SLEEP 1 ''this is how we get very low power ELSE CPU SLEEP 15 ''longer shutdown for low power, ADC goes to sleep after conversion ENDIF IF CHECK_SCREEN_TOUCH()=1 THEN DISPLAY_TIMEOUT=TIMER ''counts time awake, reset if screen touched DISPLAYSTATE=2 ''fully awake LCD_ON CLS(BG_COL) ''light up to let know that it's sensed the touch SET_BACKLIGHT(ON_BL) WAIT_FOR_RELEASE DRAW_MAIN ''draw display when touch released ENDIF ENDIF LOOP WATCHDOG 1 'in case we get here, restart END SUB CALIBRATE_MENU DRAW_CALIBRATE DO SAMPLE_MANAGER BUTTON_PRESS=CheckButtonPress(0, 5) IF BUTTON_PRESS >= 0 THEN CheckButtonRelease(BUTTON_PRESS) IF BUTTON_PRESS = 0 THEN 'volts IF OK_CANCEL_BOX("ENSURE NO LOAD","ON TERMINALS")>0 THEN DO_V_CAL DRAW_CALIBRATE 'return ENDIF IF (BUTTON_PRESS >=1) AND (BUTTON_PRESS <=4) THEN 'I1 DO_I_CAL(BUTTON_PRESS) DRAW_CALIBRATE 'return ENDIF IF BUTTON_PRESS = 5 THEN EXIT DO ENDIF LOOP DRAW_MAIN END SUB SUB SETTINGS_MENU DRAW_SETTINGS LOCAL FLOAT NUM DO TEXT 160,30," "+DATE$+" "+TIME$+" ",CT,1,1,FG_COL,BG_COL SAMPLE_MANAGER BUTTON_PRESS=CheckButtonPress(0, 13) IF BUTTON_PRESS >= 0 THEN CheckButtonRelease(BUTTON_PRESS) IF BUTTON_PRESS = 0 THEN 'year NUM=NUMBERPAD("Enter year:") IF NUM >= 2000 THEN SET_RTC(0,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 1 THEN 'month NUM=NUMBERPAD("Enter month:") IF (NUM >= 1) AND (NUM <= 12) THEN SET_RTC(1,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 2 THEN 'day NUM=NUMBERPAD("Enter day number:") IF (NUM >= 1) AND (NUM <= 31) THEN SET_RTC(2,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 3 THEN 'hour NUM=NUMBERPAD("Enter hour (24):") IF (NUM >= 1) AND (NUM <= 24) THEN SET_RTC(3,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 4 THEN 'minute NUM=NUMBERPAD("Enter minute:") IF (NUM >= 1) AND (NUM <= 60) THEN SET_RTC(4,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 5 THEN 'second NUM=NUMBERPAD("Enter second:") IF (NUM >= 1) AND (NUM <= 60) THEN SET_RTC(5,NUM) DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 6 THEN 'BL full NUM=NUMBERPAD("Enter Backlight%:") IF (NUM >= 1) AND (NUM <= 100) THEN ON_BL=NUM:SET_BACKLIGHT(ON_BL):VAR SAVE ON_BL DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 9 THEN 'BL dim NUM=NUMBERPAD("Enter Backlight%:") IF (NUM >= 1) AND (NUM <= 100) THEN IDLE_BL=NUM:VAR SAVE IDLE_BL DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 8 THEN 'BL timeout NUM=NUMBERPAD("Enter timeout(s):") IF (NUM*1000 > IDLE_TIMEOUT) THEN MN_TMOUT=NUM*1000-IDLE_TIMEOUT : VAR SAVE MN_TMOUT DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 7 THEN 'Vfull NUM=NUMBERPAD("Enter V(full):") IF (NUM>=5) AND (NUM>V_EMPTY) AND (NUM>V_SHUTDOWN) THEN V_FULL=NUM VAR SAVE V_FULL ELSE MessageBox("V(full) too low","Check and retry") ENDIF DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 10 THEN 'Vempty NUM=NUMBERPAD("Enter V(empty):") IF (NUM>=5) AND (NUM<V_FULL) AND (NUM>V_SHUTDOWN) THEN V_EMPTY=NUM VAR SAVE V_EMPTY ELSE MessageBox("V(empty) too low","or above V(full)") ENDIF DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 12 THEN 'Iscale NUM=NUMBERPAD("Enter I(scale):") IF (NUM>=1) THEN I_SCALE=NUM VAR SAVE I_SCALE ELSE MessageBox("I(scale)","too low") ENDIF DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 13 THEN 'Vshutdown NUM=NUMBERPAD("Enter V(shutdown):") IF ((NUM >= 0) AND (NUM<V_EMPTY)) THEN V_SHUTDOWN=NUM VAR SAVE V_SHUTDOWN ELSE MessageBox("V(shutdown)","too high") ENDIF DRAW_SETTINGS 'return ENDIF IF BUTTON_PRESS = 11 THEN EXIT DO 'back ENDIF LOOP DRAW_MAIN END SUB SUB SET_RTC(S AS INTEGER, P AS INTEGER) '' sets parameter s to p (y=0,m=1,d=2,h=3,m=4,s=5) as per RTC SETTIME LOCAL INTEGER T(6) T(0)=val(mid$(DATE$,7,4)) 'year T(1)=val(mid$(DATE$,4,2)) 'month T(2)=val(mid$(DATE$,1,2)) 'day T(3)=val(mid$(TIME$,1,2)) 'hour/24 T(4)=val(mid$(TIME$,4,2)) 'minute T(5)=val(mid$(TIME$,7,2)) 'second IF (S>=0) AND (S<=5) THEN T(S)=P'validation must occur before calling ON ERROR IGNORE RTC SETTIME T(0),T(1),T(2),T(3),T(4),T(5) ON ERROR ABORT END SUB SUB DATA_MENU LOCAL INTEGER GRAPH_MODE LOCAL INTEGER UPDATE_TIME UPDATE_TIME=TIMER GRAPH_MODE=0 DRAW_DATA DRAW_GRAPH(GRAPH_MODE) DO SAMPLE_MANAGER BUTTON_PRESS=CheckButtonPress(0, 4) IF BUTTON_PRESS >= 0 THEN CheckButtonRelease(BUTTON_PRESS) IF BUTTON_PRESS < 3 THEN GRAPH_MODE=BUTTON_PRESS: DRAW_GRAPH(GRAPH_MODE): UPDATE_TIME=TIMER IF BUTTON_PRESS = 3 THEN EXIT DO IF BUTTON_PRESS = 4 THEN EXPORT_DATA(GRAPH_MODE) ENDIF 'check for touches on scale and display IF (TIMER - UPDATE_TIME) > 60000 THEN DRAW_GRAPH(GRAPH_MODE): UPDATE_TIME=TIMER ''update every minute LOOP DRAW_MAIN END SUB SUB DRAW_GRAPH(N AS INTEGER) ''0=hours, 1=days, 2=weeks LOCAL INTEGER I ''clear chart area BOX 0,AXIS_TOP,319,AXIS_BOTTOM-AXIS_TOP+1,,BG_COL,BG_COL ''axes LINE AXIS_LEFT,AXIS_TOP,AXIS_RIGHT,AXIS_TOP,1,AXIS_COLOUR LINE AXIS_LEFT,AXIS_TOP,AXIS_LEFT,AXIS_BOTTOM,1,AXIS_COLOUR LINE AXIS_LEFT,AXIS_BOTTOM,AXIS_RIGHT,AXIS_BOTTOM,1,AXIS_COLOUR LINE AXIS_RIGHT,AXIS_TOP,AXIS_RIGHT,AXIS_BOTTOM,1,AXIS_COLOUR LINE AXIS_LEFT,(AXIS_TOP+AXIS_BOTTOM)\2,AXIS_RIGHT,(AXIS_TOP+AXIS_BOTTOM)\2,1,AXIS_COLOUR ''right labels TEXT AXIS_RIGHT+2,AXIS_TOP,STR$(V_FULL, 2, 1),LT,,1,V_COLOUR,BG_COL TEXT AXIS_RIGHT+2,AXIS_BOTTOM,STR$(V_EMPTY, 2, 1),LB,,1,V_COLOUR,BG_COL TEXT AXIS_RIGHT+2,(AXIS_TOP+AXIS_BOTTOM)\2,"V",LM,,1,V_COLOUR,BG_COL ''left labels TEXT AXIS_LEFT-1,AXIS_TOP,STR$(I_SCALE, 2,0),RT,,1,I2_COLOUR,BG_COL TEXT AXIS_LEFT-1,AXIS_BOTTOM,STR$(-I_SCALE, 2,0),RB,,1,I2_COLOUR,BG_COL TEXT AXIS_LEFT-1,(AXIS_TOP+AXIS_BOTTOM)\2-20,"I1",RM,,1,I1_COLOUR,BG_COL TEXT AXIS_LEFT-1,(AXIS_TOP+AXIS_BOTTOM)\2,"I2",RM,,1,I2_COLOUR,BG_COL TEXT AXIS_LEFT-1,(AXIS_TOP+AXIS_BOTTOM)\2+20,"I3",RM,,1,I3_COLOUR,BG_COL TEXT AXIS_LEFT-1,(AXIS_TOP+AXIS_BOTTOM)\2+40,"I4",RM,,1,I4_COLOUR,BG_COL ''bottom labels TEXT AXIS_RIGHT,AXIS_BOTTOM+2,"NOW",RT,,1,AXIS_COLOUR,BG_COL IF N = 0 THEN TEXT AXIS_LEFT,AXIS_BOTTOM+2,"-60 minutes",LT,,1,AXIS_COLOUR,BG_COL FOR I = 0 to S_COUNT-1 ''heaps of data points, so just draw dots IF SAMPLES(1,((SAMPLE_STATE+I+1) MOD 720))>0 THEN 'valid data DRAW_SAMPLE_PIXELS(AXIS_LEFT+((AXIS_RIGHT-AXIS_LEFT)*I)\S_COUNT,((SAMPLE_STATE+I+1) MOD 720)) END IF NEXT I ENDIF IF N = 1 THEN TEXT AXIS_LEFT,AXIS_BOTTOM+2,"-48 hours ",LT,,1,AXIS_COLOUR,BG_COL DRAW_HOUR_LINES ENDIF IF N = 2 THEN TEXT AXIS_LEFT,AXIS_BOTTOM+2,STR$(-D_COUNT)+" days ",LT,,1,AXIS_COLOUR,BG_COL DRAW_DAY_LINES ENDIF END SUB SUB DRAW_HOUR_LINES LOCAL INTEGER I,J LOCAL INTEGER X(H_COUNT),Y(6,H_COUNT) FOR I = 0 to H_COUNT-1 ''calc y values IF H_SAMP(1,I) > 0 THEN Y(1,I)=AXIS_BOTTOM+(H_SAMP(1,I)-V_EMPTY)*(AXIS_BOTTOM-AXIS_TOP)/(V_EMPTY-V_FULL) IF Y(1,I) < AXIS_TOP+1 THEN Y(1,I) = AXIS_TOP+1 IF Y(1,I) > AXIS_BOTTOM-1 THEN Y(1,I) = AXIS_BOTTOM-1 FOR J = 2 to 5 ''current values Y(J,I)=(AXIS_BOTTOM+AXIS_TOP)\2 + H_SAMP(J,I)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y(J,I) < AXIS_TOP+1 THEN Y(J,I) = AXIS_TOP+1 IF Y(J,I) > AXIS_BOTTOM-1 THEN Y(J,I) = AXIS_BOTTOM-1 NEXT J ENDIF ''calc x values X(I)= AXIS_LEFT + ((I + H_COUNT - H_PTR)*(AXIS_RIGHT-AXIS_LEFT))/H_COUNT-1 IF (X(I) < AXIS_LEFT) OR (X(I) > AXIS_RIGHT) THEN X(I)=0 ''not valid NEXT I ''draw lines FOR I = 0 to H_COUNT-2 IF (X(I)>0) AND (X(I+1)>0) AND (Y(1,I)>0)AND (Y(1,I+1)>0) THEN LINE X(I),Y(1,I),X(I+1),Y(1,I+1),1,V_COLOUR LINE X(I),Y(2,I),X(I+1),Y(2,I+1),1,I1_COLOUR LINE X(I),Y(3,I),X(I+1),Y(3,I+1),1,I2_COLOUR LINE X(I),Y(4,I),X(I+1),Y(4,I+1),1,I3_COLOUR LINE X(I),Y(5,I),X(I+1),Y(5,I+1),1,I4_COLOUR ENDIF NEXT I END SUB SUB DRAW_DAY_LINES LOCAL INTEGER I,J LOCAL INTEGER X(D_COUNT),Y(6,D_COUNT) FOR I = 0 to D_COUNT-1 ''calc y values IF D_SAMP(1,I) > 0 THEN Y(1,I)=AXIS_BOTTOM+(D_SAMP(1,I)-V_EMPTY)*(AXIS_BOTTOM-AXIS_TOP)/(V_EMPTY-V_FULL) IF Y(1,I) < AXIS_TOP+1 THEN Y(1,I) = AXIS_TOP+1 IF Y(1,I) > AXIS_BOTTOM-1 THEN Y(1,I) = AXIS_BOTTOM-1 FOR J = 2 to 5 ''current values Y(J,I)=(AXIS_BOTTOM+AXIS_TOP)\2 + D_SAMP(J,I)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y(J,I) < AXIS_TOP+1 THEN Y(J,I) = AXIS_TOP+1 IF Y(J,I) > AXIS_BOTTOM-1 THEN Y(J,I) = AXIS_BOTTOM-1 NEXT J ENDIF ''calc x values X(I)= AXIS_LEFT + ((I + D_COUNT - D_PTR)*(AXIS_RIGHT-AXIS_LEFT))/D_COUNT-1 IF (X(I) < AXIS_LEFT) OR (X(I) > AXIS_RIGHT) THEN X(I)=0 ''not valid NEXT I ''draw lines FOR I = 0 to D_COUNT-2 IF (X(I)>0) AND (X(I+1)>0) AND (Y(1,I)>0)AND (Y(1,I+1)>0) THEN LINE X(I),Y(1,I),X(I+1),Y(1,I+1),1,V_COLOUR LINE X(I),Y(2,I),X(I+1),Y(2,I+1),1,I1_COLOUR LINE X(I),Y(3,I),X(I+1),Y(3,I+1),1,I2_COLOUR LINE X(I),Y(4,I),X(I+1),Y(4,I+1),1,I3_COLOUR LINE X(I),Y(5,I),X(I+1),Y(5,I+1),1,I4_COLOUR ENDIF NEXT I END SUB SUB DRAW_SAMPLE_PIXELS(X AS INTEGER,N AS INTEGER) ''x coord, sample # LOCAL INTEGER Y ''data is validated already 'V: Y=AXIS_BOTTOM+(SAMPLES(1,N)-V_EMPTY)*(AXIS_BOTTOM-AXIS_TOP)/(V_EMPTY-V_FULL) IF Y < AXIS_TOP+1 THEN Y = AXIS_TOP+1 IF Y > AXIS_BOTTOM-1 THEN Y = AXIS_BOTTOM-1 PIXEL X,Y,V_COLOUR ''I1: Y=(AXIS_BOTTOM+AXIS_TOP)\2 + SAMPLES(2,N)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y < AXIS_TOP+1 THEN Y = AXIS_TOP+1 IF Y > AXIS_BOTTOM-1 THEN Y = AXIS_BOTTOM-1 PIXEL X,Y,I1_COLOUR ''I2: Y=(AXIS_BOTTOM+AXIS_TOP)\2 + SAMPLES(3,N)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y < AXIS_TOP+1 THEN Y = AXIS_TOP+1 IF Y > AXIS_BOTTOM-1 THEN Y = AXIS_BOTTOM-1 PIXEL X,Y,I2_COLOUR ''I3: Y=(AXIS_BOTTOM+AXIS_TOP)\2 + SAMPLES(4,N)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y < AXIS_TOP+1 THEN Y = AXIS_TOP+1 IF Y > AXIS_BOTTOM-1 THEN Y = AXIS_BOTTOM-1 PIXEL X,Y,I3_COLOUR ''I4: Y=(AXIS_BOTTOM+AXIS_TOP)\2 + SAMPLES(5,N)*(AXIS_BOTTOM-AXIS_TOP)/(2*I_SCALE) IF Y < AXIS_TOP+1 THEN Y = AXIS_TOP+1 IF Y > AXIS_BOTTOM-1 THEN Y = AXIS_BOTTOM-1 PIXEL X,Y,I4_COLOUR END SUB SUB EXPORT_DATA(N AS INTEGER) ''0=hours, 1=days, 2=weeks IF N = 0 THEN EXPORT_HOURS IF N = 1 THEN EXPORT_DAYS IF N = 2 THEN EXPORT_WEEKS END SUB SUB EXPORT_HOURS LOCAL INTEGER I local INTEGER START_TIME START_TIME = (TIME_SERIAL()\5)*5-3600 '1 hour ago, round to 5s PRINT "Silicon Chip Battery Multi-Logger Hours Data Export" PRINT "Time,Voltage(V),Current 1 (A),Current 2 (A),Current 3 (A),Current 4 (A)" FOR I = 0 to S_COUNT-1 IF SAMPLES(1,((SAMPLE_STATE+I+1) MOD 720))>0 THEN 'valid data PRINT DATE_TIME_STRING(START_TIME+I*5);","; PRINT STR$(SAMPLES(1,((SAMPLE_STATE+I+1) MOD 720)));","; PRINT STR$(SAMPLES(2,((SAMPLE_STATE+I+1) MOD 720)));","; PRINT STR$(SAMPLES(3,((SAMPLE_STATE+I+1) MOD 720)));","; PRINT STR$(SAMPLES(4,((SAMPLE_STATE+I+1) MOD 720)));","; PRINT STR$(SAMPLES(5,((SAMPLE_STATE+I+1) MOD 720))) ENDIF NEXT I END SUB SUB EXPORT_DAYS LOCAL INTEGER I local INTEGER START_TIME START_TIME = H_START*3600 'hour PRINT "Silicon Chip Battery Multi-Logger Days Data Export" PRINT "Time,Voltage(V),Current 1 (A),Current 2 (A),Current 3 (A),Current 4 (A)" FOR I = 0 to H_COUNT-1 IF H_SAMP(1,I)>0 THEN 'valid data PRINT DATE_TIME_STRING(START_TIME+I*3600);","; PRINT STR$(H_SAMP(1,I));","; PRINT STR$(H_SAMP(2,I));","; PRINT STR$(H_SAMP(3,I));","; PRINT STR$(H_SAMP(4,I));","; PRINT STR$(H_SAMP(5,I)) ENDIF NEXT I END SUB SUB EXPORT_WEEKS LOCAL INTEGER I local INTEGER START_TIME START_TIME = D_START*86400 'days PRINT "Silicon Chip Battery Multi-Logger Weeks Data Export" PRINT "Time,Voltage(V),Current 1 (A),Current 2 (A),Current 3 (A),Current 4 (A)" FOR I = 0 to D_COUNT-1 IF D_SAMP(1,I)>0 THEN 'valid data PRINT DATE_TIME_STRING(START_TIME+I*86400);","; PRINT STR$(D_SAMP(1,I));","; PRINT STR$(D_SAMP(2,I));","; PRINT STR$(D_SAMP(3,I));","; PRINT STR$(D_SAMP(4,I));","; PRINT STR$(D_SAMP(5,I)) ENDIF NEXT I END SUB FUNCTION DATE_TIME_STRING (T AS INTEGER) AS STRING 'tweak this to suit your preferred display format 'Excel format serial number DATE_TIME_STRING = STR$(T\86400,6,0)+"."+STR$((((T MOD 86400)*1000000)\86400),6,0,"0") END FUNCTION SUB DO_I_CAL(I_NUM AS INTEGER) LOCAL I_ENTERED AS FLOAT LOCAL NEW_CAL AS FLOAT LOCAL ACTUAL_NOW AS FLOAT 'temp as this may change ACTUAL_NOW=abs(ACTUAL(I_NUM+1)) IF ABS(ACTUAL_NOW) < 0.00001 THEN MessageBox("I TOO LOW","Check and retry") : EXIT SUB CLS(BG_COL) IF RAW_ACTUAL(1) < 800000 THEN MessageBox("INPUT V TOO LOW","Check and retry") : EXIT SUB I_ENTERED=NUMBERPAD("Enter I(A)") IF I_ENTERED < 0.000001 THEN EXIT SUB 'cancel NEW_CAL = I_ENTERED/ACTUAL_NOW TEXT 160,10,"New I("+STR$(I_NUM)+") factor:",CT,8,1,FG_COL,BG_COL TEXT 160,40,"I factor:",RT,1,1,FG_COL,BG_COL TEXT 160,40,STR$(NEW_CAL),LT,1,1,FG_COL,BG_COL IF OK_CANCEL_BUTTONS() > 0 THEN ''accept and store values I_CAL(I_NUM)=-NEW_CAL VAR SAVE I_CAL() ENDIF END SUB SUB DO_V_CAL LOCAL V_ENTERED AS FLOAT LOCAL ACTUAL_NOW(5) AS FLOAT 'temp as these may change LOCAL NEW_CAL(5) AS FLOAT LOCAL NEW_MIN,NEW_MAX AS FLOAT CLS(BG_COL) ACTUAL_NOW(1)=RAW_ACTUAL(1) ''mapping ACTUAL_NOW(2)=RAW_ACTUAL(3) ACTUAL_NOW(3)=RAW_ACTUAL(4) ACTUAL_NOW(4)=RAW_ACTUAL(5) ''check if valid, this will also trap /0 error IF ACTUAL_NOW(1) < 800000 THEN MessageBox("INPUT V TOO LOW","Check and retry") : EXIT SUB IF ACTUAL_NOW(2) < 800000 THEN MessageBox("INPUT V TOO LOW","Check and retry") : EXIT SUB IF ACTUAL_NOW(3) < 800000 THEN MessageBox("INPUT V TOO LOW","Check and retry") : EXIT SUB IF ACTUAL_NOW(4) < 800000 THEN MessageBox("INPUT V TOO LOW","Check and retry") : EXIT SUB V_ENTERED=NUMBERPAD("Enter Voltage") IF V_ENTERED < 5.0 THEN MessageBox("ENTERED V TOO LOW","Check and retry") : EXIT SUB 'cancel NEW_CAL(1)=V_ENTERED/ACTUAL_NOW(1) ''old method 'NEW_CAL(2)=V_ENTERED/ACTUAL_NOW(2) 'NEW_CAL(3)=V_ENTERED/ACTUAL_NOW(3) 'NEW_CAL(4)=V_ENTERED/ACTUAL_NOW(4) ''new method NEW_CAL(2)=NEW_CAL(1)*I_RATIO(2) NEW_CAL(3)=NEW_CAL(1)*I_RATIO(3) NEW_CAL(4)=NEW_CAL(1)*I_RATIO(4) NEW_MIN=NEW_CAL(1) IF NEW_CAL(2)<NEW_MIN THEN NEW_MIN=NEW_CAL(2) IF NEW_CAL(3)<NEW_MIN THEN NEW_MIN=NEW_CAL(3) IF NEW_CAL(4)<NEW_MIN THEN NEW_MIN=NEW_CAL(4) NEW_MAX=NEW_CAL(1) IF NEW_CAL(2)>NEW_MAX THEN NEW_MAX=NEW_CAL(2) IF NEW_CAL(3)>NEW_MAX THEN NEW_MAX=NEW_CAL(3) IF NEW_CAL(4)>NEW_MAX THEN NEW_MAX=NEW_CAL(4) CLS(BG_COL) TEXT 160,10,"New V factors:",CT,8,1,FG_COL,BG_COL TEXT 160,40,"V1 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,60,"V2 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,80,"V3 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,100,"V4 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,120,"Variation:",RT,1,1,FG_COL,BG_COL TEXT 160,40,STR$(NEW_CAL(1)),LT,1,1,FG_COL,BG_COL TEXT 160,60,STR$(NEW_CAL(2)),LT,1,1,FG_COL,BG_COL TEXT 160,80,STR$(NEW_CAL(3)),LT,1,1,FG_COL,BG_COL TEXT 160,100,STR$(NEW_CAL(4)),LT,1,1,FG_COL,BG_COL TEXT 160,120,STR$(((NEW_MAX-NEW_MIN)*100)/NEW_MAX)+"%",LT,1,1,FG_COL,BG_COL ''check before saving IF OK_CANCEL_BUTTONS() > 0 THEN ''accept and store values V_CAL(1)=NEW_CAL(1) V_CAL(2)=NEW_CAL(2) V_CAL(3)=NEW_CAL(3) V_CAL(4)=NEW_CAL(4) VAR SAVE V_CAL() ENDIF END SUB SUB DRAW_CALIBRATE CLS(BG_COL) TEXT 160,10,"CALIBRATE",CT,8,1,FG_COL,BG_COL TEXT 160,40,"V factor:",RT,1,1,FG_COL,BG_COL TEXT 160,60,"I1 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,80,"I2 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,100,"I3 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,120,"I4 factor:",RT,1,1,FG_COL,BG_COL TEXT 160,40,STR$(V_CAL(1)),LT,1,1,FG_COL,BG_COL TEXT 160,60,STR$(I_CAL(1)),LT,1,1,FG_COL,BG_COL TEXT 160,80,STR$(I_CAL(2)),LT,1,1,FG_COL,BG_COL TEXT 160,100,STR$(I_CAL(3)),LT,1,1,FG_COL,BG_COL TEXT 160,120,STR$(I_CAL(4)),LT,1,1,FG_COL,BG_COL DrawButton 0, 0, 20, 140, 80, 40, BUTTON_COL, "Volts" DrawButton 1, 0, 120, 140, 80, 40, BUTTON_COL, "Current 1" DrawButton 2, 0, 220, 140, 80, 40, BUTTON_COL, "Current 2" DrawButton 3, 0, 20, 190, 80, 40, BUTTON_COL, "Current 3" DrawButton 4, 0, 120, 190, 80, 40, BUTTON_COL, "Current 4" DrawButton 5, 0, 220, 190, 80, 40, BUTTON_COL, "Back" END SUB SUB DRAW_SETTINGS CLS(BG_COL) TEXT 160,5,"SETTINGS",CT,8,1,FG_COL,BG_COL DrawButton 0, 0, 20, 45, 80, 25, BUTTON_COL, "Year" DrawButton 1, 0, 120, 45, 80, 25, BUTTON_COL, "Month" DrawButton 2, 0, 220, 45, 80, 25, BUTTON_COL, "Day" DrawButton 3, 0, 20, 75, 80, 25, BUTTON_COL, "Hour" DrawButton 4, 0, 120, 75, 80, 25, BUTTON_COL, "Minute" DrawButton 5, 0, 220, 75, 80, 25, BUTTON_COL, "Second" DrawButton 6, 0, 20, 105, 80, 25, BUTTON_COL, "B/L" DrawButton 7, 0, 120, 105, 80, 25, BUTTON_COL, "V(Full)" DrawButton 8, 0, 220, 105, 80, 25, BUTTON_COL, "Timeout" DrawButton 9, 0, 20, 150, 80, 25, BUTTON_COL, "B/L (dim)" DrawButton 10, 0, 120, 150, 80, 25, BUTTON_COL,"V(empty)" DrawButton 12, 0, 20, 195, 80, 25, BUTTON_COL, "I scale" 'these were added later DrawButton 13, 0, 120, 195, 80, 25, BUTTON_COL,"V(sdown)" 'these were added later DrawButton 11, 0, 220, 150, 80, 70, BUTTON_COL, "BACK" TEXT 60,132,STR$(ON_BL)+"%",CT,1,1,FG_COL,BG_COL TEXT 160,132,STR$(V_FULL,3,2)+"V",CT,1,1,FG_COL,BG_COL TEXT 260,132,STR$((MN_TMOUT+IDLE_TIMEOUT)\1000)+"s",CT,1,1,FG_COL,BG_COL TEXT 60,177,STR$(IDLE_BL)+"%",CT,1,1,FG_COL,BG_COL TEXT 160,177,STR$(V_EMPTY,3,2)+"V",CT,1,1,FG_COL,BG_COL TEXT 60,222,STR$(I_SCALE,4,1)+"A",CT,1,1,FG_COL,BG_COL TEXT 160,222,STR$(V_SHUTDOWN,3,2)+"V",CT,1,1,FG_COL,BG_COL END SUB SUB DRAW_DATA CLS(BG_COL) TEXT 160,10,"DATA",CT,8,1,FG_COL,BG_COL DrawButton 0, 0, 5, 210, 70, 24, BUTTON_COL, "Hours" DrawButton 1, 0, 85, 210, 70, 24, BUTTON_COL, "Days" DrawButton 2, 0, 165, 210, 70, 24, BUTTON_COL, "Weeks" DrawButton 3, 0, 245, 210, 70, 24, BUTTON_COL, "Exit" DrawButton 4, 0, 245, 6, 70, 24, BUTTON_COL, "Export" END SUB SUB DRAW_MAIN CLS(BG_COL) TEXT 160,10,"SILICON CHIP",CT,8,1,FG_COL,BG_COL TEXT 160,40,"BATTERY MULTI-LOGGER",CT,8,1,FG_COL,BG_COL DrawButton 0, 0, 20, 190, 80, 40, BUTTON_COL, "Data" DrawButton 1, 0, 120, 190, 80, 40, BUTTON_COL, "Settings" DrawButton 2, 0, 220, 190, 80, 40, BUTTON_COL, "Calibrate" DISPLAY_TIMEOUT=TIMER ''reset on coming back to main END SUB FUNCTION SAMPLE_PATTERN(S AS INTEGER) ''map sample_state to channel SAMPLE_PATTERN=1 IF S=2 OR S=3 THEN SAMPLE_PATTERN=2 IF S=6 OR S=7 THEN SAMPLE_PATTERN=3 IF S=10 OR S=11 THEN SAMPLE_PATTERN=4 END FUNCTION SUB SAMPLE_MANAGER ''can be called from anywhere to handle sample taking, updated 7 stage= V/I/V/I/V/I/V/I int STATIC INTEGER SAMPLE_STATE=0 ''state machine ''states are: '0=>1 = channel 1 '2=>3 = channel 2 '4=>5 = channel 1 '6=>7 = channel 3 '8=>9 = channel 1 '10=>11 = channel 4 '12=>13 = channel 1 '14=process data STATIC INTEGER SAMPLE_TIMEOUT=0 ''to check for sampling timeouts STATIC INTEGER LAST_SAMPLE_STATE=0 LOCAL FLOAT NEW_ACTUAL(6) SELECT CASE SAMPLE_STATE ''start samples CASE 0,2,4,6,8,10,12 START_ADC(SAMPLE_PATTERN(SAMPLE_STATE)) SAMPLE_TIMEOUT=TIMER SAMPLE_STATE=SAMPLE_STATE+1 ''check if samples done/timeout CASE 1,3,5,7,9,11,13 if CHECK_ADC_DONE(SAMPLE_PATTERN(SAMPLE_STATE)) > 0 THEN NEW_RAW((SAMPLE_STATE+1)\2)=GET_ADC_RESULT() SAMPLE_STATE=SAMPLE_STATE+1 ''avoid timeout ELSEIF (TIMER-SAMPLE_TIMEOUT)> ADC_TIMEOUT THEN NEW_RAW(1)=-1 ''flag timeout SAMPLE_STATE=SAMPLE_STATE+1 ''move on ENDIF ''process data CASE 14 NEW_RAW(8)=PIN(SHUNT_ADC) 'this is in volts IF NEW_RAW(1)<0 THEN 'PRINT "SAMPLE CYCLE ERROR" ELSE RAW_ACTUAL(1)=(NEW_RAW(1)+NEW_RAW(3)+NEW_RAW(5)+NEW_RAW(7))\4 ''this is used as a flag RAW_ACTUAL(3)=NEW_RAW(2) ''this is used as a flag RAW_ACTUAL(4)=NEW_RAW(4) ''this is used as a flag RAW_ACTUAL(5)=NEW_RAW(6) ''this is used as a flag ''values for calibration IF NEW_RAW(2)>800000 THEN I_RATIO(2)=(NEW_RAW(1)+NEW_RAW(3))/(NEW_RAW(2)*2) ELSE I_RATIO(2)=1 IF NEW_RAW(4)>800000 THEN I_RATIO(3)=(NEW_RAW(3)+NEW_RAW(5))/(NEW_RAW(4)*2) ELSE I_RATIO(3)=1 IF NEW_RAW(6)>800000 THEN I_RATIO(4)=(NEW_RAW(5)+NEW_RAW(7))/(NEW_RAW(6)*2) ELSE I_RATIO(4)=1 ''debugging 'PRINT I_RATIO(2)," ",I_RATIO(3)," ",I_RATIO(4) ''actual calcs NEW_ACTUAL(1)=(NEW_RAW(1)+NEW_RAW(3)+NEW_RAW(5)+NEW_RAW(7))*V_CAL(1)/4 NEW_ACTUAL(2)=NEW_RAW(8)*I_CAL(1) ''this is a simple shunt NEW_ACTUAL(3)=(((NEW_RAW(1)+NEW_RAW(3))*V_CAL(1)/2)-(NEW_RAW(2))*V_CAL(2))*I_CAL(2) ''differential voltage NEW_ACTUAL(4)=(((NEW_RAW(3)+NEW_RAW(5))*V_CAL(1)/2)-(NEW_RAW(4))*V_CAL(3))*I_CAL(3) ''differential voltage NEW_ACTUAL(5)=(((NEW_RAW(5)+NEW_RAW(7))*V_CAL(1)/2)-(NEW_RAW(6))*V_CAL(4))*I_CAL(4) ''differential voltage 'NEW_ACTUAL(3)=((NEW_RAW(1)+NEW_RAW(3))\2-NEW_RAW(2))*V_CAL(2)*I_CAL(2) ''these are differential voltages 'NEW_ACTUAL(4)=((NEW_RAW(3)+NEW_RAW(5))\2-NEW_RAW(4))*V_CAL(3)*I_CAL(3) ''these are differential voltages 'NEW_ACTUAL(5)=((NEW_RAW(5)+NEW_RAW(7))\2-NEW_RAW(6))*V_CAL(4)*I_CAL(4) ''these are differential voltages ''unsmoothed ACTUAL(1)=NEW_ACTUAL(1) ACTUAL(2)=NEW_ACTUAL(2) ACTUAL(3)=NEW_ACTUAL(3) ACTUAL(4)=NEW_ACTUAL(4) ACTUAL(5)=NEW_ACTUAL(5) ''smoothed 'ACTUAL(1)=(ACTUAL(1)*SMOOTHING_FACTOR+NEW_ACTUAL(1))/(SMOOTHING_FACTOR+1) 'ACTUAL(2)=(ACTUAL(2)*SMOOTHING_FACTOR+NEW_ACTUAL(2))/(SMOOTHING_FACTOR+1) 'ACTUAL(3)=(ACTUAL(3)*SMOOTHING_FACTOR+NEW_ACTUAL(3))/(SMOOTHING_FACTOR+1) 'ACTUAL(4)=(ACTUAL(4)*SMOOTHING_FACTOR+NEW_ACTUAL(4))/(SMOOTHING_FACTOR+1) 'ACTUAL(5)=(ACTUAL(5)*SMOOTHING_FACTOR+NEW_ACTUAL(5))/(SMOOTHING_FACTOR+1) ENDIF ''finish off the same as state 0 NEW_RAW(1)=0'reset flag START_ADC(1) SAMPLE_TIMEOUT=TIMER SAMPLE_STATE=1 DATA_MANAGER ''save and store data END SELECT ''debugging: 'IF LAST_SAMPLE_STATE <> SAMPLE_STATE THEN PRINT "SAMPLE:";LAST_SAMPLE_STATE;">";SAMPLE_STATE;"(";TIMER-SAMPLE_TIMEOUT;")": LAST_SAMPLE_STATE=SAMPLE_STATE END SUB SUB DATA_MANAGER LOCAL INTEGER S_PERIODS '' to adjust AH/WH LOCAL FLOAT AH_NOW, WH_NOW LOCAL INTEGER S_NUM LOCAL INTEGER I,J,NEW_H_PTR LOCAL FLOAT DATA_BUFFER(6) LOCAL INTEGER DATA_COUNT ' if not all valid S_NUM=(TIME_SERIAL()\5) MOD 720 ''5 second periods 'PRINT S_NUM;":";TIME_SERIAL()/86400;":";TIME_SERIAL() 'update AH/WH usage S_PERIODS=(S_NUM + 720 - SAMPLE_STATE) MOD 720 'this takes care of occasional missed samples IF RAW_ACTUAL(1)>=0 THEN 'data is valid AH_NOW = (ACTUAL(2)+ACTUAL(3)+ACTUAL(4)+ACTUAL(5)) * S_PERIODS / 720 'sum of currents times interval in hours AH_SINCEF = AH_SINCEF + AH_NOW AH_SINCEE = AH_SINCEE + AH_NOW WH_NOW = AH_NOW * ACTUAL(1) WH_SINCEF = WH_SINCEF + WH_NOW WH_SINCEE = WH_SINCEE + WH_NOW IF ACTUAL(1) < V_EMPTY THEN AH_SINCEE=0 WH_SINCEE=0 USAGE_STATE = USAGE_STATE OR &H1 'has reached empty state ENDIF IF ACTUAL(1) > V_FULL THEN AH_SINCEF=0 WH_SINCEF=0 USAGE_STATE = USAGE_STATE OR &H2 'has reached full state ENDIF ENDIF IF SAMPLE_STATE < S_NUM THEN 'new sample in current hour 'PRINT "SAMPLE:";S_NUM;":";SAMPLE_STATE ''need to clean up old samples from S_NUM to SAMPLE_STATE, but check for off by one. ''SAMPLE_STATE+1 to S_NUM (which should usually be the same, current sample about to be written) FOR J= SAMPLE_STATE+1 TO S_NUM SAMPLES(1,J)=-1'clear and flag NEXT J 'PRINT "CLEARED:";SAMPLE_STATE+1;" to ";S_NUM FOR I=1 TO 5 SAMPLES(I,S_NUM)=ACTUAL(I) ''store NEXT I SAMPLE_STATE=S_NUM ''update state ENDIF IF S_NUM < SAMPLE_STATE THEN 'hour expired or other rollover SAMPLE_STATE=0 ''reset 'PRINT "HOUR EXPIRED" FOR I = 1 to 5 DATA_BUFFER(I)=0 NEXT I DATA_COUNT=0 FOR J = 1 TO 720 IF SAMPLES(1,J)>0 THEN ''valid data FOR I = 1 TO 5 DATA_BUFFER(I)=DATA_BUFFER(I)+SAMPLES(I,J) NEXT I DATA_COUNT=DATA_COUNT+1 ENDIF NExt J IF DATA_COUNT>0 THEN ''valid data in last hour 'PRINT "DATA IN LAST HOUR:";DATA_COUNT IF H_START=0 THEN ''prepare hour array and shift out if necessary H_START=TIME_SERIAL()\3600 ''hour number H_PTR=0 ''first valid data ELSE NEW_H_PTR=(TIME_SERIAL()\3600)-H_START 'IF NEW_H_PTR <= H_PTR THEN PRINT "TIME ERROR:";NEW_H_PTR IF NEW_H_PTR >= H_COUNT THEN NEW_H_PTR=ARCHIVE_HOUR_DATA(NEW_H_PTR) ''need to shift out old hourly data H_PTR=NEW_H_PTR''may need refining ENDIF FOR I = 1 TO 5 H_SAMP(I,H_PTR)=DATA_BUFFER(I)/DATA_COUNT NEXT I VAR SAVE H_PTR,H_START,H_SAMP() 'PRINT "Saved an hour of samples:";H_PTR 'H_PTR=H_PTR+1 ''calculated automatically ELSE 'PRINT "NO VALID DATA IN LAST HOUR" ENDIF IF (((TIME_SERIAL()\3600) MOD 24) = 0) THEN DAY_DATA_MANAGER ''handle saving days of data in first hour after midnight ENDIF 'ENDIF '? END SUB SUB DAY_DATA_MANAGER ''do what needs to be done for daily archiving, same as hourly, but different timescales LOCAL INTEGER I,J,NEW_D_PTR LOCAL FLOAT DATA_BUFFER(6) LOCAL INTEGER DATA_COUNT ' if not all valid LOCAL INTEGER H_TO_START, H_TO_END H_TO_START = (TIME_SERIAL()\3600)-24-H_START ''index of start of yesterday H_TO_END = H_TO_START+23 ''24 in a day if H_TO_START < 0 THEN H_TO_START = 0 IF H_TO_END > H_COUNT-1 THEN H_TO_END = H_COUNT-1 IF H_TO_END < H_TO_START THEN 'PRINT "H_TO_STORE INVALID:";H_TO_START;"-";H_TO_END EXIT SUB ENDIF FOR I = 1 to 5 DATA_BUFFER(I)=0 NEXT I DATA_COUNT=0 FOR J = H_TO_START TO H_TO_END IF H_SAMP(1,J)>0 THEN ''valid data FOR I = 1 TO 5 DATA_BUFFER(I)=DATA_BUFFER(I)+H_SAMP(I,J) NEXT I DATA_COUNT=DATA_COUNT+1 ENDIF NExt J 'PRINT "DATA IN LAST DAY:";DATA_COUNT;"=";H_TO_START;"-";H_TO_END IF DATA_COUNT>0 THEN ''valid data in last hour IF D_START=0 THEN ''prepare hour array and shift out if necessary D_START=TIME_SERIAL()\86400 ''day number D_PTR=0 ''first valid data ELSE NEW_D_PTR=(TIME_SERIAL()\86400)-D_START 'IF NEW_D_PTR <= D_PTR THEN PRINT "TIME ERROR:";NEW_D_PTR IF NEW_D_PTR >= D_COUNT THEN NEW_D_PTR=ARCHIVE_DAY_DATA(NEW_D_PTR) ''need to shift out old hourly data D_PTR=NEW_D_PTR''may need refining ENDIF FOR I = 1 TO 5 D_SAMP(I,D_PTR)=DATA_BUFFER(I)/DATA_COUNT NEXT I VAR SAVE D_PTR,D_START,D_SAMP() 'PRINT "Saved a day of samples:";D_PTR ELSE 'PRINT "NO VALID DATA IN LAST DAY" ENDIF END SUB FUNCTION ARCHIVE_DAY_DATA(D AS INTEGER) AS INTEGER ARCHIVE_DAY_DATA = D if D < D_COUNT THEN EXIT FUNCTION ''don't do anything if there's room left LOCAL INTEGER OFFSET,I,J OFFSET = D - D_COUNT + 1 ''should be 1 most of the time FOR J = 0 TO D_COUNT - OFFSET - 1 FOR I = 1 TO 5 D_SAMP(I,J)=D_SAMP(I,J+OFFSET) ''shift by offset NEXT I NEXT J D_START=D_START+OFFSET ''adjust sample pointer ARCHIVE_DAY_DATA=D_COUNT-1 ''should be 47 normally 'PRINT "Day data shifted by ";OFFSET END FUNCTION FUNCTION ARCHIVE_HOUR_DATA(H AS INTEGER) AS INTEGER ARCHIVE_HOUR_DATA = H if H < H_COUNT THEN EXIT FUNCTION ''don't do anything if there's room left LOCAL INTEGER OFFSET,I,J OFFSET = H - H_COUNT + 1 ''should be 1 most of the time FOR J = 0 TO H_COUNT - OFFSET - 1 FOR I = 1 TO 5 H_SAMP(I,J)=H_SAMP(I,J+OFFSET) ''shift by offset NEXT I NEXT J H_START=H_START+OFFSET ''adjust sample pointer ''VAR SAVE H_START,H_SAMP() ''will be done later ARCHIVE_HOUR_DATA=H_COUNT-1 ''should be 47 normally 'PRINT "Hour data shifted by ";OFFSET END FUNCTION FUNCTION TIME_SERIAL() AS INTEGER ''convert current date/time into a time serial number, number of seconds since 1/1/1900 (time serial number * 86400) LOCAL INTEGER T(6) T(0)=val(mid$(DATE$,7,4)) 'year T(1)=val(mid$(DATE$,4,2)) 'month T(2)=val(mid$(DATE$,1,2)) 'day T(3)=val(mid$(TIME$,1,2)) 'hour/24 T(4)=val(mid$(TIME$,4,2)) 'minute T(5)=val(mid$(TIME$,7,2)) 'second TIME_SERIAL=TIME_SERIAL+T(2)+1 'from start of current month IF T(1)=12 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+334 IF T(1)=11 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+304 IF T(1)=10 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+273 IF T(1)=9 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+243 IF T(1)=8 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+212 IF T(1)=7 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+181 IF T(1)=6 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+151 IF T(1)=5 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+120 IF T(1)=4 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+90 IF T(1)=3 THEN TIME_SERIAL=TIME_SERIAL+IS_LEAP_YEAR(T(0))+59 IF T(1)=2 THEN TIME_SERIAL=TIME_SERIAL+31 'January is already start of year DO WHILE(T(0)>1900) T(0)=T(0)-1 TIME_SERIAL=TIME_SERIAL+365+IS_LEAP_YEAR(T(0)) LOOP TIME_SERIAL=TIME_SERIAL*86400+T(3)*3600+T(4)*60+T(5) END FUNCTION FUNCTION IS_LEAP_YEAR(Y AS INTEGER) AS INTEGER IS_LEAP_YEAR=0 IF ((Y\4)*4)=Y THEN IS_LEAP_YEAR =1 IF ((Y\100)*100)=Y THEN IS_LEAP_YEAR =0 IF ((Y\400)*400)=Y THEN IS_LEAP_YEAR =1 END FUNCTION SUB WAIT_FOR_RELEASE DO WHILE (CHECK_SCREEN_TOUCH()=1) PAUSE 100 LOOP END SUB FUNCTION CHECK_SCREEN_TOUCH() AS INTEGER LOCAL PIN_10_SAVE AS INTEGER PIN_10_SAVE=PIN(10) ''save state pin(10)=1 ''power on so that touch pin is not pulled down CHECK_SCREEN_TOUCH=0 IF (PIN(15)=0) THEN CHECK_SCREEN_TOUCH=1 pin(10)=PIN_10_SAVE 'restore END FUNCTION SUB SET_BACKLIGHT(B AS INTEGER) PWM 2,50000,B 'PRINT "SET_BACKLIGHT:";B END SUB Sub LCD_ON SetPin 10,DOUT pin(10)=1 GUI RESET LCDPANEL ''redo init, this should reinstate all control lines End Sub Sub LCD_OFF 'PRINT "LCD OFF" Poke word &hBF886034,9 ''force control lines off Poke word &hBF886134,36876 'Poke word &hBF886134,36868 End Sub SUB START_ADC(C AS INTEGER) ''start conversion on channel c LOCAL INTEGER CHANNEL_MASK,JUNK,TMOUT CHANNEL_MASK=0 ''no channels 'LOCAL PIN_10_SAVE AS INTEGER 'PIN_10_SAVE=PIN(10) ''save state 'pin(10)=1 ''power on so that touch pin is not pulled down SPI OPEN 2000000, 3, 8 if C = 1 THEN CHANNEL_MASK=&h10 if C = 2 THEN CHANNEL_MASK=&h20 if C = 3 THEN CHANNEL_MASK=&h40 if C = 4 THEN CHANNEL_MASK=&h80 pin(ADC_CS)=0 ''40 DIN high bits=reset JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(8) ''write MODE, 24 bits JUNK=SPI(&h38) ''single mode, returns to pwoer down after JUNK=SPI(&h07) ''sinc4, no parity, FS9-FS8=3 JUNK=SPI(&hFF) ''FS7-FS0=FF pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(16) ''write CONFIG, 24 bits JUNK=SPI(&H00) ''CHOP off JUNK=SPI(CHANNEL_MASK) JUNK=SPI(&H48) ''unipolar, gain=1, pin(ADC_CS)=1 SPI CLOSE 'pin(10)=PIN_10_SAVE 'restore END SUB FUNCTION CHECK_ADC_DONE(C AS INTEGER) AS INTEGER LOCAL INTEGER JUNK CHECK_ADC_DONE=0 'LOCAL PIN_10_SAVE AS INTEGER 'PIN_10_SAVE=PIN(10) ''save state 'pin(10)=1 ''power on so that touch pin is not pulled down SPI OPEN 2000000, 3, 8 pin(ADC_CS)=0 JUNK=SPI(64) ''read status JUNK=SPI(0) pin(ADC_CS)=1 if (JUNK AND 7) = (C+3) THEN CHECK_ADC_DONE=1 SPI CLOSE 'pin(10)=PIN_10_SAVE 'restore END FUNCTION FUNCTION GET_ADC_RESULT() AS INTEGER LOCAL INTEGER JUNK GET_ADC_RESULT=-1 'LOCAL PIN_10_SAVE AS INTEGER 'PIN_10_SAVE=PIN(10) ''save state 'pin(10)=1 ''power on so that touch pin is not pulled down SPI OPEN 2000000, 3, 8 pin(ADC_CS)=0 JUNK=SPI(88) ''read data GET_ADC_RESULT=SPI(0)*65536 ''load valid data GET_ADC_RESULT=GET_ADC_RESULT + SPI(0)*256 GET_ADC_RESULT=GET_ADC_RESULT + SPI(0) pin(ADC_CS)=1 'print GET_ADC_RESULT SPI CLOSE 'pin(10)=PIN_10_SAVE 'restore END FUNCTION FUNCTION GET_ADC(C AS INTEGER) AS FLOAT ''blocking conversion GET_ADC=-1'default fail value LOCAL INTEGER CHANNEL_MASK,JUNK,TMOUT TMOUT=2000 CHANNEL_MASK=0 ''no channels 'LOCAL PIN_10_SAVE AS INTEGER 'PIN_10_SAVE=PIN(10) ''save state 'pin(10)=1 ''power on so that touch pin is not pulled down SPI OPEN 2000000, 3, 8 if C = 1 THEN CHANNEL_MASK=&h10 if C = 2 THEN CHANNEL_MASK=&h20 if C = 3 THEN CHANNEL_MASK=&h40 if C = 4 THEN CHANNEL_MASK=&h80 pin(ADC_CS)=0 ''40 DIN high bits=reset JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(8) ''write MODE, 24 bits JUNK=SPI(&h38) ''single mode, returns to pwoer down after JUNK=SPI(&h07) ''sinc4, no parity, FS9-FS8=3 JUNK=SPI(&hFF) ''FS7-FS0=FF pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(16) ''write CONFIG, 24 bits JUNK=SPI(&H00) ''CHOP off JUNK=SPI(CHANNEL_MASK) JUNK=SPI(&H48) ''unipolar, gain=1, pin(ADC_CS)=1 DO WHILE(TMOUT>0) pin(ADC_CS)=0 JUNK=SPI(64) ''read status JUNK=SPI(0) pin(ADC_CS)=1 'PRINT JUNK if (JUNK AND 7) = (C+3) THEN TMOUT=-1 pin(ADC_CS)=0 JUNK=SPI(88) ''read data GET_ADC=SPI(0)*65536 ''load valid data GET_ADC=GET_ADC + SPI(0)*256 GET_ADC=GET_ADC + SPI(0) pin(ADC_CS)=1 END IF PAUSE 100 TMOUT=TMOUT-100 LOOP 'Print "DATA " 'pin(ADC_CS)=0 'print hex$(SPI(88)) ''DATA, 24 bits 'print hex$(SPI(0)) 'print hex$(SPI(0)) 'print hex$(SPI(0)) 'pin(ADC_CS)=1 SPI CLOSE 'pin(10)=PIN_10_SAVE 'restore END FUNCTION FUNCTION GET_ADC_FAST(C AS INTEGER) AS FLOAT ''uses lower filter word for faster conversion GET_ADC_FAST=-1000000'default fail value LOCAL INTEGER CHANNEL_MASK,JUNK,TMOUT TMOUT=200 CHANNEL_MASK=0 ''no channels 'LOCAL PIN_10_SAVE AS INTEGER 'PIN_10_SAVE=PIN(10) ''save state 'pin(10)=1 ''power on so that touch pin is not pulled down SPI OPEN 2000000, 3, 8 if C = 1 THEN CHANNEL_MASK=&h10 if C = 2 THEN CHANNEL_MASK=&h20 if C = 3 THEN CHANNEL_MASK=&h40 if C = 4 THEN CHANNEL_MASK=&h80 pin(ADC_CS)=0 ''40 DIN high bits=reset JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) JUNK=SPI(255) pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(8) ''write MODE, 24 bits JUNK=SPI(&h38) ''single mode, returns to pwoer down after JUNK=SPI(&h00) ''sinc4, no parity, FS9-FS8=0 JUNK=SPI(32) ''FS7-FS0=value=filter word if FS9:FS8=0 pin(ADC_CS)=1 pin(ADC_CS)=0 JUNK=SPI(16) ''write CONFIG, 24 bits JUNK=SPI(&H00) ''CHOP off JUNK=SPI(CHANNEL_MASK) JUNK=SPI(&H48) ''unipolar, gain=1, pin(ADC_CS)=1 DO WHILE(TMOUT>0) pin(ADC_CS)=0 JUNK=SPI(64) ''read status JUNK=SPI(0) pin(ADC_CS)=1 'PRINT JUNK if (JUNK AND 7) = (C+3) THEN TMOUT=-1 pin(ADC_CS)=0 JUNK=SPI(88) ''read data GET_ADC_FAST=SPI(0)*65536 ''load valid data GET_ADC_FAST=GET_ADC_FAST + SPI(0)*256 GET_ADC_FAST=GET_ADC_FAST + SPI(0) pin(ADC_CS)=1 END IF PAUSE 10 TMOUT=TMOUT-10 LOOP 'Print "DATA " 'pin(ADC_CS)=0 'print hex$(SPI(88)) ''DATA, 24 bits 'print hex$(SPI(0)) 'print hex$(SPI(0)) 'print hex$(SPI(0)) 'pin(ADC_CS)=1 SPI CLOSE 'pin(10)=PIN_10_SAVE 'restore END FUNCTION ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Draw buttons and get button presses ' ' The subrouting DrawButton will draw a button (normally used when drawing ' the screen for input). ' ' The function CheckButtonPress() will check if a button has been touched. ' If it has it will set it to selected (reverse video) and return with the ' button's number. ' ' The subroutine CheckButtonRelease will wait for the touch to be released ' and will then draw the button as normal. ' ' These routines use the global arrays key_coord() and key_caption() to ' track the coordinates and size of each button and save its caption. ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' draw a button Sub DrawButton n As Integer, mode As Integer, x As Integer, y As Integer, w As Integer, h As Integer, c As Integer, s As String Local Integer bc, fc If mode = 0 Then key_coord(n,0) = x : key_coord(n,1) = y : key_coord(n,2) = w : key_coord(n,3) = h key_coord(n,4) = c : key_caption(n) = s EndIf If mode > 1 Then bc = key_coord(n,4) : fc = 0 ' draw in reverse video if it is being touched Else bc = 0 : fc = key_coord(n,4) ' a normal (untouched) button EndIf RBox key_coord(n,0), key_coord(n,1), key_coord(n,2), key_coord(n,3), , key_coord(n,4), bc) Text key_coord(n,0) + key_coord(n,2)/2, key_coord(n,1) + key_coord(n,3)/2, key_caption(n), CM, , , fc, bc End Sub Function CheckButtonPress2(startn As Integer, endn As Integer) As Integer CheckButtonPress = -1 ''dummy empty End Function ' check if a button has been touch and animate the button's image ' returns the button's number Function CheckButtonPress(startn As Integer, endn As Integer) As Integer Local Integer xt, yellowt, n CheckButtonPress = -1 If Touch(x) <> -1 Then ' we have a touch 'WatchDog 1200000 xt = Touch(x) yellowt = Touch(y) ' scan the array key_coord() to see if the touch was within the ' boundaries of a button For n = startn To endn If xt > key_coord(n,0) And xt < key_coord(n,0) + key_coord(n,2) And yellowt > key_coord(n,1) And yellowt < key_coord(n,1) + key_coord(n,3) Then ' we have a button press ' draw the button as pressed DrawButton n, 2 CheckButtonPress = n Exit For EndIf Next n EndIf End Function ' wait for the touch to be released and then draw the button as normal Sub CheckButtonRelease n As Integer ' if a button is currently down check if it has been released Do While Touch(x) <> -1 SAMPLE_MANAGER Loop ' wait for the button to be released DrawButton n, 1 ' draw the button as normal (ie, not pressed) End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' this handy routine draws a message box with an OK button ' then waits for the button to be touched ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Sub MessageBox s1 As String, s2 As String Local Integer w If Len(s1) > Len(s2) Then w = Len(s1) Else w = Len(s2) w = w * 8 ' get the width of the text (used for the box width) ' draw the box and the message in it RBox MM.HRes/2 - w - 20, 60, w * 2 + 40, 130, , FG_COL, 0 Text MM.HRes/2, 70, s1, CT, 1, 2, FG_COL Text MM.HRes/2, 100, s2, CT, 1, 2, FG_COL ' draw the OK button RBox 110, 140, 100, 34, , BUTTON_COL Text MM.HRes/2, 157, "OK", CM, 1, 2, BUTTON_COL ' wait for the button to be touched 'WatchDog 1200000 Do While Not (Touch(x) > 110 And Touch(x) < 210 And Touch(y) > 140 And Touch(y) < 180) : Loop ' draw the OK button as depressed RBox 110, 140, 100, 34, , BUTTON_COL, BUTTON_COL Text MM.HRes/2, 157, "OK", CM, 1, 2, 0, BUTTON_COL ' wait for the touch to be removed Do While Touch(x) <> -1 : Loop End Sub FUNCTION OK_CANCEL_BOX(S1 AS STRING, S2 AS STRING) AS INTEGER ''variant of MessageBox with two options OK_CANCEL_BOX=0 Local Integer w If Len(s1) > Len(s2) Then w = Len(s1) Else w = Len(s2) w = w * 8 ' get the width of the text (used for the box width) if w < 108 THEN w = 108 ' draw the box and the message in it RBox MM.HRes/2 - w - 20, 60, w * 2 + 40, 130, , FG_COL, 0 Text MM.HRes/2, 70, s1, CT, 1, 2, FG_COL Text MM.HRes/2, 100, s2, CT, 1, 2, FG_COL ' draw the OK button RBox 55, 140, 100, 34, , BUTTON_COL Text 105, 157, "OK", CM, 1, 2, BUTTON_COL ' draw the CANCEL button RBox 165, 140, 100, 34, , BUTTON_COL Text 215, 157, "CANCEL", CM, 1, 2, BUTTON_COL 'wait for press DO SAMPLE_MANAGER IF (Touch(y) > 140 And Touch(y) < 180) THEN IF (TOUCH(x)>55 AND TOUCH(x)<155) THEN ''OK RBox 55, 140, 100, 34, , BUTTON_COL, BUTTON_COL Text 105, 157, "OK", CM, 1, 2, 0, BUTTON_COL Do While Touch(x) <> -1 : SAMPLE_MANAGER : Loop OK_CANCEL_BOX=1 EXIT FUNCTION ENDIF IF (TOUCH(x)>165 AND TOUCH(x)<265) THEN ''CANCEL RBox 165, 140, 100, 34, , BUTTON_COL, BUTTON_COL Text 215, 157, "CANCEL", CM, 1, 2, 0, BUTTON_COL Do While Touch(x) <> -1 : SAMPLE_MANAGER : Loop OK_CANCEL_BOX=0 EXIT FUNCTION ENDIF ENDIF LOOP END FUNCTION FUNCTION OK_CANCEL_BUTTONS() AS INTEGER ''buttons only at bottom of screen OK_CANCEL_BUTTONS=0 ' draw the OK button RBox 55, 200, 100, 34, , BUTTON_COL Text 105, 217, "OK", CM, 1, 2, BUTTON_COL ' draw the CANCEL button RBox 165, 200, 100, 34, , BUTTON_COL Text 215, 217, "CANCEL", CM, 1, 2, BUTTON_COL 'wait for press DO SAMPLE_MANAGER IF (Touch(y) > 200 And Touch(y) < 240) THEN IF (TOUCH(x)>55 AND TOUCH(x)<155) THEN ''OK RBox 55, 200, 100, 34, , BUTTON_COL, BUTTON_COL Text 105, 217, "OK", CM, 1, 2, 0, BUTTON_COL Do While Touch(x) <> -1 : SAMPLE_MANAGER : Loop OK_CANCEL_BUTTONS=1 EXIT FUNCTION ENDIF IF (TOUCH(x)>165 AND TOUCH(x)<265) THEN ''CANCEL RBox 165, 200, 100, 34, , BUTTON_COL, BUTTON_COL Text 215, 217, "CANCEL", CM, 1, 2, 0, BUTTON_COL Do While Touch(x) <> -1 : SAMPLE_MANAGER : Loop OK_CANCEL_BUTTONS=0 EXIT FUNCTION ENDIF ENDIF LOOP END FUNCTION SUB DRAW_NUMPAD(BUTTON_START AS INTEGER,TITLE AS STRING) CLS(BG_COL) DrawButton BUTTON_START,0, 66, 195, 60, 40, BUTTON_COL, "0" DrawButton BUTTON_START+1,0, 130, 195, 60, 40, BUTTON_COL, "1" DrawButton BUTTON_START+2,0, 194, 195, 60, 40, BUTTON_COL, "2" DrawButton BUTTON_START+3,0, 258, 195, 60, 40, BUTTON_COL, "3" DrawButton BUTTON_START+4,0, 130, 150, 60, 40, BUTTON_COL, "4" DrawButton BUTTON_START+5,0, 194, 150, 60, 40, BUTTON_COL, "5" DrawButton BUTTON_START+6,0, 258, 150, 60, 40, BUTTON_COL, "6" DrawButton BUTTON_START+7,0, 130, 105, 60, 40, BUTTON_COL, "7" DrawButton BUTTON_START+8,0, 194, 105, 60, 40, BUTTON_COL, "8" DrawButton BUTTON_START+9,0, 258, 105, 60, 40, BUTTON_COL, "9" DrawButton BUTTON_START+10,0, 66, 150, 60, 40, BUTTON_COL, "." DrawButton BUTTON_START+11,0, 2, 195, 60, 40, BUTTON_COL, "<-" DrawButton BUTTON_START+12,0, 2, 150, 60, 40, BUTTON_COL, "OK" DrawButton BUTTON_START+13,0, 2, 105, 60, 40, BUTTON_COL, "Cancel" TEXT 160,10,TITLE,CT,8,1,FG_COL,BG_COL END SUB FUNCTION NUMBERPAD(TITLE AS STRING) AS FLOAT NUMBERPAD=-1'invalid LOCAL STRING ENTRY ENTRY="" ''use high numbered buttons to not interfere with other screens LOCAL INTEGER BUTTON_START BUTTON_START=BUTTON_COUNT-15 DRAW_NUMPAD(BUTTON_START,TITLE) DO SAMPLE_MANAGER BUTTON_PRESS=CheckButtonPress(BUTTON_START, BUTTON_START+13) IF BUTTON_PRESS >= 0 THEN CheckButtonRelease(BUTTON_PRESS) if BUTTON_PRESS = BUTTON_START THEN ENTRY=ENTRY+"0" if BUTTON_PRESS = BUTTON_START+1 THEN ENTRY=ENTRY+"1" if BUTTON_PRESS = BUTTON_START+2 THEN ENTRY=ENTRY+"2" if BUTTON_PRESS = BUTTON_START+3 THEN ENTRY=ENTRY+"3" if BUTTON_PRESS = BUTTON_START+4 THEN ENTRY=ENTRY+"4" if BUTTON_PRESS = BUTTON_START+5 THEN ENTRY=ENTRY+"5" if BUTTON_PRESS = BUTTON_START+6 THEN ENTRY=ENTRY+"6" if BUTTON_PRESS = BUTTON_START+7 THEN ENTRY=ENTRY+"7" if BUTTON_PRESS = BUTTON_START+8 THEN ENTRY=ENTRY+"8" if BUTTON_PRESS = BUTTON_START+9 THEN ENTRY=ENTRY+"9" if (BUTTON_PRESS = BUTTON_START+10) AND (INSTR(ENTRY,".") = 0)THEN ENTRY=ENTRY+"." 'only add one . if (BUTTON_PRESS = BUTTON_START+11) AND (LEN(ENTRY)>0) THEN ENTRY=left$(ENTRY,LEN(ENTRY)-1) IF ENTRY="." THEN ENTRY="0." IF LEN(ENTRY)>9 THEN ENTRY=LEFT$(ENTRY,9) 'truncate if BUTTON_PRESS = BUTTON_START+13 THEN NUMBERPAD=-1: EXIT FUNCTION if BUTTON_PRESS = BUTTON_START+12 THEN NUMBERPAD=VAL(ENTRY) IF OK_CANCEL_BOX("ACCEPT?",STR$(NUMBERPAD))>0 THEN EXIT FUNCTION ''OK ''OTHERWISE CANCEL NUMBERPAD=-1 DRAW_NUMPAD(BUTTON_START,TITLE) ENDIF ENDIF TEXT 0,45,RIGHT$(" "+ENTRY+"_",10),LT,8,2,FG_COL,HL_COLOUR LOOP END FUNCTION |