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.printไอเอ็นจีloop_counterและฉันยังได้รับพฤติกรรมแปลก ๆ (มันจะหยุดวน) Serial.println("hey");ทำงานในแง่ที่ว่าใน Serial Monitor ฉันได้รับ "hey" มากมาย (เช่นเร็วกว่า 100 "heys" จำนวนการวนซ้ำที่ส่วนอื่น ๆ ของรหัสควรเรียกใช้)

สิ่งที่อาจทำให้เกิดการใช้งาน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 ; led_matrix สั้น[ num_rows ] [ num_cols ];

const สั้นletter_a [ nrows ] [ ncols ] = {{ 0 , 1 , 1 , 0 }, { 1 , 0 , 0 , 1 }, { 1 , 1 , 1 , 1 }, { 1 , 0 , 0 , 0 , 1 0 , 0 , 0 }, { 1 , 1 , 1 , 0 }, { 1 } }; const สั้นletter_b [ nrows ] [ ncols ] = {{ 1 , , 0 , 1 , 0 }, { 1 , 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 สั้น* ข้อมูล; 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)


ขนาดสแต็คของคุณคืออะไร? มีโอกาสที่คุณสามารถทาสีสแต็กของคุณและดูว่ามันได้รับความเสียหาย การพิมพ์แบบอนุกรมใช้การขัดจังหวะหรือไม่รหัสของคุณเป็น reentrant หรือไม่
Ktc

การพิมพ์แบบอนุกรมไม่ได้ถูกกระตุ้นจากการขัดจังหวะใด ๆ ฉันใช้มันในloop()ฟังก์ชั่นเท่านั้น ฉันควรทาสีสแต็กของฉันอย่างไรหากผลลัพธ์ที่ฉันมี ( Serial.print()) มีเพียงวิธีเดียวที่ทำให้ฉันทำงานล้มเหลว
eqzx

2
เพื่อขจัดข้อผิดพลาดที่เป็นไปได้และผลข้างเคียงของการเปลี่ยนแปลงเข้าใจผิดดูเหมือนเล็กน้อยโปรดเปลี่ยนรหัสในคำถามของคุณด้วยตัวอักษรตัวอักษรที่แน่นอนสำเนาร่างตัดลงไปต่ำสุดที่จำเป็นในการก่อให้เกิดปัญหา ไม่ใช่ "นี่คือโปรแกรมของฉันซึ่งล้มเหลวถ้าฉัน .. " แต่โปรแกรมขั้นต่ำที่ล้มเหลวในลักษณะนี้
Chris Stratton

คำตอบ:


2

ฉันยังมีปัญหาที่คล้ายกันนี้และฉันมั่นใจว่าคุณมีพื้นที่สแต็กที่เกี่ยวข้อง ลองลดขนาดรหัสให้มากที่สุด

ในบางกรณีรหัสของฉันจะทำงานเมื่อฉันมีข้อความซีเรียลในนั้น แต่มันก็ดูเหมือนจะไม่ทำงานเมื่อฉันไม่ได้ ฉันยังมีกรณีที่การส่งข้อความแบบอนุกรมจะทำให้ arduino รีเซ็ตอย่างไม่มีที่สิ้นสุด

ฉันใช้ arduino328 ด้วย มีแนวโน้มว่าคุณควรลดขนาดอาเรย์ของคุณถ้าคุณมีขนาดที่เล็กที่สุดที่ยอมรับได้


ขอบคุณคุณและเดฟทวีดได้รับมัน ฉัน refactored ฟังก์ชั่น display_state () เพื่อไม่จำเป็นต้องจัดสรรเพิ่มเติม ฉันแทบจะทำการประมวลผลแบบฝังตัวฉันคิดว่าเราทุกคนต้องกดกำแพงหน่วยความจำในบางจุด!
eqzx

สวัสดีฉันมีสถานการณ์ที่คล้ายกัน ฉันเปลี่ยนขนาดของอาร์เรย์จาก 128 เป็น 96 และโปรแกรมของฉันทำงานได้ดี แต่ฉันคิดว่าปัญหานี้จริง ๆ แล้วไม่มีร่องรอยการตรวจแก้จุดบกพร่องเนื่องจากขนาดของอาร์เรย์ของฉันมีขนาดเล็กลงของขนาดกองซ้อนที่ประกาศ คุณรู้หรือไม่ว่าฉันสามารถหาข้อมูลเพื่อจัดการกับปัญหาประเภทนี้ได้ที่ไหน
Lion Lai

4

รหัสของคุณเริ่มต้นพอร์ตอนุกรมหรือไม่ เช่น.

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

การไม่ทำเช่นนี้อาจส่งผลให้เกิดข้อผิดพลาดในการใช้งานซีเรียลครั้งแรก


ใช่ฉันมีสิ่งนั้น
eqzx

3

บางทีคุณอาจมีหน่วยความจำไม่เพียงพอ? สตริงทั้งหมดที่คุณพิมพ์ด้วย Serial.print ("บางอย่าง") เกิดขึ้นใน SRAM เท่ากับจำนวนอักขระของสตริงนั้น + 1 สำหรับ \ 0 เทอร์มิเนเตอร์ เป็นไปได้ที่จะมีหน่วยความจำไม่เพียงพอแม้ว่าขนาดของร่างของคุณจะเล็กกว่าหน่วยความจำแฟลช Arduino เพราะ SRAM มีขนาดเพียง 2048 ไบต์สำหรับ Atmega328 และ 1024 ไบต์สำหรับ Atmega 168 ฉันมีปัญหาที่คล้ายกันซึ่งฉันแก้ไขด้วยการย่อทั้งหมด ข้อความและลบข้อความดีบักที่ไม่จำเป็น


อืมมม ฉันมีหลายมิติหลายแถวในหัวของฉันอาจเป็นปัญหาหรือไม่ พวกเขาเก็บไว้ใน SRAM หรือไม่?
eqzx

1
@ nrhine1: ในกรณีนี้คุณน่าจะแสดงให้คุณเห็นภาพร่างทั้งหมดของเราไม่ใช่เฉพาะส่วนที่คุณคิดว่าปัญหาอยู่
Dave Tweed

@DaveTweed ใช่จะทำ
eqzx

1
ฉันสังเกตเห็นว่าคุณกำหนดพื้นที่เก็บข้อมูลจำนวนมากในไฟล์ส่วนหัวของคุณแทนที่จะประกาศที่นั่น (ถ้าคุณไม่เข้าใจความแตกต่างดูหน้านี้ ) นี่จะผิดปกติในโปรแกรม C; มันเป็นเรื่องปกติใน Arduino หรือไม่? คุณอาจลงท้ายด้วยโครงสร้างเหล่านี้หลายชุด นอกจากนี้คุณกำลังกำหนดตัวแปรอัตโนมัติที่มีขนาดใหญ่มากเช่นอาร์เรย์ "alive" ใน display_state () ซึ่งต้องการพื้นที่สแต็กมากกว่า 1024 ไบต์ ฉันค่อนข้างมั่นใจว่าคุณมีหน่วยความจำหมด
เดฟทวีด

@DaveTweed ขอบคุณคุณและ Reza ได้รับมัน ฉัน refactored display_state()ฟังก์ชั่นที่ไม่จำเป็นต้องจัดสรรพิเศษ ฉันแทบจะทำการประมวลผลแบบฝังตัวฉันคิดว่าเราทุกคนต้องกดกำแพงหน่วยความจำในบางจุด!
eqzx

1

คุณยังไม่ได้แสดงรหัสที่เริ่มต้นตัวแปร "loop_counter" นั่นอยู่นอกรูทีนloop ()หรือไม่?

คุณอาจมีสิ่งที่ประกาศในลักษณะที่มันอยู่ติดกับพื้นที่เก็บข้อมูลหน่วยความจำอื่นที่ทำงานนอกขนาดที่ประกาศและ tromping นี้ในตัวแปร loop_counter หรือไม่


ฉันลองประกาศในหลาย ๆ ทางในหลาย ๆ ที่ ในส่วนหัวด้านบนloop()ฯลฯ คุณกำลังบอกว่าSerial.print()วิธีนี้อาจจะเขียนทับมันอย่างใด
eqzx

สิ่งที่ฉันหมายถึงโดยความคิดเห็นก่อนหน้านี้คือฉันเกือบจะเป็นบวกว่าฉันได้แยกพฤติกรรมที่ไม่ดีต่อการดำรงอยู่ของ Serial.print () เมื่อมันไม่อยู่ที่นั่นสิ่งต่าง ๆ ใช้ได้ดี
eqzx

@ nrbine1 - สำหรับฉันแล้วว่าตัวแปรตัวแปรทั่วโลกของคุณ "loop_counter" กำลังถูกเหยียบโดยวิธี Serial.print () เหมือนที่ฉันแนะนำในคำตอบของฉัน ในคำตอบโดยposipietคุณถูกถามว่าวัตถุอนุกรมได้รับการเริ่มต้นอย่างถูกต้อง หากยังไม่ได้ดำเนินการอาจอธิบาย "tromping" บนตัวนับของคุณเนื่องจาก Serial.print () พยายามใช้บัฟเฟอร์ที่ไม่ได้รับการจัดสรรและตั้งค่าอย่างเหมาะสม
Michael Karas

ฉันได้เพิ่มแหล่งที่มาทั้งหมดของฉันแล้ว
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/th/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 พร้อม 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.