Arduino Serial print непомітно змінює поведінку програми


10

Я використовую лічильник циклу, оголошений у заголовку:

int loop_counter = 0;

Я використовую цей лічильник, щоб викликати подію так часто. Раніше я використовував модуль для такого ж типу поведінки, але я спростив його, так що з ним легше працювати (це все одно призводить до тієї ж поведінки)

void loop() {
    if(loop_counter > 100) loop_counter = 0;
    else loop_counter++;

    //Serial.println("hey");

    if(loop_counter == 0) {
         //do_something_important();
    }      
}

Все добре і добре, доки я не намагаюся спілкуватися Serial, не коментуючи //Serial.println("hey"); ( "hey"у цьому прикладі, бо, на мою думку, ця поведінка є абсурдною).

Це призводить до того, що loop_counterніколи не запускати do_something_important();розділ коду. Я спробував оголосити , loop_counterяк volatile, що нічого не змінилося. Я спробував Serial.printING loop_counter, і я також отримував дивну поведінку (це було б заморозити петлю). Serial.println("hey");працює в тому сенсі, що в послідовному моніторі я отримую багато "ей" (тобто швидко набагато більше 100 "хей", кількість ітерацій, при яких повинен запускатись інший розділ коду)

Що, можливо, може спричинити використання Serialданих, які не є (наскільки я можу сказати) прив'язаними, щоб loop_counterповністю перешкодити роботі належним чином?

EDIT : Ось частина основного файлу, яка постала перед проблемою (ну, доклавши до неї найбільше (використовуючи занадто багато пам'яті)):



void display_state() {
  int i,j,index=0;
  short alive[256][2];

 for(i=0;i<num_rows;i++) { 
   for(j=0;j<num_cols;j++) {
     if(led_matrix[i][j]==1) { 
       alive[index][0]=i;
       alive[index][1]=j;
       index++;
     }
   }
 }
 alive[index][0]=NULL; //Null-terminate.
 alive[index][1]=NULL;

 //383 is a great number
 for(int idx=0;idx < index; idx++) {
   display(alive[idx][0],alive[idx][1]);
   delayMicroseconds(283);
 }
}

Ось "літери.h":


    #ifndef _MY_LETTERS_H
    #define _MY_LETTERS_H

#define nrows 4
#define ncols 4

#define num_rows 16
#define num_cols 16

#define MAX_WORD_LENGTH 16
#define NUMBER_OF_CHARACTERS 26

#include <stdlib.h>

int loop_counter = 0 ; коротка led_matrix [ num_rows ] [ num_cols ];

const коротка літера_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, { 1 , 0 , 0 , 1 }, { 1 , 1 , 1 , 1 }, { 1 , 0 , 0 , 1 } }; const короткий letter_b [ nrows ] [ ncols ] = {{ 1 , 0 , 0 , 0 }, { 1 , 1 , 1 , 0 }, { 1 , 0 , 1 , 0 }, { 1 , 1 , 1 , 0 }}; Const короткого letter_c [ Nrows ] [ Ncols ] = {{ 0 , 1 , 1 , 1 }, { 1 , 0 , 0 , 0 }, { 1 , 0 , 0 , 0 }, { 0 , 1 , 1 , 1 }}; const короткий letter_t [ nrows ] [ ncols ] = {{ 1 , 1 , 1 , 1 }, { 0 , 1 , 0 , 0 }, { 0 , 1 , 0 , 0 }, { 0 , 1 , 0 , 0 } };

typedef struct letter_node { const short * data ; letter_node * далі ; int x ; int y ; } letter_node ;

letter_node aa = {&letter_a[0][0],NULL,1,1}; letter_node bb = {&letter_b[0][0],NULL,1,1}; letter_node cc = {&letter_c[0][0],NULL,1,1}; letter_node tt = {&letter_t[0][0], NULL , 1 , 1 };

letter_node letter_map [ NUMBER_OF_CHARACTERS ]; #endif

Ще трохи інформації: - Я використовую Uno (ATMega328)


Який розмір вашої стеки? Чи є ймовірність, що ви можете пофарбувати свій стек і побачити, чи він пошкоджується. Чи використовує серійний друк переривання, чи є ваш код?
Ktc

Послідовний друк не спрацьовує жодних переривань, я використовую його лише у loop()функції. Як слід фарбувати мій стек, якщо єдиний метод виводу, який у мене є ( Serial.print()), не відповідає мені?
eqzx

2
Щоб усунути можливі помилки та невірно зрозумілі побічні ефекти, здавалося б, тривіальних змін, будь ласка, замініть код у вашому запиті на буквальну, точно символьну копію ескізу, скороченого до мінімуму, необхідного для запуску проблеми . Не "це моя програма, яка виходить з ладу, якщо я ..", але саме мінімальна програма, яка виходить з ладу таким чином.
Кріс Страттон

Відповіді:


2

У мене також була схожа проблема з цією, і я впевнений, що ваш також не має місця, що стосується стека. Спробуйте максимально скоротити код.

У моєму випадку код інколи запускався б, коли у мене було серійне повідомлення, але тоді, здавалося б, він не запускався, коли я цього не робив. У мене також був випадок, коли надсилання послідовних повідомлень призведе до нескінченного скидання ардуїно.

Я також використовував arduino328. Ймовірно, вам слід зменшити розмір масиву, якщо у вас є найменший розмір, який є прийнятним.


дякую, ви і Дейв Твід отримали це. Я відновив функцію display_state (), щоб не потребувати цього додаткового розподілу. Я рідко роблю вбудовану обробку, гадаю, всі ми в якийсь момент повинні потрапити на стіну пам'яті!
eqzx

Привіт, у мене схожа ситуація. Я змінюю розмір масиву з 128 на 96, і моя програма працює чудово. Але я думаю, що ця проблема насправді не виходить налагоджувати, оскільки розмір мого масиву менший від розміру заявити стек. Чи знаєте ви, де я можу знайти інформацію для вирішення подібних проблем?
Лев Лай

4

Ваш код ініціалізує послідовний порт? Напр.

void setup()
{
    Serial.begin(9600);
}

Якщо цього не зробити, це може призвести до збоїв при першому використанні серіалу.


Так, я маю це.
eqzx

3

Можливо, у вас не вистачає пам’яті? Усі рядки, які ви друкуєте з Serial.print ("щось"), мають місце в SRAM, що дорівнює кількості символів цього рядка + 1 для термінатора \ 0. Можливо, не вистачає пам'яті, навіть якщо зібраний розмір вашого ескізу набагато менший, ніж флеш-пам'ять Arduino, тому що SRAM - це лише 2048 байт для Atmega328 і 1024 байт для Atmega 168. У мене була подібна проблема, яку я вирішив, скоротивши все тексти та видалення непотрібних повідомлень про налагодження.


Хм. У мене в оголошенні заголошено кілька багатовимірних масивів, можливо, в цьому проблема? Чи зберігаються вони в SRAM?
eqzx

1
@ nrhine1: У такому випадку ви, мабуть, мусите показати нам весь ваш ескіз, а не лише ті частини, де, на вашу думку, криється проблема.
Дейв Твід

@DaveTweed Так, зроблять.
eqzx

1
Я помічаю, що ви визначаєте багато місця зберігання у файлі заголовка, а не просто декларуєте його там (якщо ви не розумієте відмінності, див. Цю сторінку ). Це було б незвично в програмі С; це нормальна практика на Ардуїно? Можливо, у вас є кілька копій цих структур. Крім того, ви визначаєте деякі дуже великі автоматичні змінні, наприклад, "живий" масив у display_state (), якому потрібно понад 1024 байти простору стека. Я впевнений, що у вас просто не вистачає пам'яті.
Дейв Твід

@DaveTweed дякую, ви та Реза отримали це. Я відновив display_state()функцію, щоб не потребувати цього додаткового виділення. Я рідко роблю вбудовану обробку, гадаю, всі ми в якийсь момент повинні потрапити на стіну пам'яті!
eqzx

1

Ви не показали код, який ініціалізує змінну "loop_counter". Це поза програмою циклу () ?

Ви, можливо, це оголосили таким чином, що він примикає до іншої області зберігання пам'яті, яка працює за межами заявленого розміру, і це тріпотіння на змінну loop_counter?


Я намагався оголосити це різними способами, у багатьох різних місцях. У заголовку праворуч loop()тощо. Ви кажете, що Serial.print()метод може якось перезаписати його?
eqzx

Що я мав на увазі під попереднім коментарем, це те, що я майже впевнений, що я виділив «погану» поведінку до існування Serial.print (). Коли його там немає, справи працюють добре.
eqzx

@ nrbine1 - мені здається, що ваша глобальна змінна змінна "loop_counter" стає наступаючою методом Serial.print (), як я запропонував у своїй відповіді. У відповіді posipiet вас запитали, чи правильно ініціалізовано Serial-об'єкт. Якщо цього не було зроблено, це може пояснити "тромпінг" на вашому лічильнику, оскільки він Serial.print () намагається використовувати буфер, який не був належним чином розподілений та встановлений.
Майкл Карась

Я додав усе своє джерело.
eqzx

1

Я не бачу у вашому коді, куди ви телефонуєте loop(). Це також не схоже на те, що ви використовуєте loop_counterпоза цією функцією. Чи є причина, що ви оголошуєте це глобальним? Я припускаю, що це тому, що ви хочете, щоб він зберігав свою цінність між дзвінками. Ви можете зробити це за допомогою статичної локальної змінної .

void loop() {
    static int loop_counter = 0;

    if(loop_counter > 100)
    {
        loop_counter = 0;
    }
    else
    {
        loop_counter++;
    }

    Serial.println("hey");

    if(loop_counter == 0)
    {
         //do_something_important();
    }      
}

Це повинно переконатися, що ніякі інші зовнішні функції не можуть перешкоджати цьому. Ви завжди повинні оголошувати свої змінні в найменшому обсязі, щоб уникнути небажаної поведінки.

Якщо це не працює, вам потрібно буде по-справжньому проаналізувати використання пам'яті. Перевірте в цьому запиті EE.SE різні зразки коду, щоб зробити це в межах Arduino.


Я вже намагався зробити його статичним. Це не допомогло. Це інша ітерація. setup()і loop()це функції, які arduino виконує за замовчуванням, по- setup()перше, loop()друге. loop()по суті схожий main(), за винятком того, що він називається повторно. посилання: arduino.cc/en/Reference/loop Я перевірю це посилання.
eqzx

знову, як я вже згадував в інших коментарях, не можу налагоджувати Serial.print(). Схоже, мені доведеться виходити за межі звичайного processingIDE, якщо я хочу мати можливість використовувати GDB
eqzx

@ nrhine1 Ви сказали, що Serial.print()це добре працює в тому, що вона надрукувала багато "ей". Саме loop_counterце створює вам проблему. Спробуйте видалити if(loop_counter == 0)код і ввести його get_free_memory()(залишити loop_counterприріст) і запустити його. Це принаймні скаже вам, якщо у вас є якісь серйозні проблеми з розподілом пам'яті.
embedded.kyle

1

Серійна бібліотека програмного забезпечення Arduino використовує переривання. (див. "softwareSerial.cpp, .h"). У вас може виникнути проблема, коли ISR "наступає" на основний код (або навпаки). Спробуйте використовувати прапори блокування, щоб код чекав, поки завершиться операція друку.


0

Якось певний час тому у мене склалося враження, що у мене однакова проблема. Тоді я вирішив це, додавши затримку (1) перед або після serial.println. Це було з Arduino 0022 на Linux. Не впевнений, на якій дошці це було, ймовірно, серіал Boarduino. Неможливо відтворити і його.

В даний час він працює для мене на boarduino USB з Arduino 1.01 в Windows:

int loop_counter = 0;
int led = 13;

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);}

void loop() {
    if(loop_counter > 100) {
      loop_counter = 0;
    }
    else {
      loop_counter++;
    }

    Serial.println(loop_counter);

    if(loop_counter == 0) {
      Serial.println("hey hey orange, hey hey!");
    }      
}

Дякую за пропозицію. Це, на жаль, не вирішило проблему.
eqzx
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.