Как создать расширенный счетчик в C? - PullRequest
1 голос
/ 12 декабря 2011

У меня есть бесконечный цикл for, который содержит функцию для непрерывного получения показаний от LDR.Код выглядит примерно так:

.
light_1=sample(1);
.
.
for(::){
 light_2=sample(2);
 if((light_2 > (light_1))
 alarm=1;
 delay(1); // wait for 1 second
.
.
.
}etc

light_2 - это источник света, который отбирается сейчас, и по сравнению с первым отобранным источником света light_1.

Я хочу создать счетчик, которыйесли light_2 больше, чем light_1 в 3 раза, прервите цикл.Но не только это, свет будет мигать 3 раза с интервалом в 1 секунду.Я хочу, чтобы петля разорвалась ТОЛЬКО, если свет мигал 3 раза менее чем за 4 секунды.

Если это не имеет смысла, пожалуйста, скажите мне, чтобы я мог объяснить это лучше.



РЕДАКТИРОВАТЬ 3

Я хочу, чтобы он продолжал выполнять нормальное время выборки и прерывал цикл только при получении 3 экземпляров показаний.Однако я все еще чувствую, что должен использовать таймер?Пожалуйста, помогите.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Я ответил одному из ответивших здесь, и, возможно, другие могут извлечь выгоду из этого дополнительного объяснения:

Есть 2 этапа:

  1. Стадия 1: обнаружение света по одному экземпляру за раз.(получил код для работы с ним)
  2. Этап 2: Обнаружение света (3 последовательных вспышки) для выполнения другой функции.

Я должен избегать использования стольких задержек для получения этапа2, чтобы работать, потому что это повлияет на скорость чтения и скорость чтения на этапе 1.

Пожалуйста, дайте мне знать, если вам нужно больше объяснений!

Ответы [ 8 ]

3 голосов
/ 12 декабря 2011

Это очень простой пример, иллюстрирующий использование SIGALRM для сохранения времени, независимого от вашей функции sample (), это в том случае, если sample () требуется некоторое время для завершения, вы всегда можете сделать сейчас = time (NULL) непосредственно перед сон / задержка

#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <unistd.h>

time_t now;
void alarm_handler(int sig);
struct flash {
    time_t first_stamp;
    int count;
};
int main(int ac, char *av[]) {
    signal(SIGALRM, alarm_handler);
    now = time(NULL);
    struct flash f = {0,0};
    int light = 0;
    alarm(1); 
    for (;;) {
//      light = sample.. 
        if (light) {
            if (f.count) {
                if (f.count > 3 && (now - f.first_stamp) > 4) {
//                  do_whatever_function or break;
                    f.count = 0;
                    f.first_stamp = 0;
                } else {
                    f.count++;
                }
            } else {
                f.first_stamp = now;
                f.count = 1;
            }
        }
        sleep(1);
    }
    return 0;
}
void alarm_handler(int sig) {
    now = time(NULL);
    alarm(1);
}

редактировать: на самом деле теперь, когда я прочитал это время () небезопасно, дай мне секунду, чтобы изменить код

второе редактирование: http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04 на самом деле это сигнал безопасно :)

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

3 голосов
/ 12 декабря 2011

Используйте некоторую структуру для группировки различных параметров.Обычно это называется «состояние».

struct state {
     int light_2_greater_than_1;
     int other_things;
};

Затем обновите этот объект и проверьте его элементы.

1 голос
/ 22 декабря 2011

Я предполагаю, что вы хотите сделать следующее: обнаружить, что индикатор мигал 3 раза в течение последних 4 секунд. Под «вспышкой» я понимаю, что вы имеете в виду, что свет был выключен, а затем он включился (Конечно, это может быть то, что под «вспышкой» вы подразумеваете, что свет должен включаться и выключаться, и это потребует более сложного решения, но, поскольку вы не дали нам определение того, что вы подразумеваете под вспышкой, я буду перейти с более простой версией.)

Прежде всего, проверка того, является ли ваше световое показание больше или меньше вашего светового показания в какой-то момент в прошлом, не скажет вам, был ли свет включен или выключен. Вам необходимо установить нижнее пороговое значение, ниже которого вы будете считать, что индикатор выключен, и высокое пороговое значение, выше которого вы будете считать, что индикатор включен. Когда показания ниже нижнего порога, вы игнорируете его. Когда показания изменяются между двумя порогами, вы также игнорируете их. И когда показания изменяются выше верхнего порога, вы догадались, опять же, вы игнорируете это. Вы заботитесь только о следующих двух случаях:

  1. Лампа была выключена, и предыдущее значение было ниже верхнего порога, а новое значение выше верхнего порога; это означает, что лампа теперь включена.

  2. Лампа была включена, и предыдущие показания были выше нижнего порога, а новые показания были ниже нижнего порога; это означает, что лампа выключена.

Если вы этого не сделаете, вы получите множество ложных срабатываний, поскольку показания вашего LDR будут меняться в зависимости от того, кто ходит, надев ярко отражающий белый лабораторный халат или просто из-за случайного шума.

И так как мы взяли вспышку, чтобы обозначить переход от «выключено» к «включено», вам на самом деле нужно заботиться только о первом случае выше. (В противном случае вам необходимо принять во внимание оба случая.)

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

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

1 голос
/ 22 декабря 2011

Проблема всего в 10 раз больше, чем вы ожидаете.Если вы хотите решить это самостоятельно, прежде всего, оставьте клавиатуру в покое и попытайтесь разработать материал.

По сути, у вас есть только одна информация о лампе: включена или выключена.Этого недостаточно для таких сложных операций, как проверка количества вспышек за указанный промежуток времени.Вы должны создать производные .

Прежде всего, вам нужно установить какой-нибудь счетчик или метку времени, которая используется для вычисления временных интервалов, таких как прошедшее время, расстояние между двумя событиями и так далее.Это может быть метка времени (предоставляемая операционной системой или языком, который вы используете), или если ваша программа представляет собой бесконечный цикл, вы можете поместить в нее sleep () и counter ++ и использовать их для измерения времени (ОК,он менее точен, потому что он не учитывается во время выполнения программы, но это не имеет значения в этом случае).

Ваши производные переменные будут выглядеть примерно так:

  • изменение света;параметры: путь (вверх / вниз), отметка времени
  • мигание: серия событий, в которых первый вверх, второй вниз, параметры: начало, конец и (рассчитывается по этим :) длительности.

Вы должны будете обнаружить и сохранить эти события, как минимум последние N, где N - наибольшее число, которое появляется в ваших условиях (например, если вы хотите обнаружить 3 раза вспышку, вы должны сохранить последние 3 вспышки).по крайней мере).Возможно, лучшим решением является кольцевой буфер.

Если у вас есть серия обнаруженных событий, вы должны проверять свое состояние при каждом изменении, например, проверять, мигает ли лампа в последние X секунд.

Используйте бумагу, нарисуйте временную шкалу, назовите и нарисуйте свои термины (например, событие), запустите свои алгоритмы обнаружения «на бумаге».

Опять же: проблема, с которой вы боретесь, еще больше , чем вы сначала это сделали.Но если вы разделите проблему на более мелкие проблемные слои (уровень 1: атомарные изменения -> события; уровень 2: события -> очередь событий; уровень 3: анализ ряда событий), это небольшие проблемы, которые легко решить.

Во-первых, в этой многослойной конструкции будет трудно думать, и трудно не смешивать слои, но если у вас есть надлежащие низкоуровневые слои, вы можете делать более сложную магию на верхних уровнях.или построить еще более сложные слои, такие как обнаружение сигналов Морзе.

1 голос
/ 22 декабря 2011

Может быть, я ошибаюсь, но не хватит ли следующего кода?

// Data type and initial value for these two vars must be apt for this scenario.
int last_light = 0;
int current_light = 0;

for(uint8_t crescent_flashes = 0; TRUE; last_light = current_light){
  current_light = sample();

  if(current_light <= last_light){
    crescent_flashes = 0;
    continue;
  }

  crescent_flashes++;

  if(crescent_flashes == 3){
    do_smart_stuff();
    crescent_flashes = 0;
  }else{
    sleep(1second);
  }
}
1 голос
/ 20 декабря 2011

Вы хотите обнаружить 3 разных вспышки, излучаемых ровно за 1 секунду между 2 вспышками? так 3 вспышки за 2 секунды (не 4) ...? (вспышка 1 - это запуск, вспышка 2 через 1 секунду, вспышка 2 через 2 секунды, поэтому 3 мигает через 2 секунды).

Вот простой код без таймера и массива, которые делают это обнаружение:

light_1=sample(1);
for(::){
    // the while loop waits for the first flash, ie : wait for sample(2) > light_1
    while(sample(2) <= (light_1))
    { 
        // if you know that a flash lasts n ms, you can add "sleep(n);" in this loop,  so you will use less cpu.
    }
    // now the first flash is emitted, we will wait for 1 second before looking for the second flash
    delay(1);
    if(sample(3) <= light_1)
        continue;
    // if after 1 second, there is no flash, ther will not be 3 flashes in 2 seconds.
    // so we restart from the first flash (the "continue;" instruction do that)   
    delay(1); // the second flash was catched, then we wait for 1 second before looking for the third flash.
    if(sample(4) <= light_1)
        continue;
    //so if sample(4 > light_1), we have 3 flashes, each 2 are separated by 1 second then you can do the function you want.
    do function...
    // once finish the function, we loop back to the beginning to start looking for the first flash again.
}

Вы должны быть уверены, что light_1 = sample (1) не было взято при испускании вспышки. я думаю о двух способах сделать это:

1 - если вы знаете длину вспышки (например, 20 мс), возьмите 3 или 4 значения, разделенные длиной вспышки, чтобы получить хорошее значение light_1:

int i; 
light_1 = sample(1); 
for(i=0 ; i<4 ; i++)
{
    light_1 = sample(1) < light_1 ? sample(1) : light_1; 
    sleep(20); // 20 = 20 ms. you can replace 20 by lenght_of_flash
}

2 - путем калибровки. тогда вы можете использовать значение, полученное без вспышки света, для инициации light_1;


Если вы хотите получить 3 вспышки в течение 4 секунд, не зная периодичности, я думаю, что необходимо использовать таймер:

здесь псевдо код:

light_1 = sample();
int nb_flashes = 0;
bool fail = false;
clock_t start;  to contain the time
for(::)
{
    fail = false;
    nb_flashes = 0;
    start = clock();  //get the time to count 4 seconds.
    while(nb_flashes <3)
    {
       while(sample() <= (light_1))
      { 
        sleep(1);
      }
      nb_flashes ++; 
      if( (clock() - start)/CLOCKS_PER_SEC >=4)
      {
        fail = true;  //more than 4 seconds where elapsed... so we restart from the beginning of the for loop.
        break;  //going outside the while loop
      }

      while(sample() > light_1 )
        sleep(1);  //waiting the end of the irst flash.

      }
      if (fail)
        continue; // there was no 3 flashes whithin 4 seconds, so we restart from the beginning of the for loop 
      else
        do function // do the function you want...


}
1 голос
/ 12 декабря 2011

Счетчик может быть простым:

int count = 0;

...

if (condition)
{
    count++;
}

Теперь, чтобы включить это в свой цикл, вы можете сделать что-то вроде:

int count = 0;

while (count < THRESHOLD)
{
    ...
}
0 голосов
/ 12 декабря 2011

Я думаю, что ваше описание может означать, что вы никогда не сломаете (если ваши условия не произойдут в течение 3 секунд).Это то, что вы намерены?У меня такое чувство, что вы хотите разбить, как только вы взяли образцы 4 раза, и образцы 2-4 были выше, чем образец 1;и это произошло в течение 3 секунд.

Для такой интерпретации вашего вопроса вы можете создать счетчик как структуру со следующими полями:

s1, s2, s3, s4 count t1, t2, t3, t4

Инициализировать все до 0. По прибытии первого сэмпла сохраните значение в s1 и его значения в t1.

Итерация: если новый образец <= s1, сохраните его в s1 / t1.Если нет, сохраните его в s2, его jiffies в t2, увеличьте счет на 1 и t_elapsed на (jiffies - t1).Пока новые сэмплы> s1 и t_elapsed <= 3 сек, обрабатывают аналогично и сохраняют в следующем свободном элементе sx и tx.Если вы достигнете 3 с t_elapsed <= 3 секунд, перерыв.</p>

Если какой-либо новый сэмпл <= s1 или t_elapsed> 3 с, поверните вниз: s2 и t2 до s1 и t1, s3 / t3 до s2 / t2 и s4 / t4 до s3 / t3.Если s1> = s2, снова поверните вниз.Один раз (если) s1

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

...