为什么这个状态机不能保持其状态?

时间:2014-03-05 03:56:20

标签: c microcontroller pic microchip xc8

嘿那里有StackOverflow!

在下面的代码中,我有一个简单的状态机,可以改变某些外部照明设备的操作(正如评论所暗示的那样)。通过按下连接到GP1的按钮更改状态。连接到GP1的电路是比较器去抖动电路,它将VDD与0.6VDD进行比较(我还尝试过RC /二极管/施密特触发器电路),然后强制信号LO。在示波器上,当按钮快速启动时,我们会看到一个干净的方波。

PIC10F200 当前(及不良行为如下:

  1. 按下开关(状态= 0)
  2. 状态机变量增量(state = 1)
  3. 照明转到案例1,然后打开
  4. 照明至少持续一秒
  5. 照明关闭
  6. 系统保持此状态,直到按钮再次启动或 关闭电源
  7. 问题是:为什么它会像这样?如果可能的话,如何修复它,只需按一下按钮就等于单个状态增量,PIC然后维护只要系统通电并且按钮没有再次启动?

    #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++;
            }
        }
    }
    

    更新:由于对于我要使用此代码/系统尝试完成的内容似乎有点混淆,让我们提供完整的上下文。该微控制器 PIC10F200 是电致发光(EL)线驱动器整体电路板设计的一部分。通过将GP0连接到驱动器IC的EN端口,微控制器简单地控制驱动器电路是否启用系统有四种操作模式,导线持续亮,导线闪烁,导线闪烁得更快,每当检测到低频节拍时导线闪烁(系统中的另一个电路) )。 从这些操作模式的转换由一个按钮(暂时)开关控制,安装在PCB上。这就要求上面代码中的state在按钮启动之间保持稳定。它目前没有这样做,并且行为与本文的原始部分中描述的相同。正如问题标题所述,为什么state目前不稳定,我该怎么做呢?

    更新(2014-03-08):解决方案

    假设GP0是输出,需要设置以下设置,GP2是你的T0CKI,你有一个开关,在启动时将信号驱动到LO。

    TRIS = 0b111110;
    OPTION = 0b11101111;
    

    OPTION的0-3位是否真正重要是判断调用以及是否选择使用WDT模块。

    此外,按钮释放检测的实现是一种简单的计数器机制,在计数期间的任何时刻将GP2重置为LO。

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

3 个答案:

答案 0 :(得分:2)

您遇到硬件/软件设计问题!

  1. 当您的程序处于延迟循环时,而不是您的按键按钮 检查!
  2. 您只检查按键事件,但您还必须按键 RELASE。
  3. 我的目的是你可以使用GP2(T0CKI)引脚而不是GP1作为密钥。如果用作计数器TMR0输入,该引脚具有施密特触发器输入。之后,将MCPU TMR0配置为GP2(T0CKI)引脚上的外部时钟计数器。您还必须将T0SE位置1以配置计数器,该计数器将在T0CKI引脚上从高电平到低电平的转换时递增。 在任何循环之后的程序中,如果按下键大于0,则检查TMR0内容。 等待一些ms并检查密钥是否在重新启动时重新启动,而不是增加state变量并清除TMR0内容。

答案 1 :(得分:0)

__delay_ms(250); <-- too small delay

当您慢慢按下按钮时,循环可能会旋转几次。尝试将其增加到1000毫秒。

<强>更新

您应该禁用WDT(看门狗定时器)运行PIC,否则它将在几秒钟内重置PIC。这与你的观察相似。您可以在主函数开头闪烁LED以检查是否发生这种情况,或者您可以初始化unsigned char state = 1;然后查看行为。

试试这个__CONFIG(MCLRE_ON & CP_OFF & OSC_IntRC & WDT_OFF);

答案 2 :(得分:0)

移动你的

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;}

switch语句之前。 char isPressed = false;循环之前的while

瓦尔特