Проверка датчика, на протяжении всей программы

Тема в разделе "Arduino & Shields", создана пользователем Alex19, 18 фев 2014.

  1. Alex19

    Alex19 Гуру

    День добрый, возник вопрос как правильно написать код.

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

    Все вроде бы просто, но есть нюанс. Программа должна остановится с разу, не допустимо выполнение хоть 1-го дополнительного шага. Датчик проверяется на протяжении все программы.

    Вот упрощенный код, удалено, все лишнее.
    Код (Text):

    /// <summary>
    /// Смыкание формы
    /// </summary>
    void CloseForm()
    {
           // Проверка, открыта ли форма
            if (analogRead(b1) == b44 && CheckDoor())
            {
                // Устанавливаем значение V1
                analogWrite(s50in, v1);

                // Запускаем запирание формы
                digitalWrite(s2, HIGH);
            }
            else if (analogRead(b1) == b22 && CheckDoor()) // Проверка, дошли ли мы до концевика b22
            {
                // Устанавливаем значение P1
                analogWrite(s51in, p1);

                // Запускается таймер t7
                if (previousT7 == 0)
                {
                    previousT7 = millis();  
                }
            }
            else if (analogRead(b1) == b46 && CheckDoor())
            {
                // Устанавливаем значение V2
                analogWrite(s50in, v2);

                // Запускаем силовое запирание формы
                digitalWrite(s9, HIGH);

                // Разогрев масла
                digitalWrite(s52, HIGH);
            }
            else if ((analogRead(b1) == b23 ||CheckTimerMillis(previousT7, t7)) &&  && CheckDoor())
            {
                // Отключаем запирание формы
                digitalWrite(s2, LOW);
       
                if (CheckTimerMillis(previousT7, t7))
                {
                    Errore("Закрытие формы. Сработал таймер t7, раньше чем форма была закрыта.", 2);
                }
                else
                {
                    Log("Закрытие формы. Завершено.", 6, false);
                }
           
                // Очищаем таймер
                previousT7 = 0;

                // Очищаем тип шага в ручном режиме
                tPAManualStepCycleEnum = TPAMSC_None;
            }

        }
    }
     
    Можно перед включением, каждого значения проверять функцию CheckDoor(), а в ней непосредственно вызывать функцию Stop(), но это очень накладно.

    Проверять придется при каждом выставлении digitalWrite, analogWrite.
    Так как у меня будет от 20 до 40 таких блоков как данная функция (CloseForm()).

    Хотя как вариант написать функцию, для выставления digitalWrite и analogWrite, с проверкой двери, примерно так
    Код (Text):

    void digitalWriteWithCheckDoor(int pinCheck, int pin, boolean value)
    {
        if (digitalRead(pinCheck))
        {
            digitalWrite(pin, value)
        }
    }
     
    Есть вариант использования прерывания.
    Но насколько я знаю, прерывание прерывает работу основного цикла и после отработки он продолжается с той точки, где был прерван. То есть опять контролировать дверь.

    Подскажите пожалуйста, укажите путь, как еще можно сделать, такую защиту?
     
  2. Alex19

    Alex19 Гуру

    Есть еще вызов функции Stop в самом прерывании, но из моего опыта это не возможно.
     
  3. rav_75

    rav_75 Гик

    Немного не понял, что вы хотите сделать и почему в прерывании нельзя вызывать функцию Stop(). Если надо наглухо остановить программу, то почему по прерыванию не вызвать функцию, которая запускает бесконечный цикл? Ну и выход из цикла сделать ) Если надо, чтоб после отработки прерывания программа начинала работать с начала (либо с любого другого места, а не там где остановилась), наверное можно попробовать использовать оператор goto. Теоретически должно работать.
     
  4. Alex19

    Alex19 Гуру

    Большое спасибо, за ответ.

    Просто был очень печальный опыт, кнопки и прерывания. Из-за него, я чуть не расстался с ардуино.
    Программа очень не стабильно работала. 20-30 циклов и сбой, так и не разобрался с этим.
    Возможно из-за дребезга, так и не понял почему. Решил по другому.

    Да именно так и надо, не подробно пояснил.

    Отличное решение, что-то я забыл о них. Но вот, только получится, ардуина записывает точку входа и возвращается к ней, по прерыванию. Попробую.
     
  5. rav_75

    rav_75 Гик

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

    geher Гуру

    Что-то смутные подозрения, основанные на опыте работы с прерываниями на других процессорах, говорят, что так (goto из прерывания) делать нельзя.
    Если я правильно понимаю, то предлагается по goto уйти из функции прерывания в любую точку программы? В таком случае, если это вообще пропустит компилятор (goto не в пределах функции), в стеке останется "висеть" фрейм функции прерывания, включая адрес возврата. А в функции, куда мы отправимся, могут возникнуть проблемы с доступом к локальным переменным и параметрам (если они есть, естественно) и с возвратом из функции (при завершении того же loop(), например).
    Чтобы все отработало правильно, вроде надо сначала не забыть откатить стек в нужную позицию или уходить не через goto, а через return с предварительной заменой адреса возврата в стеке.
    Причем уход всегда должен быть в ту же функцию, из которой вызывалось прерывание.
    Тогда получается, что в программе должна присутствовать только одна функция - main() (прощай Arduino IDE?). Или придется заниматься тонкой подстройкой стека перед уходом из прерывания.
    Иначе, как мне кажется, сразу произойдет сбой при завершении loop().
     
  7. Alex19

    Alex19 Гуру

    Не получилось пока, область видимости не позволяет использовать goto в функциях. Сейчас смотрю как можно изменить область видимости.
     
  8. Alex19

    Alex19 Гуру

    Спасибо geher

    Дело даже не в переходе в какую-то точку. Хотя пытался отправить в начало loop.
    Нужно просто, чтобы при открытии двери (прерывание, как 1 из вариантов) сработала функция Stop и при этом должна остановится сразу, не допустимо выполнение хоть 1-го дополнительного шага.

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

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

    Alex19 Гуру

    Нет увы goto, не имеет возможностей изменения уровней области видимости.

    Думаю, что решение предложенное geher, по идее должно сработать. Но к сожалению, я не могу писать кодом, с прямым управлением AVR. Во первых знания (хочу подтянуть и научится, но не сейчас, жмут сроки), во вторых усложнение кода.

    Он должен быть доступен простым пользователям. Проблема кадров, увы везде.
     
  10. rav_75

    rav_75 Гик

    спасибо за пояснения, будем знать )
     
  11. Alex19

    Alex19 Гуру

    Не за что, вам спасибо. Напомнили мне про goto, просто его всегда избегал и забыл про него:).
    Еще попытаюсь найти, решение в рамках ардуины. Если, найду отпишу.
     
  12. Корней

    Корней Гик

    Если бы мне понадобилось что-то подобное, я бы рассмотрел вот такие решения:

    1) Каждое действие Д, после которого требуется проверка П, поместил в отдельную функцию.
    Указатели на эти функции поместил в массив.
    В цикле вызывал функции по указателям, перед каждым вызовом проверял условие П.

    2) Каждое действие Д, после которого требуется проверка П, поместил в отдельную функцию.
    Создал бы функцию Ф, которая получает аргументом указатель на Д. В этой функции проверял условие П и соответственно поступал бы с указателем на Д.

    (Замыкания доступны только в новом стандарте, сделаем вид, что их нет в C)
     
  13. Megakoteyka

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

    Правильно избегали. Вспомнили - и забудьте снова навсегда :) Нет такой задачи, которую нельзя было бы решить без его использования.
     
  14. Alex19

    Alex19 Гуру

    Спасибо Корней и Megakoteyka.

    Очень интересное решение, как я понял на C++. Просто ни когда, такого решения не видел. Плюс еще пару решений в копилку знаний:). Большое спасибо.

    Но видимо я не достаточно точно, объяснил чего я хочу.
    Хочется найти решение, которое бы не требовало проверки в каждом шаге.

    Если проверять в каждом месте, то можно решить задачу, как мне кажется проще, 3-мя функциям.
    Код (Text):

    void digitalWriteWithCheckDoor(int pinCheck, int pin, boolean value)
    {
        if (digitalRead(pinCheck))
        {
            digitalWrite(pin, value)
        }
    }
     
    И еще 2, 1 для аналогового сигнала и еще 1 для таймера. Может еще появится, пару.

    В массиве указателей, есть некоторые проблемы для меня.
    1. Не могу перебирать указатели функций в цикле. Так как режимов очень много, как и вариантов работы. И они могут идти не последовательно.
    2. Большое кол-во функций с почти одинаковым функционалом.
    3. С++, если я еще смогу написать такой код (думаю, что смогу, по примерам). То объяснить другим как это работает, задача будет сложной.

    Но само решение, очень интересное. Для определенных задач великолепное.

    Так всегда думал, просто читать потом сложно. Особенно когда код измеряется тысячами строк. Планировал использовать, только хак.
     
  15. Корней

    Корней Гик

    Это как раз С.
    На С++ были бы функторы или просто объекты.
    Первый вариант это прерываемый фрейм.
    Второй вариант - С реализация шаблона ООП "Шаблонный метод" http://ru.wikipedia.org/wiki/Шаблонный_метод_(шаблон_проектирования)

    Принципиально доступно два варианта решения: синхронный и асинхронный.
    Предложенные мной варианты - синхронные. Прерывание - асинхронный вариант.
    У каждого свои плюсы и минусы.

    1. Можно создать столько массивов, сколько у вас режимов работы.
    Получите что-то вроде набора состояний конечного автомата.
    2. Для временного отключения функции можно заменить ее указатель в массивах на холостую функцию. Или можно хранить в массивах не только указатели на функции, но и, например, флаг - нужно ли вызывать данную функцию.

    Можно выделить повторяющийся код в отдельные функции.

    На С++ картинка будет более элегантной, но писанины будет больше.
     
  16. Корней

    Корней Гик

    Для "goto" из ISR можно использовать пару макросов setjmp/longjmp
    Вот тут, например, тоже человек с дверью... http://forum.arduino.cc/index.php?PHPSESSID=o3decg028t0qhrucv87srkfkk0&topic=43653.15

    Для "резкого" возврата в определенную точку кода - исключения.
    Но в ардуине врятли будет работать. http://stackoverflow.com/questions/...-in-the-arduino-environment/10096149#10096149
     
    Последнее редактирование: 19 фев 2014
  17. Alex19

    Alex19 Гуру

    Спасибо, за идею.

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

    Странная ситуация являюсь одновременно заказчиком и исполнителем, части проекта:). В дальнейшем поддержку планирую переложить на других. Надеюсь до конца Марта управимся.

    Надо разбираться с AVR и электроникой, чтобы упрощать себе жизнь, эх найти бы время.
    Всем, большое спасибо, за оперативную помощь.
     
  18. Megakoteyka

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

    Весь вопрос в том, насколько "резко" нужно вернуться. На практике поставить флаг в прерывании и среагировать на него можно очень быстро, если счет не идет на такты.
     
  19. Корней

    Корней Гик

    Под "резкостью" подразумевался возврат по стеку вызовов, минуя штатные возвраты из функций.
    Раскрутка стека никогда не являлась быстрой процедурой, что бы вести речь именно о быстродействии такого решения. Да и такое применение try/catch так же порицается, как и использование goto.
     
  20. Megakoteyka

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

    Я имел ввиду допустимое время реакции на прерывание. Обычно этого времени хватает и стек раскрутить, и еще много чего сделать :)