Задача для начинающих: коварная ошибка

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Честно говоря, первая мысль после прочтения исходного сообщения - запретить прерывания. Но IMHO можно обойтись и исключительно логикой:

static bool isPressed(void) {
   if(result = buttonState)
     buttonState = false;
   return result;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

asam пишет:

Ну зачем _все_ прерывания запрещать? Достаточно INT0 запретить.

+100500

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

я так и не понял зачем так усложнять, флаг не обработан, зачем его постоянно дёргать? "Горе от ума"?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:

Честно говоря, первая мысль после прочтения исходного сообщения - запретить прерывания. Но IMHO можно обойтись и исключительно логикой:

static bool isPressed(void) {
   if(result = buttonState)
     buttonState = false;
   return result;
}

Я обычно именно так и пишу. Не готов "спорить" что лучше, но пишу так. Только присваивание в ещё одни скобки ставлю, чтобы видно было, что оно там умышленно.

Green
Offline
Зарегистрирован: 01.10.2015

А что тут спорить! Никаких доп. действий, типа запрета/разрешения INT, всё лаконично, атомарность достигнута.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

andriano пишет:

Честно говоря, первая мысль после прочтения исходного сообщения - запретить прерывания. Но IMHO можно обойтись и исключительно логикой:

static bool isPressed(void) {
   if(result = buttonState)
     buttonState = false;
   return result;
}

Я обычно именно так и пишу. Не готов "спорить" что лучше, но пишу так. Только присваивание в ещё одни скобки ставлю, чтобы видно было, что оно там умышленно.

и

эта конструкция не даёт пропуска нажатий?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Green пишет:

А что тут спорить! Никаких доп. действий, типа запрета/разрешения INT, всё лаконично, атомарность достигнута.

Вы э тут вроде не первый день. Должны знать, что тут и не по такому "спорят" :)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

эта конструкция не даёт пропуска нажатий?

Соберите и попробуйте. Только result нужно описать.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

ua6em пишет:

эта конструкция не даёт пропуска нажатий?

Соберите и попробуйте. Только result нужно описать.

Вы же знаете, я экстремал, кнопку нажимать буду со скоростью 100кГц (скорость отработки прерывания) )))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Честно говоря, первая мысль после прочтения исходного сообщения - запретить прерывания. Но IMHO можно обойтись и исключительно логикой:

static bool isPressed(void) {
   if(result = buttonState)
     buttonState = false;
   return result;
}

если запретить прерывания, то не добиваемся цели, фиксация времени нажатия кнопки

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ua6em пишет:

Вы же знаете, я экстремал, кнопку нажимать буду со скоростью 100кГц (скорость отработки прерывания) )))

А Клапа, дак вапще 100 кнопок по 100 кГц нажимать умеет всего 10-ю пальцами. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ua6em пишет:

Вы же знаете, я экстремал, кнопку нажимать буду со скоростью 100кГц (скорость отработки прерывания) )))

А Клапа, дак вапще 100 кнопок по 100 кГц нажимать умеет всего 10-ю пальцами. 

у меня для этой самой штуки есть...вторая ардуина, да можно и на этой самой, таймером, а Клапа это жеж запущенный случай, еще с его часиков на миллис, где он временные отрезки как бог на душу положит складировал )))

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

ua6em пишет:

и эта конструкция не даёт пропуска нажатий?

Сначала выполнится присвоение и потом result будет проверяться на истинность, а не buttonState. По этому всё будет работать как положено без пропусков.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Komandir пишет:

ua6em пишет:

и эта конструкция не даёт пропуска нажатий?

Сначала выполнится присвоение и потом result будет проверяться на истинность, а не buttonState. По этому всё будет работать как положено без пропусков.

Так это понятно, не понятно, что мешает прерыванию попасть между, то-есть присвоение прошло, а сброс флага еще не наступил

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

В таком ракурсе тут концепция изначально с возможностью пропуска.

А вот вопрос с атоммарностью доступа успешно решен.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

Так это понятно, не понятно, что мешает прерыванию попасть между, то-есть присвоение прошло, а сброс флага еще не наступил

И что? Переменная buttonState станет true и будет обработана при следующем обращении к isPressed.

Всё нормально. Ничего не пропустится.

ua6em пишет:

Вы же знаете, я экстремал, кнопку нажимать буду со скоростью 100кГц (скорость отработки прерывания) )))

Таки, вперёд!

ua6em пишет:

если запретить прерывания, то не добиваемся цели, фиксация времени нажатия кнопки

Не было такой цели. Если была бы такая цель, то время бралось бы прямо в обработчике прерывания. Здесь же просто взводится флаг, а когда уж там до него онсновной loop доберётся ... вот то время и напечатается.

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

Если потенциальный новичок, отвечая на поставленный вопрос, скажет, что проблема в лишней функции isPressed и нужно просто проверить флаг в loop и сбросить его если true, будет ли он прав?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

ЕвгенийП пишет:

И что? Переменная buttonState станет true и будет обработана при следующем обращении к isPressed.

Я так понимаю что он ведет речь о том что если она и так true, а приходит второе нажатие.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

VladimirTsibrov пишет:

Если потенциальный новичок, отвечая на поставленный вопрос, скажет, что проблема в лишней функции isPressed и нужно просто проверить флаг в loop и сбросить его если true, будет ли он прав?

1. Смотря как он это напишет (ту же неатомарность можно допустить хоть в функции, хоть без неё)

2. Не сомневаюсь, что Вы это знаете не хуже меня. Зачем такой вопрос? Или он был не мне?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Komandir пишет:

Я так понимаю что он ведет речь о том что если она и так true, а приходит второе нажатие.

Ну, если так, то это троллинг. Это был простой пример с кнопкой без дребезга, а не с сигналом в пару гигагерц. 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ой! Утро всем. Чет тока проснулся. Фодка с валокордином - потрясающий эффект!...нНо - к делу!

Очем это я? А, вот: я, в отличии от нашего коллеги с соответствующим ником - логик настоящий, а не "каску на стройке нашел". Логик я математический, "у меня и справка есть" (с).

==================================

режим зануды - ВКЛ.

Так вот с точки зрения логики у нас есть две задачи:

1. обработать каждое нажатие;

2. не обрабатывать дважды.

Пропуски возникают в трех случаях:

1. еще не обработали одно и случилось другое;

2. сами отказались от обработки;

3. запретили регистрацию событий.

П 3. - неактуален, так как в нашем случае события защелкиваются (особенность способа фиксации).

П 1. - в нашем случае игнорируется, так как особенность системы (человек) не может генерить события чаще раз в 3-5 мс.

Остался  п.2. Почему такое может происходить:

ОШИБКА, заложенная ЕвгениемП в задачу, состоит в том, что нельзя ставить пометку "исполнено" не будучи уверенным, что действительно исполнено. Решением является как запрет всех или части прерываний, или, что гораздо ценнее педагогически, вариант с присвоением флагу false ИСКЛЮЧИТЕЛЬНО, если result установлен в true.

То есть мы устанавливает отказ в обработке, только если обработка произошла (точно произойдет).

Мой личный совет новичкам: не мешать мух и котлеты. То есть заводить отдельный флаг для проверки на первичность/вторичность обработки - классический isFirst, "как учили в автошкле".  В примере корень ошибки в том, что "лирический герой" задачи решил "сделать красиво" и не использовать isFirst. Хотя помечать событие, как обработанное, нас учат - в обработчике. Тут же это сделано заранее, но неправильно.

Истиное решение - от Андриано, запрет прерываний - в случае прерывания по фронту на АВР - тоже решение.

=================================================

режим зануды - ВЫКЛ.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

wdrakula пишет:

Вкратце это пошло от ПИКов. ...

Это про другое. Ты про выбор инструмента под задачу, а я про вечный спор дураков по то, кто масдай, а кому лонг лайф ту.

Примерно также как с делэй. Грамотные люди понимают где и что применимо, и используют то, что удобно в данный момент, а дураки слышали где-то, что делэй - бяка и сделали "писать без делэй" целью, а не средством.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Komandir пишет:

Я так понимаю что он ведет речь о том что если она и так true, а приходит второе нажатие.

Ну, если так, то это троллинг. Это был простой пример с кнопкой без дребезга, а не с сигналом в пару гигагерц. 

выше спрашивал, почему нельзя просто считывать в лупе, выводить в сериал, сбрасывать флаг...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

Логик я математический, "у меня и справка есть" (с).

Вчерась слушал длинющий и зануднейший спич про динамические системы поддержки принятия решений. Автор всё упирал на многозначные (вплоть до "счётнозначных") логики. Через час этой пытки, я сдуру решил его потроллить и скромно сросил: "А нельзя ли здесь применить непрерывные логики? Заодно, при случае, чё-нить проинтегрировать можно будет?". Как я потом пожалел - это было ещё на час. Остальные слушатели меня тихо ненавидели :(

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

выше спрашивал, почему нельзя просто считывать в лупе, выводить в сериал, сбрасывать флаг...

Как именно? Если так, как в #14, то можно, конечно.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:
Автор всё упирал на многозначные (вплоть до "счётнозначных") логики. Через час этой пытки, я сдуру решил его потроллить и скромно сросил: "А нельзя ли здесь применить непрерывные логики?

Ща... поем немного и тоже чуть позанудствую на эту тему... совсем немного, не на час! ;)

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

ЕвгенийП пишет:

VladimirTsibrov пишет:

Если потенциальный новичок, отвечая на поставленный вопрос, скажет, что проблема в лишней функции isPressed и нужно просто проверить флаг в loop и сбросить его если true, будет ли он прав?

1. Смотря как он это напишет (ту же неатомарность можно допустить хоть в функции, хоть без неё)

2. Не сомневаюсь, что Вы это знаете не хуже меня. Зачем такой вопрос? Или он был не мне?

Не конкретно Вам. В принципе интересна реакция форумчан: давить на неатомарное выполнение кода (ua6em кстати подобный фрагмент уже привел и Вы уже ответили в #75) или согласиться, что его прерывание и потеря нажатия все-таки невоможны. Речь ведь о кнопке, нажимаемой человеком.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Как то так:

static volatile bool buttonState = false;

void processButton(void) {
   buttonState = true;
}

//
// Возвращаем текущее значение buttonState
// а саму её делаем false, чтобы не обработать 
// тоже самое нажатие дважды
//
static bool isPressed(void) {
   const bool result = buttonState;
   buttonState = false;
   return result;
}

void setup(void){
   Serial.begin(57600);
   Serial.println("Fun begins!");
   pinMode(2, INPUT_PULLUP);
   attachInterrupt(0, processButton, FALLING);
}

//
// Если клавиша была нажата, печатаем время,
// когда мы об этом узнали.
//
void loop(void) {
boolean _isPressed=isPressed();
   if (_isPressed) {
      Serial.print("Button is pressed: ");
      Serial.println(millis());
   }
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Kakmyc пишет:

Как то так:

Вы это запускали? Запустите :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

ua6em пишет:

выше спрашивал, почему нельзя просто считывать в лупе, выводить в сериал, сбрасывать флаг...

Как именно? Если так, как в #14, то можно, конечно.

начинающий по другому наверное и не будет писать...

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Хотя не, фигня.

Вот так надо:

static volatile bool buttonState = false;

void processButton(void) {
   buttonState = true;
}

//
// Возвращаем текущее значение buttonState
// а саму её делаем false, чтобы не обработать 
// тоже самое нажатие дважды
//
static bool isPressed(void) {
   const bool result = buttonState;
  // buttonState = false;
   return result;
}

void setup(void){
   Serial.begin(57600);
   Serial.println("Fun begins!");
   pinMode(2, INPUT_PULLUP);
   attachInterrupt(0, processButton, FALLING);
}

//
// Если клавиша была нажата, печатаем время,
// когда мы об этом узнали.
//
void loop(void) {
   if (isPressed()) {
      Serial.print("Button is pressed: ");
      Serial.println(millis());
buttonState=false;
   }
}

 

 

Для чего вообще функция isPressed(), для объема кода ?

Или что бы было где ошибиться ?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

А почему дискуссия продолжается? Я ж вроде изложил всё? Или это уже самостоятельная стихия? ;))

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

2ЕвгенийП:

Если интересно, то немного про всякие экзотные "логики".

После того, как была сформулирована и доказана теорема Гёделя о неполноте, стало ясно, что что-то интересное может быть лишь в противоречивых теориях. А значит нужно их как-то делить на бред и не бред.

Можно оставить бинарность и разделать теории по длине вывода  лжи, "сложности" в том или ином мсысле.

Можно ввести градации той самой "правды" или "лжи", по сложности формального вывода или опровержения.

Логические операции в этих случаях строятся замыканиями булевых. Как следствие - не все, кажущиеся естественными, построения выдерживают испытание на согласованность

-------------------

Я к чему это рассказал? К тому, что смотреть на все эти построения нужно с конструктивной точки зрения, а не как на пустое желание повыпендриваться.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:
смотреть на все эти построения нужно с конструктивной точки зрения, а не как на пустое желание повыпендриваться.

Так вчера так и было. Задача-то как стояла: имеется множество фактов, необходимо строить частичные теории (непротиворечивые системы утверждений) из которых все имеющиеся факты логически  следовали бы. Причём вся эта система динамическая в том смысле, что если добавить ещё ведро фактов, множество теорий должно адаптироваться, чтобы все факты по прежнему из него следовали. Собственно, именно такая задача обсуждалась.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Kakmyc пишет:

Для чего вообще функция isPressed(), для объема кода ?

Или что бы было где ошибиться ?

Есть такой подход - эквивалентность сущностей: всякой сущности в предметной области должна соответсвоввать одна и только одна сущность программы. Это здорово выручает в "средних и крупнее" проектах, а при современных средствах разработки, обходится бесплатно.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ЕвгенийП пишет:

 всякой сущности в предметной области должна соответсвоввать одна и только одна сущность программы. Это здорово выручает в "средних и крупнее" проектах, а при современных средствах разработки, обходится бесплатно.

Это да.  А иначе можно получить лопатой по спине и трудовую книшку вдогонку. 

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Поделитесь препаратами :-)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DetSimen пишет:

ЕвгенийП пишет:

 всякой сущности в предметной области должна соответсвоввать одна и только одна сущность программы. Это здорово выручает в "средних и крупнее" проектах, а при современных средствах разработки, обходится бесплатно.

Это да.  А иначе можно получить лопатой по спине и трудовую книшку вдогонку. 

Жестоко там у вас )))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Честно говоря, первая мысль после прочтения исходного сообщения - запретить прерывания. Но IMHO можно обойтись и исключительно логикой:

static bool isPressed(void) {
   if(result = buttonState)
     buttonState = false;
   return result;
}

вот хоть стреляй, не могу понять, почему именно такая конструкция не пропустит нажатие кнопки, если прерывание произошло после присвоения переменной result значения true но до присвоения buttonState = false, оно отработает, то есть два нажатия кнопки будет отработано как одно, в чём я не прав?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ua6em пишет:

вот хоть стреляй, не могу понять, почему именно такая конструкция не пропустит нажатие кнопки, если прерывание произошло после присвоения переменной result значения true но до присвоения buttonState = false, оно отработает, то есть два нажатия кнопки будет отработано как одно, в чём я не прав?

Вы правы.

Вот только НИКАКОЙ код не может гарантировать обработку всех сигналов, если последние поступают чаще, чем МК способен их обрабатывать.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Вам бы ребята Флудильню завести... Там и будите «писюнами меряться». А из того что выше написано с новичку процентов 15 полезной информации и то «почитать». Все же песочница....

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

BOOM пишет:

Вам бы ребята Флудильню завести... Там и будите «писюнами меряться». А из того что выше написано с новичку процентов 15 полезной информации и то «почитать». Все же песочница....

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

Green
Offline
Зарегистрирован: 01.10.2015

andriano пишет:

Вот только НИКАКОЙ код не может гарантировать обработку всех сигналов, если последние поступают чаще, чем МК способен их обрабатывать.

Если поступают часто и много). При двойном прерывании и в случае возникновения второго прерывания в критический момент, это прерывание не будет потеряно при cli()/sei(). Только применительно к кнопке вся эта возня и нафиг не нужна.)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

andriano пишет:

Вот только НИКАКОЙ код не может гарантировать обработку всех сигналов, если последние поступают чаще, чем МК способен их обрабатывать.

Если поступают часто и много). При двойном прерывании и в случае возникновения второго прерывания в критический момент, это прерывание не будет потеряно при cli()/sei(). Только применительно к кнопке вся эта возня и нафиг не нужна.)

в этом конкретном случае, когда прерывание оперирует с переменной - да, а с реальными импульсными сигналами, увы нет

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

VladimirTsibrov пишет:

Можно отдельную тему создать: "найди ошибку в коде". Для интересных и неочевидных моментов.

Я, кстати, серьезно. При условии что наберется материал для темы. Могу предложить пример с прерыванием и многобайтной переменной:

volatile int val = 1000;

void setup() {
  Serial.begin(9600);
  TIMSK2 = (TIMSK2 & B11111110) | 0x01;
  TCCR2B = (TCCR2B & B11111000) | 0x07;
}

void loop() {
  int a = val;
  if (abs(a) != 1000)
    Serial.println(a);
}

ISR(TIMER2_OVF_vect) {
  val = -val;
}

Значение переменой изменяется в обработчике. В данном случае мы просто меняем знак и не ожидаем значений кроме 1000 и -1000. Но в монитор порта почему-то выводится число 792...

 

 

Green
Offline
Зарегистрирован: 01.10.2015

Ну так теж самые яйца, вид сбоку.)

  cli();
  int a = val;
  sei();

 

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

Не соглашусь.

wdrakula пишет:

ОШИБКА, заложенная ЕвгениемП в задачу, состоит в том, что нельзя ставить пометку "исполнено" не будучи уверенным, что действительно исполнено. Решением является как запрет всех или части прерываний, или, что гораздо ценнее педагогически, вариант с присвоением флагу false ИСКЛЮЧИТЕЛЬНО, если result установлен в true.

Здесь же упор именно на невозможность атомарного доступа к многобайтной переменной без использования специальных конструкций.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

VladimirTsibrov пишет:

Не соглашусь.

Здесь же упор именно на невозможность атомарного доступа к многобайтной переменной без использования специальных конструкций.

Хренукций. Boolean - однобайтный тип.  Не нужно со мной спорить. Вообще никогда. Женя позволяет с собой спорить - он демократ (он оценит шутку). А я - нет.

VladimirTsibrov
Offline
Зарегистрирован: 05.03.2019

wdrakula

Вам нужно либо перечитать последние сообщения, либо пояснить своё, в каком месте я спорю

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

VladimirTsibrov пишет:

wdrakula

Вам нужно либо перечитать последние сообщения, либо пояснить своё, в каком месте я спорю

Так ты уже про другую задачу? Сорри тогда.

Чот я не с той ноги встал и "чувствую себя не всего" (с). Прости уж тогда.

------------------------------

Есть такое наблюдение, что если с утра мутит и вус ржавой железки во рту, то зачем, ЗАЧЕМ ты вчера жрал несвежие, немытые, ржавые железки?????