วิธีย่อขนาดร่างจริง ๆ


9

ฉันต้องการสร้างภาพร่างที่มีขนาดเล็กที่สุดเพื่อจุดประสงค์ในการทดสอบ ปัญหาคือเมื่อฉันรวบรวมร่าง BareMinimum (ด้วยการเซ็ตอัพและลูปที่ว่างเปล่า) ฉันได้ 466 ไบต์สำหรับ Uno และ 4,242 สำหรับ Leonardo มีวิธีการเขียนรหัสของคุณเองที่ไม่มีฟังก์ชั่นพิเศษใด ๆ (เช่น Timer0 สำหรับmillis()และdelay()) ฉันต้องการที่จะปิดการใช้งานฟังก์ชั่นแป้นพิมพ์ / เมาส์สำหรับ Leonardo


4
สิ่งนี้จะไม่ถูกแท็กเลโอนาร์โดและไม่ใช่ uno (และมุ่งเน้นที่บอร์ดเดียว)? นี่เป็นคำถามแยกต่างหาก
asheeshr

ฉันแค่ชี้ให้เห็นว่าร่างที่รวบรวมว่างเปล่ามีขนาดใหญ่สำหรับบอร์ดจำนวนมากโดยเฉพาะอย่างยิ่งคนที่ใช้ USB พื้นฐาน
TheDoctor

ฉันต้องการที่จะปิดการใช้งานฟังก์ชั่นแป้นพิมพ์ / เมาส์สำหรับ Leonardo เป็นคำถามที่สอง
asheeshr

คำตอบ:


3

คุณควรจะสามารถที่จะสร้างคำนิยามของคณะกรรมการของคุณเองด้วยไฟล์ boards.txt ที่กำหนดเองตามhttps://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification อย่างที่ฉันเห็นมีคุณสมบัติ usb หลายอย่างในนิยามของเลโอนาร์โด ฉันหวังว่าการรวมการรวมของ 4K จะยึดตามแฟล็กเหล่านี้ไม่ใช่ตัวประมวลผล

โดยที่ boards.txt จะใช้การอัปโหลดส่วน bootloader จาก Leonardo และบิลด์จาก uno

นี่คือทั้งหมดที่สมมติว่า core library build ไม่ได้ใช้แฟล็กเฉพาะของตัวประมวลผลเพื่อรวมฟังก์ชัน USB

หากคุณได้รับการทำงานดังกล่าว โพสต์กลับฉันมั่นใจว่าคนอื่นจะสนใจเช่นนี้


เมื่อเร็ว ๆ นี้ฉันวิ่งเข้าไปในข้อ จำกัด การใช้งาน 4K นี้ในการสาธิตไลบรารีที่ทำให้ UNO สูงสุดและต้องใส่ใน

#if !defined(__AVR_ATmega32U4__)
...

ล้อมรอบคุณสมบัติพิเศษขนาดใหญ่ในภาพร่างเพื่อให้พอดีกับเลโอนาร์โด

ฉันถือว่า (ผิด) ว่า 4K นี้เป็นเพราะฉันยังคงรวม Serial.print ซึ่งเมื่อผ่าน CDC ของ USB บน Leo แต่ฉันเห็นหลังจากการถ่ายโอนข้อมูลหน่วยความจำของร่างว่างเปล่าพวกเขายังคงมี

C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst

ซึ่งทำให้รู้สึก เนื่องจาก Leonardo ยังคงต้องใช้ไคลเอนต์ USB-CDC (4K) เพื่อตรวจจับการเชื่อมต่อ 1200 Baud จาก AVR-DUDE เพื่อการรีบูตเครื่องจากระยะไกล


ดังนั้นการสร้าง boards.txt แบบกำหนดเองโดยไม่มี USB ในบิลด์จำเป็นต้องมี

leonardo.upload.use_1200bps_touch=true

ลบออก

เมื่อโหลดบนเป้าหมายแล้วสิ่งนี้จะต้องทำการซิงโครไนซ์การอัปโหลดด้วยการรีเซ็ตเป้าหมายด้วยตนเอง ในฐานะที่เป็นความสามารถในการรีบูตระยะไกลจะหายไป


อัปเดตเกี่ยวกับสาเหตุที่ 4K ยังคงคอมไพล์แม้ว่าจะไม่ได้ใส่ Serial.print
mpflaga

3

ฉันเพิ่งต้องการทำสิ่งนี้ เนื่องจากไม่มีวิธีที่ดีในการทำเช่นนั้นฉันจึงเลิกเขียนโปรแกรมเสริมสำหรับปลั๊กอิน arduino ของStino ที่ดีเลิศเพื่อทำสิ่งนี้ เป็นที่ยอมรับในภายหลังดังนั้นจึงควรติดตั้ง Stino ที่ทันสมัย

นี่เป็นการเพิ่มตัวเลือกใหม่ให้กับ Stino:

ป้อนคำอธิบายรูปภาพที่นี่

การใช้โหมดนี้จะสร้างผลลัพธ์การรวบรวมดังนี้:

สำหรับ Uno:

ขนาดร่างแบบไบนารี: 172 ไบต์ (สูงสุด 32256 ไบต์, 0.53 เปอร์เซ็นต์)
การใช้หน่วยความจำโดยประมาณ: 0 ไบต์ (สูงสุด 1024 ไบต์, 0.00 เปอร์เซ็นต์)

สำหรับเลโอนาร์โด

ขนาดร่างแบบไบนารี: 240 ไบต์ (สูงสุด 28672 ไบต์, 0.84 เปอร์เซ็นต์)
การใช้หน่วยความจำโดยประมาณ: 0 ไบต์ (สูงสุด 2560 ไบต์, 0.00 เปอร์เซ็นต์)

จริงๆแล้วการเขียนโปรแกรมเลโอนาร์โดด้วยเอาต์พุตที่รวบรวมไว้ข้างต้นอาจเป็นความคิดที่ไม่ดีเพราะมันอาจทำให้ฟังก์ชั่นรีเซ็ตอัตโนมัติผิดปกติ แต่คุณสามารถทำได้ถ้าคุณต้องการ Hat-tip เพื่อ mpflaga สำหรับการสังเกตในคำตอบของเขา

ทราบว่ารายงานที่หน่วยความจำไม่ถูกต้องจริง ๆ แต่ที่เป็นปัญหาที่แยกต่างหาก

รหัสที่ใช้สำหรับด้านบนคือ:

int main()
{
    while (1)
    {

    }
}

หมายเหตุบางส่วน:

  • คุณจะไม่ได้เขียนเป็น "ร่าง" อีกต่อไปไม่ว่าคุณเคยจริงไม่เขียนร่าง คุณเขียนโปรแกรม ระยะเวลา ฉันไม่สนใจสิ่งที่ Arduino ต้องการที่จะพูดพวกเขาไม่ได้รับการกำหนดเงื่อนไข
  • การจัดการขัดจังหวะทั้งหมดเป็นคู่มือ ซึ่งหมายความว่าไม่มีmilis()หรือคล้ายกัน
  • คุณยังสามารถใช้ไลบรารีอนุกรม arduino และอื่น ๆ ได้หากต้องการ #include <Arduino.h>คุณจะต้อง
  • mainคุณกำหนด mainคุณไม่เคยกลับมาจาก while (1)หากคุณต้องการสิ่งที่ติดตั้งมันไปก่อน

@jfpoilpret คุณเรียกว่า IDE หรือไม่ เหมือนสมุดบันทึกที่มีมาโครมากขึ้น ...
Ron

@ Ron-E ฉันไม่เรียกมันว่า IDE แต่Arduino IDEเป็นชื่อของมันดังนั้นฉันจึงใช้ชื่อของมันถึงแม้ว่ามันจะไม่คุ้มกับชื่อนั้นก็ตาม
jfpoilpret

2
@FakeName ไม่อนุญาตให้ใช้ภาษาที่ไม่เหมาะสมในไซต์ Stack Exchange (ดู: stackoverflow.com/help/behavior ) ฉันได้ทำการแก้ไขในกรณีนี้ แต่โปรดพยายามอย่าใช้คำเสริมในเว็บไซต์นี้ในอนาคต ขอบคุณ
Peter Bloomfield

2

แม้ว่ามันจะขึ้นอยู่กับร่างของคุณ แต่คุณสามารถลดขนาดลงได้ด้วยการนำโค้ดกลับมาใช้ใหม่ด้วยวิธีการต่างๆ

ใช้รหัสนี้:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  val = digitalRead(10);
}

1,322 ไบต์บน Arduino Uno ทีนี้ลองลดขนาดลงหน่อย:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  for(uint8_t i = 0; i < 8; i++) {
    blink(HIGH);
    blink(LOW);
  }    
  val = digitalRead(10);
}

void blink(uint8_t state) {
  digitalWrite(led, state);   // turn the LED to the right state
  delay(1000);                // wait for a second
}

1,194 ไบต์ นั่นคือลดลงประมาณ 10%!

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


โดยทั่วไปถ้าคุณดึงรหัสออกมาในฟังก์ชั่นคอมไพเลอร์จะทำงานหนักและได้รับส่วนที่เหลือสำหรับคุณ
Cybergibbons

@Cybergibbons คุณสามารถกำหนด [สำหรับผู้ใช้ที่ไม่คุ้นเคย] ได้หรือไม่
ไม่ระบุชื่อเพนกวิน

3
หากคุณแบ่งรหัสเป็นฟังก์ชันและไม่มีประสิทธิภาพโดยทั่วไปคอมไพเลอร์จะทำตามบรรทัดให้คุณ อย่างไรก็ตามคอมไพเลอร์จะไม่แยกโค้ดออกเป็นฟังก์ชัน ดังนั้นจึงเป็นการดีกว่าที่จะเขียนฟังก์ชั่นมากขึ้น
Cybergibbons

1
การใส่รหัสลงในฟังก์ชั่นทำให้ง่ายต่อการอ่านและเข้าใจมากขึ้น

เมื่อใช้การเข้าถึงพอร์ตโดยตรงขนาดจะลดลงเป็น 646 ไบต์ ใช้ avr-libc เท่านั้น (ไม่มี Arduino core), มันลดลงเหลือ 220 ไบต์
Edgar Bonet

0

@annonomus penguin แน่นอนว่าเราทำได้แม้ว่ารหัสจะรวมเป็น 1180 ไบต์แฟลช + RAM ขนาด 13 ไบต์สำหรับ uno บนคอมพิวเตอร์ของฉัน แต่เราสามารถปรับปรุงมันได้ :) ดังนั้นการยอมรับความท้าทายของกอล์ฟและเคล็ดลับที่มีประโยชน์เนื่องจากเราอยู่ในธุรกิจของ การเรียนรู้

ขั้นตอนที่ 1: ลดความต้องการตัวแปร การใช้ int สำหรับพอร์ตนำดูเหมือนว่าเกินความเป็นจริงเราไม่มีพอร์ต IO ที่สามารถระบุได้ 65535 แอดเดรสใน arduino :) ดังนั้นเราจึงเปลี่ยนเป็นไบต์เพียงเพื่อความสนุกของมัน เราจะเปลี่ยนเป็น #define ในภายหลัง แต่เพื่อแสดงผลกระทบของการใช้ประเภทตัวแปรที่มีขนาดใหญ่เกินไป

byte led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

คอมไพล์เป็น RAM 1172 + 13 ไบต์ วิธีนี้ช่วยประหยัด 8 ไบต์ของแฟลชเนื่องจากการทำงานที่จำเป็นน้อยลงสำหรับไบต์แทนจำนวนเต็ม ฉันคาดว่าจะได้ ram 12 ไบ แต่ก็โอเค ไม่มากนัก แต่ทุก ๆ ไบต์ที่บันทึกไว้นั้นดี

ขั้นตอนที่ 2: เปลี่ยนตัวแปรเป็นนิยามเมื่อมันสมเหตุสมผล ตัวอย่างเช่นไม่จำเป็นต้องใช้ไบต์นำ

#define LED 13
int val;

void setup() {                
  pinMode(LED, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

คอมไพล์เป็น 1142 ไบต์ไบต์ + RAM 11 ไบต์ บันทึกไปแล้ว 38 ไบต์ นี่คือเนื่องจากการดำเนินการลงทะเบียนน้อยลงที่จำเป็นในการดึงค่า int นอกจากนี้เรายังบันทึก 2 ไบต์จาก RAM (ยังคงสงสัยว่าทำไมไบต์ไม่คอมไพล์เป็น RAM น้อยกว่า 1 ไบต์ ..... )

ขั้นตอนที่ 3: ปรับรหัสให้เหมาะสม ฉันเห็นความล่าช้า 2 ครั้ง ฉันสงสัยว่าถ้าฉันเปลี่ยนมันเป็น 1 ดีเลย์มันจะประหยัดพื้นที่ แต่ฉันต้องคิดออกค่าของพิน LED และสลับ (สลับ) มัน เราสามารถทำได้ด้วย digitalRead () แต่มันจะประหยัดพื้นที่หรือไม่

#define LED 13
int val;
void setup() {                
  pinMode(LED, OUTPUT);     
}
void loop() {
  blink();
  val = digitalRead(10);
}
void blink() {
  digitalWrite(LED, !digitalRead(LED));   // toggle the led based on read value
  delay(1000);               // wait for a second and spare yourself the other delay
}

รวบรวมเป็น 1134 ไบต์ + 11 ไบต์ ram เย้! อีก 8 ไบต์ นั่นทำให้จำนวน 46 ไบต์และโค้ดน้อยลง 2 บรรทัด

อีกหนึ่งเคล็ดลับทั่วไปในการลดขนาดโค้ด อย่าใช้คลาส String มันมีขนาดใหญ่มากเรียนรู้วิธีจัดการกับอาร์เรย์ char, strcpy (), strcmp () หากคุณมีการใช้งานสตริงขั้นพื้นฐานการใช้งานคลาส String นั้นส่วนใหญ่จะเป็นการสิ้นเปลืองพื้นที่บนแฟลชและ RAM

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