שְׁאֵלָה:
מדוע סקיצות תופסות כל כך הרבה מקום וזיכרון?
hichris123
2014-02-22 03:29:25 UTC
view on stackexchange narkive permalink

כשאני מרכיב סקיצה זו עבור ה- Yún:

  int led = 7; setup void () {pinMode (led, OUTPUT); } loop void () {digitalWrite (led, HIGH);}  

אני מקבל:

Sketch משתמש ב -5,098 בתים (17%) משטח אחסון התוכנית .

המקסימום הוא 28,672 בתים. משתנים גלובליים משתמשים ב -153 בתים (5%) של הזיכרון הדינמי, ומשאירים 2,407 בתים למשתנים מקומיים. מקסימום הוא 2,560 בתים.

גם כשאני מרכיב את הסקיצה BareMinimum:

  התקנת חלל () {// setup} loop loop () {// loop}  

אני מקבל:

סקיצה משתמשת ב -4,548 בתים (15%) משטח אחסון התוכנית.

המקסימום הוא 28,672 בתים . משתנים גלובליים משתמשים ב -151 בתים (5%) של הזיכרון הדינמי, ומשאירים 2,409 בתים למשתנים מקומיים. מקסימום הוא 2,560 בתים.

מדוע סקיצה מינימלית מוחלטת תופסת 15% משטח האחסון של התוכנית שהוקצה? ולמה סקיצה מאוד פשוטה תופסת 17% משטח אחסון התוכנית? על פי אתר Arduino:

קל להשתמש בכל זה על ידי כך שיש לך הרבה מחרוזות בתוכנית שלך. לדוגמא, הצהרה כמו: char message [] = "אני תומך בפרויקט Cape Wind."; מכניס 33 בתים ל- SRAM (כל תו לוקח בתים, בתוספת המסוף '\ 0').

עם זאת, אין שום מחרוזות שהוכרזו באף אחד מהשרטוטים הללו.

נראה כאילו הם עשויים לייבא או להשתמש בספריות / כיתות אחרות שאני לא '. לא לציין. אולי היא מייבאת ספריית ברירת מחדל של המערכת? או שזה משהו אחר?

ארבע תשובות:
#1
+7
jippie
2014-02-22 03:36:27 UTC
view on stackexchange narkive permalink

Arduino מקבץ בהמון ספריות סטנדרטיות, הפרעות, וכו '. לדוגמא פונקציות pinMode ו- digitalWrite משתמשות בטבלת בדיקה כדי להבין בזמן הריצה לאיזה GPIO רושם לכתוב נתונים. דוגמא נוספת היא שארדואינו עוקב אחר הזמן, הוא מגדיר כמה הפרעות כברירת מחדל וכל הפונקציונליות הזו דורשת מעט מקום. תוכלו להבחין שאם תארכו את התוכנית, הדפסת הרגל תשתנה רק מעט.

אני אישית אוהבת לתכנת בקרים במינימום מוחלט, ללא "נפח", אך תיכנסו במהירות לעולם של EE.SE ו- SO מכיוון שכמה פונקציות קלות לשימוש כבר לא יעבדו מהקופסה. ישנן כמה ספריות חלופיות עבור pinMode ו- digitalWrite המתאספות לטביעת רגל קטנה יותר, אך מגיעות עם חסרונות אחרים כמו למשל סיכות מהודרות סטטיות (כאשר led לא יכול להיות משתנה, אלא הוא קבוע).

אז בעצם זה מתאסף בכל מיני ספריות סטנדרטיות בלי ששאלתם? נקי.
כן, בדרך כלל אני קורא לזה "נפח", אבל זה באמת דבר שמישות. ארדואינו היא סביבת כניסה נמוכה שפשוט עובדת בלי יותר מדי מחשבה. אם אתה זקוק ליותר, Arduino מאפשר לך להשתמש בספריות חלופיות או שאתה יכול להרכיב כנגד מתכת חשופה. האחרון הוא כנראה מחוץ לתחום עבור Arduino.SE
ראה את תשובת @mpflaga שלי. אין כל כך הרבה נפיחות. או לפחות בספריית הליבה למינימום פונקציונליות. אין ממש הרבה מספריות סטנדרטיות כלולות, אלא אם כן קוראים לה סקיצה. במקום זאת 15% נובעים מתמיכת ה- USB של ה- 32u4.
#2
+6
mpflaga
2014-02-22 11:58:43 UTC
view on stackexchange narkive permalink

ה- YUN הוא משולב. חלק Arduino וחלק OpenWRT (לינוקס). שאלתך מתייחסת לארדואינו. איפה מדובר למעשה ב- ATmega32u4 הדומה לליאונרדו ולא ל- UNO (ATmega328p). ה- 32u4 (Leo) מתקשר דרך יציאות סדרתיות וירטואליות דרך ה- USB (תשובה קצרה: צריך לתמוך בזה) , שם ל- UNO יש יציאה טורית אמיתית (aka UART). להלן נתונים סטטיסטיים של סוגי הלוחות השונים עבור מעבדי AVR. למאתחל. לעומת זאת ה- USB ל- Serial של Leo / Yun מיושם בקושחת ה- 32u4. מכאן שכדי לאתחל מרחוק את שבב 32u4 של Leo או YUN, הקושחה הטעונה חייבת תמיד לתמוך במנהל ההתקן של צד הלקוח USB. אשר צורכת כ -4 K.

אם ה- USB לא היה נחוץ ולא נקראו משאבי ספרייה אחרים כמו במקרה BareMinimum.ino ב- UNO, רק כ 466 בתים נדרשים לספריית הליבה של Arduino.

ערוך נתונים סטטיסטיים של BareMinimum.ino ב- UNO (ATmega328p)

  Sketch משתמש ב 466 בתים (1%) של שטח אחסון התוכנית. המקסימום הוא 32,256 בתים. משתנים כלליים משתמשים ב- 9 בתים (0%) של זיכרון דינמי, ומשאירים 2,039 בתים עבור משתנים מקומיים. מקסימום הוא 2,048 בתים.  

סטטיסטיקות קומפילציה של BareMinimum.ino על לאונרדו (ATmega32u4)

  סקיצה משתמשת ב -4,554 בתים (15%) משטח אחסון התוכנית . מקסימום הוא 28,672 בתים. משתנים כלליים משתמשים ב -151 בתים (5%) של זיכרון דינמי, ומשאירים 2,409 בתים עבור משתנים מקומיים. מקסימום הוא 2,560 בתים.  

סטטיסטיקות הידור של BareMinimum.ino ב- Yun (ATmega32u4)

  סקיצה משתמשת ב -4,548 בתים (15%) משטח אחסון התוכנית . מקסימום הוא 28,672 בתים. משתנים כלליים משתמשים ב -151 בתים (5%) של זיכרון דינמי, ומשאירים 2,409 בתים עבור משתנים מקומיים. מקסימום הוא 2,560 בתים.  
#3
+4
Edgar Bonet
2015-07-07 13:12:17 UTC
view on stackexchange narkive permalink

יש לך כבר כמה תשובות טובות לחלוטין. אני מפרסם את זה רק כדי לשתף נתונים סטטיסטיים שעשיתי יום אחד ושאלתי את עצמי את אותו סוג של שאלות: מה לוקח כל כך הרבה מקום בסקיצה מינימלית? מה הנדרש ביותר כדי להשיג את אותה פונקציונליות?

להלן שלוש גרסאות של תוכנית מצמצמת מינימלית המעבירה את ה- LED על סיכה 13 בכל שנייה. כל שלוש הגרסאות הורכבו עבור anUno (ללא USB מעורב) באמצעות avr-gcc 4.8.2, avr-libc 1.8.0 andarduino-core 1.0.5 (אני לא משתמש ב- Arduino IDE).

ראשית, דרך Arduino הסטנדרטית:

  const uint8_t ledPin = 13; setup void () {pinMode (ledPin, OUTPUT);} loop loop () {digitalWrite (ledPin, HIGH); עיכוב (1000); digitalWrite (ledPin, LOW); עיכוב (1000);}  

זה מתאסף ל -1018 בתים. תוך שימוש ב- avr-nm וגם בפירוק פירקתי את הגודל הזה לפונקציות בודדות. מהגדול לקטן ביותר:

  148 A ISR (TIMER0_OVF_vect) 118 init 114 A pinMode 108 A DigitalWrite 104 C טבלת וקטור 82 TurnOffPWM 76 A delay 70 A micros 40 U loop 26 A main 20 A digital_pin_to_timer_PGM 20 A digital_pin_to_port_PGM 20 A digital_pin_to_bit_mask_PGM 16 C __do_clear_bss 12 C __init 10 A port_to_output_PGM 10 A port_to_mode_PGM 8 U setup 8 C .init9 (main) ------------------------ 1018 TOTAL  

ברשימה שלמעלה העמודה הראשונה היא בגודל בתים , והעמודה השנייה מספרת אם הקוד מגיע מספריית הליבה של Arduino (A, 822 בתים סה"כ), זמן הריצה C (C, 148 בתים) או מהמשתמש (U, 48 בתים).

כפי שניתן כפי שנראה ברשימה זו, הפונקציה הגדולה ביותר היא השגרה המשרתת את הפרעת הצפת הטיימר 0. השגרה הזו אחראית על זמן המעקב, והיא נחוצה על ידי מילי () , micros () ו- delay () . הפונקציה השנייה בגודלה היא init () , המגדיר את טיימרי החומרה עבור PWM, מאפשר להפריע ל- TIMER0_OVF ולנתק את ה- USART (ששימש את מנהל האתחול). גם זו וגם הפונקציה הקודמת מוגדרים ב <Arduino directory> / hardware / arduino / cores / arduino / wiring.c .

הבא הוא גרסת C + avr-libc:

  # include <avr / io.h> # include <util / delay.h>int main (void) {DDRB | = _BV (PB5); / * הגדר סיכה PB5 כפלט * / עבור (;;) {PINB = _BV (PB5); / * החלף PB5 * / _ Delay_ms (1000); }}  

פירוט הגדלים האינדיבידואליים:

  104 טבלת וקטורים 26 U ראשי 12 C __init 8 C .init9 (call main, יציאה jmp) 4 C __bad_interrupt 4 C _צא ---------------------------------- 158 TOTAL  

זהו 132 בתים לזמן הריצה C ו- 26 בתים של קוד משתמש, כולל הפונקציה המשופעת _delay_ms().

ניתן לציין כי מכיוון שזה התוכנית אינה משתמשת בהפרעות, אין צורך בטבלת הווקטורים להפסיק וניתן לשים קוד קוד משתמש רגיל במקומה. גרסת ההרכבה הבאה עושה בדיוק את זה:

  #include <avr / io.h> # define io (reg) _SFR_IO_ADDR (reg) sbi io (DDRB), 5; הגדר את PB5 כמוצא לולאה: sbi io (PINB), 5; החלף PB5 ldi r26, 49; עיכוב עבור 49 * 2 ^ 16 * 5 מחזורים עיכוב: sbiw r24, 1 sbci r26, 0 brne עיכוב rjmp לולאה  

זה מורכב (עם avr-gcc -nostdlib ) ל 14 בתים בלבד, שרובם משמשים לעיכוב המתגים כך שהמצמץ נראה. אם תסיר את לולאת העיכוב ההיא, בסופו של דבר תכנית בת 6 בתים המהבהבת מהר מכדי שניתן יהיה לראות אותה (ב -2 מגה-הרץ):

  sbi io (DDRB), 5; הגדר את PB5 כמוצא לולאה: sbi io (PINB), 5; החלף PB5 rjmp loop  
#4
+3
Nick Gammon
2015-07-07 07:17:10 UTC
view on stackexchange narkive permalink

כתבתי פוסט על למה לוקח 1000 בתים כדי למצמץ נורית אחת?.

התשובה הקצרה היא: "לא צריך 2000 בתים כדי למצמץ שתיים נוריות! "

התשובה הארוכה יותר היא שלספריות הארדואינו הסטנדרטיות (שאינך צריך להשתמש בהן אם אינך רוצה) יש פונקציונליות נחמדה לפשט את חַיִים. לדוגמא, תוכל לפנות לסיכות לפי מספר בזמן הריצה, כאשר הספרייה ממירה (נניח) סיכה 8 ליציאה הנכונה ומספר הסיביות הנכון. אם יש לך גישה קשה ליציאה, תוכל לשמור את התקורה.

גם אם אינך משתמש בהן, הספריות הסטנדרטיות כוללות קוד לספירת "קרציות" כדי שתוכל לגלות את "הזמן" הנוכחי ( על ידי התקשרות ל- millis () ). לשם כך יש להוסיף את התקורה של כמה שגרות שירות להפסיק.

אם אתה מפשט את מטה (ב- Arduino Uno) לשרטוט זה אתה מקבל את השימוש בזיכרון התוכנית ל -178 בתים (ב- IDE 1.0. 6):

  int main () {DDRB = bit (5); ואילו (נכון) PINB = ביט (5); }  

בסדר, 178 בתים זה לא כל כך הרבה, ומתוכם 104 הבתים הראשונים הם וקטורי הפרעת החומרה (4 בתים כל אחד, עבור 26 וקטורים).

כך ניתן לטעון כי נדרשים 74 בתים בלבד כדי למצמץ נורית LED. ומתוכם 74 בתים רובם הם באמת הקוד שנוצר על ידי המהדר לאתחול הזיכרון הגלובלי. אם אתה מוסיף מספיק קוד כדי למצמץ שתי נוריות נוריות:

  int main () {DDRB = bit (5); // סיכה 13 DDRB | = ביט (4); // סיכה 12 בעוד (true) {PINB = bit (5); // סיכה 13 PINB = ביט (4); // סיכה 12}}  

ואז גודל הקוד גדל ל 186 בתים. אז אתה יכול לטעון שלוקח רק 186 - 178 = 8 בתים כדי למצמץ נורית.

אז, 8 בתים כדי להבהב נורית. נשמע לי די יעיל.


אם אתה מתפתה לנסות את זה בבית, עלי לציין שלמרות שהקוד המפורסם למעלה מהבהב עם שתי נוריות, זה אכן עושה זאת במהירות רבה. למעשה, הם ממצמצים ב -2 מגה הרץ - ראה צילום מסך. ערוץ 1 (צהוב) הוא סיכה 12, ערוץ 2 (ציאן) הוא סיכה 13.

Rapid blinking of pins 12 and 13

כפי שאתה יכול לראות, לסיכות הפלט יש גל מרובע בתדר של 2 מגה-הרץ. סיכה 13 משנה את המצב 62.5 ns (מחזור שעון אחד) לפני סיכה 12, בגלל סדר החלפת הסיכות בקוד.

אז אלא אם כן יש לך עיניים הרבה יותר טובות משלי, לא למעשה לראות כל אפקט מהבהב.


כתוספת משעשעת, אתה יכול למעשה להחליף שני סיכות באותה כמות שטח התוכנית בהחלפה סיכה אחת.

  int main () {DDRB = bit (4) | סיבית (5); // הגדר את הפינים 12 ו- 13 לפלט בעוד (true) PINB = bit (4) | סיבית (5); // החלף סיכות 12 ו -13} // סוף ראשי  

המצטבר ל- 178 בתים.

זה נותן לך תדירות גבוהה יותר:

Very rapid blinking of pins 12 and 13

כעת אנו מגיעים ל -2.66 מגה הרץ.

זה הגיוני. אז האם הספריות הסטנדרטיות רק כותרות כלולות אוטומטית בזמן הבנייה? ואיך הצלחת * לא * לכלול אותם?
המקשר מפשט באגרסיביות קוד שאינו בשימוש. בכך שלא נקרא 'init ()' (כפי שעושה 'הראשי () הרגיל'), לא נקשר הקישור wiring.c (שיש בו 'init'). כתוצאה מכך העיבוד של מטפלי הפסיקה ( עבור `מיליס ()`, `מיקרו () וכו ') הושמט. זה כנראה לא פרקטי במיוחד להשמיט אותו, אלא אם כן אתה אף פעם לא צריך לתזמן דברים, אבל העובדה היא שהסקיצה גדלה בהתאם למה שאתה מכניס לתוכה. לדוגמה, אם אתה משתמש בסידורי, גם זיכרון התוכנה וגם זיכרון RAM מקבלים מכה.


שאלה ותשובה זו תורגמה אוטומטית מהשפה האנגלית.התוכן המקורי זמין ב- stackexchange, ואנו מודים לו על רישיון cc by-sa 3.0 עליו הוא מופץ.
Loading...