Cetak serial Arduino mengubah perilaku program yang tidak diinginkan

10

Saya menggunakan penghitung lingkaran, dinyatakan dalam tajuk:

int loop_counter = 0;

Saya menggunakan penghitung ini untuk memicu acara sesering mungkin. Saya dulu menggunakan modulo untuk tipe perilaku yang sama ini, tetapi saya menyederhanakannya sehingga lebih mudah untuk dikerjakan (masih menghasilkan perilaku yang sama)

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

    //Serial.println("hey");

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

Semuanya baik dan baik, sampai saya mencoba berkomunikasi dengan Serialmembatalkan komentar //Serial.println("hey"); ( "hey"dalam contoh ini karena, bagi saya, perilaku ini tidak masuk akal).

Ini menghasilkan loop_countertidak pernah memicu do_something_important();bagian kode. Saya mencoba menyatakan loop_countersebagai volatile, itu tidak mengubah apa pun. Aku mencoba Serial.printing loop_counter, dan saya juga mendapatkan perilaku aneh (itu akan membekukan loop). Serial.println("hey");bekerja dalam arti bahwa di monitor Serial saya mendapatkan banyak "hei", (yaitu dengan cepat lebih dari 100 "heys", jumlah iterasi di mana bagian lain dari kode harus dipicu)

Apa yang mungkin menyebabkan penggunaan Serial, dengan data yang tidak (sejauh yang saya tahu) terikat untuk loop_countersepenuhnya mencegahnya bekerja dengan baik?

EDIT : Ini adalah bagian dari file utama yang akhirnya menimbulkan masalah (well, berkontribusi paling banyak untuk itu (menggunakan terlalu banyak memori)):



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

Ini adalah "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 singkat [num_rows] [num_cols];led_matrix singkat [ num_rows ] [ num_cols ];

const short letter_a [nrows] [ncols] = {{0,1,1,0}, letter_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 } pendek , {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 { struct letter_node { const * data pendek;const * data pendek ; letter_node * selanjutnya;* selanjutnya ; int x;int x ; int y;int y ; } letter_node;} letter_node ;

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

letter_node letter_map [NUMBER_OF_CHARACTERS];[ NUMBER_OF_CHARACTERS ]; #berakhir jika#berakhir jika

Beberapa informasi lebih lanjut: - Saya menggunakan Uno (ATMega328)

eqzx
sumber
Apa ukuran tumpukan Anda? Apakah ada kemungkinan Anda bisa mengecat tumpukan Anda dan melihat apakah sudah rusak. Apakah Serial Print menggunakan interupsi, apakah kode Anda reentrant?
Ktc
Pencetakan Serial tidak dipicu oleh interupsi, saya hanya menggunakannya dalam loop()fungsi. Bagaimana saya harus mengecat stack saya jika satu-satunya metode output yang saya miliki ( Serial.print()) gagal saya?
eqzx
2
Untuk menghilangkan kemungkinan kesalahan dan efek samping yang disalahpahami dari perubahan yang tampaknya sepele, harap ganti kode dalam pertanyaan Anda dengan salinan sketsa yang secara harfiah dan eksak dari karakter, dikurangi hingga minimum yang diperlukan untuk memicu masalah . Bukan "ini program saya yang gagal jika saya .." tetapi justru program minimum yang gagal dengan cara ini.
Chris Stratton

Jawaban:

2

Saya juga punya masalah yang mirip dengan ini, dan saya sangat yakin bahwa Anda juga keluar dari ruang stack terkait. Coba menyusutkan kode sebanyak mungkin.

Dalam kode kasus saya kadang-kadang akan berjalan ketika saya memiliki pesan serial di dalamnya, tetapi kemudian tampaknya tidak berjalan ketika saya tidak. Saya juga punya kasus di mana mengirim pesan serial akan menyebabkan arduino mereset tanpa henti.

Saya juga menggunakan arduino328. Kemungkinan Anda harus mengurangi ukuran array Anda jika Anda memiliki ukuran terkecil yang dapat diterima.

Reza Hussain
sumber
terima kasih, kamu dan Dave Tweed mengerti. Saya refactored fungsi display_state () untuk tidak memerlukan alokasi tambahan. Saya jarang melakukan pemrosesan tertanam, saya kira kita semua harus menabrak dinding memori di beberapa titik!
eqzx
Halo, saya punya situasi yang sama. Saya mengubah ukuran array dari 128 menjadi 96 dan program saya berfungsi dengan baik. Tapi saya pikir masalah ini benar-benar keluar dari jejak untuk debug, karena ukuran array saya lebih kecil dari ukuran stack. Apakah Anda tahu di mana saya dapat menemukan info untuk menangani masalah seperti ini?
Lion Lai
4

Apakah kode Anda menginisialisasi port serial? Misalnya.

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

Gagal melakukan ini dapat menyebabkan kerusakan pada penggunaan pertama serial.

Toby Jaffey
sumber
Ya saya memilikinya.
eqzx
3

Mungkin Anda kehabisan memori? Semua string yang Anda cetak dengan Serial.print ("sesuatu") terjadi di SRAM, sama dengan jumlah karakter dari string itu + 1 untuk terminator \ 0. Dimungkinkan untuk kehabisan memori bahkan jika ukuran kompilasi sketsa Anda jauh lebih kecil daripada memori flash Arduino, karena SRAM hanya 2048 byte untuk Atmega328 dan 1024 byte untuk Atmega 168. Saya punya masalah yang sama, yang saya selesaikan dengan memperpendek semua teks dan menghapus pesan debug yang tidak perlu.

Erion
sumber
Hmm. Saya memiliki beberapa array multidimensi yang diumumkan di header saya, mungkin itu masalahnya? Apakah mereka disimpan dalam SRAM?
eqzx
1
@ nrhine1: Dalam hal ini, Anda mungkin harus menunjukkan kepada kami seluruh sketsa Anda, bukan hanya bagian-bagian yang menurut Anda masalahnya.
Dave Tweed
@ DaveTeed Ya, akan lakukan.
eqzx
1
Saya perhatikan Anda mendefinisikan banyak penyimpanan dalam file header Anda, daripada hanya mendeklarasikannya di sana (jika Anda tidak mengerti perbedaannya lihat halaman ini ). Ini tidak biasa dalam program C; apakah itu praktik normal di Arduino? Anda mungkin berakhir dengan banyak salinan dari struktur ini. Selain itu, Anda mendefinisikan beberapa variabel otomatis yang sangat besar, seperti array "hidup" di display_state (), yang membutuhkan lebih dari 1024 byte ruang stack. Saya cukup yakin Anda hanya kehabisan memori.
Dave Tweed
@DaveTweed terima kasih, Anda dan Reza mengerti. Saya refactored display_state()fungsi untuk tidak memerlukan alokasi tambahan itu. Saya jarang melakukan pemrosesan tertanam, saya kira kita semua harus menabrak dinding memori di beberapa titik!
eqzx
1

Anda belum menunjukkan kode yang menginisialisasi variabel "loop_counter". Apakah itu di luar rutinitas loop () ?

Apakah Anda mungkin mendeklarasikannya sedemikian rupa sehingga berbatasan dengan area penyimpanan memori lain yang beroperasi di luar ukurannya yang dinyatakan dan ini menginjak-injak variabel loop_counter?

Michael Karas
sumber
Saya sudah mencoba mendeklarasikannya dengan berbagai cara, di banyak tempat berbeda. Di header, tepat di atas loop(), dll. Apakah Anda mengatakan bahwa Serial.print()metode itu mungkin menimpanya?
eqzx
Apa yang saya maksud dengan komentar sebelumnya adalah bahwa saya hampir positif bahwa saya telah mengisolasi perilaku 'buruk' dengan keberadaan Serial.print (). Ketika itu tidak ada, semuanya bekerja dengan baik.
eqzx
@ nrbine1 - Sepertinya bagi saya bahwa variabel global variabel Anda "loop_counter" sedang diinjak oleh metode Serial.print () seperti yang saya sarankan dalam jawaban saya. Dalam jawaban oleh posipiet Anda telah ditanya apakah objek Serial telah diinisialisasi dengan benar. Jika itu belum dilakukan, ini dapat menjelaskan "tromping" pada penghitung Anda karena Serial.print () mencoba menggunakan buffer yang belum dialokasikan dan disetel dengan benar.
Michael Karas
Saya telah menambahkan semua sumber saya.
eqzx
1

Saya tidak melihat kode Anda di mana Anda menelepon loop(). Itu juga tidak terlihat seperti Anda menggunakan di loop_counterluar fungsi itu. Apakah ada alasan Anda menyatakannya global? Saya berasumsi itu karena Anda ingin mempertahankan nilainya di antara panggilan. Anda bisa melakukan ini dengan variabel lokal statis sebagai gantinya.

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

Itu harus memastikan bahwa tidak ada fungsi eksternal lain yang dapat menginjaknya. Anda harus selalu mendeklarasikan variabel Anda dalam ruang lingkup sekecil mungkin untuk menghindari perilaku yang tidak diinginkan.

Jika itu tidak berhasil, Anda harus benar-benar menganalisis penggunaan memori Anda. Periksa Tanya Jawab EE.SE ini untuk berbagai kode sampel untuk melakukan ini dalam Arduino.

tertanam.kyle
sumber
Saya sudah mencoba membuatnya statis. Itu tidak membantu. Ini adalah iterasi yang berbeda. setup()dan loop()merupakan fungsi yang Arduino berjalan secara default, setup()pertama, loop()kedua. loop()pada dasarnya seperti main(), kecuali disebut berulang kali. referensi: arduino.cc/en/Reference/loop Saya akan memeriksa tautan itu.
eqzx
lagi, seperti yang telah saya sebutkan di komentar lain, saya tidak bisa melakukan debug dengan Serial.print(). Sepertinya saya harus keluar dari processingIDE normal jika saya ingin dapat menggunakan GDB
eqzx
@ nrhine1 Anda mengatakan Serial.print()itu berfungsi dengan baik karena banyak mencetak "hei". Itu loop_counteryang memberimu masalah. Coba hapus if(loop_counter == 0)kode dan masukkan get_free_memory()kode (tinggalkan loop_counterkenaikan) dan jalankan. Setidaknya ini akan memberi tahu Anda jika Anda memiliki masalah besar dengan alokasi memori Anda.
embedded.kyle
1

Pustaka serial perangkat lunak Arduino menggunakan interupsi. (lihat "softwareSerial.cpp, .h"). Anda mungkin memiliki masalah ketika ISR "melangkah" pada kode utama (atau sebaliknya). Coba gunakan bendera interlock, sehingga kode menunggu sementara operasi cetak selesai.

Bob Kugler
sumber
0

Pada satu titik beberapa waktu yang lalu saya mendapat kesan memiliki masalah yang sama. Saat itu, saya menyelesaikannya dengan menambahkan penundaan (1) di depan atau setelah serial.println. Itu dengan Arduino 0022 di Linux. Tidak yakin papan mana itu, mungkin serial Boarduino. Juga tidak bisa mereproduksi.

Saat ini, ini berfungsi untuk saya di boarduino USB dengan Arduino 1.01 di 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
sumber
Terima kasih untuk sarannya. Sayangnya itu tidak menyelesaikan masalah.
eqzx