Внешнее прерывание кнопки (цифровой вывод 3) Arduino не работает
Я пытаюсь выполнить прерывание внешней кнопки с помощью Arduino и буквенно-цифрового ЖК-дисплея 16*2. То, что я пытаюсь сделать, - это когда я нажимаю кнопку, экран должен переключаться между различными вариантами. Когда я нажал кнопку один раз, первая опция отображается на ЖК-дисплее, но при нажатии кнопки во второй раз экран остается прежним. Но код вводит другие условия, если, как я проверил с последовательным выходом, но он быстро переключается с нажатия 2 - 8 или около того за одно нажатие, а затем, когда я нажал снова, он переключается на 9, а при повторном нажатии переключается на 10. В чем может быть проблема? Код -
#include <LiquidCrystal.h>
const int rs = 12, en = 13, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
#define BUTTON
unsigned long int timer = 0;
uint8_t buttonState = 0;
uint8_t buttonPressNo = 0; // stores number of times button is pressed
uint8_t enter_flag = 1;
void setup()
{
Serial.begin(9600);
pinMode(BUTTON, INPUT);
attachInterrupt(digitalPinToInterrupt(BUTTON), button, RISING); // use interrupt 1 (pin 3) and run function
// wakeUpNow when pin 3 gets HIGH
lcd.begin(16, 2);
Serial.println(F("Setup done"));
}
void loop()
{
buttonPressNo += buttonState;
Serial.print(F("buttonState: "));Serial.println(buttonState);
Serial.print(F("buttonPressNo: "));Serial.println(buttonPressNo);
if(buttonPressNo == 1)
{
Serial.println(F("F1"));
if(enter_flag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print("Calib");
buttonState = 0;
Serial.println(F("F1"));
enter_flag = 0;
}
if(2-1 == 2)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
if(millis() - timer >= 10000)
{
reset();
}
}
else if(buttonPressNo == 2)
{
Serial.println(F("F2"));
if(enter_flag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print("scale");
buttonState = 0;
Serial.println(F("F2"));
enter_flag = 0;
}
if(2-1 == 2)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
if(millis() - timer >= 10000)
{
reset();
}
}
else if(buttonPressNo == 3)
{
Serial.println(F("F3"));
if(enter_flag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print("memory");
buttonState = 0;
Serial.println(F("F3"));
enter_flag = 0;
}
if(2-1 == 2)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
if(millis() - timer >= 10000)
{
reset();
}
}
else if(buttonPressNo == 4)
{
Serial.println(F("F4"));
if(enter_flag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print("surface");
buttonState = 0;
Serial.println(F("F4"));
enter_flag = 0;
}
if(2-1 == 2)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
if(millis() - timer >= 10000)
{
reset();
}
}
else if(buttonPressNo == 5)
{
Serial.println(F("F5"));
if(enter_flag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print("buzzer");
buttonState = 0;
Serial.println(F("F5"));
enter_flag = 0;
}
if(2-1 == 2)
{
Serial.println("1");
}
else
{
Serial.println("0");
}
if(millis() - timer >= 10000)
{
reset();
}
}
else
{
//delay(1000);
buttonState = 0;
Serial.println(F("no function"));
if(millis() - timer >= 10000)
{
reset();
}
}
}
void reset()
{
buttonState = 0;
buttonPressNo = 0;
enter_flag = 1;
Serial.println(F("reset done"));
Serial.flush();
}
// debouncing
void button()
{
buttonState = 0;
timer = 0;
while(1)
{
timer++;
if(timer > 100)
{
buttonState++;
timer = millis();
break;
}
}
}
@Robot, 👍0
Обсуждение2 ответа
Это не ответ, но он делает вашу программу намного меньше/удобнее в обслуживании.
- Сначала удалите
2-1 == 2
оператора if, которые всегда являются ложными (вероятно, это было для тестирования). - Переместите все дублированное содержимое в отдельную функцию (используя параметры для переменных элементов).
- Используйте
оператор switch вместо
if/else
. - Используйте последовательные имена для переменных (изменен enter_flag на enterFlag);
Код:
void loop()
{
buttonPressNo += buttonState;
Serial.print(F("buttonState: "));Serial.println(buttonState);
Serial.print(F("buttonPressNo: "));Serial.println(buttonPressNo);
switch (buttonPressNo)
{
case 1:
processMenu(F("F1"), F("Calib"));
break;
case 2:
processMenu(F("F2", F("Scale"));
break;
case 3:
processMenu(F("F3", F("Memory"));
break;
case 4:
processMenu(F("F4"), F("Surface"));
break;
case 5:
processMenu(F("F5"), F("Buzzer"));
break;
default:
{
//delay(1000);
buttonState = 0;
Serial.println(F("no function"));
if(millis() - timer >= 10000) // 2 mins timeout
{
reset();
}
}
}
void processMenu(char* button, char* title)
{
Serial.println(button);
if(enterFlag == 1)
{
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("T=");
lcd.setCursor(3, 1);
lcd.print(title);
buttonState = 0;
Serial.println(button);
enterFlag = 0;
}
if(millis() - timer >= 10000) // 2 mins timeout
{
reset();
}
}
Вы определили вывод кнопки как
#define BUTTON
Чего - то не хватает.
Просто заметка о написании кода.
Всегда обращайте внимание на то, что делает код, и старайтесь не повторять один и тот же код снова и снова.
Эти два фрагмента кода делают одно и то же.
if(buttonPressNo == 1) {
if(enter_flag == 1) {
Serial.println(F("F1"));
enter_flag = 0;
}
}
else if(buttonPressNo == 2) {
if(enter_flag == 1) {
Serial.println(F("F2"));
enter_flag = 0;
}
}
else if(buttonPressNo == 3) {
if(enter_flag == 1) {
Serial.println(F("F3"));
enter_flag = 0;
}
}
...
if(enter_flag == 1) { // это повторяется во всех блоках "если"
if(buttonPressNo == 1) {
Serial.println(F("F1"));
}
else if(buttonPressNo == 2) {
Serial.println(F("F2"));
}
else if(buttonPressNo == 3) {
Serial.println(F("F3"));
}
enter_flag = 0; // это повторяется во всех блоках "если"
}
Я действительно удивлен, что это компилируется тогда. Потому что при отсутствии половины define вызов pinMode становится pinMode( ,INPUT), и это должно привести к ошибке компиляции., @Delta_G
- Как прервать функцию цикла и перезапустить ее?
- Кнопка Отправить работает только при нажатии сразу после этого
- Программное обеспечение, устраняющее дребезг кнопки при отпускании
- Устранение дребезга кнопки с помощью прерывания
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Хорошая кнопка debouncing/Библиотека StateChange
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Остановить мигание светодиодов
у вас есть понижающий резистор на кнопке? что такое
таймер
? count или milliis()?, @JurajISR никогда не должен иметь блокирующий цикл while. Прерывание на самом деле не подходит для чего-то столь медленного, как нажатие кнопки. Гораздо лучше было бы просто прочитать кнопку в цикле и сохранить код цикла неблокирующим., @Delta_G
Вы ведь знаете, что миллис не считается во время ИСР, верно? Когда ваш код входит в прерывание, он отключает все остальные прерывания. Так что там многое перестает работать. Вот почему прерывания не являются хорошим пластырем для блокировки кода., @Delta_G
`таймер " - это только счетчик. и у меня есть понижающий резистор, подключенный к кнопке. Как я уже сказал, прерывание работает в первый раз, а затем не работает, и я подозреваю, что цикл while во всех случаях if может вызвать некоторую неисправность, @Robot
Итак, вместо прерывания я должен использовать вложенный цикл if?, @Robot
Вместо прерывания вы должны просто прочитать кнопку в функции цикла. Похоже, что в вашем цикле нет кода блокировки, поэтому, если вы не можете нажать и отпустить кнопку за пару микросекунд (для сравнения, моргание глазом занимает около 200 000 микросекунд), у вас нет шансов пропустить нажатие., @Delta_G
Используя вложенный цикл if, я смог реализовать многократное нажатие кнопки и переключение между настройками нажатием кнопки. Но иногда нажатие кнопки вообще не работает. Я должен оказать дополнительное давление на кнопку или нажать кнопку несколько раз, чтобы зарегистрировать одно нажатие кнопки. И иногда он получает 2 или более нажатий кнопок, когда я просто нажал кнопку один раз. Есть идеи?, @Robot