Как часто/когда C выполняет содержимое внутри операторов if/else?

Я работаю над встроенным (avr) проектом, и в основном я хочу распечатать несколько разных вещей в зависимости от того, как долго была нажата булавка. Я не могу понять, что происходит, когда значение проходит и удовлетворяет операторам if по пути (кнопка все еще нажата, поэтому счетчик увеличивается).

Настройка выглядит следующим образом:

если переполнение находится между 7-48 (кнопка нажата в течение 30-200 мс), распечатайте '.'
если переполнение больше 48 (кнопка нажата более 200 мс), распечатайте '-'
если переполнения больше 97 (кнопка не была нажата более 400 мс), распечатайте ' '

Мой текущий код выглядит следующим образом:

static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
if (type == 'e') { // edge captured
    if (TCCR1B & 0x40) { // rising edge
        if (overflows < 7) {
            // do nothing
        } else if (overflows < 49) {
            buffer[idx++] = '.';
            size++;
        } else {
            buffer[idx++] = '-';
            size++;
        }
    }
    overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
    overflows++;
    if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
        buffer[idx++] = ' ';
        size++;
    }
}

Я не уверен, что это правильно, так как может показаться, что всегда будет '.' перед '-', поскольку при увеличении значения переполнения оно удовлетворяет условию ‹49.

есть идеи?


person MS9T1    schedule 19.02.2016    source источник
comment
Вы делаете одно измерение, сохраняете его где-то, а затем выполняете логику с этим значением? Или вы переоцениваете каждый раз, когда спрашиваете if?   -  person e0k    schedule 19.02.2016
comment
По сути, когда я нажимаю кнопку, она обнаруживает край. Пока я удерживаю эту кнопку, она начнет считать. Это детектор азбуки Морзе, поэтому я не хочу печатать «.-» каждый раз, когда я удерживаю кнопку достаточно долго, чтобы получить «-».   -  person MS9T1    schedule 19.02.2016
comment
Кнопки тоже прыгают. Когда вы нажимаете ее, вы получаете более одного края, который вы обнаруживаете. Отскок быстрый, но микроконтроллер работает быстрее, поэтому он улавливает его несколько раз. Вам, вероятно, придется отключить кнопку, чтобы сделать то, что вы хотите сделать.   -  person e0k    schedule 19.02.2016
comment
Что ж, мой вопрос больше связан с тем, как C выполняет действия внутри операторов if. Например, поскольку я буду некоторое время удерживать кнопку и хочу, чтобы она выводила «-», когда прошло более 200 мс (49 переполнений), я не хочу, чтобы она также выводила «.». поскольку, очевидно, его нужно было удерживать между 30-200 мс (7-49 переполнений). Не обращайте внимания на переполнение, это больше связано с моей тактовой частотой и размером таймера.   -  person MS9T1    schedule 19.02.2016
comment
Не публикуйте псевдокод, публикуйте свой реальный код и предоставляйте информацию об ожидаемом и фактическом поведении.   -  person Randy the Dev    schedule 19.02.2016
comment
Вы выполняете проверки снова и снова в цикле? Или только один раз проверить? Порядок операций зависит от написанного кода.   -  person e0k    schedule 19.02.2016
comment
Хорошо, только что обновил вопрос с моим фактическим кодом и (надеюсь) более ясным пониманием проблемы.   -  person MS9T1    schedule 19.02.2016
comment
Вы должны делать как можно меньше внутри процедуры обслуживания прерывания. Например, просто установите флажок и уйдите. Вы можете опросить состояние флага, а затем ответить, если он установлен. Этот AVR использует ввод-вывод с отображением памяти. Каждый раз, когда вы читаете TCCR1B, вы делаете новое измерение.   -  person e0k    schedule 19.02.2016
comment
Как вы настроили этот isr()? Это вызвано для каждого ребра?   -  person e0k    schedule 19.02.2016
comment
Подключение переключателей к контактам, запускаемым прерыванием, является проблематичным и несколько сложным, пожалуйста, прочитайте и поймите >это.   -  person Lundin    schedule 19.02.2016
comment
Что происходит? Что вы хотите сделать? Вы не прояснили ни одну из этих вещей. Ответ на вопрос в вашем заголовке — это когда условие истинно, но это не то же самое, что и ваш основной текст.   -  person Clifford    schedule 19.02.2016
comment
Учитывая код и вашу неуверенность в том, как он работает, я могу только предположить, что на самом деле это не ваш код.   -  person Clifford    schedule 19.02.2016


Ответы (3)


если вы хотите подсчитать количество нажатий переключателя, вы можете использовать цикл while. Например,

    if(sw==0) //sw is switch connected with I/O pin
    {
      while(sw==0)
      {
       led=1; //LED is output
       delay(); // use delay function
       led=0;
       delay();
       count++;
       }
     }

с помощью цикла while вы можете избежать многократного нажатия переключателя. если вы включите и выключите один переключатель, счет будет увеличен на единицу.

person Arul    schedule 19.02.2016
comment
if(count‹7) { //сделать что-нибудь... } if((count›7)&&(count‹49)) передать('.'); if(count›=49) передать('-'); void transfer(unsigned char b)//эта функция предназначена для отображения на ЖК-дисплее символа { P1 = a;//port rs = 1; //rs=0 для команды и rs=1 для данных rw = 0; эн = 1; задерживать(); эн = 0; } - person Arul; 19.02.2016
comment
....а как насчет устранения дребезга....? - person LPs; 19.02.2016
comment
вручную можно сделать. переключатель соединен с контактом. когда вы нажмете переключатель и отпустите его, счетчик будет увеличен на единицу - person Arul; 19.02.2016

Я не уверен, что это правильно, поскольку может показаться, что всегда будет '.' перед '-', так как при увеличении значения переполнения оно удовлетворяет условию ‹49.

Но тесты выполняются только по переднему фронту - когда и type == 'e', и (TCCR1B & 0x40) != 0. Таким образом, количество overflow оценивается только тогда, когда кнопка отпущена, поэтому вы не увидите промежуточное значение . перед -.

Итак, чтобы ответить на ваш вопрос, условный оператор или блок выполняется, когда условие истинно. Здесь у вас есть вложенные условные операторы, поэтому все предыдущие условия должны быть истинными, чтобы внутреннее условие могло быть оценено.

person Clifford    schedule 19.02.2016

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

#define BUTTON_UNKNOWN  0
#define BUTTON_DOWN     1
#define BUTTON_UP       2

#define FALSE           0
#define TRUE            1

static inline unsigned char debounce( unsigned char current_state)
{
static unsigned char ret_value;
unsigned char state_changed = FALSE;
// Counter for number of equal states
static unsigned char count = 0;
// Keeps track of current (de-bounced) state
static unsigned char button_state = 0;
// Check if button is high or low for the moment
if (current_state != button_state) 
{
    // Button state is about to be changed, increase counter
    count++;
    if (count >= 3) 
        {
        // The button have not bounced for four checks, change state
        button_state = current_state;
        // If the button was pressed (not released), tell main so
        count = 0;
        state_changed = TRUE;
        }
} 
else 
{
state_changed = FALSE;
// Reset counter
count = 0;
}

//if butten press or release detected
if (state_changed == TRUE)
{
    //check for the current state of the button
    if (current_state != 0) 
        {
        ret_value = BUTTON_DOWN;
        }
    else
        {
        ret_value = BUTTON_UP;
        }
}

return ret_value;
}

int main(void)
{
//perform proper initialization of your pin

unsigned char button = BUTTON_UNKNOWN;    
unsigned char cycle_count  = 0;
unsigned char idx = 0;
unsigned char buffer[255];
unsigned char current_state;
unsigned char no_activity;
//unsigned char current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;

while(1)
{
//read the button state
current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
// Update button_state
button = debounce(current_state);
// Check if the button is pressed.
if (button == BUTTON_DOWN)
{
    //count cycles in which the button was pressed
    //one cycle is 10 ms - see delay below
    cycle_count++;
}
else
{
    //check if the button was pressed before
    if ((button != BUTTON_UNKNOWN) && (cycle_count != 0))
    {
        //if button was pressed for 200ms
        if (cycle_count <= 20)
        {
            buffer[idx] = '.';
            idx++;            
        }
        else
        {
            //if the button was pressed between 200 and 400 ms
            if ((cycle_count > 20) && (cycle_count <= 40))
            {
               buffer[idx] = '-';
               idx++;
            }
            //the button was pressed for more than 400ms, uncomment if you need it

            /*else
            {
               buffer[idx] = ' ';
               idx++;
            }*/

        }
        //reset counting mechanism
        cycle_count = 0;
        no_activity = 0; 
    }
    else
    {
        no_activity++;
        if (no_activity >= 40)
        {
            buffer[idx] = ' ';
            idx++;
            no_activity = 0;
        }
    }
}

// Delay for a while so we don’t check to button too often
_delay_ms(10);
}
}

Вы можете адаптировать этот код в соответствии с вашими потребностями: измените строку current_state = (~BUTTON_PIN & BUTTON_MASK) != 0; так, чтобы она считывала состояние вашего вывода, и измените объявление буфера в соответствии с вашими потребностями unsigned char buffer[255];

Обратите внимание, что из-за устранения дребезга измеренное время не точно равно 200 мс (это 200 мс + 2*debounce_time = 260 мс (время устранения дребезга составляет 3 цикла, каждый цикл равен 10 мс, см. задержку в конце), но вы можете компенсировать эти ошибки, уменьшение констант в сравнениях cycle_count в конце.

Надеюсь это поможет!

Если вы действительно придерживаетесь своего решения, то, чтобы избежать проблемы, с которой вы сталкиваетесь, это не оценивать значение переполнения непрерывно, не пытаться определить длину нажатия кнопки на лету, вместо этого попробуйте измерить длину нажатия и после этого оцените его и поместите символ в буфер. Вам нужно дождаться «кнопки освобождения», а затем оценить, сколько времени кнопка была нажата. Что-то вроде этого:

static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
unsiged char button_status;

if (type == 'e') { // edge captured
    if (TCCR1B & 0x40) { // rising edge
        //perform a debounce otherwise wont be good
        button_status = 1;

    }
    overflows = 0; // restart counting overflows at each edge
} else { // overflow occured  
    overflows++;
     //if button was pressed and its now released evaluate result
    if (!(TCCR1B & 0x40) && (button_status == 1))
    {
        if (overflows < 7) {
            // do nothing
        } else if (overflows < 49) {
            buffer[idx++] = '.';
            size++;
        } else {
            buffer[idx++] = '-';
            size++;
        }
        button_status = 0;
    }
    if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
        buffer[idx++] = ' ';
        size++;
    }
}
person TheElderWisedom    schedule 19.02.2016