есть ли возможность создать функцию и вызвать ее дважды вместо повторения внутри l oop? если да, то как? они в основном симметричны c, но все же имеют некоторые различия, такие как флаги и манипуляции с num_people.
Наверняка ваши две части очень похожи, и это более заметно при изменении порядка выражений в 2 ifs.
Например, во второй части у вас есть
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_val на sens_2_val и SENS_1_MIN на SENS_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!");
}
b потому что при выполнении теста в , если , вы не знаете, включен или выключен ваш свет, вы потеряли эту информацию в первой строке, и вы можете ошибочно принять решение об изменении ее состояния.
редактировать после редактирования кода
Для меня ваш новый код выглядит нормально, в любом случае вы можете обойтись без prev_num_people .
Вы установили prev_num_people to 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 больше не достаточно, чтобы решить, каково текущее состояние света.
отредактируйте вашу новую версию, содержащую:
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!");
}
это 'тревожно', потому что когда вы достигаете второго , если , вы знаете только, откуда вы пришли благодаря prev_num_people ( num_people потерял историю), и вы проводите много тестов впустую
Я настоятельно рекомендую вам использовать упрощенную версию, которую я дал вам раньше, без prev_num_people . Чем более простой код, тем легче его читать и тем более он устойчив
1142 *
изменить, чтобы добавить симуляцию
Если я симулирую ваши датчики, ваш код отключается "#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 #)