Arduino прекращает отправку данных на последовательный порт после длительного периода времени - PullRequest
9 голосов
/ 05 декабря 2011

Я использую устройство Arduino Uno rev2 в качестве постоянно подключенного устройства, которое иногда отправляет сигналы на ПК (Windows 7 x64).Код, скомпилированный с помощью программного обеспечения Arduino 1.0 от arduino.cc

Тема на arduino.cc, Arduino прекращает отправку данных в Serial после длительного периода времени

Souce code

Работает отлично, но иногда, по прошествии длительного времени, ПК перестает получать данные с устройства Arduino.Это не проблема программного обеспечения для ПК, так как все программное обеспечение (putty, telnet и т. Д.) Действует одинаково - я могу отправлять данные в Arduino (устройство реагирует на команды);Я просто не могу получить его обратно.

Подобная проблема была описана здесь в Последовательная связь прекращается после длительных периодов. , но решение не было предложено.

Отключение / подключение устройства временно решило проблему, но это не может быть решением, поскольку устройство предполагается использовать постоянно и полностью автоматически.

Использование кнопки сброса платы, которая сбрасывает программу ивсе значения для начала не помогут.Данные не начинают получать на ПК.

Примечания:

  1. Ошибка при опрокидывании millis () не воспроизводится на плате Arduino Uno с программным обеспечением Arduino 1.0 - думаю, это исправлено, и теперь millis () действительно выполняет опрокидываниетолько через 50 дней, как сказано в документации.Кроме того, код имеет миллис () независимый код , который тоже не отвечает.

  2. Светодиод, который мигает при отправке данных на ПК, продолжает мигать.

  3. Использование строк может увеличить использование памяти, но эта программа слишком мала для этой проблемы.Никакая дополнительная память не использовалась после 10+ часов работы программы, поэтому я не собираюсь заменять Strings чем-то другим, поскольку проблема последовательного порта гораздо более серьезная.

Если вы считаете, что проблема связана с ошибкой программы arduino, подумайте, как объяснить, что мигание TX и сброс не помогают.

Ответы [ 4 ]

2 голосов
/ 23 мая 2015

Возможно, после сброса программного обеспечения ваша проблема будет решена. Я запустил следующий код, чтобы узнать, сбросит ли программный сброс часы и, следовательно, функцию millis():

void setup()
{
  Serial.begin(9600);
  Serial.println("Will start sending millis values in 5 seconds...");
  delay(5000);
}

void loop()
{
  Serial.println(String(millis()));

  if (Serial.available() > 0)
  {
    if (Serial.read() == '@')
    {
      Serial.println("Rebooting. . .");
      delay(100); // Give the computer time to receive the "Rebooting. . ." message, or it won't show up
      void (*reboot)(void) = 0; // Creating a function pointer to address 0 then calling it reboots the board.
      reboot();
    }
  }
}

Как объяснено в коде, для перезагрузки программного обеспечения просто создайте указатель функции на адрес 0 и вызовите его. У меня действительно были удовлетворительные результаты:

Will start sending clock values in 5 seconds...
5000
5000
5000
5001
5001
5001
5002
5002
5002
. . .
6804
Rebooting...
Will start sending millis value in 5 seconds...
5000
5000
5000
5001
5001
5001
5002
5002
5002
5003
5003
. . .

Надеюсь, это решит вашу проблему:)

0 голосов
/ 16 апреля 2017

Arduino через несколько часов не может выполнять команды от Arayks и TX 900 с проводом, но после перезапуска Arduino включен.

0 голосов
/ 09 декабря 2011

Вполне возможно, что часы складываются.

previousclock = millis () может застрять в высоком значении непосредственно перед сворачиванием.Вы можете расширить тест, включив в него случай, когда (currentmilis

BTW. Использовался исходный код игнаса (исходный код OP не читался без регистрации, и я не хочузарегистрировать)

РЕДАКТИРОВАТЬ: Я скопировал фрагмент ниже из wakkerbot, и немного отредактировал его.Это просто для демонстрации того, как с помощью wraparound ваши метки времени last_action застряли в верхней части интервала int (если значение bump не является делителем для int_max). Возможно, вы могли бы немного упростить логику выше / ниже, так как вас интересует тольковнутренние / внешние интервальные испытания.Конечно, typedef для Stamp должен быть адаптирован к типу millis () (unsigned long?) И fakemillis (), а ссылки на него заменены на millis ().

#include <stdio.h>

#define STAMP_INSIDE 0
#define STAMP_BELOW -1
#define STAMP_ABOVE 1
#define STAMP_BEYONDO -1

    /* Intentionally very small, for fast wraparound
    ** Intentionally signed to stress test the logig.
    */
typedef signed char Stamp;

    /* fake clock, returns incrementing value, but folds around
    */
Stamp fakemillis(void)
{
static Stamp ticker =0;
return ticker++;
}

/* Check if "test" is inside or above/below the interval {low,high}
** low and high may have been wrapped around zero (--> low > high)
** return
**      0 := "test" inside interval
**      1 := "test" below interval
**      -1 := "test" above interval (but wrapped)
** The two impossible cases return -2.
*/
static int check_interval(Stamp low, Stamp high, Stamp test)
{
switch (4 *(high >= low)
        +2 *(test >= low)
        +1 *(test > high)
        ) {
        case 0: return STAMP_INSIDE;    /* inside (wrapped) */
        case 1:                 /* outside (wrapped) */
                return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
        case 2: break;      /* impossible */
        case 3: return STAMP_INSIDE;    /* inside (wrapped) */
        case 4:                 /* all below */
                return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
        case 5: break;      /* impossible */
        case 6: return STAMP_INSIDE;    /* inside normal case */
        case 7:                 /* all above) */
                return ((Stamp)(low - test) < (Stamp)(test - high)) ? STAMP_BELOW : STAMP_ABOVE;
        }   
return STAMP_BEYONDO;
}   

    /* Get new clock value, test if it is inside interval {*old, *old+width)
    ** iff inside: return STAMP_INSIDE;
    ** iff above (or below) return STAMP_ABOVE or STAMP_BELOW
    ** and UPDATE *old
   */
static int test_or_set(Stamp *old, Stamp width)
{
Stamp tick;
int diff;
tick = fakemillis();

diff = check_interval( *old, *old+width, tick);
if (!diff) return 0;
*old = tick;
return diff;
}


int main(void) {
Stamp goodlast=0;
Stamp tick=0;
Stamp badlast=0;
int goodtest;
int badtest;
unsigned uu;

for (uu = 0; uu < 260; uu++) {
    tick= fakemillis();
    if (tick > badlast+10) { badlast=tick; badtest=1; } else {badtest =0;}
    goodtest = test_or_set ( &goodlast, 10);
    printf("%x:Tick=%x bad=%x, badtest=%d good=%x goodtest=%d\n"
    , uu, (unsigned) tick
    , (unsigned) badlast, badtest
    , (unsigned) goodlast, goodtest
    );
    }
return 0;
}

Если вы компилируете и запускаетевышеупомянутая программа на «нормальном» компьютере, вы можете увидеть, как плохое и самое плохое застревает.ИМХО, это то, что происходит и на вашем arduino.

Обновление: определенно переполнение / опрокидывание.(GIYF) http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200662708

Update2: не связано, но плохая практика кодирования:

#define CMD_SET_SPEED "S"
...
/* Internal configuration */
if(buffer.substring(0,1)==CMD_SET_SPEED) {
  updateSpeed(buffer.substring(1));
  }

Здесь вы сравниваете две строки.(это может быть обработано, как задумано c ++, но в C это просто неправильно. Я бы также предложил заменить повторяющийся if (...) {...} гигантским оператором switch, который по крайней мере избежал бы вызовафункция substr () многократно. (или она встроенная?)

ОБНОВЛЕНИЕ 20111211: здесь есть функция сравнения и установки, не требующая переноса, для которой требуется указатель на значение для сравнения и установки, иширина предполагаемого интервала:

int test_and_set_if_beyond( unsigned long *pprev, unsigned long width )
{
unsigned long tick, low,high;
low = *pprev;
high = low+width;
tick = millis();

if (low < high) {
    if (tick >= low && tick < high ) return 0; /* normal case */
    }
else { /* interval is wrapped , clock could have wrapped */
    if (tick >= low || tick < high) return 0;
    }
*pprev = tick;
return 1;
}

Эта функция используется в разделе loop () следующим образом:

if (test_and_set_if_beyond ( &lightTimer, lightnessCheckPeriod)) {
    int newLightness = analogRead(brightnessPin);
    if(newLightness-lightness > LIGHT_TRESHOLD) {
      say(RESPONSE_FLASH);
    }
    lightness = newLightness;
  }
  if (test_and_set_if_beyond ( &pingTimer, pingTimerPeriod)) {
    say(RESPONSE_PING);
  }
  if (test_and_set_if_beyond ( &pingLEDTimer, pingTimerPeriod*2)) {
    digitalWrite(failPin, HIGH);
  }
  feed();

Наконец: ИМХО причина, по которой RESET не работает, заключается вчто не все глобальные переменные инициализируются в функции setup (). Кроме того: я думаю, что вам следует избавиться от String Thessies (есть ли GC во время выполнения?) и использовать вместо этого обычные символьные буферы.

0 голосов
/ 09 декабря 2011

Если вы постоянно опрашиваете Arduino, то в качестве обходного пути вы можете реализовать сторожевой таймер в Arduino, который будет сбрасывать Arduino, если он долгое время не выводил данные на ПК.Вы можете контролировать вывод Arduino TX, перенести его на другой входной вывод, использовать прерывание ... Смысл в том, чтобы сбросить сторожевой таймер после каждого действия TX.

...