Menu

Pin condition check to change state in a State Machine

G. C.
2026-08-02
4 days ago
  • G. C.

    G. C. - 2026-08-02

    Hi there,

    I am preparing a little program for a new project in wich I use a simple program architecture with a State Machine.

    Checking the pressure of a button to ground on a pin, doing it in the main Do-Loop before entering the Select Case block of the State Machine, I can cycle trough 1 to 5 states without problem..

    But if I want to check the pin condition WHITIN one of the states, in order to move from one state to another, the button pressure gets ignored..

    I made several tests, but I am still stuck because of this at the very beginning of the development.

    Any suggestion? Thanks!

     
  • Anobium

    Anobium - 6 days ago

    I think you have an error in the display of the state.

    Try

    Do   
    
        ' 1. Handle Button Inputs & State Transitions independently 
        Select Case stato
    
            case 1  'Attesa input Utente
                Riga1 = " Press Start to "
                Riga2 = " make a Measure "
    
                if Start_Btn = 0 then       
                    wait 100 mS 'debounce
                    if Start_Btn = 0 then        
                        Wait Until Start_Btn = 1
                        stato = 2
                    end If               
                end if
    
            case 2      
                Riga1 = "This is State 2"
                Riga2 = "press to go 3rd!"
    
                ' Add your button check here to advance to state 3!
                if Start_Btn = 0 then       
                    wait 100 mS
                    if Start_Btn = 0 then        
                        Wait Until Start_Btn = 1
                        stato = 3
                    end If               
                end if
    
            case 3  
                Riga1 = "This is State 3"
                Riga2 = "press to go 4th!"
    
                if Start_Btn = 0 then       
                    wait 100 mS
                    if Start_Btn = 0 then        
                        Wait Until Start_Btn = 1
                        stato = 4
                    end If               
                end if
    
            case 4
                Riga1 = "This is State 4"
                Riga2 = "press to 1st!" // or 5
    
                if Start_Btn = 0 then       
                    wait 100 mS
                    if Start_Btn = 0 then        
                        Wait Until Start_Btn = 1
                        stato = 1 ' Cycle back or go to 5
                    end If               
                end if
    
            case 5   
                Riga1 = "Error ! Shutdown"
                Riga2 = "System & Restart"
    
                StartTimer 1    
                if Timer_Steps = 15 Then 
                    Led_diagnostico = Not Led_diagnostico    
                    Timer_Steps = 0                         
                    ClearTimer 1
                end If
    
        end select
    
    
        ' 2. Display refresh managed strictly on state change
        if stato_precedente <> stato then
            cls
            Print Riga1
            Locate 1,0
            Print Riga2
            stato_precedente = stato    
        End if
    
        ' 3. Diagnostic LED cleanup
        if stato <> 5 then Led_diagnostico = 0
    
    Loop
    
     
  • G. C.

    G. C. - 6 days ago

    Thanks for your answer, Evan..

    However, I can't see the difference in respect to my code. It does'nt matter (for the moment) to add more button checks into the other states. The cycling was made only to begin the development, during the final version states may change on different criteria..

    The problem is that this block here is completely ignored:

    (whitin State=1)

    if Start_Btn = 0 then
    wait 100 mS 'debounce
    if Start_Btn = 0 then
    Wait Until Start_Btn = 1
    stato = 2
    end If
    end if

    I found an error of mine in not disabling the analog inputs on port A that I tought could be the problem, so I changed my previous line (acting only on B port) as follows:
    from:
    ADCON1 = 0x0F
    to:
    ANSEL = 0
    ANSELH = 0 ' should disable analog on both portA & portB

    Hoping this was the issue, but the problem is the same. Test on button made outside the Select Case block works, inside one of the Case x does not..

    Can't really thing of anything else happening.. ?!?
    Should the "Case Else" statement addition mandatory to have the Select Case working?

    updated file attached for reference

     
  • G. C.

    G. C. - 5 days ago

    Might it be possible that multiple if/then blocks nested whitin a Do-loop that contains a Select Case etc.. creates some reentrance prolems with this small uCtr?

     
  • Anobium

    Anobium - 5 days ago

    The ports are disabled automatically. so that is is not the issue.

    This is logic code not the state of the port. I have refactored so the logic makes sense to me.

    It works here.

    Evan

    ' =====================================================================
    ' CONFIGURAZIONE DEL CHIP E DELLE PERIFERICHE
    ' =====================================================================
    #Chip 16F886, 8       ' Imposta il microcontrollore a 8 MHz
    #config FOSC = HS       ' utilizza il quarzo esterno
    
    ' =====================================================================
    ' CONFIGURAZIONE DEL DISPLAY LCD (Modalit� 4-bit)
    ' =====================================================================
    #Define LCD_IO 4
                                        'linee valide per Protoboard, cambiare in
    #Define LCD_Enable PORTA.0          '#Define LCD_Enable PORTA.2   nel PCB finale
    #Define LCD_RW PORTA.1  
    #Define LCD_RS PORTA.2              '#Define LCD_RS PORTA.0   nel PCB finale
    
    #Define LCD_DB4 PORTB.4
    #Define LCD_DB5 PORTB.5
    #Define LCD_DB6 PORTB.6
    #Define LCD_DB7 PORTB.7
    
    
    ' =====================================================================
    ' CONFIGURAZIONE Altre Costanti
    ' =====================================================================
    #Define On = 1              'costanti per chiarire i valori assegnati ai flag, Pin I/O e variabili
    #Define Off = 0
    
    #Define Start_Btn PORTA.4           'Pulsante Utente per avviare le misure
    #Define Led_diagnostico PORTC.3     'Uscita led lampeggiante per Diagnostica Programma
    
    
    ' =====================================================================
    ' DICHIARAZIONE DELLE VARIABILI
    ' =====================================================================
    
    Dim stato as Byte               'identificatore dello stato macchina
    Dim stato_precedente as Byte    'per decidere se effettuare refresh display senza sfarfallio 
    Dim Timer_Steps as Byte         'numero di overflows del Timer1
    Dim Riga1 as string (16)        'contiene buffer 1a riga display
    Dim Riga2 as string (16)        'contiene buffer 2a riga display
    Dim debug = 1
    
    ' =====================================================================
    ' CONFIGURAZIONE HARDWARE
    ' =====================================================================
    Dir PORTB.0 In              ' RB0 (INT0) come ingresso su cui misurare l'impulso
    ADCON1 = 0x0F               ' Disabilita i convertitori A/D su PORTB
    
    Dir PORTC.3 out             ' uscita per Led diagnostico
    Dir PortA.4 in              ' pulsante Utente
    
    
    ' Configura il Timer1 (Incremento ogni 1/2 microsecondo)
    InitTimer1 Osc, PS1_1
    StopTimer 1
    ClearTimer 1
    
    
    ' =====================================================================
    ' CONFIGURAZIONE INTERRUPT
    ' =====================================================================
    
    'gestione interrupt per overflow Timer1
    On interrupt Timer1Overflow call Incrementa_Timer_Steps
    
    
    Print "Started"
    
    ' =====================================================================
    ' Avvio Programma, eseguito solo all'accensione
    ' =====================================================================
    
    'inizializza stati
    stato = 1
    stato_precedente = 0
    
    ' =====================================================================
    ' CICLO PRINCIPALE della macchina a stati
    ' =====================================================================
    
    Do   
    
     '***** This commented block down here works when a pushbutton is pressed to ground on a 10K Ohm pull-upped PORTA.4
     ' and cycles to the various states without problems
    
    /*
        'se premo il pulsante passa allo stato successivo
                    if Start_Btn = 0 then               
                        wait 100 mS 'debounce
    
                        if Start_Btn = 0 then         
                            'Attesa rilascio pulsante per evitare passaggi di stato multipli
                            Wait Until Start_Btn = 1
                            stato ++
                        end If
    
                        if stato= 6 then stato = 1    
    
                    end if
    
    */
    
            Locate 2,0
            Print stato
            Locate 3,0
            Print leftpad(Str(debug), 3, " ")
            debug++
    
        Select Case   Stato  
    
            case 1  'Attesa input Utente per avviare una Misura    
    
                    Riga1 = " Press Start to "
                    Riga2 = " make a Measure "
    
                    '************ The same condition checked here whitin one state gets ignored!
                    '*** Hardware is ok, using the condition on the above mentioned block
                    '*** outside the states, everything goeas as expected.. Why?? 
                    ShowLCD
                    waitforbtn
                    stato = 2
    
            case 2      
    
                    Riga1 = "This is State 2"
                    Riga2 = "press to go 3rd!"
                    stato_precedente = 0
                    ShowLCD
                    waitforbtn
                    stato = 3
    
    
                    'later on more code
    
            case 3  'in questo stato si determina la durata del tempo in microsecondi
    
                    Riga1 = "This is State 3"
                    Riga2 = "press to go 4th!"
                    stato_precedente = 0
                    ShowLCD
                    waitforbtn
                    stato = 4
    
    
                    'later on more code
    
            case 4
    
                    Riga1 = "This is State 4"
                    Riga2 = "press to 5th!"
                    stato_precedente = 0
                    ShowLCD
                    waitforbtn
                    stato = 5
    
    
                    'later on more code
    
    
            case 5   'solo lampeggio Led su porta C3 , ad uso diagnostico programma
    
                    'segnala errore e fa lampeggiare Led
                    Riga1 = "Error ! Shutdown"
                    Riga2 = "System & Restart"
                    stato_precedente = 0
                    ShowLCD
                    waitforbtn
    
    
    
                    StartTimer 1    'avvia il timer. Se gi� attivo, non viene resettato  il conteggio
    
                    if Timer_Steps = 15 Then 
    
                    Led_diagnostico= Not Led_diagnostico    'inverto polarit�
                    Timer_Steps = 0                         'riazzero timer
                    ClearTimer 1
    
                    'se ci sono stati 15 Overflows del Timer1, il
                    'led commuta ogni 0,49152 secondi - circa 2.032 Hz
    
                    end If
    
    
        end select
    
    
    
    
        'Per evitare che resti acceso il led blinker se non necessario
        if stato <> 5 then Led_diagnostico = 0
    
    Loop 
    
    Sub ShowLCD
        'gestione aggiornamento display
        if stato_precedente <> stato then
    
            cls
            Print Riga1
            Locate 1,0
            Print Riga2
            stato_precedente = stato    'necessario per evitare 'flickering' del dispaly
            Wait 100 ms
    
        End if
    End Sub
    
    
    ' =====================================================================
    ' Gestione Interrupt da Timer1 Overflow
    ' =====================================================================
    Sub Incrementa_Timer_Steps              
    
        Timer_Steps++ ' Timer_Steps +1
    
    End Sub
    
    Sub WaitforBtn
                    'se premo il pulsante passa allo stato successivo
                    'di gestione interrupt impulso  
                    if Start_Btn = 0 then               
                        wait 100 mS 'debounce
    
                        if Start_Btn = 0 then         
                            'Attesa rilascio pulsante per evitare passaggi di stato multipli
                            Wait Until Start_Btn = 1
                        end If                  
                    end if
    End Sub
    
     
  • G. C.

    G. C. - 5 days ago

    Thanks for yr answer.. I made additional tests.
    Your code for some reasons gives me errors, starting as soon as the row "Dim debug = 1".. And others..
    I reduced my code to the bare minum of two states, and in this case it works( see test1.gcb attached). But as soon as more "case is" block get added, I find troubles.
    Therefore I decided to abandon the Select Case approach e moved to a series of "if state is.." and my code works fine.
    Finally, I improved the display refresh method and also the pushbutton detection, making it a function callable from any state - and it works ok. See test2.gcb).
    I am not sure, but perhaps there is something stange in the Select Case -Case is structure.

    Thanks for yr help given, I appreciated it.

     
    • Anobium

      Anobium - 5 days ago

      There was/is nothing wrong with Case. :-) This is logic issue.

      You have a method that works. And, this is a good result for you.

       
  • Anobium

    Anobium - 5 days ago

    Good news. All working.

    I am using the new compiler and you can now assign a value to a variable when you DIMension it.

     

    Last edit: Anobium 5 days ago
  • G. C.

    G. C. - 4 days ago

    I apologize if I cast a doubt on the Select Case correct working..
    I persisted a while with some tests and found my error being in the need to prepare the new text and display refresh flag at the moment of leaving the present state and moving to the following one..
    Now the sequence is correct, and the flow and readability of the program been improved with Select Case, a subroutine for LCD refresh and a Function for the button pressed test. Attached a working version of this prime stage. Sorry having bothered.

    Answering yr last post:
    So, there is an updated version of the compiler coming, great news. Is there any thinking about a debugger (even a limited one) that might permit to pause the program and look at the variables/registers etc on fly? That would makemuch speedier the development with GC Basic.
    Thanks for the great work, and regards.

     
    • Anobium

      Anobium - 4 days ago

      No problem with CASE. I am just grumpy at the moment. :-)

      And, no problem with you asking. Sometimes just sharing helps. :-)

      The new code looks good. :-)


      There is a new version on the toolchain and compiler. We are close to a release.

      There is a new debugger. See the picture. Yes, your code in the GCODE Debuuger!

      Soon!

      Evan

       

Log in to post a comment.