Использовать прерывания с аналоговыми выводами в Arduino или другое возможное решение?
У меня очень простая схема, но моя программа несколько сложна.
Вот принципиальная схема:
Вот код:
/*
01 - GND -------- GND
02 - +5V -------- 5V
03 - V0 -------- Potentiometer Middle
04 - Reset ------ 9
05 - Read/Write - GND
06 - Enable ----- 8
07 - Data0 ------ NC
08 - Data1 ------ NC
09 - Data2 ------ NC
10 - Data3 ------ NC
11 - Data4 ------ 10
12 - Data5 ------ 11
13 - Data6 ------ 12
14 - Data7 ------ 13
15 - +LCD ------- 5V
16 - -LCD ------- GND
*/
//подключаем библиотеку LCD
#include <LiquidCrystal.h>
//Инициализируем ЖК-объект
/*Pins should be mentioned in this order:
Reset
Enable
Data4
Data5
Data6
Data7
*/
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
int onTimePin = A0;
int onTime = 0;
int offTimePin = A1;
int offTime = 0;
int ledPin = 13;
void setup()
{
pinMode(onTimePin, INPUT);
pinMode(offTimePin, INPUT);
pinMode(ledPin, OUTPUT);
//Запускаем ЖК-интерфейс
lcd.begin(16, 2);
lcd.print("ON TIME : ");
lcd.setCursor(0, 2);
lcd.print("OFF TIME : ");
}
void loop()
{
onTime = map(analogRead(onTimePin), 0, 1023, 1, 3);
lcd.setCursor(11, 0);
lcd.print(onTime);
offTime = map(analogRead(offTimePin), 0, 1023, 1, 9);
lcd.setCursor(11, 1);
lcd.print(offTime);
digitalWrite(ledPin, HIGH);
delay(onTime * 1000);
digitalWrite(ledPin, LOW);
delay(offTime * 1000);
}
Приведенный выше код работает. Но есть небольшая проблема:
Когда я поворачиваю дворник потенциометра, происходит задержка.
Это очевидно, потому что после завершения цикла отображается измененное значение потенциометра. Итак, я решил сделать то же самое, используя прерывания. Но прерывания есть только у цифровых выводов.
Я хотел бы узнать решение по использованию прерываний на аналоговом входе.
@Vishal, 👍2
Обсуждение2 ответа
Лучший ответ:
Избегайте задержек
.
Очень упрощенная альтернатива:
unsigned long lastLedToggleTime;
unsigned long currentLedToggleInterval;
void loop() {
...
unsigned long now = millis();
if ( (now - lastLedToggleTime) > currentLedToggleInterval) {
lastLedToggleTime = now;
// Теперь нам нужно переключить светодиод.
if ( digitalRead( ledPin ) == LOW ) {
// Светодиод был НИЗКИМ, поэтому мы установили его ВЫСОКИЙ и настроили следующее переключение после onTime.
digitalWrite(ledPin, HIGH);
currentLedToggleInterval = (onTime * 1000);
} else {
// Светодиод был ВЫСОКИМ, поэтому мы установили его НИЗКИЙ и настроили следующее переключение после времени выключения.
digitalWrite(ledPin, LOW);
currentLedToggleInterval = (offTime * 1000);
}
}
...
}
Обратите внимание, что здесь мы имеем дело с 32-битными целочисленными значениями без знака, поэтому этот код будет работать, даже если/когда millis()
перейдет в 0. В частности, now - LastLedToggleTime
не только всегда будет возвращать положительное значение (поскольку оно приведено к беззнаковому типу данных), но также будет возвращать правильное значение из-за дополнения до двух. представление и арифметическое основание по модулю 2^32.
Пример: для простоты давайте посмотрим на 8-битное значение:
Скажем, lastLedToggleTime
находился на последнем такте 8-битного значения таймера, т.е. lastLedToggleTime == 255
. В следующем такте таймера now
переполнится до 0
, поэтому далее у нас будет now
- lastLedToggleTime
= 0 - 255 = -255. В дополнении до двух для представления этого значения потребуется (как минимум) 9 бит (двоичный код: 1 0000 0001
), но поскольку у нас есть только 8 бит памяти, бит знака (MSB) просто отбрасывается, в результате чего 0000 0001
двоичный = 1. Мы видим, что 1 — правильное значение. чтобы количество тиков изменилось с 255 до 0; это ровно один тик.
Ваше решение потерпит неудачу, когда millis()
перевернется. Хотя это может быть и не очень серьезная проблема, нет смысла сохранять эту ошибку, тем более что ее очень легко избежать. См. [Учебное пособие по Blink Without Delay Arduino](https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay), чтобы узнать, как правильно написать код., @Edgar Bonet
millis()
["переполнится (вернётся к нулю) примерно через 50 дней."](https://www.arduino.cc/en/Reference/Millis), @JimmyB
Вот почему я говорю: «Возможно, это не очень серьезная проблема». Но все же нет веской причины показывать ошибочный код в ответе, когда избежать ошибки _так просто_. Псевдокод на странице, на которую вы ссылаетесь, также верен., @Edgar Bonet
@EdgarBonet Вы заметили, что OP имеет как переменное, так и независимое время *включения* и *выключения*?, @JimmyB
@EdgarBonet Поскольку, похоже, вас это действительно беспокоит, я сейчас отредактировал предложенное вами решение., @JimmyB
Спасибо. Я проверил образец кода, и он работает нормально., @Vishal
@EdgarBonet Это также не удастся с кодом мигания без задержки. Как только millis() перейдет через вывод в приведенном примере, он больше никогда не станет ВЫСОКИМ. Оно останется низким. После прокрутки вы больше никогда не получите результат, превышающий *интервал*. Вам нужно абсолютное значение интервала... *abs(интервал)*, @Fred Hendricks
@FredHendricks, ты не понимаешь, что такое переворот. прочитайте https://arduinoprosto.ru/q/12587/how-can-i-handle-the-millis-rollover, @Juraj
@FredHendricks Обратите внимание, что здесь мы имеем дело с *беззнаковыми* 32-битными целыми числами, что означает, что мы неявно имеем арифметику по модулю. Вот почему now -lastLedToggleTime
всегда будет возвращать правильное значение, даже если lastLedToggleTime
больше, чем now
, потому что now
снова переполнился до 0., @JimmyB
Вы ищете плохое решение для простой проблемы. Как Игнасио
Васкес-Абрамс говорит, проблема в том, что вы используете delay()
. Самый простой
Решение — управлять таймингами с помощью millis()
. Смотрите Blink
Без задержки Arduino
учебник.
- Потенциометр 10 кОм против резистора 10 кОм на ЖК-дисплее
- ЖК-дисплей странные символы
- ЖК-дисплей не отображает текст
- Потенциометр отображает только аналоговое значение напряжения 1023 в proteus
- Изменить текст на LCD экране, вращая потенциометр?
- Печать string and integer LCD
- Как отобразить символ º на ЖК-дисплее?
- Отправка значения с одного Arduino на другой
Задержка происходит потому, что вы задерживаетесь., @Ignacio Vazquez-Abrams
Я бы поместил мигание светодиода в таймер (-прерывание). Или используйте технику, описанную в [моргайте без задержки](https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay)., @Gerben
@IgnacioVazquez-Abrams Я знаю, что есть задержка, и получаю ожидаемый результат. Короче говоря, я хочу, чтобы светодиод мигал в соответствии со значениями, заданными потенциометром., @Vishal