PIC16F1937 и UART: продолжайте светиться во время приема - PullRequest
1 голос
/ 06 мая 2019

Я пытаюсь держать светодиод включенным, пока ПИК получает символ (пока нажата кнопка), светодиод по умолчанию выключен, но я не могу найти решение.

Я 3 месяца изучаю кодирование на микроконтроллерах (в частности, PIC) с помощью MPLABX IDE и начинаю понимать связь UART.Сначала я пытался включить / выключить светодиод при получении символа, все прошло довольно хорошо и работало, но сейчас я пытаюсь поддерживать светодиод активным, пока нажата кнопка, но не могу решить эту проблему.У меня есть код в функции прерывания, такой как:

//#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
}

Использование приведенного выше кода делает так, чтобы светодиод включался / выключался очень быстро, пока я продолжал нажимать кнопку, и это не совсем то, что я хотел.
Я надеюсь, что кто-нибудь поможет мне понять, что мне нужно делать.Спасибо!

Ответы [ 3 ]

1 голос
/ 06 мая 2019

Светодиод гаснет быстро после получения любого символа.Флаг RCIF будет установлен только при получении данных UART.Таким образом, чтобы выключить светодиод, вы должны запустить таймер определенного миллисекунды и, если ваш прием не завершен, продолжать перезапуск таймера.


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;
        }
    }
}```
1 голос
/ 06 мая 2019

Светодиод гаснет быстро, потому что вы выключаете его сразу после включения:

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, если не хотите, чтобы она выполняласьEverytime.

Может быть так:

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.

0 голосов
/ 07 мая 2019

Я предлагаю вам создать конечный автомат для этого в app.c.

Определите некоторые состояния с помощью enum и struct для хранения состояния и помещения их в 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, которое включит светодиод, а затем перейдет к 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

    }

}

Теперь вам просто нужно убедиться, что вы вызываете uartFSM() где-то в APP_Tasks, чтобы конечный автомат обслуживался.

...