【问题标题】:Problem with counting number of visitors in my smart room在我的智能房间计算访客人数的问题
【发布时间】:2020-07-31 06:56:32
【问题描述】:

我正在使用 Arduino、IR 发射器和两个 SHARP IR 传感器在我的房间里建造一个访客柜台。 传感器计算我房间里的人数——一个人开灯,更多人什么都不做,零人关灯。 红外发射器工作得很好(它可以打开/关闭灯),所以作为检测,但我有一个问题和一个问题。

我的问题是,是否可以选择创建一个函数并调用它两次,而不是在循环中重复自己?如果是这样,如何?它们大多是对称的,但仍然存在一些差异,例如 flags 和 num_people 操作。

我现在的主要问题是计算 num_people,我发现这行是问题所在:num_people = (num_people > 0) ? num_people-1 : 0; 当我将这一行放在评论中时,我可以计算多个人,但是当我不是时,它会运行代码并计算 1,0,1,0,1,0(仅在进入房间时)。需要说的是,当我出去时,它应该减少 num_people,当它为零时,保持这个数字。

代码在这里:



/*
    Smart Light V1.0 Software
    ==========================
    Copyright (C) 2020 Yuval Kedar - KD Tech
    The program counts visitors in my room and controls the light using SHARP IR sensors
    Board: Arduino Pro Mini
*/


#include "Arduino.h"
#include <IRremote.h>
// TODO: try a dedicated library for the sensors. Raw readings aren't the best way to do that - need to overcome oversampling, debouncing, hysteresis, etc.

#define IR_TRANSMITTER_PIN  (3)
#define SENS_1_PIN (A1)
#define SENS_2_PIN (A0)

#define SENS_1_MIN  (160)
#define SENS_2_MIN  (160)
#define MAX_TIME    (1000)
#define IR_KEY      (0x68B92)
#define DEBOUNCE_MS (300)

IRsend irsend;

uint8_t num_people = 0;
uint8_t prev_num_people = 0;
bool sens_1_flag = 0;
bool sens_2_flag = 0;
uint32_t timeout;

void setup() {
    Serial.begin(115200);
    pinMode(SENS_1_PIN, INPUT);
    pinMode(SENS_2_PIN, INPUT);
    pinMode(IR_TRANSMITTER_PIN, OUTPUT);
    Serial.println(F(
                "_______________________________\n"
                "\n"
                "      S M A R T    R O O M     \n"
                "_______________________________\n"
                "\n"
                "      Made by KD Technology    \n"
                "\n"));
}

void loop() {
    uint16_t sens_1_val = analogRead(SENS_1_PIN);
    uint16_t sens_2_val = analogRead(SENS_2_PIN);
    /*
    Serial.print("LDR 1: ");
    Serial.print(sens_1_val);
    Serial.print("\t LDR 2: ");
    Serial.println(sens_2_val);
    delay(200);
    */

    //TODO: there is a duplication here. Create a function and call it twice inside the loop.

    //Someone goes in
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_2_flag = 1;
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 1) {
        // TODO: add timeout to while loop. Otherwise, the program will stuck because of a sensor reading.
        // timeout = millis() + MAX_TIME;
        // while (sens_2_val > SENS_2_MIN && (millis() > timeout));
        num_people = num_people+1;
        if (num_people == 1 && prev_num_people == 0) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
        sens_1_flag = 0;
        sens_2_flag = 0;
        prev_num_people = num_people;           
        Serial.print("People in the room: ");
        Serial.println(num_people);
        delay(DEBOUNCE_MS);
    }

    //Someone goes out
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_1_flag = 1;
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 1 && sens_2_flag == 0) {
        timeout = millis() + MAX_TIME;
        while (sens_1_val > SENS_1_MIN && (millis() > timeout));
        num_people = (num_people > 0) ? num_people-1 : 0;
        if (num_people == 0 && prev_num_people != 0) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
        sens_1_flag = 0;
        sens_2_flag = 0;
        prev_num_people = num_people;           
        Serial.print("People in the room: ");
        Serial.println(num_people);
        delay(DEBOUNCE_MS);
    }
}

编辑:


/*
    Smart Light V1.0 Software
    ==========================
    Copyright (C) 2020 Yuval Kedar - KD Tech
    The program counts visitors in my room and controls the light using SHARP IR sensors
    Board: Arduino Pro Mini
*/


#include "Arduino.h"
#include <IRremote.h>
// TODO: try a dedicated library for the sensors. Raw readings aren't the best way to do that - need to overcome oversampling, debouncing, hysteresis, etc.

#define IR_TRANSMITTER_PIN  (3)
#define SENS_1_PIN (A1)
#define SENS_2_PIN (A0)

#define SENS_1_MIN  (160)
#define SENS_2_MIN  (160)
#define MAX_TIME    (1000)
#define IR_KEY      (0x68B92)
#define DEBOUNCE_MS (300)

IRsend irsend;

uint8_t num_people = 0;
uint8_t prev_num_people = 0;
bool sens_1_flag = 0;
bool sens_2_flag = 0;
uint32_t timeout;

void setup() {
    Serial.begin(115200);
    pinMode(SENS_1_PIN, INPUT);
    pinMode(SENS_2_PIN, INPUT);
    pinMode(IR_TRANSMITTER_PIN, OUTPUT);
    Serial.println(F(
                "_______________________________\n"
                "\n"
                "      S M A R T    R O O M     \n"
                "_______________________________\n"
                "\n"
                "      Made by KD Technology    \n"
                "\n"));
}

void loop() {
    uint16_t sens_1_val = analogRead(SENS_1_PIN);
    uint16_t sens_2_val = analogRead(SENS_2_PIN);
    /*
    Serial.print("LDR 1: ");
    Serial.print(sens_1_val);
    Serial.print("\t LDR 2: ");
    Serial.println(sens_2_val);
    delay(200);
    */

    //TODO: there is a duplication here. Create a function and call it twice inside the loop.

    //Someone goes in
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_2_flag = 1;
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 1) {
        // TODO: add timeout to while loop. Otherwise, the program will stuck because of a sensor reading.
        // timeout = millis() + MAX_TIME;
        // while (sens_2_val > SENS_2_MIN && (millis() > timeout));
        num_people += 1;
        if (num_people == 1 && prev_num_people == 0) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
        sens_1_flag = 0;
        sens_2_flag = 0;
        prev_num_people = num_people;           
        Serial.print("People in the room: ");
        Serial.println(num_people);
        delay(DEBOUNCE_MS);
    }

    //Someone goes out
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_1_flag = 1;
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 1 && sens_2_flag == 0) {
        // timeout = millis() + MAX_TIME;
        // while (sens_1_val > SENS_1_MIN && (millis() > timeout));
        // num_people = (num_people > 0) ? num_people-1 : 0;
        if (num_people > 1) num_people -= 1;
        if (num_people == 1 && prev_num_people != 0) {
            num_people -= 1;
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
        sens_1_flag = 0;
        sens_2_flag = 0;
        prev_num_people = num_people;           
        Serial.print("People in the room: ");
        Serial.println(num_people);
        delay(DEBOUNCE_MS);
    }
}

不同的方法:

我弄清楚了新机器的状态。我需要通过 4 个状态: 1. sens_1 检测到而 sens_2 没有 2. 两个传感器都检测到 3. sens_2 检测到而 sens_1 没有 4. 他们都没有发现。

这是我的代码:


/*
    Smart Light V1.0 Software
    ==========================
    Copyright (C) 2020 Yuval Kedar - KD Tech
    The program counts visitors in my room and controls the light using SHARP IR sensors
    Board: Arduino Pro Mini
*/


#include "Arduino.h"
#include <IRremote.h>
// TODO: try a dedicated library for the sensors. Raw readings aren't the best way to do that - need to overcome oversampling, debouncing, hysteresis, etc.

#define IR_TRANSMITTER_PIN  (3)
#define SENS_1_PIN (A0)
#define SENS_2_PIN (A1)

#define SENS_1_MIN  (115)
#define SENS_2_MIN  (115)
#define IR_KEY      (0x68B92)
#define DEBOUNCE_MS (2000)


IRsend irsend;

int8_t num_people = 0;
uint8_t state = 0;

void setup() {
    Serial.begin(115200);
    pinMode(SENS_1_PIN, INPUT);
    pinMode(SENS_2_PIN, INPUT);
    pinMode(IR_TRANSMITTER_PIN, OUTPUT);
    Serial.println(F(
                "_______________________________\n"
                "\n"
                "      S M A R T    R O O M     \n"
                "_______________________________\n"
                "\n"
                "      Made by KD Technology    \n"
                "\n"));
}

void loop() {
    uint16_t sens_1_val = analogRead(SENS_1_PIN);
    uint16_t sens_2_val = analogRead(SENS_2_PIN);
    switch (state) {
        case 0:
            if ((sens_1_val > SENS_1_MIN) && (sens_2_val < SENS_2_MIN)) {
            // if (!sens_1_val && sens_2_val) {
                state = 4;
                Serial.println("0 to 4");
            }
            if ((sens_2_val > SENS_2_MIN) && (sens_1_val < SENS_1_MIN)) {
            // if (!sens_2_val && sens_1_val) {
                state = 1;
                Serial.println("0 to 1");
            }
            break;
        case 1:
            if ((sens_1_val > SENS_1_MIN) && (sens_2_val > SENS_2_MIN)) {
            // if (!sens_1_val && !sens_2_val) {
                state = 2;
                Serial.println("1 to 2");
            } else state = 0;
            break;
        case 2:
            if ((sens_1_val > SENS_1_MIN) && (sens_2_val < SENS_2_MIN)) {
            // if (!sens_1_val && sens_2_val) {
                state = 3;
                Serial.println("2 to 3");
            } else state = 1;
            break;
        case 3:
            if ((sens_1_val < SENS_1_MIN) && (sens_2_val < SENS_2_MIN)) {   //someone went out
            // if (sens_1_val && sens_2_val) {  //someone went out
                num_people -= 1;
                if (num_people == 0) {
                    irsend.sendSony(IR_KEY, 20);
                    Serial.println("BLING!");
                }
                else if (num_people == -1) num_people = 0;
                Serial.print("People in the room: ");
                Serial.println(num_people);
                // delay(DEBOUNCE_MS);
                state = 0;
            }  else state = 2;
            break;
        case 4:
            if ((sens_1_val > SENS_1_MIN) && (sens_2_val > SENS_2_MIN)) {
            // if (!sens_1_val && !sens_2_val) {
                state = 5;
                Serial.println("4 to 5");
            } else state = 0;
            break;
        case 5:
            if ((sens_2_val > SENS_2_MIN) && (sens_1_val < SENS_1_MIN)) {
            // if (!sens_2_val && sens_1_val) {
                state = 6;
                Serial.println("5 to 6");
            } else state = 4;
            break;
        case 6:
            if ((sens_1_val < SENS_1_MIN) && (sens_2_val < SENS_2_MIN)) {   //someone came in
            // if (sens_1_val && sens_2_val) {  //someone came in
                num_people += 1;
                if (num_people == 1) {
                    irsend.sendSony(IR_KEY, 20);
                    Serial.println("BLING!");
                }
                Serial.print("People in the room: ");
                Serial.println(num_people);
                // delay(DEBOUNCE_MS);
                state = 0;
            } else state = 5;
            break;
    }
    // Serial.print("LDR 1: ");
    // Serial.print(sens_1_val);
    // Serial.print("\t LDR 2: ");
    // Serial.println(sens_2_val);
    // delay(DEBOUNCE_MS);
}

我首先用按钮和数字读数检查了代码,它运行良好!但是,当我回到模拟读数时,出现了一个问题:我在每个状态下向串行监视器打印了一个字符串以查找问题并注意到它通过了所有状态,但是当它达到最后一个状态并假设增加\减少 num_people 并打印它,它不会。相反,它会回到状态 0...

【问题讨论】:

  • 通常不赞成帖子中的图片,但在这种情况下,它将有助于说明您的代码。并确定您的逻辑是否需要调整。请编辑您的帖子,并附上一张简单的图表/图片,显示(和标记)您的传感器相对于门的布局。包括门的位置,帖子中提到的传感器相对于门的位置。
  • 选择 C ​​或 C++。不必要的双重标记会招来反对票。
  • @ryyker 拼写是结 mi strong sute。评论已修改。
  • 我将两个传感器水平(一个并排)安装在门柱的一侧——这样我就可以知道是否有人进出房间(哪个传感器先检测到)跨度>
  • 您的状态机很“奇怪”(我的意思是我认为无效)。我不确定是否理解红色过渡,房间里有人可以手动关灯吗?如果是,则必须也可以穿上 if。如果是的话,要确保开/关命令仅在房间内 inside 吗?

标签: c++ arduino sensors infrared


【解决方案1】:

是否可以选择创建一个函数并调用它两次而不是在循环中重复自己?如果是这样,如何?它们大多是对称的,但仍然存在一些差异,例如 flags 和 num_people 操作。

当然,你的两个部分非常相似,这更明显地改变了 2 个 if 中的表达式顺序。

例如在第二部分中你有

if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_1_flag = 1;
if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 1 && sens_2_flag == 0) {

相当于重新排序后的:

if (sens_2_val < SENS_2_MIN && sens_1_val > SENS_1_MIN && sens_2_flag == 0 && sens_1_flag == 0) sens_1_flag = 1;
if (sens_2_val > SENS_2_MIN && sens_1_val < SENS_1_MIN && sens_2_flag == 0 && sens_1_flag == 1) {

sens_1_valsens_2_valSENS_1_MINSENS_2_MIN 交换时,第一部分中的两个测试完全相同,其余行都是一样的。

然后:

void f(int sens1, int sens1_min, int sens2,int sens2_min, int offset, int bling)
{
    if (sens1 < sens1_min && sens2 > sens2_min && sens_1_flag == 0 && sens_2_flag == 0) sens_2_flag = 1;
    if (sens1 > sens1_min && sens2 < sens2_min && sens_1_flag == 0 && sens_2_flag == 1) {
        timeout = millis() + MAX_TIME;
        while (sens2 > sens2_min && (millis() > timeout));
        if ((num_people += offset) < 0)
          num_people = 0;
        Serial.print("People in the room: ");
        Serial.println(num_people);
        sens_1_flag = 0;
        sens_2_flag = 0;
        delay(DEBOUNCE_MS);
        if (num_people == bling) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
    }
}

代码的第一部分由

完成
 f(sens_1_val, SENS_1_MIN, sens_2_val, SENS_2_MIN, 1, 1);
 sens_1_val = sens_2_val = 0;

第二个由

f(sens_2_val, SENS_2_MIN, sens_1_val, SENS_1_MIN, -1, 0); 
sens_1_val = sens_2_val = 0;

我不想将函数中的 sens_x_val 重置为不必给出指针

剩下的对不起,我不明白你的问题,解释一下


添加状态机后进行编辑

你的状态机很奇怪,我觉得你不需要那么多状态。机器定义取决于房间内外的人是否可以手动关闭/打开灯。

如果灯仅由您的传感器发出指令,则超时,以防一段时间后没人出去或进来:

我在这里使用 UML 表示法,在转换中,'[]' 表示要尊重的保护/条件,否则转换无法完成,'/' 之后的主体在转换完成后执行。

为了处理几个人同时出来但传感器只计数一个的情况,我使用了超时。

如果房间里里面的人也可以控制灯,当有人进来时强制打开灯,当房间变空时/超时后强制关闭灯:


编辑,发现初始问题

在您的初始版本中,您的问题出在:

   num_people = (num_people > 0) ? num_people-1 : 0;
   ...
   if (num_people == 0) {
       irsend.sendSony(IR_KEY, 20);
       Serial.println("BLING!");
   }

因为当你在 if 中进行测试时,你不知道你的灯是开还是关,你在第一行丢失了那个信息,你可能错误地决定改变它的状态。

在您的代码编辑后进行编辑

对我来说,你的新代码似乎没问题,反正你可以不用 prev_num_people

您在每次进/出后将 prev_num_people 设置为 num_people,所以在“进来”的情况下:

   num_people = num_people+1;
   if (num_people == 1 && prev_num_people == 0) {
     irsend.sendSony(IR_KEY, 20);
     Serial.println("BLING!");
   }

在增加 num_people 之前你有 prev_num_people == num_people 然后在有 num_people == 1 之后意味着 prev_num_people == 0 并且测试它是没有用的。做吧

if (++num_people == 1) {
   /* light is off, put it on */
   irsend.sendSony(IR_KEY, 20);
   Serial.println("BLING!");
 }

万一“出去”而不是去做

   num_people = (num_people > 0) ? num_people-1 : 0;
   if (num_people == 0 && prev_num_people != 0) {
       irsend.sendSony(IR_KEY, 20);
       Serial.println("BLING!");
   }

只是做

 if (--num_people == 0) {
    /* light is on, put it off */
    irsend.sendSony(IR_KEY, 20);
    Serial.println("BLING!");
 }
 else if (num_people == -1) {
    /* light is already off but in past several person
       went out at the same time and only one was count */
    num_people = 0;
 }

所有这些都假设您正确检测到有人进出,我无法帮助您,我不知道您的传感器是如何工作的。

请注意,如果您想允许手动更改灯光,您需要记住灯光的状态,NumPerson 不再足以决定灯光的当前状态。 p>


编辑您的新版本,其中包含:

   if (num_people > 1) num_people -= 1;
   if (num_people == 1 && prev_num_people != 0) {
       num_people -= 1;
       irsend.sendSony(IR_KEY, 20);
       Serial.println("BLING!");
   }

这很“令人不安”,因为当你到达第二个 if 时,你只知道你来自哪里,感谢 prev_num_peoplenum_people 失去了历史),而你做很多测试都是徒劳的

我强烈建议您使用我之前给您的简化版本,不带 prev_num_people。代码越简单,越容易阅读,越健壮


编辑以添加模拟

如果我模拟你的传感器,你的代码会被“#if 0”禁用:

#include <stdio.h>

int main()
{
  int num_people = 0;
  int real_people = 0;
  int n;

  while (scanf("%d", &n) == 1) {
    real_people += n;

    //Someone goes in
#if 0
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_2_flag = 1;
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 1)
#else
    if (n > 0)
#endif
    {
      if (++num_people == 1) {
        /* light is off, put it on */
#if 0
        irsend.sendSony(IR_KEY, 20);
        Serial.println("BLING!");
#else
        puts("put light on");
#endif
      }
#if 0
      sens_1_flag = 0;
      sens_2_flag = 0;
      Serial.print("People in the room: ");
      Serial.println(num_people);
      delay(DEBOUNCE_MS);
#else
      printf("People supposed the room: %d (real %d)\n", num_people, real_people);
#endif
    }

    //Someone goes out
#if 0
    if (sens_1_val > SENS_1_MIN && sens_2_val < SENS_2_MIN && sens_1_flag == 0 && sens_2_flag == 0) sens_1_flag = 1;
    if (sens_1_val < SENS_1_MIN && sens_2_val > SENS_2_MIN && sens_1_flag == 1 && sens_2_flag == 0)
#else
    if (n < 0)
#endif
    {
      if (--num_people == 0) {
        /* light is on, put it off */
#if 0
        irsend.sendSony(IR_KEY, 20);
        Serial.println("BLING!");
#else
        puts("put light off");
#endif
      }
      else if (num_people == -1) {
        /* light is already off but in past several person
           went out at the same time and only one was count */
        num_people = 0;
      }
#if 0
      sens_1_flag = 0;
      sens_2_flag = 0;
      prev_num_people = num_people;           
      Serial.print("People in the room: ");
      Serial.println(num_people);
      delay(DEBOUNCE_MS);
#else
      printf("People supposed the room: %d (real %d)\n", num_people, real_people);
#endif
    }
  }
  return 0;
}

输入一个正数对应“进来”的情况,输入负数一个“想出去”。我还添加了 real_people 对应房间里的真实人数

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall light.c 
pi@raspberrypi:/tmp $ ./a.out
1
put light on
People supposed the room: 1 (real 1)
-1
put light off
People supposed the room: 0 (real 0)
1
put light on
People supposed the room: 1 (real 1)
1
People supposed the room: 2 (real 2)
-1
People supposed the room: 1 (real 1)
1
People supposed the room: 2 (real 2)
-1
People supposed the room: 1 (real 1)
-1
put light off
People supposed the room: 0 (real 0)
2
put light on
People supposed the room: 1 (real 2)
-1
put light off
People supposed the room: 0 (real 1)
-1
People supposed the room: 0 (real 0)
1
put light on
People supposed the room: 1 (real 1)
1
People supposed the room: 2 (real 2)
-2
People supposed the room: 1 (real 0)
^C
pi@raspberrypi:/tmp $ 

如果没有进/出超时,则灯不能从最后关闭,除非 2 人同时进来,然后 1 人熄灭,然后再 1 人熄灭

不管怎样,你看到算法没问题,所以如果你有问题,这是在传感器管理中(代码被 #if 0# 禁用)

【讨论】:

【解决方案2】:

如果我是对的,你的三元运算符的语法是错误的,应该是这样的:

(condition) ? (if_true) : (if_false)

所以应该是这样的:

num_people > 0 ? num_people-- : num_people = 0;

等同于:

if (num_people > 0)
{
 num_people--;
}
else
{
 num_people = 0;
}

如果你想使用一个函数,为什么不这样呢?

void MyFuntion(uint16_t& SensVal, uint8_t const MinSensVal, uint8_t& NumPeople)
{
  timeout = millis() + MAX_TIME;
  while (SensVal > MinSensVal && (millis() > timeout));
  NumPeople++;
  Serial.print("People in the room: ");
  Serial.println(num_people);
}

你不必把所有东西都放在函数里,只要有相同结构的代码就行了。

【讨论】:

  • "应该是这样的:num_people &gt; 0 ? num_people-- : num_people = 0;" --> OP的num_people = (num_people &gt; 0) ? num_people-1 : 0;就可以了。
  • SensVal &gt; MinSensVal 是不变的,无论是真还是假。 volatile 也不是。
【解决方案3】:

警告:这不是对您问题中单行的回答,而是对代码的简化/清理[按照您的 cmets 建议的行]。

我很难理解您的逻辑 [所有复制],因此我将其简化为第一步。当我这样做的时候,其他人已经做出了回应,所以如果你愿意的话,你可以合并他们的答案。

我创建了一个struct,而不是硬连线所有内容,它完全描述了每个设备和一些作用于该结构中的值的函数。

无论如何,这是代码。我努力打破你现有的逻辑,但你可能想检查一下。希望简化能让您更轻松地看到真正的问题:

/*
    Smart Light V1.0 Software
    ==========================
    Copyright (C) 2020 Yuval Kedar - KD Tech
    The program counts visitors in my room and controls the light using
    SHARP IR sensors
    Board: Arduino Pro Mini
*/

#include "Arduino.h"
#include <IRremote.h>
// TODO: try a dedicated library for the sensors. Raw readings aren't the best
// way to do that - need to overcome oversampling, debouncing, hysteresis, etc.

#define IR_TRANSMITTER_PIN  (3)
#define SENS_1_PIN (A1)
#define SENS_2_PIN (A0)

#define SENS_1_MIN  (160)
#define SENS_2_MIN  (160)
#define MAX_TIME    (1000)
#define IR_KEY      (0x68B92)
#define DEBOUNCE_MS (300)

IRsend irsend;

typedef struct {
    int sens_id;
    int sens_pin;
    int sens_min;
    int sens_flag;
    uint16_t sens_val;
} sens_t;

sens_t sensall[2];
#define s1  (&sensall[0])
#define s2  (&sensall[1])

uint8_t num_people = 0;
uint32_t timeout;

void
sensinit(sens_t *sens,int id,int pin,int min)
{

    sens->sens_id = id;
    sens->sens_pin = pin;
    sens->sens_min = min;
    sens->sens_flag = 0;
    pinMode(sens->sens_pin,INPUT);
}

void
sensread(sens_t *sens)
{
    sens->sens_val = analogRead(sens->sens_pin);
}

void
setup()
{
    Serial.begin(115200);

    sensinit(s1,1,SENS_1_PIN,SENS_1_MIN);
    sensinit(s2,2,SENS_2_PIN,s2->sens_min);

    pinMode(IR_TRANSMITTER_PIN, OUTPUT);
    Serial.println(F("_______________________________\n"
        "\n"
        "      S M A R T    R O O M     \n"
        "_______________________________\n"
        "\n"
        "      Made by KD Technology    \n"
        "\n"));
}

int
sensif(int lt_gt,int v1,int v2)
{
    int cond1;
    int cond2;
    int match;

    if (lt_gt) {
        cond1 = (s1->sens_val < s1->sens_min);
        cond2 = (s2->sens_val > s2->sens_min);
    }
    else {
        cond1 = (s1->sens_val > s1->sens_min);
        cond2 = (s2->sens_val < s2->sens_min);
    }

    match = (cond1 && cond2 && (s1->sens_flag == v1) && (s2->sens_flag == v2));

    return match;
}

void
senswait(sens_t *sens,int newval)
{
    timeout = millis() + MAX_TIME;

    // TODO: add timeout to while loop. Otherwise, the program will stuck
    // because of a sensor reading.
    while ((sens->sens_val > sens->sens_min) && (millis() > timeout));

#if 0
    switch (sens->sens_id) {
    case 1:
        num_people = (num_people > 0) ? num_people - 1 : 0;
        break;
    case 2:
        num_people = num_people + 1;
        break;
    }
#else
    num_people = newval;
#endif

    Serial.print("People in the room: ");
    Serial.println(num_people);

    // FIXME -- why clear both instead of just one (e.g. sens->sens_flag)???
    s1->sens_flag = 0;
    s2->sens_flag = 0;

    delay(DEBOUNCE_MS);
}

void
loop(void)
{

    sensread(s1);
    sensread(s2);

#if 0
    Serial.print("LDR 1: ");
    Serial.print(s1->s1_val);
    Serial.print("\t LDR 2: ");
    Serial.println(s2->sens_val);
    delay(200);
#endif

    // Someone goes in
    if (sensif(1,0,0))
        s2->sens_flag = 1;

    if (sensif(0,0,1)) {
        senswait(s2,num_people + 1);
        if (num_people == 1) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
    }

    // Someone goes out
    if (sensif(0,0,0))
        s1->sens_flag = 1;

    if (sensif(1,1,0)) {
        senswait(s1,(num_people > 0) ? num_people - 1 : 0);
        if (num_people == 0) {
            irsend.sendSony(IR_KEY, 20);
            Serial.println("BLING!");
        }
    }
}

【讨论】:

  • tnx,但它看起来比应有的复杂得多。
  • 嗯 ... 采用基于 struct 的方法和传感器阵列是可行的方法。它最终更容易。假设您要管理 5000 个传感器?你会怎么做?这种方法是 [linux] 内核所做的。我已经编写了 20 多个商业级 unix/linux 设备驱动程序,并且每个设备的结构几乎总是第一步。
  • 你完全正确,但我只使用两个传感器来检测是否有人进出。因此,简单的代码对我来说是正确的方式。
  • 唉,你没有有简单的代码。你有不必要的复杂意大利面条代码。使用(例如)foo_1/foo_2 而不是数组 foo[2] 已经够糟糕的了。但是,然后,将这四个单独的变量放大到总共 8 个,只会使问题更加复杂。当您添加另一个每个设备变量 [或两个或三个] 时会发生什么?此外,您的代码是高度非模块化的。您正在为每个传感器复制几乎相同的代码,而不是使用函数。
  • 而且,我相信您说过:我的问题是,是否可以选择创建一个函数并调用它两次而不是在循环中重复自己?如果是这样,如何?它们大多是对称的,但仍然存在一些差异,例如 flags 和 num_people 操纵。说真的,您希望这样的解决方案采取什么形式?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-08
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 2021-04-25
相关资源
最近更新 更多