Код Arduino (на борту) работает очень медленно
Сталкиваясь с этим странным поведением время от времени, мой Arduino (UNO) работает очень медленно.
Поиск по этому вопросу ничего не прояснил, у большинства людей проблемы с самой IDE. Моя проблема связана с реальной платой.
Вот пример моего потока:
- Я компилирую & загрузите мой скетч, все хорошо
- первый запуск программы на плате кажется "быстрым"
- когда я начинаю "анимировать" неопиксели, они идут в 3-4 раза медленнее, чем должны
- Я коснусь платы, и анимация снова пойдет быстрее.
Вот клип, в конце вы увидите "медленность"
Тестовая среда:
Текущая среда:
Прикосновение почти такое же, как если бы я «добавил» статическое электричество с пальца на плату, она просыпается и ведет себя нормально.
Для вас, кому интересно (не связанное с этим), какую анимацию я делаю на неопикселях, я включаю 15 пикселей от 0 до 54. Как «эффект слайда».
(Я не использую задержку, только задержку (30) в цикле, остальные задержки основаны на millis()
)
Есть ли какая-либо общая информация/объяснение, объясняющее такое поведение, например, в электронике, особенно в платах arduino?
РЕДАКТИРОВАТЬ: я должен также добавить, что при печати журналов в последовательный монитор эта медлительность также влияет на выходные данные... они выглядят "медленными" по мере потока пикселей. Когда все работает нормально, я вижу, как пиксели меняются и регистрируются 50 раз в секунду (примерно), но в этом замедленном движении я вижу, как пиксели меняются и регистрируются около 20 раз в секунду. Полное удаление Serial
из кода не дает результата.
Код:
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#define LEFT_BLINK_IN 2
#define RIGHT_BLINK_IN 3
#define PIN 6
#define NUMPIXELS 54
Adafruit_NeoPixel leftLight = Adafruit_NeoPixel(NUMPIXELS, 6, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel rightLight = Adafruit_NeoPixel(NUMPIXELS, 10, NEO_GRB + NEO_KHZ800);
int leftBlinkCount = 0;
int rightBlinkCount = 0;
int PIXELTOSHOW = 20;
bool OEM_RIGHT_ON = false;
bool OEM_LEFT_ON = false;
int R_PIXEL = -1;
int L_PIXEL = -1;
int G_PIXEL = -1;
int D_PIXEL = -1;
char LAST_COMMAND;
bool DRL_ON = false;
int DRL_STARTPIXEL = 35;
uint32_t COLOR_YEL = rightLight.Color(240, 120, 0);
uint32_t COLOR_RED = rightLight.Color(255, 0, 0);
uint32_t COLOR_BLU = rightLight.Color(0, 0, 255);
uint32_t COLOR_NON = rightLight.Color(0, 0, 0);
uint32_t COLOR_WHI = rightLight.Color(255, 255, 255);
unsigned long rightPrevMillis = 0;
unsigned long leftPrevMillis = 0;
unsigned long generalPrevMillis = 0;
const long PIXEL_SWITCH_INTERVAL = 5;
int DRL_RESETER_LEFT = 0;
int DRL_RESETER_RIGHT = 0;
void welcome()
{
int totalPixels = (NUMPIXELS + PIXELTOSHOW);
while (G_PIXEL < totalPixels) {
unsigned long leftCurrentMillis = millis();
if (leftCurrentMillis - leftPrevMillis >= 12) {
leftLight.setPixelColor(totalPixels - G_PIXEL, COLOR_WHI);
rightLight.setPixelColor(totalPixels - G_PIXEL, COLOR_WHI);
if (G_PIXEL >= 10) {
leftLight.setPixelColor(totalPixels - G_PIXEL + PIXELTOSHOW , COLOR_NON);
rightLight.setPixelColor(totalPixels - G_PIXEL + PIXELTOSHOW , COLOR_NON);
}
leftLight.show();
rightLight.show();
G_PIXEL++;
leftPrevMillis = leftCurrentMillis;
}
}
G_PIXEL = 0;
while (G_PIXEL < totalPixels) {
unsigned long leftCurrentMillis = millis();
if (leftCurrentMillis - leftPrevMillis >= 12) {
leftLight.setPixelColor(G_PIXEL, COLOR_WHI);
rightLight.setPixelColor(G_PIXEL, COLOR_WHI);
if (G_PIXEL >= 10) {
leftLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
rightLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
}
leftLight.show();
rightLight.show();
G_PIXEL++;
leftPrevMillis = leftCurrentMillis;
}
}
}
void blinkRight()
{
//slidePixels(rightBlinkCount, R_PIXEL, rightLight);
if (rightBlinkCount > 0 && R_PIXEL > -1)
{
//Serial.println("ПРАВО"+String(rightBlinkCount));
LAST_COMMAND = ' ';
unsigned long rightCurrentMillis = millis();
if (rightCurrentMillis - rightPrevMillis >= PIXEL_SWITCH_INTERVAL) {
rightLight.setPixelColor(R_PIXEL, COLOR_YEL);
if (R_PIXEL >= PIXELTOSHOW)
{
rightLight.setPixelColor(R_PIXEL - PIXELTOSHOW, COLOR_NON);
if (G_PIXEL > -1 && DRL_ON == false) {
leftLight.setPixelColor(R_PIXEL - PIXELTOSHOW, COLOR_NON);
}
}
leftLight.show();
rightLight.show();
R_PIXEL++;
rightPrevMillis = rightCurrentMillis;
}
if ( R_PIXEL >= (NUMPIXELS + PIXELTOSHOW)) {
rightBlinkCount--;
if ( rightBlinkCount > -1 ) {
R_PIXEL = DRL_RESETER_RIGHT = 0;
} else {
L_PIXEL = G_PIXEL = -1;
}
if(DRL_ON){
D_PIXEL=DRL_STARTPIXEL;
}
}
}
}
void blinkLeft() {
// slidePixels(leftBlinkCount, L_PIXEL, leftLight);
if (leftBlinkCount > 0 && L_PIXEL > -1)
{
//Serial.println("left"+String(rightBlinkCount));
LAST_COMMAND = ' ';
unsigned long leftCurrentMillis = millis();
if (leftCurrentMillis - leftPrevMillis >= PIXEL_SWITCH_INTERVAL) {
leftLight.setPixelColor(L_PIXEL, COLOR_YEL);
if (L_PIXEL >= PIXELTOSHOW)
{
Serial.print(" "+String(L_PIXEL));
leftLight.setPixelColor(L_PIXEL - PIXELTOSHOW, COLOR_NON);
if (G_PIXEL > -1 && DRL_ON == false) {
rightLight.setPixelColor(L_PIXEL - PIXELTOSHOW, COLOR_NON);
}
}
rightLight.show();
leftLight.show();
L_PIXEL++;
leftPrevMillis = leftCurrentMillis;
}
if ( L_PIXEL >= (NUMPIXELS + PIXELTOSHOW) ) {
leftBlinkCount--;
Serial.println("Count "+leftBlinkCount);
if ( leftBlinkCount > -1 ) {
L_PIXEL = DRL_RESETER_LEFT = 0;
} else {
L_PIXEL = G_PIXEL = -1;
}
if(DRL_ON){
D_PIXEL=DRL_STARTPIXEL;
}
}
}
}
/*void slidePixels(int &blinkCount, int &blinkPixel, Adafruit_NeoPixel &sideLight){
if (blinkCount > 0 && blinkPixel > -1)
{
LAST_COMMAND = ' ';
unsigned long leftCurrentMillis = millis();
if (leftCurrentMillis - leftPrevMillis >= PIXEL_SWITCH_INTERVAL) {
sideLight.setPixelColor(blinkPixel, COLOR_YEL);
if (blinkPixel >= PIXELTOSHOW)
{
if(G_PIXEL>-1){
rightLight.setPixelColor(blinkPixel - PIXELTOSHOW, COLOR_NON);
leftLight.setPixelColor(blinkPixel - PIXELTOSHOW, COLOR_NON);
}
}
rightLight.show();
leftLight.show();
blinkPixel++;
leftPrevMillis = leftCurrentMillis;
}
if ( blinkPixel >= (NUMPIXELS + PIXELTOSHOW) ) {
blinkCount--;
if ( blinkCount > -1 ) {
blinkPixel = 0;
} else {
blinkPixel = -1;
if(DRL_ON){
G_PIXEL = -1;
}
}
}
}
}*/
int switchRB = 0; // 0 = красный, 1 = синий
void slideBlueRed() {
unsigned long currentMillis = millis();
if (currentMillis - generalPrevMillis >= 100) {
if (switchRB == 0) {
leftLight.setPixelColor(G_PIXEL, COLOR_RED);
rightLight.setPixelColor(G_PIXEL, COLOR_RED);
} else {
leftLight.setPixelColor(G_PIXEL, COLOR_BLU);
rightLight.setPixelColor(G_PIXEL, COLOR_BLU);
}
if (G_PIXEL >= 10) {
leftLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
rightLight.setPixelColor(G_PIXEL - PIXELTOSHOW, COLOR_NON);
}
leftLight.show();
rightLight.show();
G_PIXEL++;
generalPrevMillis = currentMillis;
}
}
void drlLight(){
unsigned long currentMillis = millis();
if (D_PIXEL < NUMPIXELS) {
leftLight.setPixelColor(NUMPIXELS-DRL_RESETER_LEFT, DRL_ON == true ? COLOR_WHI : COLOR_NON);
rightLight.setPixelColor(NUMPIXELS-DRL_RESETER_RIGHT, DRL_ON == true ? COLOR_WHI : COLOR_NON);
rightLight.setBrightness(128);
leftLight.setBrightness(128);
rightLight.show();
leftLight.show();
D_PIXEL++;
//x //Serial.println(String(DRL_RESETER_LEFT) + " "+ String(NUMPIXELS - DRL_STARTPIXEL));
if(DRL_RESETER_LEFT+1 < (NUMPIXELS - DRL_STARTPIXEL)){
DRL_RESETER_LEFT++;
}
if(DRL_RESETER_RIGHT+1 < (NUMPIXELS - DRL_STARTPIXEL)){
DRL_RESETER_RIGHT++;
}
generalPrevMillis = currentMillis;
}
}
void setup() {
Serial.begin(115200);
leftLight.begin();
rightLight.begin();
pinMode(LEFT_BLINK_IN, INPUT);
pinMode(RIGHT_BLINK_IN, INPUT);
delay(50);
welcome();
}
void loop() {
if (digitalRead(LEFT_BLINK_IN) == HIGH) {
if ( OEM_LEFT_ON == false ) {
OEM_LEFT_ON = true;
leftBlinkCount++;
//Serial.println("LEFT"+String(leftBlinkCount));
if (leftBlinkCount == 1) {
L_PIXEL = 0;
}
}
} else {
OEM_LEFT_ON = false;
}
if (digitalRead(RIGHT_BLINK_IN) == HIGH) {
if ( OEM_RIGHT_ON == false ) {
OEM_RIGHT_ON = true;
rightBlinkCount++;
if (rightBlinkCount == 1) {
R_PIXEL = 0;
}
}
} else {
OEM_RIGHT_ON = false;
}
if(DRL_ON && leftBlinkCount < 1 && rightBlinkCount < 1){
drlLight();
}
blinkRight();
blinkLeft();
if(rightBlinkCount < 1 || leftBlinkCount < 1){
delay(30);
switch (LAST_COMMAND) {
case 'q':
case '?': {
for ( int gp = 0; gp < NUMPIXELS + PIXELTOSHOW; gp++) {
leftLight.setPixelColor(gp, COLOR_NON);
rightLight.setPixelColor(gp, COLOR_NON);
}
leftLight.show();
rightLight.show();
G_PIXEL = -1;
break;
}
case 's': {
slideBlueRed();
//Serial.println("bluuu");
if (G_PIXEL >= NUMPIXELS ) {
G_PIXEL = -1;
switchRB = switchRB == 0 ? 1 : 0;
}
break;
}
case 'w': {
welcome();
if (G_PIXEL >= NUMPIXELS + PIXELTOSHOW) {
G_PIXEL = -1;
}
break;
}
case 'd': {
if(DRL_ON==false){
D_PIXEL = DRL_STARTPIXEL;
DRL_ON = true;
LAST_COMMAND = '-';
}else{
D_PIXEL = 0;
DRL_ON = false;
}
break;
}
}
if (Serial.available()) {
LAST_COMMAND = '-';
while (Serial.available()) {
char command = Serial.read();
G_PIXEL=-1;
LAST_COMMAND = command;
}
}
}
}
@Deko, 👍3
Обсуждение2 ответа
Лучший ответ:
Такое поведение почти всегда вызвано плавающими цифровыми входными контактами. «Плавающий» означает, что они не подключены ни к питанию, ни к земле, поэтому их напряжение свободно плавает. Эти входы имеют очень высокий импеданс (обычно менее 1 мкА тока утечки), поэтому достаточно поднести к ним заряженный объект, чтобы изменить их состояние.
Возможно, самый простой способ устранить (а иногда и исправить) эту проблему — включить подтягивающие резисторы на цифровых входах.
В вашей программе это может быть простым изменением режима цифровых входных контактов с INPUT
на INPUT-PULLUP
...
void setup() {
Serial.begin(115200);
leftLight.begin();
rightLight.begin();
pinMode(LEFT_BLINK_IN, INPUT_PULLUP );
pinMode(RIGHT_BLINK_IN, INPUT_PULLUP );
delay(50);
welcome();
}
Это почти наверняка устранит прерывистое поведение, которое вы видите.
То, что вы получите в итоге, может быть не тем, что вы хотите (вы можете захотеть, чтобы вывод сбрасывался на 0, когда он не подключен), и в этом случае вы можете добавить внешний подтягивающий резистор или изменить программное обеспечение для работы с подтягиванием по умолчанию. -вверх.
Да, кажется, плавающий ввод вызывал такое поведение., @Deko
Теперь, спустя 3 года, я нашел настоящий источник вашей проблемы. У меня была похожая проблема, поэтому я пишу здесь, чтобы другие могли найти это решение.
Проблема в том, что библиотека NeoPixel отключает ВСЕ прерывания во время отправки данных пикселей. Функция millis() зависит от прерываний. Он работает путем увеличения счетчика один раз в миллисекунду на основе прерывания, вызванного аппаратным таймером. Если вы отключите все прерывания, счетчик не будет увеличиваться в течение всего времени.
Библиотека NeoPixel должна отключить их, потому что NeoPixel требует очень точной синхронизации сигналов, и в противном случае вы будете страдать от видимых прерывистых сбоев.
Счетчик millis() падает примерно на 30 микросекунд для каждого пикселя RGB или на 40 микросекунд для пикселя RGBW. У вас есть 54 пикселя RGB в вашей светодиодной ленте. 54*0,030 = 1,62 мс. Это означает, что между каждым из ваших обновлений millis() проходит 1,62 миллисекунды. Т.е. обновляется слишком медленно.
Ваша нестабильная кнопка, должно быть, просто вызвала непрерывные обновления неопикселей из-за какой-то логики в вашем коде.
Это не так легко исправить, но существует несколько специализированных альтернативных или сопутствующих библиотек, которые используют очень специфичные для устройства периферийные устройства, чтобы обойти эту проблему. Например, вы можете использовать один из аппаратных таймеров для измерения времени, затраченного на отправку данных NeoPixel, а затем вручную войти в систему и соответствующим образом обновить счетчик millis(), когда закончите. Для этого необходимо взломать библиотеку NeoPixel и прочитать спецификации для вашего конкретного процессора Arduino.
Спасибо, что вернулись с обновлением, вы определенно провели хорошее исследование! Слава!, @Deko
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
Кстати, не обращайте внимания на случай, когда 12 В и 3,3 В связаны вместе, кнопка может использоваться только для тестирования, а транзистор предназначен для использования в активных соединениях., @Deko
Эта схема полностью соответствует действительности? Особенно тот момент, когда у вас есть - источника 3,3 В, подключенного к контакту + 3,3 В Arduino?, @Majenko
На самом деле, извините, думал, что предыдущая схема была грязной, вот то, что было как в живом, так и в (одном) тестовом ENV. d.pr/i/BTxm У меня закончилось пробное время в тестовой лаборатории, и я не смог добавить грязную тестовую среду. Это подключение v3.3 напрямую к D2 с помощью перемычки., @Deko
Действительно ли R3 220 Ом или он больше?, @Majenko
Во всяком случае, теперь, когда я увидел схему, у меня появилось больше идей. Ваш код использует D3 для сдвига вправо или что-то в этом роде, да? У вас ничего не привязано к D3?, @Majenko
нет, я просто протестировал несколько резисторов, чтобы увидеть, как они себя ведут и работают (не моя сильная сторона, хе-хе). да, D2 для одной полосы нео пикселей, а d3 для другой полосы, но при тестировании я использую только по одному, в основном это d2, @Deko
Вам нужно удерживать неиспользуемый вход в известном состоянии (прижать его к земле), иначе он будет *плавать* и будет случайным образом срабатывать и улавливать окружающий шум — от таких вещей, как ваша рука, когда она рядом., @Majenko
аааааааа, в этом есть смысл, хотя я никогда не подозревал, что D3 вызывает это. Я проверю это завтра и добавлю ваше решение в качестве нового поста, чтобы сделать его ответом. и вам, кто отредактировал мой исходный пост с правильными изображениями, большое спасибо, я все еще ужасный нуб в встроенном кодировании переполнения/обмена, @Deko
Я думаю, что эти схемы помогли в конце концов. Спасибо за размещение этого вопроса. Я немного новичок в создании правильных цифровых схем, и я вижу, что совершаю подобную ошибку. Это облегчит распознавание., @GuitarPicker