Пинбол — бонусный счет «Все дорожки освещены» работает не так, как ожидалось.
Я пытаюсь построить (очень простой) автомат для игры в пинбол с помощью Arduino Uno. Эта часть кода определяет, когда мяч проходит 3 дорожки. Когда полоса пройдена, полоса активируется (laneState), начисляется балл (+10) и загорается светодиод.
Ожидаемый результат:
- Когда все 3 полосы освещены, присвойте оценку проезду по полосе (+10), назначьте бонусную оценку (+100), сбросьте все состояния полосы на 0 и переведите все светодиоды в положение НИЗКИЙ.
- Всего добавляется 110 баллов.
Фактический результат:
- Огни последней пройденной полосы снова становятся активными (хотя я отключил их все)
- Всего добавляется 120 баллов (вместо 110?)
Любые намеки на то, почему я вижу такое поведение, приветствуются!
Скетч и плату можно найти здесь: https://circuits.io/circuits/2739062 -poc-lane-passage-001/ Включите «Редактор кода» и включите последовательный монитор, чтобы увидеть результаты.
Дополнительная информация: Я рассматривал возможность использования прерываний, но здесь это не вариант (у Uno только 2 контакта для прерываний, мне нужно 3)
Спасибо!
РЕДАКТИРОВАТЬ: сюда также добавлен код:
// Результаты
int totalScore = 0;
const int lanePassageScore = 10; // 10 очков за прохождение полосы
const int allLaneActiveBonus = 100; // 100 баллов за активацию ВСЕХ полос
// Цифровые контакты для определения состояния кнопок
const int laneButtonPin[] = {2,3,4};
const int laneStateLedPin[] = {10,11,12};
// все три линии «неактивны» в начале игры
int laneButtonState[] = {0,0,0};
int lastLaneButtonState[] = {0,0,0};
int laneState[] = {0,0,0};
void setup() {
Serial.begin(9600); // для отладки
}
void loop() {
// определяем, были ли активированы полосы с 1 по 3
detectLaneButtonPassage(0); // Полоса 1
checkAllLanesLit();
detectLaneButtonPassage(1); // Полоса 2
checkAllLanesLit();
detectLaneButtonPassage(2); // Полоса 3
checkAllLanesLit();
Serial.println(totalScore); // для отладки
delay(5);
}
void detectLaneButtonPassage(int laneId){
// Проверяем состояние кнопки
laneButtonState[laneId] = digitalRead(laneButtonPin[laneId]);
if(laneButtonState[laneId] != lastLaneButtonState[laneId]){
if(laneButtonState[laneId] == HIGH){
// Кнопка полосы переводится в положение ВКЛ, переключает состояние полосы
if(laneState[laneId] == 0){
// полоса еще не была активной, теперь она становится активной
laneState[laneId] = 1;
digitalWrite(laneStateLedPin[laneId], HIGH);
rewardScore(lanePassageScore);
}else{
// полоса уже была активна, теперь она становится неактивной
laneState[laneId] = 0;
digitalWrite(laneStateLedPin[laneId], LOW);
rewardScore(lanePassageScore/2);
}
}
}
lastLaneButtonState[laneId] = laneButtonState[laneId];
}
void rewardScore(int score){
totalScore += score;
}
void checkAllLanesLit(){
// Проверяем, активированы ли ВСЕ полосы
if(laneState[0]==1 && laneState[1]==1 && laneState[2]==1){
// сбрасываем все кнопки и состояния
for(int laneId=0; laneId<=2; laneId++){
laneButtonState[laneId] = 0;
lastLaneButtonState[laneId] = 0;
laneState[laneId] = 0;
digitalWrite(laneStateLedPin[laneId], LOW); //Выключаем светодиод
}
rewardScore(allLaneActiveBonus);
}
}
@Cagy79, 👍3
2 ответа
Лучший ответ:
Из функции checkAllLanesLit()
необходимо удалить две строки кода:
laneButtonState[laneId] = 0;
lastLaneButtonState[laneId] = 0;
Объяснение:
Происходит следующее: detectLaneButtonPassage()
срабатывает как обычно. Затем запускается checkAllLanesLit()
и очищает флаг lastLaneButtonState
.
Программа снова повторяется, но кнопка полосы все еще нажата. Однако detectLaneButtonPassage()
срабатывает снова, поскольку lastLaneButtonState
был сброшен и отображается в программе как нарастающий фронт. Отсюда дополнительные 10 баллов.
Кстати, следующие две строки можно сократить до одной:
if(laneButtonState[laneId] != lastLaneButtonState[laneId]){
if(laneButtonState[laneId] == HIGH){
Приведенные выше строки кода обнаруживают нарастающий фронт. Они могут быть выражены как:
if(laneButtonState[laneId] && !lastLaneButtonState[laneId]){
Чтобы оператор if сработал, laneButtonState
должен иметь высокий уровень, а lastLaneButtonState
должен быть низким.
Похоже, проблема со временем.
В каком бы порядке вы ни нажимали кнопки в последнем, остается
горящим (и вы получаете дополнительные 10 баллов).
Я установил точку останова:
rewardScore(allLaneActiveBonus);
...и просто подождал секунду, а затем продолжил, и ваш код работал как положено.
Поэтому я думаю, что вы устанавливаете для всех строк НИЗКИЙ уровень в checkAllLanesLit()
, а затем имеете лишь небольшую задержку (5 мс) перед повторным циклом и проверкой (в этот момент кнопка все еще ВЫСОКАЯ) поскольку вы недостаточно быстро убрали с него палец) - в результате вы получаете дополнительные 10 очков и эта полоса снова освещается.
- avrdude ser_open() can't set com-state
- Float печатается только 2 десятичных знака после запятой
- ошибка: espcomm_upload_mem failed при загрузке скетча
- Печать массива байтов на экране последовательного монитора Arduino IDE
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
- Arduino IDE Отказано В Разрешении На Загрузку, Ubuntu
- Нет заголовочных файлов (.h) в Documents\Arduino\libraries\arduino_144469 с демонстрационным кодом
- Связь Arduino master/slave с использованием RS485
Я попробую это как можно скорее. Спасибо, что уже уделили время., @Cagy79
Работает идеально! Теперь имеет смысл не иметь этих строк. Я также еще не настолько опытен и эффективен в объединении двух строк кода в одну. Но я обязательно учту это на будущее! Еще раз спасибо!, @Cagy79