Once you learn how to use BASIC you'll never use it again.
Nonsense!!!
I have a Toshiba T1200 laptop with an LCD screen from about 1988 that runs QBASIC in DOS 3.3.
I still use it to collect data for my weather station. A 720K floppy disk holds months of data, and the laptop runs for hours on 6xAA batteries if the power goes out!
Also keeps a nice plot of the last ~20 hours of average wind speed and gusts on the screen.
For the BASIC aficionados among you, here is the wind gauge code:
REM read wind gauge and store statistics on disk.
REM circular buffer push and pull
DECLARE SUB gbuf (array!(), v!, nsp%, nsmax%)
DECLARE SUB pbuf (array!(), v!, ns%, nsp%, nsmax%)
REM plot wind speed data in box 1-600 on x, 0-99 on y, lower screen
DIM t0(600), t1(600)
DEFINT I-N
DEFSNG K
nsec = 300 'sample save interval in seconds
SCREEN 2 '640x200
'
' VIEW defines graphics viewport in absolute screen coords, subsequent
' pixel coords are relative to view window
'
' VIEW SCREEN (ditto) but subsequent pixel coords are absolute
' Order of coordinate pairs is immaterial!
'
VIEW (21, 98)-(620, 198), , 1: REM view won't frame extreme edges
WINDOW (1, 0)-(600, 99): REM logical coords 1-600 on x, 0-99 on y
CLS
OPEN "com1:4800,n,8,1,cs0,ds0,cd0" FOR INPUT AS #1
LOCATE 1, 1: PRINT "Starting wind monitor at: "; DATE$; " "; TIME$
LOCATE 2, 1
INPUT "Output file name: ", n$
OPEN n$ FOR OUTPUT AS #2
PRINT #2, DATE$; " "; TIME$; " sample:"; nsec
r% = 0
REM number of points in graph, buffer pointers
n0m = 300: n0 = 0: n0p = 1
n1m = 300: n1 = 0: n1p = 1
REM get version #
'ON ERROR GOTO handler
LINE INPUT #1, a$
LOCATE 3, 1: PRINT "Version and time: "; a$
LOCATE 4, 1: PRINT "Hit Esc to exit..."
nsamp = 0: wmaxt0 = 0: avgt0 = 0: vart0 = 0
ON TIMER(nsec) GOSUB 5000
TIMER ON
10 LINE INPUT #1, a$: LOCATE 9, 33: PRINT a$; " "
nc = INSTR(a$, ","): a$ = MID$(a$, nc + 1)
nc = INSTR(a$, ","): a$ = MID$(a$, nc + 1)
15 temp0 = VAL(a$) / 22.6
nc = INSTR(a$, ",")
20 temp1 = VAL(MID$(a$, nc + 1)) / 22.6: REM max reported by sensor
IF (wmaxt0 < temp1) THEN wmaxt0 = temp1
avgt0 = avgt0 + temp0
vart0 = vart0 + temp0 * temp0
nsamp = nsamp + 1
LOCATE 11, 26
PRINT USING "& Avg: ### Max: ### mph"; LEFT$(TIME$, 5); temp0; temp1;
IF INKEY$ <> CHR$(27) THEN GOTO 10
REM escape key hit, all done
GOSUB 5000
CLOSE #2
STOP
5000 r% = r% + 1: REM write record: average, max and s.d. this interval
avgt0 = avgt0 / nsamp
vart0 = vart0 / nsamp - avgt0 * avgt0
vart0 = SQR(ABS(vart0))
PRINT #2, USING "###.#,###.#,###.#"; avgt0; wmaxt0; vart0
CALL pbuf(t0(), avgt0, n0, n0p, n0m)
CALL pbuf(t1(), wmaxt0, n1, n1p, n1m)
nsamp = 0: avgt0 = 0: wmaxt0 = 0: vart0 = 0
REM plot data
CLS 1
' dotted gridlines
FOR i = 1 TO 600 STEP 4
PSET (i, 30): LOCATE 21, 4: PRINT "10";
PSET (i, 60): LOCATE 17, 4: PRINT "20";
PSET (i, 90): LOCATE 13, 4: PRINT "30";
NEXT i
' pull out most recent temp0 and max measurements
nsp = n0p
FOR i = n0 TO 1 STEP -1
CALL gbuf(t0(), v, nsp, n0m)
v = 3 * v: i2 = 2 * i
PSET (i2, v): PSET (i2, v + 1): PSET (i2, v - 1): PSET (i2 + 1, v): PSET (i2 - 1, v)
NEXT i
RETURN
handler:
LOCATE 3, 30
PRINT "error "; ERR; " at line "; ERL; TIME$; " "; DATE$;
LOCATE 4, 30
PRINT a$
RESUME NEXT
DEFINT K
SUB gbuf (array!(), v!, nsp%, nsmax%)
DEFINT I-N
REM NO check for buffer underflow
v = array(nsp)
nsp = nsp - 1
IF nsp < 1 THEN nsp = nsmax
END SUB
SUB pbuf (array!(), v!, ns%, nsp%, nsmax%)
DEFINT I-N
REM returns ns%, number of values pushed
array(nsp) = v
nsp = nsp + 1: ns = ns + 1
IF nsp > nsmax THEN nsp = 1
IF ns > nsmax THEN ns = nsmax
END SUB