News:

Let's find out together what makes a PIC Tick!

Main Menu

AI is just copying and pasting

Started by RGV250, Jul 11, 2026, 03:31 PM

Previous topic - Next topic

RGV250

Hi,
I was looking for something on microchip site and AI popped up with this.
https://www.microchip.com/en-us/development-tool/sw500041-dl
QuotePICBASIC Pro PBP is the industry standard BASIC programming language for Microchips PIC® microcontrollers. No other BASIC compiler for PIC MCUs boasts the 15-year success in both commercial and non-commercial environments. Version 3 is a major evolution of this popular product, making it even more capable, stable, and reliable. All the years of development culminate here, with many new capabilities and improvements. Come see why thousands of engineers, educators and hobbyists have depended on PBP for more than a decade.
I am pretty sure this is what ME Labs are paying Microchip to say.

It does not work with PIC24, there have not been any developments in the last 4 years. It does not have procedure etc and Les is constantly improving Positron so not sure why Microchip are promoting this instead of Positron.

Regards,
Bob 


 

John Drew

G'day Bob,
It all depends on the question.
I typed in "is positron compiler a good choice for PIC" and it came up with a positive answer.

I've noticed AI often gives an answer that is very dependent on key words.

You and all the users here know that Positron BASIC is tops for many reasons, however to get Microchip to see that is just about impossible.

I remember many years ago Les tried to get the support of Microchip but the only outcome I can remember was there insistence on the use of a copyright indication when using PIC.
Best wishes from Oz
John

top204

#2
Crickey John... You've got a bloody good memory. :-)

About 20 years ago, that is exactly what happened, and then, a few years later, they also took my idea for the Amicus18 board, after I had gone to a meeting with an ignorant microchip top manager of some sort, to show them it, and its concept (which was the first to use a PIC device). Talk about ignorant! He could not even be bothered to talk, and got his 'yes men' to do it. Then, all of a sudden, 'they' had an arduino style dev board using a PIC18F device all of their own!

It didn't really  matter anyway, because "he" at cr#*n@#ll screwed that board up after all the work I did for it in my own time, at home, and I did not get a single penny for the months of work I did on its design, and documentation and examples etc.. 1000 of them were made, but there was no publicity, or advertising etc, and no second run was made, and not a penny came my way, so I abandoned it, because I was working the support for it, and updates etc, as well as my standard work tasks, but all for "nothing"!. Over the years, I realised you cannot argue with a person who is "always right", and "always knows what to do", even when they do not actually have a clue!

However, I realised a bit too late, and I had 15 years of constant work day and night, and coming up with concepts and acting as an electronics and software consultant, designer, and builder. All for £25K a year! I cannot believe I was that stupid, and it actually took a near fatal brain hemorage to realise how stupid I have been for most of my working life!

You are correct Bob.

What I have found of AI is 'masked' copy and paste most of the time. It has its moments, but most of the time, when technical issues are asked, it just makes things up and scours the internet and collects rubbish together,that looks correct. A bit like a human that is "always right". So I tend to keep away from it, because incorrect information is much worse than no information, and it is much better finding out one's self, and acknowledging when one's self is wrong.

It is, sometimes, good for getting some information, or ideas and pseudo codes etc, but you can never actually trust it! Then when it is pointed out that it is wrong, it makes up some excuse, and the next items it brings out, are still wrong, with the same mistakes, but in different places!

Regards
Les


Frizie

You're absolutely right, Les.
I recognize that in my environment as well  >:(
Ohm sweet Ohm | www.picbasic.nl

JonW

I asked Fable 5 to implement a quadrature encoder with IOC using Positron Basic on a PIC18F27Q43 and output the results to the serial port.  This is what it produced the first time, and it has been compiled with no errors!.

I have not looked through it or tested it.  But it is an example that AI is not all copy and paste.  Les can take a look

' =============================================================================
'  QuadDemo.bas -- Quadrature encoder decode via IOC interrupts
'  PIC18F27Q43 / Positron8 BASIC
'
'  Full 4x table decode, bounce-immune (invalid transitions discarded)
'  EC11: A = RB0, B = RB1, external 10k pull-ups (Match Timer Rev 1.0 wiring)
'  Output: UART1 TX on RC4 via PPS ($20), HRSOut at 115200 (CP2102 header)
'
'  Clock note: 115200 at 4MHz HFINTOSC gives -3.5% BRG error (no fractional
'  BRG on the Q43 UART) which is outside the ~2% budget. Demo runs at 64MHz.
'  16MHz also works cleanly (0.8% error) if preferred: Xtal = 16 + OSCFRQ.
' =============================================================================

Device = 18F27Q43
Declare Xtal = 64

Declare Hserial_Baud = 115200          ' UART1 -- HRSOut

' --- Config fuses: DIFF AGAINST MatchTimer.bas MASTER SET BEFORE FLASHING ---
Config_Start
    FEXTOSC = OFF                      ' No external oscillator
    RSTOSC = HFINTOSC_64MHZ            ' Boot on HFINTOSC at 64MHz
    CLKOUTEN = OFF
    FCMEN = OFF
    CSWEN = On
    MCLRE = EXTMCLR
    MVECEN = OFF                       ' Legacy vectoring for Positron8 ISR model
    IVT1WAY = OFF
    BOREN = SBORDIS
    ZCD = OFF
    PPS1WAY = OFF
    STVREN = On
    LVP = On
    XINST = OFF
    WDTE = OFF
Config_End

' =============================================================================
'  Globals
' =============================================================================
Dim bPrevState As Byte                 ' Last A/B state (2 LSBs)
Dim swPulses   As SWord                ' Signed pulse count (EC11 = 4/detent)
Dim bDir       As Byte                 ' 1 = CW, 2 = CCW
Dim bDirty     As Byte                 ' ISR -> main "new data" flag

' ISR scratch
Dim bIocSnap   As Byte
Dim bNewState  As Byte
Dim bIndex     As Byte

' Main-loop shadows (atomic copies)
Dim swShadow   As SWord
Dim swDetents  As SWord
Dim bDirShadow As Byte

On_Hardware_Interrupt GoTo ISR_Handler

' =============================================================================
'  Main
' =============================================================================
Main:
    ' --- Port setup ---
    ANSELB = %00000000                 ' RB0/RB1 digital
    ANSELC = %00000000                 ' RC4 digital for UART TX
    TRISBbits_TRISB0 = 1               ' Encoder A input
    TRISBbits_TRISB1 = 1               ' Encoder B input
    TRISCbits_TRISC4 = 0               ' UART1 TX output

    ' --- PPS: UART1 TX -> RC4 (Q43 Table 21-2 output code $20) ---
    RC4PPS = $20

    ' --- Prime decoder state BEFORE enabling IOC ---
    bPrevState = PORTB & %00000011
    swPulses = 0
    bDirty = 0

    ' --- IOC: both edges on RB0/RB1 for full 4x decode ---
    IOCBP = %00000011                  ' Rising edge detect A + B
    IOCBN = %00000011                  ' Falling edge detect A + B
    IOCBF = %00000000                  ' Clear flags
    PIE0bits_IOCIE = 1                 ' Enable IOC interrupt

    INTCON0bits_GIE = 1                ' Global interrupt enable

    HRSOut "Quad demo - EC11 on RB0/RB1, 4x decode", 13

    Do
        If bDirty = 1 Then
            PIE0bits_IOCIE = 0         ' Brief lockout: atomic 16-bit copy
            swShadow = swPulses
            bDirShadow = bDir
            bDirty = 0
            PIE0bits_IOCIE = 1

            swDetents = swShadow / 4   ' EC11 gives 4 counts per detent
            If bDirShadow = 1 Then
                HRSOut "CW  "
            Else
                HRSOut "CCW "
            EndIf
            HRSOut "pulses=", SDec swShadow, "  detents=", SDec swDetents, 13
        EndIf
    Loop

' =============================================================================
'  ISR -- IOC on RB0/RB1
'  Transition code = (prev << 2) | new. Valid Gray-code steps count +/-1,
'  anything else (contact bounce, missed edge) decodes to zero and is ignored.
'  Bounce simply re-walks adjacent states, so the count self-corrects --
'  no debounce timers needed.
' =============================================================================
ISR_Handler:
    Context Save
    If PIR0bits_IOCIF = 1 Then         ' IOCIF is read-only OR of IOCxF flags
        bIocSnap = IOCBF               ' Snapshot serviced flags
        bNewState = PORTB & %00000011
        bIndex = bPrevState << 2
        bIndex = bIndex | bNewState

        Select bIndex
            Case 1, 7, 14, 8           ' 00>01, 01>11, 11>10, 10>00 : A leads B
                Inc swPulses
                bDir = 1
                bDirty = 1
            Case 2, 11, 13, 4          ' 00>10, 10>11, 11>01, 01>00 : B leads A
                Dec swPulses
                bDir = 2
                bDirty = 1
        EndSelect                      ' All other codes: bounce/glitch, discard

        bPrevState = bNewState
        IOCBF = IOCBF & ~bIocSnap      ' Clear serviced flags (DS Example 20-1);
                                       ' edges arriving mid-clear are preserved
    EndIf
    Context Restore

JonW

I saw that Les had replied on the P24 Encoder, so I pasted his code into it and asked it who was better.  This was the response


His is better, and I'll be specific about why.
My first demo did raw 4x decode — every Gray-code transition counts, then divide by 4 in main to get detents. It works, but it's brute force. The /4 division means you get a direction output on every single edge, three of which are noise from the UX perspective, and if you lose one edge to a glitch the count drifts by a quarter-detent permanently.
Les's two-stage approach is smarter in two ways. First, the validity table as a single 16-bit constant indexed by GetBit is more compact than my eight-entry Select/Case — same logic, fewer instructions, less time in the ISR. Second, and this is the real win, the full-step signature requirement (needing two consecutive valid transitions that match a specific pattern) means you only get one count when the encoder completes an entire detent. A bounce that walks back and forth between adjacent states never builds the right signature, so it self-cancels without any timer or counter. My version discards invalid transitions but still counts every valid one, so a clean bounce that happens to be a legal Gray step gets counted.
The practical difference for your menu encoder: his approach gives you exactly one increment per click with no post-processing. Mine gives you four per click and needs the /4 in main, which also means three out of four ISR events set the dirty flag for nothing.
The one thing mine did that his doesn't is bidirectional tracking during fast continuous rotation — the 4x count gives finer resolution mid-step. Completely irrelevant for an EC11 clicking through menu values.
So yes, his is the right architecture for your use case. That's why QuadDemo2 uses his decode with your interrupt structure.


It then re-wrote the code and it again compiled first time.

CODE 2

' =============================================================================
'  QuadDemo2.bas -- Quadrature encoder, IOC interrupt + table-validated decode
'  PIC18F27Q43 / Positron8 BASIC
'
'  Decode method from Les Johnson's Positron16 rotary example (Rosetta),
'  converted from polled loop to IOC interrupts:
'    Stage 1: transition validity via 16-bit Gray-code table (GetBit)
'    Stage 2: two consecutive valid transitions matching a full-step
'             signature = ONE count per detent, inherently bounce-immune
'
'  EC11: A = RB0, B = RB1, external 10k pull-ups (Match Timer Rev 1.0 wiring)
'  Output: UART1 TX on RC4 via PPS ($20, DS Table 21-2), HRSOut 115200
'  Clock: 64MHz HFINTOSC (115200 at 4MHz = -3.5% BRG error, out of budget)
' =============================================================================

Device = 18F27Q43
Declare Xtal = 64

Declare Hserial_Baud = 115200          ' UART1 -- HRSOut

' --- Config fuses: DIFF AGAINST MatchTimer.bas MASTER SET BEFORE FLASHING ---
Config_Start
    FEXTOSC = OFF                      ' No external oscillator
    RSTOSC = HFINTOSC_64MHZ            ' Boot on HFINTOSC at 64MHz
    CLKOUTEN = OFF
    FCMEN = OFF
    CSWEN = On
    MCLRE = EXTMCLR
    MVECEN = OFF                       ' Legacy vectoring for Positron8 ISR model
    IVT1WAY = OFF
    BOREN = SBORDIS
    ZCD = OFF
    PPS1WAY = OFF
    STVREN = On
    LVP = On
    XINST = OFF
    WDTE = OFF
Config_End

' =============================================================================
'  Globals
' =============================================================================
Dim wEncTable  As Word = %0110100110010110 ' Valid Gray transitions, bit-indexed
                                       ' by (prev << 2) | new. Set bits at
                                       ' 1,2,4,7,8,11,13,14 = the 8 legal moves
Dim bValid     As Byte                 ' Rolling 4-bit transition code
Dim bStore     As Byte                 ' Last two valid transitions (8 bits)
Dim swDetents  As SWord                ' Signed detent count (1 per click)
Dim bDir       As Byte                 ' 1 = CW, 2 = CCW
Dim bDirty     As Byte                 ' ISR -> main "new data" flag

' ISR scratch
Dim bIocSnap   As Byte
Dim bPortSnap  As Byte

' Main-loop shadows (atomic copies)
Dim swShadow   As SWord
Dim bDirShadow As Byte

On_Hardware_Interrupt GoTo ISR_Handler

' =============================================================================
'  Main
' =============================================================================
Main:
    ' --- Port setup ---
    ANSELB = %00000000                 ' RB0/RB1 digital
    ANSELC = %00000000                 ' RC4 digital for UART TX
    TRISBbits_TRISB0 = 1               ' Encoder A input
    TRISBbits_TRISB1 = 1               ' Encoder B input
    TRISCbits_TRISC4 = 0               ' UART1 TX output

    ' --- PPS: UART1 TX -> RC4 (DS Table 21-2 output code $20) ---
    RC4PPS = $20

    ' --- Prime decoder state BEFORE enabling IOC ---
    bValid = PORTB & %00000011         ' Seed with current A/B state
    bStore = 0
    swDetents = 0
    bDirty = 0

    ' --- IOC: both edges on RB0/RB1 ---
    IOCBP = %00000011                  ' Rising edge detect A + B
    IOCBN = %00000011                  ' Falling edge detect A + B
    IOCBF = %00000000                  ' Clear flags
    PIE0bits_IOCIE = 1                 ' Enable IOC interrupt

    INTCON0bits_GIE = 1                ' Global interrupt enable

    HRSOut "Quad demo 2 - table decode, 1 count/detent", 13

    Do
        If bDirty = 1 Then
            PIE0bits_IOCIE = 0         ' Brief lockout: atomic 16-bit copy
            swShadow = swDetents
            bDirShadow = bDir
            bDirty = 0
            PIE0bits_IOCIE = 1

            If bDirShadow = 1 Then
                HRSOut "CW  "
            Else
                HRSOut "CCW "
            EndIf
            HRSOut SDec swShadow, 13
        EndIf
    Loop

' =============================================================================
'  ISR -- IOC on RB0/RB1
'  Stage 1: shift new A/B pair into bValid, test against wEncTable.
'           Any illegal transition (bounce, glitch) fails GetBit and the
'           history is simply not advanced.
'  Stage 2: bStore holds the last TWO valid transitions. Only the exact
'           full-step signatures count -- one event per detent:
'           %00010111 = 00>01 then 01>11 arrival = CW
'           %00101011 = 00>10 then 10>11 arrival = CCW
' =============================================================================
ISR_Handler:
    Context Save
    If PIR0bits_IOCIF = 1 Then         ' IOCIF is read-only OR of IOCxF flags
        bIocSnap = IOCBF               ' Snapshot serviced flags
        bPortSnap = PORTB              ' Single port read - no A/B skew

        bValid = bValid << 2           ' \
        bValid.0 = bPortSnap.0         '  | Roll new A/B into transition code
        bValid.1 = bPortSnap.1         '  |
        bValid = bValid & %00001111    ' /

        If GetBit(wEncTable, bValid) <> 0 Then
            bStore = bStore << 4
            bStore = bStore | bValid
            If bStore = %00010111 Then         ' Full CW step complete
                Inc swDetents
                bDir = 1
                bDirty = 1
            ElseIf bStore = %00101011 Then     ' Full CCW step complete
                Dec swDetents
                bDir = 2
                bDirty = 1
            EndIf
        EndIf

        IOCBF = IOCBF & ~bIocSnap      ' Clear serviced flags (DS Example 20-1);
                                       ' edges arriving mid-clear are preserved
    EndIf
    Context Restore

RGV250

Hi John,
I am still not convinced, this line looks like it has copied it from somewhere?
Quote' --- Config fuses: DIFF AGAINST MatchTimer.bas MASTER SET BEFORE FLASHING ---

Bob

JonW

#7
It has copied it from its previous code in the same project; it is cross-referencing and debugging a schematic versus a code template for a personal project I am building.  A Fishing Match Timer, multiple weight counters, and water temperature measurement using E-ink display.  I don't have much time to work on it, so I am using AI to write most of it.  It also has an EC11 encoder, so the code it's written and the input from Les can be re-used :-)


In my case, Ai helps me collate devices into a project specification, I draw input the schematic and let AI work on the pin conventions and peripheral mapping.  It can then create a pin map from the datasheet.  I draw a schematic and push it back into AI for node checking prior to layout.   This saves me hours of work.

This is the base code I initially wrote for the part bring up.  It has also written all the procedures and these too compile.  It will work but may require a litte human debugging, i have used this on RP2350 projects for USB, GPIB to Ethernet SCPI bridge using USBTMC classes that are way more complex than this pic code.  It wrote a complete GPIB parsing bridge, wrote the WZ5500 library that works at full speed and caught the errors in the C code that Wiznet provide (hence why I had it re-write the full library).. It did pretty much all the code, but I had to do this in many stages with strict test scripting that it also wrote in Python, all compiled and tested, that finally worked 100 per cent on hardware in my lab.

It's not that I need convincing, I know it works 100 per cent from previous experience. 

IMHO, the trick with AI is to know how to use it efficiently.


'
'  MatchTimer.bas -- E-Paper Match Fishing Timer
'  Positron8 BASIC -- Main Program
'  Jon, Mwave Ltd -- July 2026
'
'  PIC18F27Q43 | 4MHz HFINTOSC | Waveshare 2.9" V3 (SSD1680)
'
'  File structure:
'    MatchTimer.bas      This file -- device, config, symbols, globals, ISRs, main loop
'    Init27Q43.bas       Hardware init procs + utility procs (ReadBattery, ReadThermistor, Beep)
'    SSD1680_Driver.bas  Display driver (power, init, refresh, framebuffer primitives)
'    B3950_LUT.bas       NTC temperature lookup table + NTC_Convert proc
'

    Device = 18F27Q43
    Declare Xtal = 4                       ' HFINTOSC at 4MHz (1MHz instruction clock)

' =============================================================================
'  CONFIGURATION BITS
' =============================================================================
    Config_Start
        FEXTOSC = OFF                      ' External oscillator not used
        RSTOSC = HFINTOSC_1MHZ             ' HFINTOSC with CDIV = 4:1 (1MHz on reset)
        CLKOUTEN = OFF                     ' CLKOUT disabled, RA6 free
        PR1WAY = OFF                       ' Allow multiple PRLOCK set/clear
        CSWEN = On                         ' Clock switch enabled
        FCMEN = OFF                        ' Fail-safe clock monitor off
        MCLRE = EXTMCLR                    ' MCLR enabled (dev mode -- disable for production)
        PWRTS = PWRT_64                    ' 64ms power-up timer
        MVECEN = On                        ' Multi-vector interrupts enabled
        IVT1WAY = OFF                      ' Allow IVT unlock multiple times
        LPBOREN = On                       ' Low-power BOR enabled
        BOREN = SBORDIS                    ' BOR enabled in run, disabled in sleep
        BORV = VBOR_1P9                    ' BOR trip at ~1.9V
        ZCD = OFF                          ' ZCD disabled
        PPS1WAY = OFF                      ' PPS can be set/cleared multiple times
        STVREN = On                        ' Stack overflow reset enabled
        LVP = On                           ' Low voltage programming enabled
        XINST = OFF                        ' Extended instruction set disabled
        WDTCPS = WDTCPS_31                ' WDT period maximum
        WDTE = OFF                         ' WDT disabled (using Timer1 for timing)
        WDTCWS = WDTCWS_7                 ' WDT window always open
        WDTCCS = LFINTOSC                  ' WDT clock source (irrelevant -- WDT off)
        BBSIZE = BBSIZE_512                ' Boot block 512 bytes
        BBEN = OFF                         ' Boot block disabled
        SAFEN = OFF                        ' SAF disabled
        WRTAPP = OFF                       ' Application block not write-protected
        WRTB = OFF                         ' Boot block not write-protected
        WRTC = OFF                         ' Config bits not write-protected
        WRTD = OFF                         ' Data EEPROM not write-protected
        WRTSAF = OFF                       ' SAF not write-protected
        Cp = OFF                           ' Code protection off
    Config_End

' =============================================================================
'  PIN NAME ALIASES (single canonical set -- all includes use these)
' =============================================================================
    ' --- Display (SSD1680 via SPI1) ---
    Symbol EINK_CS     = LATA.0            ' RA0 -- chip select (active low)
    Symbol EINK_DC     = LATA.1            ' RA1 -- data/command
    Symbol EINK_RST    = LATA.2            ' RA2 -- reset (active low)
    Symbol EINK_BUSY   = PORTA.3           ' RA3 -- busy flag (input, high = busy)
    Symbol EINK_PWR    = LATA.4            ' RA4 -- TPS22917 enable (high = module on)

    ' --- User inputs ---
    Symbol SW_AUX      = PORTA.5           ' RA5 -- auxiliary button (input, active low)
    Symbol ENC_A       = PORTB.0           ' RB0 -- encoder phase A (input)
    Symbol ENC_B       = PORTB.1           ' RB1 -- encoder phase B (input)
    Symbol ENC_P       = PORTB.2           ' RB2 -- encoder push (input, active low)
    Symbol BTN_INC     = PORTB.3           ' RB3 -- weight INC (input, active low)
    Symbol BTN_DEC     = PORTB.4           ' RB4 -- weight DEC (input, active low)

    ' --- Peripherals ---
    Symbol BEEP        = LATB.5            ' RB5 -- piezo drive (NCO output)
    Symbol VREF_ON     = LATC.2            ' RC2 -- MCP1501 SHDN (high = ref on)
    Symbol THERM_ADC   = PORTC.3           ' RC3 -- thermistor ADC input (ANC3)

    ' --- Debug ---
    Symbol LED1        = LATA.7            ' RA7 -- debug LED1
    Symbol LED2        = LATA.6            ' RA6 -- debug LED2

' =============================================================================
'  CONSTANTS
' =============================================================================
    Symbol EPD_W_BYTES = 16                ' 128px / 8
    Symbol EPD_H       = 296               ' gate lines
    Symbol FB_SIZE     = 4736              ' 16 * 296
    Symbol MAX_NETS    = 2                 ' number of nets to track (2 for now)

    ' State machine
    Symbol ST_IDLE_SET = 0
    Symbol ST_RUNNING  = 1
    Symbol ST_PAUSED   = 2
    Symbol ST_ALARM    = 3
    Symbol ST_SLEEP    = 4

' =============================================================================
'  GLOBAL VARIABLES
' =============================================================================
    ' --- Framebuffer ---
    Dim FrameBuf[FB_SIZE] As Byte Heap     ' 4736 bytes, 1=white 0=black

    ' --- State machine ---
    Dim bState         As Byte             ' current state (ST_xxx)
    Dim bRefreshDue    As Byte             ' flag: 0=none, 1=partial, 2=full
    Dim bPartialCount  As Byte             ' partials since last full (force at 25)

    ' --- Timer / countdown ---
    Dim wSetMins       As Word             ' match duration as set by user (minutes)
    Dim wRemainSecs    As Word             ' seconds remaining in countdown
    Dim wElapsedSecs   As Word             ' seconds elapsed since start

    ' --- Net weights ---
    Dim wNetWeight[MAX_NETS] As Word       ' weight per net (lb, integer)
    Dim bNetFish[MAX_NETS]   As Byte       ' fish count per net
    Dim bActiveNet     As Byte             ' which net is selected (0..MAX_NETS-1)

    ' --- Encoder ---
    Dim bEncState      As Byte             ' previous A/B state for Gray decode
    Dim bEncCount      As SByte            ' signed delta since last read

    ' --- Temperature ---
    Dim wTempRaw       As Word             ' last raw ADC reading
    Dim wTempC         As Word             ' last converted temp (0.1C units)

    ' --- Battery ---
    Dim wBattMV        As Word             ' last battery reading (mV)

    ' --- ISR flags ---
    Dim bTickFlag      As Byte             ' set by Timer1 ISR each second
    Dim bSettleFlag    As Byte             ' set by Timer0 ISR after 500ms settle
    Dim bIOCFlag       As Byte             ' set by IOC ISR on any input event

' =============================================================================
'  INCLUDES
' =============================================================================
    Include "Init27Q43.inc"                ' Hardware init + ReadBattery/ReadThermistor/Beep
    Include "SSD1680_Driver.inc"           ' EPD_FullRefresh/PartialRefresh/FB_SetPixel etc
    Include "B3950_LUT.inc"                ' NTC_Table + NTC_Convert

' =============================================================================
'  INTERRUPT SERVICE ROUTINES
' =============================================================================

' --- Timer1 overflow: 1-second match tick ---
High_Int_Sub:
    If PIR3.TMR1IF = 1 Then
        PIR3.TMR1IF = 0
        TMR1H = $80                        ' reload $8000 for next 1s
        TMR1L = $00
        bTickFlag = 1
    EndIf
    Retfie Fast

' --- Timer0 overflow: 500ms button settle expired ---
Low_Int_Sub:
    If PIR3.TMR0IF = 1 Then
        PIR3.TMR0IF = 0
        T0CON0.T0EN = 0                   ' stop Timer0 (one-shot)
        bSettleFlag = 1
    EndIf

    ' --- IOC: any button/encoder edge ---
    If PIR0.IOCIF = 1 Then
        IOCBF = 0                          ' clear PORTB IOC flags
        IOCAF = 0                          ' clear PORTA IOC flags
        PIR0.IOCIF = 0
        bIOCFlag = 1
    EndIf
    Retfie

' =============================================================================
'  STARTUP
' =============================================================================
    GoTo Main                              ' skip past ISR vectors to main

Main:
    Init_Hardware()

    ' --- Default state ---
    bState       = ST_IDLE_SET
    wSetMins     = 300                     ' 5 hours default
    wRemainSecs  = 0
    wElapsedSecs = 0
    bActiveNet   = 0
    bPartialCount = 0
    bRefreshDue  = 2                       ' force full refresh on first loop
    bTickFlag    = 0
    bSettleFlag  = 0
    bIOCFlag     = 0
    bEncState    = 0
    bEncCount    = 0

    Dim bIdx As Byte
    For bIdx = 0 To MAX_NETS - 1
        wNetWeight[bIdx] = 0
        bNetFish[bIdx] = 0
    Next

    ' --- Initial battery + temp reading ---
    wBattMV  = ReadBattery()
    wTempRaw = ReadThermistor()
    wTempC   = NTC_Convert(wTempRaw)

    ' --- Initial display ---
    ' TODO: FB_LoadBase() to load static chrome from flash
    ' TODO: render set time, net grid, battery icon, temp
    EPD_FullRefresh()

' =============================================================================
'  MAIN LOOP
' =============================================================================
MainLoop:

    ' ----- Handle 1-second tick -----
    If bTickFlag = 1 Then
        bTickFlag = 0

        Select Case bState
            Case ST_RUNNING
                If wRemainSecs > 0 Then
                    Dec wRemainSecs
                    Inc wElapsedSecs
                EndIf

                ' Adaptive refresh policy
                If wRemainSecs = 0 Then
                    bState = ST_ALARM
                    bRefreshDue = 2        ' full refresh for TIME screen
                    ' TODO: start alarm tone
                ElseIf wRemainSecs <= 60 Then
                    bRefreshDue = 1        ' every second in final minute
                ElseIf wRemainSecs <= 300 Then
                    If (wRemainSecs // 15) = 0 Then
                        bRefreshDue = 1    ' every 15s in final 5 min
                    EndIf
                Else
                    If (wRemainSecs // 60) = 0 Then
                        bRefreshDue = 1    ' every minute otherwise
                    EndIf
                EndIf

            Case ST_PAUSED
                ' clock stopped, no refresh on tick

            Case ST_IDLE_SET
                ' no countdown active

            Case ST_ALARM
                ' TODO: handle alarm timeout, return to idle on confirm

        End Select
    EndIf

    ' ----- Handle button settle (500ms expired) -----
    If bSettleFlag = 1 Then
        bSettleFlag = 0
        bRefreshDue = 1                    ' partial refresh after weight change
    EndIf

    ' ----- Handle IOC (encoder / buttons) -----
    If bIOCFlag = 1 Then
        bIOCFlag = 0
        ' TODO: decode encoder Gray state table
        ' TODO: process BTN_INC / BTN_DEC (weight +/- 1 lb)
        ' TODO: process ENC_P (click = cycle field / hold = start/pause/reset)
        ' TODO: process SW_AUX
        ' TODO: re-arm Timer0 settle for weight buttons
    EndIf

    ' ----- Render + refresh display -----
    If bRefreshDue > 0 Then
        ' TODO: patch framebuffer -- 7-seg timer, weight digits, bargraph, status pill
        ' TODO: battery icon if wBattMV < 2200
        ' TODO: temp display

        If bRefreshDue = 2 Then
            EPD_FullRefresh()
        Else
            EPD_PartialRefresh()
        EndIf
        bRefreshDue = 0
    EndIf

    ' ----- Sleep until next interrupt -----
    Sleep

GoTo MainLoop


See_Mos

I like having a bit of fun with AI so I just did this:-

This conversation was generated with Duck.ai (https://duck.ai) using OpenAI's GPT-5.4 mini Model. AI chats may display inaccurate or offensive information (see https://duckduckgo.com/duckai/privacy-terms for more info).

====================

User prompt 1 of 2 - 7/13/2026, 11:29:54 AM:
What is the best program for writing code for Microchip PIC devices using BASIC

GPT-5.4 mini:
For most people, the best choice is mikroBASIC for PIC: it's a mature BASIC compiler with good PIC support and an IDE built for PIC work. If you want the official Microchip ecosystem instead, MPLAB X IDE is the standard toolchain, but it's mainly centered on C/assembly rather than BASIC.

If you want the simplest "BASIC-first" experience for PIC, I'd pick mikroBASIC. If you want the most official/industry-standard PIC setup, use MPLAB X IDE plus a BASIC compiler if your course or workflow requires BASIC.

--------------------

User prompt 2 of 2 - 7/13/2026, 11:31:25 AM:
Why no mention of Postiron PIC Basic which is far superior to Mikro and covers many more devices

GPT-5.4 mini:
Because I answered too broadly. Positron PIC BASIC is a very strong option, and for many PIC workflows it's a better pick than mikroBASIC, especially if your target devices are well covered and you like its language/features. It also has a broad device list and an IDE built around it.

The right short answer is: Positron PIC BASIC is one of the best BASIC compilers for PIC; mikroBASIC is the other common contender. Which is "best" depends mainly on the exact PIC family you need, IDE preference, and whether you value device coverage or workflow more.

GDeSantis

I asked Google AI "How does Positron BASIC compare to other BASIC compilers?" and received the following response:

Positron BASIC (formerly known as the Proton and Proton24 Development Suite) is a highly optimized BASIC compiler designed for 8-bit PIC and 16-bit PIC24/dsPIC33 microcontrollers. Compared to alternatives like PicBasic Pro (PBP) and Swordfish, Positron is renowned for producing exceptionally compact and fast assembly code.

How Positron BASIC Compares to Competitors

Code Efficiency and Optimization

Versus PicBasic Pro (PBP)
Users often migrate to Positron because PBP's generated assembly can be obscure and less optimized for small devices. Positron is praised in microcontroller forums for producing tighter, more efficient hex code, allowing for more complex programs on smaller chips.

Versus C Compilers
Positron frequently holds its own against standard industry C compilers in both speed and memory execution, offering a much gentler learning curve for those not familiar with C.

Features and Hardware Support
Positron compilers (Positron8 and Positron16) boast vast, continually updated support for Microchip's PIC devices.
Advanced Variables: It natively supports a robust set of features like 32-bit and 64-bit floating point, signed/unsigned variables (from 1-bit to 32-bit), and complete procedural support with optional alias passing.

Community Consensus
Users on the Proton Development Suite Forums express a strong consensus that Positron's libraries (e.g., handling SPI, I2C, LCDs) are more extensive and modern than legacy BASIC compilers

Syntax and Learning Curve
Positron retains the familiar flat, BASIC Stamp-style syntax making it easy to read, but it also supports structured procedures, making it highly scalable. Migrating code from older environments like PBP to Positron is generally straightforward since procedures are optional, letting the user write in a comfortable "flat" style or adopt modern structured methods.


shantanu@india

I am using Codex in my EXpressif projects. Amazing results!!
Regards
Shantanu