A impressão serial do Arduino altera o comportamento do programa de maneira indesejável

10

Estou usando um contador de loop, declarado em um cabeçalho:

int loop_counter = 0;

Eu uso esse contador para acionar um evento de vez em quando. Eu costumava usar um módulo para esse mesmo tipo de comportamento, mas simplifiquei para facilitar o trabalho (ainda resulta no mesmo comportamento)

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

    //Serial.println("hey");

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

Tudo está bem, até que eu tente me comunicar Serialdescomentando o //Serial.println("hey"); ( "hey"neste exemplo, porque, para mim, esse comportamento é absurdo).

Isso resulta em loop_counternunca acionar a do_something_important();seção do código. Eu tentei declarar loop_countercomo volatile, isso não muda nada. Tentei Serial.printing loop_counter, e eu também estava ficando comportamento estranho (ele iria congelar o loop). Serial.println("hey");funciona no sentido de que, no monitor serial, recebo bastante "ei", (ou seja, rapidamente, muito mais do que 100 "ei", o número de iterações nas quais a outra seção do código deve ser acionada)

O que poderia estar causando o uso de Serial, com dados que não estão (até onde eu saiba) vinculados para loop_counterimpedir completamente que funcionem corretamente?

EDIT : Aqui está a parte do arquivo principal que acabou apresentando o problema (bem, contribuindo mais para ele (usando muita memória)):



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

Aqui está "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 ; led_matrix curto [ num_rows ] [ num_cols ];

const short letter_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, { 1 , 0 , 0 , 1 }, { 1 , 1 , 1 , 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_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 } };

typedef struct letter_node { const short * data ; 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 ]; #fim se

Mais algumas informações: - Estou usando um Uno (ATMega328)

eqzx
fonte
Qual é o tamanho da sua pilha? Existe uma chance de você poder pintar sua pilha e ver se ela está sendo corrompida. A impressão serial usa interrupções, seu código é reentrante?
Ktc
A impressão em série não é acionada por nenhuma interrupção, estou usando apenas na loop()função. Como devo pintar minha pilha se o único método de saída que tenho ( Serial.print()) está falhando comigo?
eqzx
2
Para eliminar possíveis erros e efeitos colaterais incompreensíveis de alterações aparentemente triviais, substitua o código na sua pergunta por uma cópia literal e exata do caractere de um esboço reduzido ao mínimo necessário para desencadear o problema . Não "esse é o meu programa que falha se eu ..", mas exatamente o programa mínimo que falha dessa maneira.
Chris Stratton

Respostas:

2

Eu também tive um problema semelhante a isso e tenho certeza de que o seu também está sem espaço em pilha. Tente reduzir o código o máximo possível.

No meu caso, o código algumas vezes era executado quando eu tinha uma mensagem serial, mas depois parecia não ser executado quando não era. Também tive um caso em que o envio de mensagens seriais faria com que o arduino fosse redefinido infinitamente.

Eu também estava usando um arduino328. Provavelmente, você deve reduzir o tamanho da sua matriz, se tiver algum tamanho aceitável.

Reza Hussain
fonte
obrigado, você e Dave Tweed entenderam. Refatorei a função display_state () para não precisar dessa alocação extra. Eu raramente faço processamento incorporado, suponho que todos nós tenhamos que atingir a parede da memória em algum momento!
eqzx
Olá, eu tenho uma situação semelhante. Eu mudo o tamanho da matriz de 128 para 96 ​​e meu programa funciona bem. Mas acho que esse problema está realmente fora de rastreio para depuração, porque o tamanho da minha matriz é menor do tamanho da pilha declarada. Você sabe onde posso encontrar informações para lidar com esse tipo de problema?
Lion Lai
4

Seu código inicializa a porta serial? Por exemplo.

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

Não fazer isso pode resultar em uma falha no primeiro uso da série.

Toby Jaffey
fonte
Sim, eu tenho isso.
eqzx
3

Talvez você esteja ficando sem memória? Todas as seqüências impressas com Serial.print ("something") ocorrem na SRAM, igual ao número de caracteres dessa sequência + 1 para o terminador \ 0. É possível ficar sem memória mesmo que o tamanho compilado do seu esboço seja muito menor que a memória flash do Arduino, porque a SRAM tem apenas 2048 bytes para o Atmega328 e 1024 bytes para o Atmega 168. Eu tive um problema semelhante, que resolvi encurtando tudo textos e remover mensagens de depuração desnecessárias.

Erion
fonte
Hmm. Tenho várias matrizes multidimensionais declaradas no meu cabeçalho, talvez seja esse o problema? Eles são armazenados na SRAM?
eqzx
11
@ nrhine1: Nesse caso, você provavelmente deve nos mostrar todo o seu esboço, não apenas as partes em que acha que o problema está.
Dave Tweed
@DaveTweed Sim, servirá.
eqzx
11
Percebo que você está definindo muito armazenamento em seu arquivo de cabeçalho, em vez de simplesmente declará-lo lá (se você não entender a distinção, consulte esta página ). Isso seria incomum em um programa C; é a prática normal no Arduino? Você pode acabar com várias cópias dessas estruturas. Além disso, você está definindo algumas variáveis ​​automáticas muito grandes, como a matriz "viva" em display_state (), que precisa de mais de 1024 bytes de espaço na pilha. Tenho certeza que você está simplesmente ficando sem memória.
Dave Tweed
@DaveTweed obrigado, você e Reza conseguiram. Refatorei a display_state()função para não precisar dessa alocação extra. Eu raramente faço processamento incorporado, suponho que todos nós tenhamos que atingir a parede da memória em algum momento!
eqzx
1

Você não mostrou o código que inicializa a variável "loop_counter". Isso está fora da rotina loop () ?

Você pode declarar isso de maneira que seja adjacente a outra área de armazenamento de memória que esteja operando fora do tamanho declarado e esta pisando na variável loop_counter?

Michael Karas
fonte
Eu tentei declarar isso de muitas maneiras diferentes, em muitos lugares diferentes. No cabeçalho, logo acima loop(), etc. Você está dizendo que o Serial.print()método pode estar sobrescrevendo-o de alguma forma?
eqzx
O que eu quis dizer com comentário anterior é que tenho quase certeza de que isolei o comportamento 'ruim' da existência do Serial.print (). Quando não está lá, as coisas funcionam bem.
eqzx
@ nrbine1 - Parece-me que sua variável variável global "loop_counter" está sendo pisada pelo método Serial.print () como sugeri na minha resposta. Na resposta da posipiet, você foi perguntado se o objeto Serial foi inicializado corretamente. Se isso não tiver sido feito, pode explicar o "tromping" no seu contador, pois Serial.print () tenta usar um buffer que não foi alocado e configurado corretamente.
Michael Karas
Eu adicionei toda a minha fonte.
eqzx
1

Não vejo no seu código para onde você está ligando loop(). Também não parece que você esteja usando loop_counterfora dessa função. Existe uma razão para você declarar global? Presumo que seja porque você deseja que ele retenha seu valor entre as chamadas. Você poderia fazer isso com uma variável local estática .

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

Isso deve garantir que nenhuma outra função externa possa pisar nela. Você sempre deve declarar suas variáveis ​​no menor escopo possível para evitar comportamentos indesejados.

Se isso não funcionar, você precisará realmente analisar seu uso de memória. Verifique estas perguntas e respostas do EE.SE para obter vários códigos de amostra para fazer isso em um Arduino.

embedded.kyle
fonte
Eu já tentei torná-lo estático. Não ajudou. Esta é uma iteração diferente. setup()e loop()são funções que o arduino executa por padrão, setup()primeiro, loop()segundo. loop()é essencialmente como main(), exceto que é chamado repetidamente. referência: arduino.cc/en/Reference/loop Vou verificar esse link.
eqzx
novamente, como mencionei em outros comentários, não consigo depurar Serial.print(). Parece que eu vou ter que fora do normal de processingIDE se eu quero ser capaz de usar GDB
eqzx
@ nrhine1 Você disse que Serial.print()estava funcionando bem porque estava imprimindo muito "ei". É loop_counterisso que está lhe dando um problema. Tente remover o if(loop_counter == 0)código e inseri get_free_memory()-lo (deixe o loop_counterincremento) e execute-o. Isso indica pelo menos se você tiver algum problema grave com a alocação de memória.
embedded.kyle
1

A biblioteca serial do software Arduino usa interrupções. (consulte "softwareSerial.cpp, .h"). Você pode ter um problema em que o ISR está "pisando" no código principal (ou vice-versa). Tente usar sinalizadores de intertravamento, para que o código aguarde enquanto as operações de impressão são concluídas.

Bob Kugler
fonte
0

A certa altura, tive a impressão de ter o mesmo problema. Naquela época, resolvi adicionando um atraso (1) na frente ou depois do serial.println. Isso foi com o Arduino 0022 no Linux. Não tenho certeza de qual placa era, provavelmente uma série do Boarduino. Também não é possível reproduzi-lo.

Atualmente, ele funciona para mim em um boarduino USB com Arduino 1.01 no 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
fonte
Obrigado pela sugestão. Infelizmente, não resolveu o problema.
eqzx