Why does this state machine not maintain its state?

不问归期 提交于 2019-12-11 03:54:12

问题


Hey there StackOverflow!

In the following code I have a simple state machine that changes the operation of some external lighting device (as the comments imply). The state is changed via the pressing of the button connected to GP1. The circuit connected to GP1 is a comparator debouncing circuit that compares VDD to 0.6VDD (I've also tried an RC/diode/schmitt trigger circuit), which then forces the signal LO. On a scope, we see a clean square wave when the button is actuated rapidly.

The current (and undesirable) behavior of the PIC10F200 is as follows:

  1. Switch is pressed (state = 0)
  2. State machine variable increments (state = 1)
  3. Lighting goes to case 1, and turns on
  4. Lighting remains on for at least a second
  5. Lighting turns off
  6. System remains in this state until button is actuated again or powered off

The question is: Why does it behave like this? And how if possible, do I fix it such that a single press of the button equates to a single state increment, which the PIC then maintains for as long as the system is powered and the button is not actuated again?

#define SYS_FREQ        8000000L
#define FCY             SYS_FREQ/4
#define _XTAL_FREQ      4000000

/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/


/******************************************************************************/
/* Main Program                                                               */
/******************************************************************************/

__CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC);

void main(void)
{
    TRIS = 0b111110;

    unsigned char state = 0;

    while(1)
    {
        switch (state)
        {
            case 0: // IDLE/OFF
                if (GPIObits.GP0) GPIObits.GP0 = 0;
                break;
            case 1: // ON
                if (!GPIObits.GP0) GPIObits.GP0 = 1;
                break;
            case 2: // BLINK (slow)
                GPIObits.GP0 = !GPIObits.GP0;
                __delay_ms(100);
                break;
            case 3: // BLINK (fast)
                GPIObits.GP0 = !GPIObits.GP0;
                __delay_ms(50);
                break;
            case 4: // BEAT DETECT
                GPIObits.GP0 = GPIObits.GP2;
                break;
            default:
                state = 0;
                break;
        }

        if (!GPIObits.GP1)
        {
            __delay_ms(250);
            state++;
        }
    }
}

UPDATE: Since there seems to be a little confusion as to what I am trying to accomplish with this code/system, lets provide the full context. This microcontroller, the PIC10F200 is part of an overall board design for an electroluminescent (EL) wire driver. The miconcontroller simply controls whether or not the driver circuit is enabled by connecting GP0 to the EN port of the driver IC. The system has four modes of operation, the wire is constantly on, the wire is blinking, the wire is blinking faster, and the wire blinks whenever a low-frequency beat is detected (another circuit in the system). The transition from these modes of operation is governed by a pushbutton (on momentarily) switch to be mounted on the PCB. This necessitates that state in the code above remains stable between button actuations. It currently does not do this and behaves as described in the original part of this post. As the question title states, why isn't state stable currently, and how do I make it so?

UPDATE (2014-03-08): Solution

The following settings need to be set assuming GP0 is the output, GP2 is your T0CKI and you have a switch that drives the signal to LO when actuated.

TRIS = 0b111110;
OPTION = 0b11101111;

Whether or not bits 0-3 for OPTION really matter is a judgement call and whether or not you choose to use the WDT module.

Additionally, the implementation for the button release detection is a simple counter mechanism that resets upon GP2 being LO at any point during the count.

if (TMR0 > 0)
{
    while (count < 20)
    {
        if (!GPIObits.GP2) count = 0;
        __delay_ms(10);
        count++;
    }
    TMR0 = 0;
    state++;
}

回答1:


You have a hardware/software design problem!

  1. When your program is in delay loop than your key button is not checked!
  2. You are checking only on key press event, but you must also on key relase.

My purpose is that you can use GP2 (T0CKI) pin instead GP1 for key buttom. This pin has schmitt trigger input if is used as counter TMR0 input. After that configure your MCPU TMR0 as counter with external clock on GP2 (T0CKI) pin. You must also set the T0SE bit to configure counter that will increment on high-to-low transition on the T0CKI pin. In program after any loop check the TMR0 content if biger than 0 the key was pressed. Wait some ms and check if key was relased if relased than increase the state variable and clear TMR0 content.




回答2:


move your

if (!GPIObits.GP1){
    if(isPressed == false){
        //__delay_ms(250); //you dont need the delay
        state++;
        if(state == 5){state = 0;}
        isPressed = true;
    }
}
else{isPressed = false;}

before the switch statement. char isPressed = false; before the while loop

valter




回答3:


__delay_ms(250); <-- too small delay

While you are pressing the button slowly, the loop may rotate several times. Try increasing it to 1000ms.

Update

You should run the PIC with WDT (watch dog timer) disabled, otherwise it will reset the pic in few seconds. That is similar to your observation. You can blink a LED at the beginning of main function to check if this happen or you can initialization unsigned char state = 1; and see the behavior then.

Try this __CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC & WDT_OFF);



来源:https://stackoverflow.com/questions/22188194/why-does-this-state-machine-not-maintain-its-state

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!