Проверка битовой маски

Тема в разделе "Arduino & Shields", создана пользователем Valrond, 15 май 2018.

  1. Valrond

    Valrond Нуб

    Добрый день. Нужна помощь в решении следующей проблемы:
    В данном коде есть битовая маска размером 32. Я написал три простых функции, которые выставляют бит, убивают бит и проверяет его состояние. Маска в функции передается по указателю, а не по значению, так как масок может быть более одной. Нужно осуществлять контроль бита до его записи или уничтожения. Никак получается это реализовать если я вызываю функцию проверки в функциях записи или уничтожения... Думаю дело в том, что я не правильно передаю указатель на битовую маску. Если проводить проверку отдельно - то все получается. Но это извращение...
    Пример кода с проверкой проводимой отдельно (где все срабатывает):
    Биты выставляются и убиваются через передачу в сиреал нажатия кнопок (см test()), проверка проводится в функции test().

    Код (C++):
    uint32_t flags_list=0;

    void setup(){
    Serial.begin(9600);
    };
    void loop(){
    Serial.println(flags_list, BIN);
    test();
    delay(1000);
    };

    void SetFlag(uint32_t *flags_list, uint32_t flag){
           // if (!CheckFlag(* flags_list , flag))
            *flags_list = *flags_list + flag;
    };
    void DropFlag(uint32_t * flags_list, uint32_t flag){
           // if (CheckFlag(* flags_list , flag))
            *flags_list = *flags_list - flag;
    };
    uint8_t CheckFlag(uint32_t * flags_list, uint32_t flag){
        Serial.print(F("* flags_list = "));
        Serial.println (*flags_list);
        if (* flags_list & flag) return 1;
        else
            return 0;
    };


    void test(){
        if (Serial.available()){
            byte symbol = Serial.read();
             if (symbol == '6'){
                Serial.println("6 pressed");
                if(!CheckFlag(&flags_list, 2))
                SetFlag(&flags_list, 2);
            }
             else  if (symbol == '7'){
                 Serial.println("7 pressed");
                if(CheckFlag(&flags_list, 2))
                DropFlag(&flags_list, 2);
            }
             else  if (symbol == '8'){
                 Serial.println("8 pressed");
               if(!CheckFlag(&flags_list, 4))
               SetFlag(&flags_list, 4);

            }
             else  if (symbol == '9'){
                 Serial.println("9 pressed");
                if(CheckFlag(&flags_list, 4))
                DropFlag(&flags_list, 4);

            }

        }
    }
     
    Пример кода где возникают глюки, это видно при выводе в сиреал.
    Биты выставляются и убиваются через передачу в сиреал нажатия кнопок (см test()), проверка проводится в функциях SetFlag() и DropFlag(), как это и должно быть, но не работает ;(((.

    Код (C++):
    uint32_t flags_list=0;

    void setup(){
    Serial.begin(9600);
    };
    void loop(){
    Serial.println(flags_list, BIN);
    test();
    delay(1000);
    };

    void SetFlag(uint32_t *flags_list, uint32_t flag){
           if (!CheckFlag(* flags_list , flag)) // думаю ошибка где-то здесь
            *flags_list = *flags_list + flag;
    };
    void DropFlag(uint32_t * flags_list, uint32_t flag){
           if (CheckFlag(* flags_list , flag))// думаю ошибка где-тоз десь
            *flags_list = *flags_list - flag;
    };
    uint8_t CheckFlag(uint32_t * flags_list, uint32_t flag){
        Serial.print(F("* flags_list = "));
        Serial.println (*flags_list);
        if (* flags_list & flag) return 1;
        else
            return 0;
    };


    void test(){
        if (Serial.available()){
            byte symbol = Serial.read();
             if (symbol == '6'){
                Serial.println("6 pressed");
             //   if(!CheckFlag(&flags_list, 2))
                SetFlag(&flags_list, 2);
            }
             else  if (symbol == '7'){
                 Serial.println("7 pressed");
              //  if(CheckFlag(&flags_list, 2))
                DropFlag(&flags_list, 2);
            }
             else  if (symbol == '8'){
                 Serial.println("8 pressed");
             //  if(!CheckFlag(&flags_list, 4))
               SetFlag(&flags_list, 4);

            }
             else  if (symbol == '9'){
                 Serial.println("9 pressed");
             //   if(CheckFlag(&flags_list, 4))
                DropFlag(&flags_list, 4);

            }

        }
    }
     
     
    Последнее редактирование: 15 май 2018
  2. SergeiL

    SergeiL Оракул Модератор

    Попробуйте заменить это:
    Код (C++):
    if (!CheckFlag(* flags_list , flag)) // думаю ошибка где-то здесь
     
    На это:
    Код (C++):
    if (!CheckFlag(flags_list , flag))
     
    Valrond и arkadyf нравится это.
  3. SergeiL

    SergeiL Оракул Модератор

    И еще, я бы Вам хотел посоветовать, делать имена локальных переменных не совпадающими с глобальными.

    У Вас есть глобальная:
    Код (C++):
    uint32_t flags_list=0;
    Сделайте локальные хоть так:
    Код (C++):
    uint8_t CheckFlag(uint32_t * flags_list_ptr, uint32_t flag){
    Так будет видно, что это - раз указатель (pointer), два не спутаешь с глобальной.

    Иначе, если Вы вдруг поменяете название переменной в определении функции - компилятор даже ошибки не выдаст - будите мучиться искать ошибку.
     
    Последнее редактирование: 15 май 2018
    arkadyf нравится это.
  4. SergeiL

    SergeiL Оракул Модератор

    Ну и по операциям, то, что у Вас делается, не является работой с битами, если я правильно Вас понял:
    Код (C++):
    void SetFlag(uint32_t *flags_list, uint32_t flag){
           // if (!CheckFlag(* flags_list , flag))
            *flags_list = *flags_list + flag;
    };
    void DropFlag(uint32_t * flags_list, uint32_t flag){
           // if (CheckFlag(* flags_list , flag))
            *flags_list = *flags_list - flag;
    };
    uint8_t CheckFlag(uint32_t * flags_list, uint32_t flag){
        Serial.print(F("* flags_list = "));
        Serial.println (*flags_list);
        if (* flags_list & flag) return 1;
        else
            return 0;
    };
    Это добавление и вычитание числа к / из переменной "flags_list"

    Оно, конечно, работает, как частный случай, с проверкой состояния бита,
    Но правильно это сделать, как то так:
    Код (C++):
    int checkbit(const uint32_t value, const uint32_t position) {
        return ((value & (1 << position)) != 0);
    }
    uint32_t setbit(const uint32_t value, const uint32_t position) {
        return (value | (1 << position));
    }
    uint32_t unsetbit(const uint32_t value, const uint32_t position) {
        return (value & ~(1 << position));
    }
    При таком варианте не нужно проверять, взведен ли уже бит, при новом взведении бита.
     
    Последнее редактирование: 15 май 2018
    arkadyf нравится это.
  5. SergeiL

    SergeiL Оракул Модератор

    Ну или Ваш вариант с указателями:
    Код (C++):
    void SetFlag(uint32_t *flags_list, uint32_t flag){
            *flags_list |=  flag;
    };
    void DropFlag(uint32_t * flags_list, uint32_t flag){
            *flags_list &=  ~flag;
    };
    uint8_t CheckFlag(uint32_t * flags_list, uint32_t flag){
        Serial.print(F("* flags_list = "));
        Serial.println (*flags_list);
        if ((*flags_list) & flag) return 1;
        else
            return 0;
    };
     
    arkadyf нравится это.
  6. Valrond

    Valrond Нуб

    Спасибо! Очень доходчиво!