Печать Arduino Serial изменяет поведение программы нежелательно

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");работает в том смысле, что в мониторе Serial я получаю много «эй» (т. е. быстро намного больше, чем 100 «хей», количество итераций, при которых должен сработать другой раздел кода)

Что может быть причиной использования Serialданных, которые (насколько я могу судить) не связаны, чтобы loop_counterполностью помешать их нормальной работе?

РЕДАКТИРОВАТЬ : Вот часть основного файла, которая в конечном итоге создает проблему (ну, вкладывая в нее больше всего (используя слишком много памяти)):



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);
 }
}

Вот "letters.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;loop_counter = 0 ; короткий led_matrix [num_rows] [num_cols];короткий led_matrix [ num_rows ] [ num_cols ];

const short letter_a [nrows] [ncols] = {{0,1,1,0}, короткая буква_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, {1,0,0,1},{ 1 , 0 , 0 , 1 }, {1,1,1,1},{ 1 , 1 , 1 , 1 }, {1,0,0,1}};{ 1 , 0 , 0 , 1 }}; const short letter_b [nrows] [ncols] = {{1,0,0,0}, {1,1,1,0}, {1,0,1,0}, {1,1,1,0} };const short letter_b[nrows][ncols] = {{1,0,0,0},{1,1,1,0},{1,0,1,0},{1,1,1,0}}; const short letter_c [nrows] [ncols] = {{0,1,1,1}, {1,0,0,0}, {1,0,0,0}, {0,1,1,1} };const short letter_c [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 1 }, { 1 , 0 , 0 , 0 }, { 1 , 0 , 0 , 0 }, { 0 , 1 , 1 , 1 } }; const short letter_t [nrows] [ncols] = {{1,1,1,1}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0} };const short 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 * данные ; letter_node * next ; 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)

eqzx
источник
Каков ваш размер стека? Есть ли шанс, что вы сможете раскрасить свой стек и посмотреть, не испортился ли он? Использует ли Serial Print прерывания, ваш код повторяется?
Ktc
Серийная печать не вызывается никакими прерываниями, я использую ее только в loop()функции. Как мне нарисовать мой стек, если единственный метод вывода, который у меня есть ( Serial.print()), дает мне ошибку?
eqzx
2
Чтобы исключить возможные ошибки и неправильно понять побочные эффекты, казалось бы, тривиальных изменений, замените код в своем вопросе на буквально точную символьную копию эскиза, сокращенную до минимума, необходимого для возникновения проблемы . Не «это моя программа, которая терпит неудачу, если я ..», а именно минимальная программа, которая терпит неудачу таким образом.
Крис Страттон

Ответы:

2

У меня также была похожая проблема с этим, и я очень уверен, что у вас тоже не хватает стекового пространства. Попробуйте сжать код как можно больше.

В моем случае код иногда запускался, когда у меня было последовательное сообщение, но тогда, казалось бы, он не запускался, когда я этого не делал. У меня также был случай, когда отправка последовательных сообщений приводила к бесконечному сбросу arduino.

Я также использовал Arduino328. Вероятно, вам следует уменьшить размер вашего массива, если он у вас есть, до наименьшего приемлемого размера.

Реза Хуссейн
источник
спасибо, ты и Дэйв Твид получили это. Я реорганизовал функцию display_state (), чтобы не нуждаться в этом дополнительном выделении. Я редко выполняю встроенную обработку, я полагаю, что мы все должны в какой-то момент поразить стену памяти!
августа
Здравствуйте, у меня похожая ситуация. Я изменяю размер массива с 128 на 96, и моя программа работает нормально. Но я думаю, что эта проблема на самом деле не подходит для отладки, потому что размер моего массива меньше объявленного размера стека. Вы знаете, где я могу найти информацию для решения этой проблемы?
Лев Лай
4

Ваш код инициализирует последовательный порт? Например.

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

Невыполнение этого требования может привести к сбою при первом использовании сериала.

Тоби джеффи
источник
Да, у меня есть это.
eqzx
3

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

Erion
источник
Хм. У меня есть несколько многомерных массивов, объявленных в моем заголовке, может быть, в этом проблема? Они хранятся в SRAM?
eqzx
1
@ nrhine1: В этом случае вам, вероятно, следует показать нам весь эскиз, а не только те части, в которых, по вашему мнению, заключается проблема.
Дэйв Твид,
@DaveTweed Да, сделаю.
eqzx
1
Я заметил, что вы определяете много места в вашем заголовочном файле, а не просто объявляете его там (если вы не понимаете различий, смотрите эту страницу ). Это было бы необычно в программе на Си; это нормальная практика на Arduino? Вы можете получить несколько копий этих структур. Кроме того, вы определяете некоторые очень большие автоматические переменные, такие как «живой» массив в display_state (), которому требуется более 1024 байтов стекового пространства. Я почти уверен, что у тебя просто не хватает памяти.
Дэйв Твид
@DaveTweed спасибо, ты и Реза получили это. Я реорганизовал display_state()функцию, чтобы не нуждаться в этом дополнительном выделении. Я редко выполняю встроенную обработку, я полагаю, что мы все должны в какой-то момент поразить стену памяти!
августа
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 Q & A для различного образца кода, чтобы сделать это в Arduino.

embedded.kyle
источник
Я уже пытался сделать это статичным. Это не помогло. Это другая итерация. 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. Не могу воспроизвести это тоже.

В настоящее время он работает для меня на USB-диске Boarduino с 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!");
    }      
}
posipiet
источник
Спасибо за предложение. Это, к сожалению, не решило проблему.
eqzx