תוכן עניינים:

הדרכה להרכבת AVR 3: 9 שלבים
הדרכה להרכבת AVR 3: 9 שלבים

וִידֵאוֹ: הדרכה להרכבת AVR 3: 9 שלבים

וִידֵאוֹ: הדרכה להרכבת AVR 3: 9 שלבים
וִידֵאוֹ: פיגום נייד קפרו 9 שלבים -פתרון בטיחותי וקל לעבודות בניין בגובה 2024, יולי
Anonim
הדרכה להרכבת AVR 3
הדרכה להרכבת AVR 3

ברוכים הבאים להדרכה מספר 3!

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

היום אנחנו הולכים לחבר מעגל פשוט מאוד ואז להיכנס קצת לתאוריה. מצטער על זה, אבל אנחנו צריכים את הכלים! אני מבטיח שנפצה על זה בהדרכה 4 שבה נעשה מבנה מעגלים רציני יותר והתוצאה תהיה די מגניבה. עם זאת, הדרך שבה אתה צריך לבצע את כל ההדרכות האלה היא בצורה איטית ומהורהרת מאוד. אם אתה פשוט חורש, בנה את המעגל, העתק והדבק את הקוד והפעל אותו אז, בטוח שזה יעבוד, אבל לא תלמד דבר. אתה צריך לחשוב על כל שורה. הַפסָקָה. לְנַסוֹת. לִהַמצִיא. אם אתה עושה את זה ככה, עד שתסיים את ההדרכה החמישית, אתה לא תבנה דברים מגניבים ולא תצטרך יותר הדרכה. אחרת אתה פשוט צופה במקום ללמוד וליצור.

בכל מקרה, מספיק פילוסופיה, בואו נתחיל!

בהדרכה זו תזדקק ל:

  1. לוח האב טיפוס שלך
  2. LED
  3. חיבור חוטים
  4. נגד סביב 220 עד 330 אוהם
  5. מדריך מערך ההוראות: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. גליון הנתונים: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. מתנד קריסטל אחר (אופציונלי)

להלן קישור לאוסף ההדרכות המלא:

שלב 1: בניית המעגל

בניית המעגל
בניית המעגל

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

חבר נורית ל- PD4, ואז לנגד 330 אוהם ואז לקרקע. כְּלוֹמַר

PD4 - LED - R (330) - GND

וזהו!

התיאוריה הולכת להיות קשקוש קשה …

שלב 2: מדוע אנו זקוקים להערות ולקובץ M328Pdef.inc?

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

הנה הקוד שאנו הולכים לכתוב היום, פרט לכך שהסרתי את ההערות ואת קובץ ה- include:

.התקן ATmega328P

.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16, 0x05 out 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 out 0x26, r16 sbi 0x0a, 0x04 sbi 0x0b, 0x04 b: sbi 0x0b, cbi 0x0b, 0x04 rcall c rjmp bc: clr r17 d: cpi r17, 0x1e brne d ret e: inc r17 cpi r17, 0x3d brne PC+2 clr r17 reti

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

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

אז בואו נכניס את ההערות ונכלול את הקובץ בחזרה על מנת שנוכל להבין זאת.

שלב 3: עפעף

להלן הקוד עליו נדון היום:

;************************************

; נכתב על ידי: 1o_o7; תאריך:; גרסה: 1.0; הקובץ נשמר כ: blink.asm; עבור AVR: atmega328p; תדר השעון: 16 מגה -הרץ (אופציונלי); פונקציית התוכנית: ---------------------; סופר שניות על ידי מהבהב LED;; PD4 - LED - R (330 אוהם) - GND;; --------------------------------------.nolist.include "./m328Pdef.inc".list; ===============; הצהרות:.def temp = r16.def overflows = r17.org 0x0000; מיקום הזיכרון (PC) של איפוס המטפל rjmp איפוס; jmp עולה 2 מחזורי מעבד ו- rjmp עולה רק 1; אז אלא אם כן אתה צריך לקפוץ יותר מ 8k בתים; אתה צריך רק rjmp. כמה בקרי מיקרו לפיכך בלבד; יש rjmp ולא jmp.org 0x0020; מיקום הזיכרון של Timer0 overflow handler rjmp overflow_handler; עבור לכאן אם מתרחשת הפרעה של הצפת טיימר 0; ============ איפוס: ldi temp, 0b00000101 out TCCR0B, temp; הגדר את Bits Selector Selector CS00, CS01, CS02 ל- 101; זה מכניס את Timer Counter0, TCNT0 למצב FCPU/1024; כך שהוא מתקתק בתדירות המעבד/1024 ldi temp, 0b00000001 sts TIMSK0, temp; הגדר את ביט ההפעלה של Timer Overflow Interrupt Enable (TOIE0); של רשם מסכות הטיימר (TIMSK0) sei; לאפשר הפרעות גלובליות - שווה ערך ל- "sbi SREG, I" clr temp out TCNT0, temp; לאתחל את הטיימר/מונה ל- 0 sbi DDRD, 4; הגדר את PD4 לפלט; ========================= גוף התוכנית העיקרי: מצמוץ: sbi PORTD, 4; להדליק LED על PD4 rcall עיכוב; העיכוב יהיה 1/2 שניות cbi PORTD, 4; לכבות את ה- LED על עיכוב rcall PD4; ההשהיה תהיה מהבהב rjmp של 1/2 שנייה; לולאה חזרה לעיכוב ההתחלה: clr עולה על גדותיו; הגדר הצפות ל- 0 sec_count: cpi overflows, 30; השווה את מספר הצפות ו- 30 brne sec_count; סניף לגב ל sec_count אם לא שווה ret; אם התרחשו 30 הצפות חזור למצמץ overflow_handler: inc overflows; הוסף 1 למשתנה הצפות cpi overflows, 61; השווה עם 61 brne PC+2; דלפק התוכנית + 2 (דלג על השורה הבאה) אם הצפות CLR לא שוות; אם התרחשו 61 הצפות אפס את המונה לאפס reti; לחזור מהפסקה

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

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

ראשית הגדרנו את ביט 4 של PORTD עם "sbi PORTD, 4" זה שולח 1 ל- PD4 אשר מעמיד את המתח ל- 5V על אותו סיכה. פעולה זו תדליק את הנורית. לאחר מכן אנו קופצים לשגרת המשנה "עיכוב" הסופרת 1/2 לשנייה (נסביר כיצד היא עושה זאת בהמשך). לאחר מכן אנו חוזרים למצמץ ולנקות את ביט 4 ב- PORTD אשר מגדיר את PD4 ל- 0V ומכבה את הנורית. לאחר מכן אנו מתעכבים עוד 1/2 שניות, ולאחר מכן קופצים חזרה לתחילת המצמוץ שוב עם "מצמוץ rjmp".

עליך להריץ את הקוד הזה ולראות שהוא עושה מה שהוא צריך.

והנה יש לך את זה! זה כל מה שהקוד הזה עושה פיזית. המכניקה הפנימית של מה שהמיקרו -בקר עושה מעורבים קצת יותר ולכן אנו עושים את ההדרכה הזו. אז בואו נדון בכל חלק בתורו.

שלב 4: הוראות מכלול.org

אנחנו כבר יודעים מה ההנחיות של.nolist,.list,.include ו-.def עושות מהדרכות הקודמות שלנו, אז קודם כל נסתכל על 4 שורות הקוד שיבואו לאחר מכן:

.org 0x0000

jmp אפס.org 0x0020 jmp overflow_handler

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

ובכן זה המקום שבו הדברים נעשים מעניינים. כעת תצטרך לפתוח מציג pdf עם גליון הנתונים המלא של ATmega328p עליו הצבעתי בעמוד הראשון של מדריך זה (לכן זהו פריט 4 בסעיף "תצטרך"). אם המסך שלך קטן מדי או שיש לך יותר מדי חלונות פתוחים כבר (כפי שקורה אצלי) תוכל לעשות מה שאני עושה ולשים אותו על Ereader או על טלפון Android שלך. אתה תשתמש בו כל הזמן אם אתה מתכנן לכתוב קוד הרכבה. הדבר המגניב הוא שכל בקרי המיקרו מאורגנים בדרכים דומות מאוד ולכן ברגע שתתרגלו לקרוא גליונות נתונים וקידוד מהם תגלו שזה כמעט טריוויאלי לעשות את אותו הדבר עבור מיקרו -בקר אחר. אז למעשה אנו לומדים כיצד להשתמש בכל בקרי המיקרו במובן מסוים ולא רק ב- atmega328p.

אוקיי, פנה לעמוד 18 בגיליון הנתונים והסתכל באיור 8-2.

כך מוגדר זיכרון התוכנית במיקרו -בקר. אתה יכול לראות שהוא מתחיל בכתובת 0x0000 והוא מופרד לשני חלקים; קטע פלאש יישומי ומקטע פלאש אתחול. אם תתייחס בקצרה לעמוד 277 טבלה 27-14 תראה שמקטע פלאש היישומים תופס את המיקומים מ- 0x0000 עד 0x37FF וחלק הבזק האתחול תופס את שאר המיקומים מ- 0x3800 ל- 0x3FFF.

תרגיל 1: כמה מיקומים יש בזיכרון התוכנית? כְּלוֹמַר. להמיר 3FFF לעשרוני ולהוסיף 1 מכיוון שאנו מתחילים לספור ב 0. מכיוון שכל מיקום זיכרון הוא ברוחב 16 סיביות (או 2 בתים) מהו המספר הכולל של בתים של זיכרון? עכשיו המירו את זה לקילובייט, זכרו שיש 2^10 = 1024 בתים בקילובייט. קטע הבזק האתחול עובר מ 0x3800 ל 0x37FF, כמה קילובייט זה? כמה קילוגרמים של זיכרון נותרו לנו לשימוש לאחסון התוכנית שלנו? במילים אחרות, עד כמה התוכנית שלנו יכולה להיות גדולה? לבסוף, כמה שורות קוד יכולות להיות לנו?

בסדר, עכשיו כשאנחנו יודעים הכל על ארגון זיכרון תוכנת הפלאש, בואו נמשיך בדיון שלנו בהצהרות.org. אנו רואים שמיקום הזיכרון הראשון 0x0000 מכיל את ההנחיה שלנו לקפוץ לקטע שלנו שסימנו אותו איפוס. כעת אנו רואים מה עושה הצהרת ".org 0x0020". כתוב שאנחנו רוצים שההוראה בשורה הבאה תוצב במיקום הזיכרון 0x0020. ההוראה שהצבנו שם היא קפיצה לחלק בקוד שלנו שסימנו "overflow_handler" … עכשיו למה לעזאזל היינו דורשים שהקפיצה הזו תוצב במיקום הזיכרון 0x0020? כדי לברר זאת, אנו פונים לעמוד 65 בגיליון הנתונים ומסתכלים בטבלה 12-6.

טבלה 12-6 היא טבלה של "איפוס וקטעי וקטורים" והיא מראה בדיוק לאן המחשב יגיע כשהוא יקבל "הפרעה". לדוגמה, אם אתה מסתכל על מספר וקטור 1. "המקור" של ההפרעה הוא "איפוס" שמוגדר כ"סיכה חיצונית, איפוס הפעלה, איפוס השחמה ואיפוס מערכת כלב השמירה ", אם בכלל הדברים האלה קורים לבקר המיקרו שלנו, המחשב יתחיל לבצע את התוכנית שלנו במיקום זיכרון התוכנית 0x0000. מה עם ההנחיה שלנו.org אז? ובכן, הנחנו פקודה במיקום הזיכרון 0x0020 ואם תסתכל למטה בטבלה תראה שאם יתרחש הצפה של טיימר/מונה 0 (שמגיע מ- TIMER0 OVF) הוא יבצע כל מה שנמצא במיקום 0x0020. אז בכל פעם שזה יקרה, המחשב האישי יקפוץ למקום שסימנו "overflow_handler". מגניב נכון? תראה תוך דקה מדוע עשינו זאת, אך ראשית בוא נסיים את שלב זה של ההדרכה בצד.

אם ברצוננו להפוך את הקוד שלנו למסודר ומסודר יותר עלינו באמת להחליף את 4 השורות בהן אנו דנים כרגע בפריטים הבאים (ראה עמוד 66):

.org 0x0000

איפוס rjmp; מחשב = 0x0000 רטי; מחשב = 0x0002 reti; מחשב = 0x0004 reti; מחשב = 0x0006 reti; מחשב = 0x0008 reti; מחשב = 0x000A… reti; PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti; מחשב = 0x0030 reti; מחשב = 0x0032

כך שאם מתרחשת הפרעה נתונה היא רק "reti" שפירושה "חזרה מהפרעה" ושום דבר אחר לא יקרה. אבל אם לעולם לא "הפעל" את ההפרעות השונות הללו, אז הן לא ישמשו אותנו ונוכל לשים את קוד התוכנית בנקודות אלה. בתוכנית "blink.asm" הנוכחית שלנו אנו הולכים רק לאפשר את מפסק הצפת הטיימר 0 (וכמובן את הפרעת האיפוס שתמיד מופעלת) וכך לא נתעסק באחרים.

כיצד אנו "מאפשרים" את הפרעת הצפת הטיימר 0 אז? … זה הנושא של השלב הבא שלנו במדריך זה.

שלב 5: טיימר/מונה 0

טיימר/מונה 0
טיימר/מונה 0

תסתכל על התמונה למעלה. זהו תהליך קבלת ההחלטות של ה- "PC" כאשר השפעה חיצונית כלשהי "קוטעת" את זרימת התוכנית שלנו. הדבר הראשון שהוא עושה כאשר הוא מקבל אות מבחוץ כי התרחשה הפרעה הוא לבדוק אם הגדרנו את ביט "הפסקת ההפסקה" לסוג ההפסקה הזה. אם לא עשינו זאת, זה פשוט ממשיך לבצע את שורת הקוד הבאה שלנו. אם הגדרנו את ביט ההפסק הספציפי הזה (כך שיש 1 במיקום הסיביות במקום 0) הוא יבדוק אם הפעלנו "הפרעות גלובליות" או לא, אם לא הוא יעבור שוב לשורה הבאה או לא. של קוד והמשך. אם אפשרנו גם הפרעות גלובליות, הוא יעבור למיקום זיכרון התוכניות של סוג ההפסקה (כפי שמוצג בטבלה 12-6) ויבצע את כל הפקודות שהצבנו שם. אז בואו נראה איך יישמנו את כל זה בקוד שלנו.

הקטע 'איפוס שכותרתו' בקוד שלנו מתחיל בשתי השורות הבאות:

אִתחוּל:

ldi temp, 0b00000101 out TCCR0B, temp

כפי שאנו כבר יודעים, זה עולה לטמפ '(כלומר R16) את המספר מיד לאחר מכן, שהוא 0b00000101. לאחר מכן הוא כותב את המספר הזה לרשם בשם TCCR0B באמצעות הפקודה "החוצה". מה זה הרישום הזה? ובכן, נעבור לעמוד 614 של גליון הנתונים. זהו באמצע טבלה המסכמת את כל הרשמים. בכתובת 0x25 תמצא TCCR0B. (עכשיו אתה יודע מאיפה הגיע השורה "out 0x25, r16" בגרסה שלי ללא הערות של הקוד). אנו רואים לפי קטע הקוד למעלה שהגדרנו את הסיביות ה -0 והסיביה השנייה ופינינו את כל השאר. על ידי התבוננות בטבלה אתה יכול לראות שזה אומר שהגדרנו CS00 ו- CS02. כעת נעבור לפרק בגיליון הנתונים שנקרא "טיימר 8-ביט/מונה 0 עם PWM". בפרט עברו לעמוד 107 של אותו פרק. אתה תראה את אותו תיאור של פנקס "טיימר/בקרת נגד נגד B" (TCCR0B) שראינו זה עתה בטבלת סיכום הרשומות (כך שיכולנו להגיע ישירות לכאן, אך רציתי שתראה כיצד להשתמש בטבלאות הסיכום) לייחוס בעתיד). גיליון הנתונים ממשיך לתת תיאור של כל אחד מהסיביות ברשם זה ומה הם עושים. נדלג על כל זה לעת עתה ונעבור את הדף לטבלה 15-9. טבלה זו מציגה את "תיאור סיביות בחר שעון". עכשיו תסתכל למטה בטבלה עד שתמצא את השורה התואמת את הביטים שהרגע הגדרנו ברגיסט זה. בשורה כתוב "clk/1024 (ממריץ)". המשמעות של זה היא שאנחנו רוצים ש- Timer/Counter0 (TCNT0) יתקתק בקצב שהוא תדר המעבד המחולק ב- 1024. מכיוון שאנו מקבלים את המיקרו -בקר שלנו על ידי מתנד קריסטל של 16 מגה -הרץ, המשמעות היא שהקצב שהמעבד שלנו מבצע הוראות הוא 16 מיליון הוראות לשנייה. אז השיעור שמונה TCNT0 שלנו יתקתק הוא 16 מיליון/1024 = 15625 פעמים בשנייה (נסה אותו עם סיביות שונות של שעון ותראה מה קורה - זוכר את הפילוסופיה שלנו?). בואו נשמור את המספר 15625 בעוכרינו להמשך ונעבור לשתי שורות הקוד הבאות:

ldi טמפ ', 0b00000001

sts TIMSK0, טמפ '

זה מגדיר את הסיביה ה -0 של רישום בשם TIMSK0 ומנקה את כל השאר. אם תסתכל על עמוד 109 בגיליון הנתונים תראה כי TIMSK0 מייצג "Timer/Counter Interrupt Mask Register 0" והקוד שלנו קבע את הביט ה 0 שנקרא TOIE0 שמייצג "Timer/Counter0 Overflow Interrupt Enable" … שם! עכשיו אתה רואה על מה מדובר. כעת יש לנו את "סט ההפעלה של הפסקת ההפסקה" כפי שרצינו מההחלטה הראשונה בתמונה שלנו למעלה. אז כל שעלינו לעשות הוא לאפשר "הפרעות גלובליות" והתוכנית שלנו תוכל להגיב להפרעות מסוג זה. אנו נאפשר הפרעות גלובליות בקרוב, אך לפני שנעשה זאת יתכן שהתבלבלת ממשהו.. למה לעזאזל השתמשתי בפקודה "sts" כדי להעתיק לרשם TIMSK0 במקום "החוצה" הרגילה?

בכל פעם שאתה רואה אותי השתמש בהוראה שלא ראית לפני שהדבר הראשון שעליך לעשות הוא לפנות לעמוד 616 בגיליון הנתונים. זהו "סיכום מערך ההוראות". כעת מצא את ההוראה "STS" שהיא זו שהשתמשתי בה. כתוב שהוא לוקח מספר מרשם R (השתמשנו ב- R16) ומיקום "אחסן ישירות ל- SRAM" k (במקרה שלנו ניתן על ידי TIMSK0). אז למה היינו צריכים להשתמש ב- "sts" שלוקח 2 מחזורי שעון (ראה עמודה אחרונה בטבלה) כדי לאחסן ב- TIMSK0 והיינו צריכים רק "out", שלוקח רק מחזור שעון אחד, כדי לאחסן אותו ב- TCCR0B לפני? כדי לענות על שאלה זו עלינו לחזור לטבלת סיכום הרישומים שלנו בעמוד 614. אתה רואה שהרשם TCCR0B נמצא בכתובת 0x25 אבל גם ב (0x45) נכון? המשמעות היא שמדובר ברישום ב- SRAM, אך זהו גם סוג מסוים של רגיסטר הנקרא "יציאה" (או רשום i/o). אם תסתכל על טבלת סיכום ההוראות לצד הפקודה "החוצה" תראה שהיא לוקחת ערכים מ"רישומי העבודה "כמו R16 ושולחת אותם לנמל. כך שנוכל להשתמש ב"אאוט "בעת כתיבה ל- TCCR0B ולחסוך לעצמנו מחזור שעון. אבל עכשיו חפש את TIMSK0 בטבלת הרישום. אתה רואה שיש לה כתובת 0x6e. זה מחוץ לטווח היציאות (שהן רק המיקומים הראשונים של 0x3F של SRAM) ולכן עליך לחזור להשתמש בפקודה sts ולוקח שני מחזורי שעון מעבד כדי לעשות זאת. אנא קראו הערה 4 בסוף טבלת סיכום ההוראות בעמוד 615 כרגע. שימו לב גם שכל יציאות הקלט והפלט שלנו, כמו PORTD, ממוקמות בתחתית הטבלה. לדוגמה, PD4 הוא ביט 4 בכתובת 0x0b (עכשיו אתה רואה מאיפה כל החומרים של 0x0b הגיע בקוד שלי שלא הגיב!).. בסדר, שאלה מהירה: האם שינית את ה"סטס "ל"חוצה" וראית מה קורה? זכור את הפילוסופיה שלנו! שבור את זה! אל תיקח את דבריי לדברים.

אוקיי, לפני שנמשיך, פנה לדף 19 בגיליון הנתונים לדקה. אתה רואה תמונה של זיכרון הנתונים (SRAM). 32 הרישומים הראשונים ב- SRAM (מ- 0x0000 עד 0x001F) הם "רישומי העבודה למטרות כלליות" R0 עד R31 בהם אנו משתמשים כל הזמן כמשתנים בקוד שלנו.64 הרשמים הבאים הם יציאות הקלט/פלט עד 0x005f (כלומר אלה שדיברנו עליהן שיש להן את הכתובות הלא-סוגריות לצידן בטבלת הרישום בהן נוכל להשתמש בפקודה "out" במקום ב- "sts") לבסוף החלק הבא של SRAM מכיל את כל הרשמים האחרים בטבלת הסיכום עד לכתובת 0x00FF, ולבסוף השאר הוא SRAM פנימי. עכשיו מהר, בואו נעבור לדף 12 לשנייה. שם אתה רואה טבלה של "רשימות העבודה למטרות כלליות" שתמיד אנו משתמשים בהן כמשתנים שלנו. אתה רואה את הקו העבה בין המספרים R0 עד R15 ואז R16 עד R31? השורה הזו היא הסיבה לכך שאנחנו תמיד משתמשים ב- R16 כקטן ביותר ואני אכנס לזה קצת יותר במדריך הבא שבו נזדקק גם לשלושת רשימות הכתובות העקיפות של 16 סיביות, X, Y ו- Z. לא אעשה זאת להיכנס לזה עדיין אבל מכיוון שאנחנו לא צריכים את זה עכשיו ואנחנו מסתבכים מספיק כאן.

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

sbi SREG, אני

מה שמגדיר את הקטע שנקרא "אני" במרשם SREG. עם זאת, במקום זה השתמשנו בהוראה

אמר

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

בסדר! כעת הכנו את הפרעות ההצפה לדרך כך ש- jmp overflow_handler שלנו יופעל בכל פעם שתתרחש.

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

טמפ 'clr

out TCNT0, temp sbi DDRD, 4

השורה האחרונה כאן די ברורה. זה רק מגדיר את הקטע הרביעי של Register Data Direction עבור PortD וגורם ל- PD4 להיות OUTPUT.

הראשון מגדיר את הטמפ 'משתנה לאפס ולאחר מכן מעתיק את זה לרשם TCNT0. TCNT0 הוא טיימר/מונה 0 שלנו. זה מגדיר את זה לאפס. ברגע שהמחשב יבצע קו זה הטיימר 0 יתחיל באפס ויספור בקצב של 15625 פעמים בכל שנייה. הבעיה היא כזו: TCNT0 הוא רישום "8 סיביות" נכון? אז מהו המספר הגדול ביותר שמרשם 8 סיביות יכול להכיל? ובכן 0b11111111 זה. זהו המספר 0xFF. שזה 255. אז אתה רואה מה קורה? הטיימר מתרחב לאורך 15625 פעמים בשנייה ובכל פעם שהוא מגיע ל -255 הוא "עולה על גדותיו" וחוזר ל 0 שוב. במקביל לחזרה לאפס הוא שולח אות הפרעה של טיימר. המחשב מקבל את זה ואתה יודע מה זה עושה עכשיו נכון? כֵּן. הוא עובר למיקום זיכרון התוכנית 0x0020 ומבצע את ההוראה שהוא מוצא שם.

גדול! אם אתה עדיין איתי אתה גיבור על בלתי נלאה! בואו נמשיך…

שלב 6: מטפל בהצפה

אז נניח שהרשם טיימר/counter0 פשוט עלה על גדותיו. כעת אנו יודעים כי התוכנית מקבלת אות הפסקה ומפעילה 0x0020 שאומרת לדלפק התוכניות, המחשב האישי לקפוץ לתווית "overflow_handler" להלן הקוד שכתבנו לאחר אותה תווית:

overflow_handler:

inc overflows cpi overflows, 61 brne PC+2 clr overflows reti

הדבר הראשון שהוא עושה הוא להגדיל את המשתנה "הצפות" (שזה השם שלנו לרשם עבודה למטרות כלליות R17) ואז הוא "משווה" את תוכן הצפות למספר 61. הדרך שבה ההפעלה cpi עובדת היא שהיא פשוט מפחיתה שני המספרים ואם התוצאה היא אפס זה מגדיר את דגל ה- Z בפנקס ה- SREG (אמרתי לך שנראה את הרישום הזה כל הזמן). אם שני המספרים שווים אז דגל Z יהיה 1, אם שני המספרים אינם שווים אז הוא יהיה 0.

בשורה הבאה כתוב "brne PC+2" שפירושו "ענף אם לא שווה". בעיקרו של דבר, הוא בודק את דגל Z ב- SREG ואם הוא אינו אחד (כלומר שני המספרים אינם שווים, אם היו שווים, דגל האפס היה מוגדר) ה- PC מסתעף ל- PC+2, כלומר הוא מדלג על הבא קו ויוצא ישר אל "reti" שחוזר מההפסקה לכל מקום שהיה בקוד כשההפסקה הגיעה. אם הוראת ה- brne הייתה מוצאת סיבית 1 בדגל האפס היא לא הייתה מסתעפת ובמקום זאת היא פשוט תמשיך לשורה הבאה שתגרום ל- clr הצפות לאפס אותה ל- 0.

מה התוצאה נטו של כל זה?

ובכן אנו רואים כי בכל פעם שיש הצפת טיימר המטפל הזה מעלה את ערך "הצפות" באחד. לכן המשתנה "הצפות" הוא ספירת מספר הצפות כפי שהן מתרחשות. בכל פעם שהמספר מגיע ל -61 אנו מאפסים אותו לאפס.

עכשיו למה בכלל לעשות את זה?

בוא נראה. נזכיר שמהירות השעון שלנו עבור המעבד שלנו היא 16 מגה -הרץ ואנחנו "מסדרנו אותו מראש" באמצעות TCCR0B כך שהטיימר נספר רק בקצב של 15625 ספירות לשנייה נכון? ובכל פעם שהטיימר מגיע לספירה של 255 הוא עולה על גדותיו. אז זה אומר שהוא עולה על גדותיו 15625/256 = 61.04 פעמים בשנייה. אנו עוקבים אחר מספר הצפות עם המשתנה שלנו "הצפות" ואנו משווים מספר זה עם 61. אז אנו רואים ש"הצפות "יהיו שוות 61 פעם בשנייה! אז המטפל שלנו יאפס את "הצפות" לאפס אחת לשנייה. אז אם היינו פשוט עוקבים אחר המשתנה "הצפות" ושמים לב בכל פעם שהוא מתאפס לאפס היינו סופרים שנייה-שנייה בזמן אמת (שימו לב שבמדריך הבא נראה איך להגיע למדויק יותר עיכוב באלפיות השנייה באותה הדרך בה פועלת שגרת ה"השהיה "של ארדואינו).

כעת "טיפלנו" בהפרעות הצפת הטיימר. וודא שאתה מבין כיצד זה עובד ולאחר מכן המשך לשלב הבא שבו אנו משתמשים בעובדה זו.

שלב 7: עיכוב

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

תסתכל על הקוד הבא מתוך העיכוב שלנו: תווית

לְעַכֵּב:

clr מציף sec_count: cpi עולה, 30 brne sec_count ret

אנחנו הולכים לקרוא לזה תת -שגרה בכל פעם שאנחנו צריכים עיכוב בתוכנית שלנו. אופן פעולתו הוא שהוא מגדיר תחילה את המשתנה "הצפות" לאפס. ואז הוא נכנס לאזור שכותרתו "sec_count" ומשווה הצפות עם 30, אם הם לא שווים הוא מסתעף חזרה לתווית sec_count ומשווה שוב ושוב וכו 'עד שהם שווים סוף סוף (זכרו שכל הזמן זה הולך ב- handler interrupt timer שלנו ממשיך להגדיל את הצפי של המשתנה ולכן הוא משתנה בכל פעם שאנו מסתובבים כאן. כאשר הצפות בסופו של דבר שוות 30 זה יוצא מהלולאה וחוזר לכל מקום אליו קראנו עיכוב: מ. התוצאה נטו היא עיכוב של 1/2 שנייה

תרגיל 2: שנה את שגרת overflow_handler לשורות הבאות:

overflow_handler:

inc מציף reti

ולהפעיל את התוכנית. האם משהו שונה? למה או למה לא?

שלב 8: מצמוץ

לבסוף בואו נסתכל על שגרת ההבהוב:

לְמַצְמֵץ:

sbi PORTD, 4 rcall delay cbi PORTD, 4 rc delay delay rjmp blink

ראשית אנו מפעילים את PD4, ולאחר מכן אנו קוראים לתת שגרת העיכוב שלנו. אנו משתמשים ב- rcall כך שכאשר המחשב יגיע להצהרת "ret" הוא יחזור לשורה שאחרי rcall. לאחר מכן עיכוב שגרת העיכוב במשך 30 ספירות במשתנה ההצפה כפי שראינו וזה כמעט 1/2 שנייה בדיוק, לאחר מכן אנו מכבים את PD4, מעכבים עוד 1/2 שנייה ולאחר מכן חוזרים שוב להתחלה.

התוצאה נטו היא נורית מהבהבת!

אני חושב שעכשיו תסכים ש"מצמץ "היא כנראה לא התוכנית הטובה ביותר" עולם שלום "בשפת הרכבה.

תרגיל 3: שנה את הפרמטרים השונים בתוכנית כך שהנורית מהבהבת בקצב שונה כמו שנייה או 4 פעמים בשנייה וכו 'תרגיל 4: שנה אותו כך שהנורית תידלק וכיבוי במשך פרקי זמן שונים. לדוגמה מופעל למשך 1/4 שנייה ולאחר מכן כבוי למשך 2 שניות או משהו כזה. תרגיל 5: שנה את שעון TCCR0B בחר סיביות ל -100 ולאחר מכן המשך בעלייה בטבלה. באיזה שלב הוא לא ניתן להבחין בין התוכנית "hello.asm" שלנו מהדרכה 1? תרגיל 6 (אופציונלי): אם יש לך מתנד קריסטל אחר, כמו 4 מגה -הרץ או 13.5 מגה -הרץ או כל דבר אחר, שנה את מתנד 16 מגה -הרץ שלך על לוח הלחם שלך עבור החדש ולראות כיצד זה משפיע על קצב המהבהב של הנורית. כעת אתה אמור להיות מסוגל לעבור את החישוב המדויק ולחזות בדיוק כיצד הוא ישפיע על התעריף.

שלב 9: מסקנה

לאלה מביניכם שהגיעו עד לכאן, מזל טוב!

אני מבין שזה די קשה לזרוק כשאתה קורא ומסתכל למעלה מאשר שאתה מחווט ומתנסה אבל אני מקווה שלמדת את הדברים החשובים הבאים:

  1. כיצד פועל זיכרון התוכנית
  2. כיצד פועל SRAM
  3. כיצד לחפש את הרשומות
  4. כיצד לחפש הוראות ולדעת מה הן עושות
  5. כיצד ליישם הפרעות
  6. כיצד ה- CP מבצע את הקוד, כיצד פועל ה- SREG ומה קורה במהלך הפרעות
  7. איך לעשות לולאות וקפיצות ולהקפיץ את הקוד
  8. כמה חשוב לקרוא את גליון הנתונים!
  9. איך ברגע שתדע איך לעשות את כל זה עבור המיקרו -בקר Atmega328p זה יהיה הליכה עוגה יחסית ללמוד כל בקרים חדשים שמעניינים אותך.
  10. כיצד לשנות את זמן המעבד לזמן אמת ולהשתמש בו בשגרות עיכוב.

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

תרגיל 7: "שברו" את הקוד בדרכים שונות וראו מה קורה! סקרנות מדעית מותק! מישהו אחר יכול לשטוף את הכלים נכון תרגיל 8: הרכיב את הקוד באמצעות האפשרות "-l" ליצירת קובץ רשימה. כְּלוֹמַר. "avra -l blink.lst blink.asm" והסתכל על קובץ הרשימה. אשראי נוסף: הקוד שלא נתנו הערות שנתתי בהתחלה והקוד שהגיב עליו נדון אחר כך שונים! יש שורת קוד אחת שונה. האם תוכל למצוא אותו? למה ההבדל הזה לא משנה?

מקווה שנהנת! נתראה בפעם הבאה…

מוּמלָץ: