如何在C中创建高级计数器?

时间:2011-12-12 15:15:31

标签: c timer counter

我有一个无限的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次,则打破循环。但不仅如此,一盏灯将以1秒的间隔闪烁3次。如果光线在4秒内闪烁3次,我希望循环中断。

如果这没有意义,请告诉我,以便我能更好地解释它。



编辑3

我希望它继续正常的采样时间,只有在获得3个读数实例时才会中断循环。但是我还是觉得我应该用一个计时器?请帮忙。

额外信息:我在这里回复了其中一位回答者,也许其他人可以从这个额外的解释中受益:

有两个阶段:

  1. 第1阶段:一次检测一个实例。 (让代码适用于这个)
  2. 第2阶段:检测灯光(连续3次闪烁)以执行其他功能。
  3. 我应该避免使用这么多延迟让第2阶段工作,因为这会影响第1阶段的阅读控制和速度。

    如果您需要更多解释,请与我们联系!

8 个答案:

答案 0 :(得分:3)

使用某种结构将各种参数组合在一起。这通常被称为“州”。

struct state {
     int light_2_greater_than_1;
     int other_things;
};

然后更新该对象,并检查其成员。

答案 1 :(得分:3)

这是一个非常简单的例子,说明使用SIGALRM来保持时间独立于你的sample()函数,这是因为sample()需要一些时间才能完成,你现在可以在之前做到这一点=时间(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);
}

编辑: 实际上现在我读它time()不是信号安全,给我一个修改代码的时间

第二次编辑: http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04 实际上它是信号安全的:)

  
    

下表定义了一组函数,这些函数应该是信号的可重入或不可中断的,并且应该是异步信号安全的。因此,应用程序可以无限制地调用信号捕获功能:     ...时间()

  

答案 2 :(得分:1)

计数器可以简单如下:

int count = 0;

...

if (condition)
{
    count++;
}

现在,要将其合并到循环中,您可能会执行以下操作:

int count = 0;

while (count < THRESHOLD)
{
    ...
}

答案 3 :(得分:1)

你想要在两次闪光之间检测到3个闪烁的闪烁,恰好是1秒? 所以3秒闪烁2秒(不是4)...? (flash1是开始,1秒后flash2,2秒后flash2。所以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;


如果你想在不知道周期的情况下在4秒钟内获得3次闪光,我认为有必要使用计时器:

这里是代码:

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...


}

答案 4 :(得分:1)

也许我弄错了,但是下面的代码不够用吗?

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

答案 5 :(得分:1)

这个问题比你预期的要大10倍。如果你想自己解决这个问题,那就单独留下键盘,并尝试设计这些东西。

基本上,您只有一个关于灯泡的信息:打开或关闭。对于这种复杂的操作来说,这还不够,例如在指定的时间间隔内检查闪存计数。您必须创建衍生物

首先,您必须设置某种计数器或时间戳,用于计算时间间隔,如经过时间,两个事件之间的距离等。它可以是时间戳(由操作系统或您正在使用的语言提供),或者如果您的程序是无限循环,您可以将sleep()和counter ++放入其中,并使用它来测量时间(好的,它不太准确,因为它不会与程序运行期间的时间一致,但在这个时间精度上无关紧要。)

您的衍生变体将类似于:

  • 变光;参数:方式(上/下),时间戳
  • flash:一系列事件,第一个是up,第二个是down,参数:begin,end和(根据这些:)计算持续时间。

您必须检测并存储这些事件,最少N个,其中N是您的条件中出现的最大数字(例如,如果您想要检测3次闪光,则必须至少存储最后3次闪光)。也许,一个ringbuffer是最好的解决方案。

如果您有一系列检测到的事件,则必须检查每次更改的情况,例如:检查灯泡在最后X秒闪烁。

使用纸张,绘制时间轴,命名和绘制术语(如事件),“在纸上”运行检测算法。

再说一次:你所面临的问题是甚至更大,而不是你先付出的。但是如果你把问题分成更小的问题层(第1层:原子变化 - >事件;第2层:事件 - &gt;事件队列;第3层:事件序列分析),它们是小问题,很容易解决

首先,很难在多层构造中思考,并且很难不混合图层,但如果你有适当的低级图层,你可以在上层做更复杂的魔术,或者建立更复杂的层,比如检测莫尔斯信号。

答案 6 :(得分:1)

我假设您要做的是:在最后4秒内检测到灯闪烁了3次。通过“闪光”,我认为你的意思是灯已关闭,然后它继续。 (当然可能是因为'闪光'你的意思是光必须继续然后关闭,这需要一个更复杂的解决方案,但是因为你还没有给我们一个闪光的含义的定义,我会选择更简单的版本。)

首先,检查您现在的光线读数是否大于或小于过去某个时刻的光线读数,不会告诉您灯光是打开还是关闭。您需要建立一个低阈值,低于该阈值,您将考虑关闭灯光,以及一个高阈值,高于该阈值,您将考虑灯光亮起。当读数变化低于低阈值时,您将忽略它。当读数在两个阈值之间变化时,您也会忽略它。当读数变化超过高阈值时,你猜对了,你再次忽略它。您只关心以下两种情况:

  1. 灯泡熄灭,之前的读数低于高阈值,新读数高于高阈值;这意味着灯已经亮了。

  2. 灯泡点亮,之前的读数高于低阈值,新读数低于低阈值;这意味着灯已关闭。

  3. 如果你不这样做,那么你会得到很多错误的触发因为你的LDR读数会因为穿着高度反光的白色实验室外套走路而变化,或仅仅是因为随机噪音。

    由于我们已经采取行动意味着从“关闭”转变为“开启”,因此您实际上只需要关注上面的第一个案例。 (否则,您需要考虑这两种情况。)

    因此,您需要做的是拥有一个包含三个条目的数组,您可以在其中存储最后三次闪烁发生的时间。每次发生新的闪存时,您都会丢弃数组第一个元素中的时间值,然后将下两个向下移动,并将新的时间值存储在数组的最后一个元素中。每次执行此操作时,都要检查第一个和最后一个条目之间的差异是否小于或等于4秒。

    注意:在任何情况下你都不应该使用睡眠或等待或延迟功能,因为当你的程序处于睡眠状态时,指示灯会闪烁,你会错过它。

答案 7 :(得分:0)

我认为你的描述可能意味着你永远不会破裂(如果你的情况不会在3秒内发生)。这是你想要的吗?我有一种感觉,一旦你采样4次你想要打破,样品2-4高于样品1;这发生在3秒内。

对于您的问题的解释,您可以将计数器创建为具有以下字段的结构:

s1,s2,s3,s4 计数 t1,t2,t3,t4

将所有值初始化为0.在第一个样本到达时,将值存储在s1中,将其值存储在t1中。

迭代:如果新样本&lt; = s1,则将其存储在s1 / t1中。如果没有,将它存储在s2中,将其存储在t2中,将计数增加1,并将t_elapsed存储为(jiffies-t1)。只要新样品> s1和t_elapsed&lt; = 3秒,处理类似并存储在下一个自由sx和tx元素中。如果你在t_elapsed&lt; = 3秒时达到3,请休息。

如果有任何新样本&lt; = s1或t_elapsed&gt; 3秒,向下旋转:s2和t2到s1和t1,s3 / t3到s2 / t2,s4 / t4到s3 / t3。如果s1> = s2,则再次向下旋转。一次(如果)s1

对于算法中经过的时间,这显然不会完全准确。您还面临进程抢占,中断等风险,并且可能想要考虑如果这是可以接受的,或者您想要使用互斥锁等保护您的结构。