Strip.clear() не очищает/отключает полосу NeoPixel после сброса ESP8266.
В приведенном ниже коде, который работает на WEMOS D1 (ESP8266), полоска NeoPixel включает 1 светодиод красного цвета, который перемещается слева направо, а затем справа налево, пока плата пытается подключиться к Wi-Fi в while (WiFi.status() != WL_CONNECTED)
цикл.
Если я удержу кнопку «SW», подключенную к контакту D7, и нажму кнопку сброса, код включит 7-сегментный дисплей, однако светодиод на полоске NeoPixel, который светился последним, останется включенным (как будто он «замороженный»). Как только я выхожу из цикла while(configRPM > 0){
, все возвращается в норму, и полоса NeoPixel размораживается.
Я думал, что strip.clear()
очистит полосу NeoPixel в начале setup()
, но, похоже, это не сработало. Я думал, что добавление задержки может исправить это, но это не так. Почему полоска NeoPixel не выключается при перезагрузке платы и как это исправить?
Вот код:
#include <ESP8266WiFi.h> // Подключаем библиотеку ESP8266WiFi.
#include <ELMduino.h> // Подключаем библиотеку ELMduino.
#include <Adafruit_NeoPixel.h> // Подключаем библиотеку Adafruit NeoPixel.
#include <Encoder.h>
#include <TM1637Display.h>
#include <EEPROM.h>
// Определите адреса, по которым вы хотите хранить переменные в EEPROM
#define ADDR_MINIMUMRPM 0
#define ADDR_MAXIMUMRPM (ADDR_MINIMUMRPM + sizeof(int))
#define CLK D1
#define DT D2
#define SW D7
#define CLK_TM1637 D5
#define DIO_TM1637 D6
TM1637Display display(CLK_TM1637, DIO_TM1637);
Encoder encoder(CLK, DT);
int configTriggered = 0;
int buttonReleased = 0;
int configRPM = 0;
int minimumRPM = 2500;
int maximumRPM = 6000;
int currentPosition = minimumRPM - 100;
int oldPosition = -1000;
int newPosition = 0;
// Учетные данные Wi-Fi и сведения о сервере
const char* ssid = "WIFI_OBDII"; // Установите SSID ELM327.
WiFiClient client; // WiFiClient — это класс, определяющий, как создавать объекты, представляющие клиентов Wi-Fi. client — объект этого класса, позволяющий ESP8266 работать как клиент WiFi.
ELM327 myELM327; // Создает объект с именем myELM327 класса ELM327. Этот объект представляет собой экземпляр интерфейса ELM327 OBD-II, позволяющий программе взаимодействовать с ним, используя методы, предоставляемые классом ELM327.
const int neopixel_Count = 16; // Указывает, что в полосе имеется 16 NeoPixel с идентификаторами от 0 до 15.
Adafruit_NeoPixel strip(neopixel_Count, D8, NEO_GRB + NEO_KHZ800); // Инициализирует объект полосы NeoPixel с 16 NeoPixel, подключенными к выводу D2, используя порядок цветов Зеленый-Красный-Синий и частоту передачи данных 800 КГц.
const int potentiometer_Pin = A0; // Устанавливает постоянную переменную potentiometer_Pin в значение A0, которое является идентификатором аналогового контакта
int rpm = 0; // Переменная RPM, которая берется из автомобиля и используется в коде.
void setup() { // Функция настройки для инициализации NeoPixels и установления соединений Wi-Fi и ELM327.
pinMode(SW, INPUT_PULLUP);
Serial.begin(9600);
display.clear();
strip.begin(); // Инициализируем NeoPixels.
delay(100);
strip.clear(); // Инициализируем все пиксели как «выключенные».
EEPROM.begin(sizeof(minimumRPM) + sizeof(maximumRPM));
EEPROM.get(ADDR_MINIMUMRPM, minimumRPM);
EEPROM.get(ADDR_MAXIMUMRPM, maximumRPM);
if (digitalRead(SW) == LOW){
configRPM = 1;
display.setBrightness(0x0f); // Устанавливаем яркость на максимум
delay(50);
}
while(configRPM > 0){
if (digitalRead(SW) == HIGH) {
buttonReleased = 1;
delay(50);
}
if (digitalRead(SW) == LOW && buttonReleased == 1 && configRPM == 1) {
buttonReleased = 0;
configRPM = 2;
minimumRPM = currentPosition;
Serial.println("Value saved for minimum RPM is " + String(minimumRPM));
currentPosition = maximumRPM;
display.showNumberDec(currentPosition);
delay(50); // Задержка устранения дребезга
}
if (digitalRead(SW) == LOW && buttonReleased == 1 && configRPM == 2) {
buttonReleased = 0;
configRPM = 0;
maximumRPM = currentPosition;
Serial.println("Value saved for maximum RPM is " + String(maximumRPM));
display.clear();
EEPROM.put(ADDR_MINIMUMRPM, minimumRPM);
EEPROM.put(ADDR_MAXIMUMRPM, maximumRPM);
EEPROM.commit();
EEPROM.end();
delay(50); // Задержка устранения дребезга
}
newPosition = encoder.read();
if (newPosition != oldPosition) {
if (newPosition > oldPosition) {
currentPosition += 100; // Увеличение на 100 за каждый поворот по часовой стрелке
} else {
currentPosition -= 100; // Уменьшение на 100 за каждый поворот против часовой стрелки
}
// Ограничиваем текущую позицию в пределах от 0 до 9990
if (currentPosition < 0) {
currentPosition = 0;
} else if (currentPosition > 9900) {
currentPosition = 9900;
}
display.showNumberDec(currentPosition);
oldPosition = newPosition;
}
}
Serial.println("Connecting to " + String(ssid)); // Распечатываем SSID на последовательном мониторе.
WiFi.mode(WIFI_STA); // Установите режим Wi-Fi как «станция», где ESP8266 выступает в качестве клиента сети.
WiFi.begin(ssid); // Инициирует процесс подключения к сети Wi-Fi ELM327.
while (WiFi.status() != WL_CONNECTED) { // Пока статус Wi-Fi ESP8266 не подключен к сети Wi-Fi ELM327, выполните следующий код.
movePixels("right", neopixel_Count, 100); // Перемещение от самого левого светодиода к самому правому с задержкой в 100 миллисекунд.
movePixels("left", neopixel_Count, 100); // Переход от самого правого светодиода к самому левому с задержкой в 100 миллисекунд.
Serial.print("."); // Печать "." в последовательном мониторе.
}
Serial.println("\nConnected to Wifi. The IP address of the ESP8266 is: " + WiFi.localIP().toString()); // Распечатываем IP-адрес ESP8266.
if (!client.connect(IPAddress(192, 168, 0, 10), 35000)) { // Эта строка пытается подключить клиентский объект к серверу по IP-адресу 192.168.0.10 и порту 35000. Если соединение не удалось , он выполняет код внутри блока if.
Serial.println("Connection to ELM327 failed. Resetting and restarting the ESP8266."); // Если соединение не установлено, выведите эту строку.
ESP.reset(); // полностью сбрасывает микроконтроллер ESP8266, отключая его от любой сети Wi-Fi и перезапуская процесс настройки, определенный в функции setup().
}
myELM327.begin(client); // Инициализируем ELM327.
}
void loop() { // Функция цикла для непрерывного чтения RPM и обновления NeoPixels.
rpm = myELM327.rpm(); // Считаем число оборотов в минуту из ELM327.
if (myELM327.nb_rx_state == ELM_SUCCESS) { // Проверка состояния связи ELM327. В случае успеха сделайте следующее.
Serial.print("RPM: " + rpm); // Выводим число оборотов в минуту на последовательный монитор.
updateNeopixels(rpm); // Обновляем NeoPixels на основе RPM.
} else if (myELM327.nb_rx_state != ELM_GETTING_MSG) { // Проверяем, не получает ли ESP8266 в данный момент сообщение от ELM327.
myELM327.printError(); // Выводим ошибку ELM327, если связь не удалась.
}
}
void updateNeopixels(int rpm) { // Функция для обновления NeoPixels на основе RPM
strip.clear(); // Очистить все NeoPixels.
if (rpm >= 2500 && rpm < 5900) { // Если число оборотов в минуту находится между этими двумя значениями, сделайте следующее. Максимальное число оборотов в минуту для этого контура выше, поэтому все светодиоды становятся красными в диапазоне от 5800 до 5900.
// Указание количества светодиодов слева и справа для создания эффекта схождения.
int leftIndex = map(rpm, 2500, 5800, 0, neopixel_Count / 2 - 1); // Сопоставьте число оборотов в минуту от 2500 до 5800 с диапазоном от 0 до 7.
int rightIndex = neopixel_Count - 1 - leftIndex; // Берем leftIndex из 15.
// Например, если число оборотов в минуту равно 5800, leftIndex = 7 и rightIndex = 8.
// Сопоставляем RPM с цветами
int red = map(constrain(rpm, 2500, 5800), 2500, 5800, 0, 255); // Сопоставление числа оборотов в минуту с количеством «красных» светодиодов. Чем выше обороты, тем больше красного.
int green = map(constrain(rpm, 2500, 5800), 2500, 5800, 255, 0); // Сопоставление числа оборотов в минуту с количеством «зеленого» свечения светодиодов. Чем выше число оборотов в минуту, тем меньше зеленого цвета.
// Например, если частота вращения равна 5800, красный = 255 и зеленый = 0. Это будет применяться ко всем горящим светодиодам.
// Левая часть полосы
for (int i = 0; i <= leftIndex; i++) { // Цикл увеличивает i на 1, пока i <= leftIndex, перемещаясь к правому концу полосы. i++ выполняется после завершения тела цикла.
strip.setPixelColor(i, strip.Color(red, green, 0)); // Устанавливаем цвет NeoPixel, соответствующий идентификатору i.
}
// Правая часть полосы (отражает левую сторону)
for (int i = neopixel_Count - 1; i >= rightIndex; i--) { // Цикл уменьшается на 1, пока i >= rightIndex, перемещаясь к левому концу полосы. i-- выполняется после завершения тела цикла.
strip.setPixelColor(i, strip.Color(red, green, 0)); // Устанавливаем цвет NeoPixel, соответствующий идентификатору i.
}
} else if (rpm >= 5900) { // Если число оборотов в минуту не менее 5900, сделайте следующее.
for (int i = 0; i < neopixel_Count; i++) { // Цикл увеличивает i на 1, пока i < neopixel_Count (16), поскольку вы не можете отправить одну команду для изменения цвета всех светодиодов.
strip.setPixelColor(i, strip.Color(255, 0, 255)); // Установите фиолетовый цвет каждого NeoPixel.
}
}
strip.setBrightness(map(analogRead(potentiometer_Pin), 0, 1023, 0, 255)); // Сопоставьте значение потенциометра с диапазоном яркости (0-255) и соответствующим образом установите яркость полосы. 1023 — максимальное значение, получаемое от аналого-цифрового преобразователя (АЦП).
strip.show(); // Обновляем полосу NeoPixel.
}
void movePixels(String direction, int numPixels, int delayTime) { // Функция для перемещения NeoPixels слева направо, а затем справа налево.
for(int i = 0; i < numPixels; i++) { // Цикл увеличивает i на 1, пока i < число пикселей (16).
int index;
if (direction == "right") { // Если направление равно 'right'...
index = i; // Установить индекс в i.
} else if (direction == "left") { // Если направление равно 'left'...
index = numPixels - 1 - i; // Установите индекс в numPixels (16) - 1 - i.
} else { // Обрабатываем ввод неверного направления (ни вправо, ни влево).
return; // Выход из функции без ответа.
}
strip.setPixelColor(index, strip.Color(255, 0, 0)); // Установите красный светодиод, который разделяет идентификатор индекса.
strip.setBrightness(map(analogRead(potentiometer_Pin), 0, 1023, 0, 255)); // Сопоставьте значение потенциометра с диапазоном яркости (0-255) и соответствующим образом установите яркость полосы. 1023 — максимальное значение, получаемое от аналого-цифрового преобразователя (АЦП).
strip.show(); // Обновляем полосу NeoPixel.
delay(delayTime); // Отрегулируйте задержку на основе значения потенциометра.
strip.setPixelColor(index, 0); // Выключаем светодиод в текущей позиции.
}
}
1 ответ
Лучший ответ:
Мы можем взглянуть на функцию clear()
внутри библиотеки Adafruit_Neopixel. В Adafruit_Neopixel.cpp вы можете найти строку 3396 (поиск по clear(void)
приведет вас туда):
void Adafruit_NeoPixel::clear(void) { memset(pixels, 0, numBytes); }
Это очень короткая функция. memset()
присваивает всем байтам в определенном диапазоне указанное значение. Таким образом, все байты в пикселях
будут установлены в ноль. Хотя это только внутренняя память библиотеки. Здесь нет никаких действий ввода-вывода, никакого кода, отправляющего данные в Neopixels.
Это означает: clear()
действует только на внутреннее представление полосы библиотеки, точно так же, как setPixel()
и его родственные элементы. Чтобы фактически отправить данные в Neopixels, вам все равно нужно вызвать strip.show()
, который затем берет внутреннее представление полосы библиотеки и отправляет данные через цифровой контакт с Neopixels.
Я хочу побудить людей изучить исходный код библиотек, которые они используют. Когда вы научитесь их читать, вы сможете получать быстрые ответы, даже не понимая фактической полной реализации библиотеки.
Большое спасибо за ваш ответ @chrisl, очень ценю!, @Lachlan Etherton
- ESP8266, похоже, убивает цикл while
- Напряжение меняется, но цифровой поток всегда HIGH
- Остановить мигание светодиодов
- ESP8266 — Отправка команды сброса программного обеспечения
- Интеграция 2 кнопок для включения и выключения светодиода.
- Код Arduino для управления 4 светодиодами с 4 кнопок
- Нужен ли подтягивающий/понижающий резистор для цепи светодиода кнопки?
- Как переназначить кнопку сброса Arduino
Я думаю, вам нужно вызвать «strip.show()» также при использовании очистки, @chrisl