PIC16F1937 和 UART:接收时保持 LED 亮起

PIC16F1937 and UART : keep led ON while receiving

我试图在 PIC 接收字符时(按下按钮时)保持 LED 亮起,默认情况下 LED 处于关闭状态,但我似乎找不到解决方案。

我用了 3 个月的时间学习使用微控制器(特别是 PIC)和 MPLABX IDE 编码,并开始了解 UART 通信。起初我尝试在收到字符时打开 LED ON/OFF,它运行良好并且工作正常,但现在我试图在按下按钮时保持 LED 处于活动状态但无法真正克服这个问题问题。我的代码在这样的中断函数中:

//#define LED RB5

void __interrupt () ISR (void)
{   
    if(RCIF) // data is received
    {
        data = RCREG; // get the value
        if (data == '1') // if value received is '1'
            LED = 1; //turn ON led
        RCIF = 0;
    }
    LED = 0; // turn OFF led
}

使用上面的代码,当我一直按下按钮时,led 会 on/off 转得非常快,这并不是我想要的。
我希望有人能帮助我理解我的意思需要做。谢谢!

LED 熄灭很快,因为您在打开后立即关闭:

void __interrupt () ISR (void)
{   
    if(RCIF) // data is received
    {
        data = RCREG; // get the value
        if (data == '1') // if value received is '1'
            LED = 1; //turn ON led
        RCIF = 0;
    }
    LED = 0; // turn OFF led   <<=== This is executed unconditionally.
}

如果你不想每次都执行它,你可以将 LED = 0; 放在 else 分支中。

可能是这样的:

void __interrupt () ISR (void)
{   
    if(RCIF) // data is received
    {
        data = RCREG; // get the value
        if (data == '1') // if value received is '1'
            LED = 1; //turn ON led
        else
            LED = 0; // turn OFF led
        RCIF = 0;
    }
}

根据您的逻辑,else 可能会放在外部 if 块的末尾之后。

接收到任何字符后,LED 会迅速熄灭。 RCIF 标志只有在接收到 UART 数据时才会设置。因此,要关闭 LED,您应该启动一个特定毫秒的计时器,除非您的接收完成,否则请继续重新启动计时器。


void __interrupt () ISR (void)
{   
    if(RCIF) // data is received
    {
        data = RCREG; // get the value
        if (data == '1') // if value received is '1'
            LED = 1; //turn ON led
        RCIF = 0;
        start_timer_interrupt(x_ms);  //set x_ms optimum timing so as to LED ON is visable with UART Rx
        flag_rx_timer=1;
    }

    if(TIMER_OVERFLOW) //TIMER_OVERFLOW is an example keyword used here. Pleas add exact timer overflow flag
    {
        if(flag_rx_timer)  //check if timer overflow is because of timer started during UART Rx
        {
             LED = 0;
             flag_rx_timer=0;
        }
    }
}```

我建议您在 app.c 中为此创建一个状态机。

enumstruct 定义一些状态来保存状态并将它们放在 app.h 中,在您希望使用它的文件中包含 app.h模块(例如您的 system_interrupt.c 文件)。

例如你可以这样做:

typedef enum{
    IDLE,
    START_RECEIVING,
    STILL_RECEIVING,
}uart_state_t;

typedef struct{
    uart_state_t current_state;
}uart_module_t

volatile uart_module_t uart_module = {0}; // initial state = IDLE, needs to be volatile because it will be updated via interrupt

然后创建一个函数来为您的状态机提供服务。这将处理它当前所处的状态并根据需要转换到其他状态。例如,状态机以 IDLE 状态开始,但是一旦您的中断被触发并且 RCIF 位被设置,那么您将转换到 START_RECEIVING 状态,这将打开 LED然后转换到 STILL_RECEIVING 状态,它将轮询 RCIF 位直到被清除。那看起来像这样:

void uartFSM(void){

    switch(uart_module.current_state){

        case IDLE:
        {

            break;

        }

        case START_RECEIVING:
        {

            LED = 1; // Turn LED on
            uart_module.current_state = STILL_RECEIVING; // state update

            break;

        }
        case STILL_RECEIVING:
        {

            if(!RCIF){

                // done receiving
                LED = 0; // Turn LED off
                uart_module.current_state = IDLE; // state update

            }

            break;

        }

        default:
        {
            // whoops
            break;
        }

    }

}

现在您的中断将如下所示:

void __interrupt () ISR (void)
{   
    if(RCIF) // data is received
    {

        data = RCREG; // get the value

        // if value received is '1'
        if (data == '1') uart_module.current_state = START_RECEIVING; // state update

    }

}

现在您只需确保在 APP_Tasks 中的某个地方调用 uartFSM() 以便状态机得到服务。