Բովանդակություն:

AVR Assembler ձեռնարկ 3: 9 քայլեր
AVR Assembler ձեռնարկ 3: 9 քայլեր

Video: AVR Assembler ձեռնարկ 3: 9 քայլեր

Video: AVR Assembler ձեռնարկ 3: 9 քայլեր
Video: LDmicro 22: Arduino տախտակներ AVRDUDESS- ով (միկրոկառավարիչների ծրագրավորում LDmicro- ով) 2024, Հուլիսի
Anonim
AVR Assembler ձեռնարկ 3
AVR Assembler ձեռնարկ 3

Բարի գալուստ ձեռնարկ թիվ 3:

Նախքան սկսելը, ես ուզում եմ մի փիլիսոփայական միտք անել: Մի վախեցեք փորձարկել այն սխեմաները և ծածկագիրը, որը մենք կառուցում ենք այս ձեռնարկներում: Փոխեք լարերը շուրջը, ավելացրեք նոր բաղադրիչներ, հանեք բաղադրիչները, փոխեք ծածկագրի տողերը, ավելացրեք նոր տողեր, ջնջեք տողերը և տեսեք, թե ինչ է տեղի ունենում: Շատ դժվար է ինչ -որ բան կոտրելը, և եթե դա անում ես, ո՞ւմ է դա հետաքրքրում: Ոչ մի բան, ինչ մենք օգտագործում ենք, ներառյալ միկրոկառավարիչը, շատ թանկ չէ և միշտ կրթական է տեսնել, թե ինչպես կարող են ամեն ինչ ձախողվել: Ոչ միայն կիմանաք, թե ինչ չանել հաջորդ անգամ, այլ, որ ավելի կարևոր է, կիմանաք, թե ինչու դա չանել: Եթե դուք ինձ նման եք, երբ դուք դեռ երեխա էիք և նոր խաղալիք ունեիք, շատ ժամանակ չանցավ, երբ այն կտոր -կտոր արեցիք ՝ տեսնելու, թե ինչն է այն ստիպում ճիշտ նշել: Երբեմն խաղալիքը հայտնվում էր անուղղելի վնասված, բայց ոչ մի մեծ բան: Թույլ տալ երեխային ուսումնասիրել իր հետաքրքրասիրությունը նույնիսկ կոտրված խաղալիքներով, այն է, ինչ նրան աման լվացող մեքենայի փոխարեն դարձնում է գիտնական կամ ճարտարագետ:

Այսօր մենք միացնելու ենք շատ պարզ միացում, այնուհետև մի փոքր ծանրաբեռնվելու ենք տեսության մեջ: Կներեք դրա համար, բայց մեզ գործիքներ են պետք: Ես խոստանում եմ, որ մենք դա կփոխհատուցենք ձեռնարկ 4 -ում, որտեղ մենք կանենք ավելի լուրջ շրջանի կառուցում, և արդյունքը կլինի բավականին զով: Այնուամենայնիվ, այն ամենը, ինչ դուք պետք է անեք այս բոլոր ձեռնարկները կատարելու համար, շատ դանդաղ, խորհրդածող ձևով է: Եթե դուք պարզապես թափանցեք, կառուցեք միացումը, պատճենեք և տեղադրեք ծածկագիրը և գործարկեք այն, իհարկե, այն կաշխատի, բայց դուք ոչինչ չեք սովորի: Պետք է մտածել յուրաքանչյուր տողի մասին: Դադար: Փորձ Հորինել. Եթե դուք այդպես վարվեք, ապա 5 -րդ ձեռնարկի վերջում դուք կազատվեք զովացուցիչ նյութերից և այլևս կրկնուսուցման կարիք չեք ունենա: Հակառակ դեպքում դուք պարզապես դիտում եք, այլ ոչ թե սովորում և ստեղծագործում:

Ամեն դեպքում, բավական փիլիսոփայություն, եկեք սկսենք:

Այս ձեռնարկում ձեզ հարկավոր է.

  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: Շղթայի կառուցում

Շղթայի կառուցում
Շղթայի կառուցում

Այս ձեռնարկի սխեման չափազանց պարզ է: Մենք ըստ էության պատրաստվում ենք գրել «թարթել» ծրագիրը, այնպես որ մեզ անհրաժեշտ է միայն հետևյալը.

Միացրեք LED- ը PD4- ին, այնուհետև 330 օմ ռեզիստորին, այնուհետև գետնին: այսինքն

PD4 - LED - R (330) - GND

ու վերջ!

Տեսությունը, սակայն, կոշտ խեղաթյուրում է լինելու…

Քայլ 2. Ինչու՞ են մեզ պետք մեկնաբանությունները և M328Pdef.inc ֆայլը:

Կարծում եմ, որ մենք պետք է սկսենք ցույց տալով, թե ինչու են ներառման ֆայլը և մեկնաբանությունները օգտակար: Դրանցից ոչ մեկն իրականում անհրաժեշտ չէ, և առանց դրանց նույն կերպ կարող եք գրել, հավաքել և վերբեռնել ծածկագիրը, և այն միանգամայն լավ կաշխատի (չնայած առանց ներառման ֆայլի դուք կարող եք որոշ բողոքներ ստանալ հավաքողից, բայց ոչ մի սխալ)

Ահա այն ծածկագիրը, որը մենք պատրաստվում ենք գրել այսօր, բացառությամբ, որ ես հեռացրել եմ մեկնաբանությունները և ներառող ֆայլը.

. սարք ATmega328P

.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16, 0x05 դուրս 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 դուրս 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

բավականին պարզ է, չէ՞ Հահա. Եթե հավաքեք և վերբեռնեք այս ֆայլը, դուք կհանգեցնեք LED- ի թարթմանը 1 վայրկյան արագությամբ, իսկ թարթումը ՝ 1/2 վայրկյան, իսկ թարթումների միջև ընդմիջումը ՝ 1/2 վայրկյան:

Այնուամենայնիվ, այս ծածկագրին նայելը դժվար թե լուսավորի: Եթե դուք գրեիք այսպիսի ծածկագիր, ապա կցանկանայիք այն փոփոխել կամ հետագայում նպատակ դնել, ձեզ համար դժվար կլիներ:

Այսպիսով, եկեք մեկնաբանությունները դնենք և ֆայլը նորից ներառենք, որպեսզի կարողանանք դրան որոշակի իմաստ տալ:

Քայլ 3: Blink.asm

Ահա այն կոդը, որը մենք այսօր կքննարկենք.

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

; գրել է ՝ 1o_o7; ամսաթիվ: տարբերակ `1.0; ֆայլը պահված է ՝ blink.asm; AVR- ի համար `atmega328p; ժամացույցի հաճախականությունը ՝ 16 ՄՀց (ըստ ցանկության); ***********************************; Funրագրի գործառույթը. ---------------------; վայրկյանները հաշվում է ՝ LED- ը թարթելով;; PD4 - LED - R (330 օմ) - GND;; --------------------------------------. անվանակոչ. ներառել "./m328Pdef.inc". ցանկ; ===============; Հռչակագրեր.. Def temp = r16.def overflows = r17.org 0x0000; հիշողության (ԱՀ) տեղադրման վերականգնման կարգավորիչի rjmp Վերակայում; jmp- ն արժե 2 պրոցեսորի ցիկլ, իսկ rjmp- ն ՝ ընդամենը 1; այնպես որ, եթե ձեզ հարկավոր չէ ցատկել ավելի քան 8k բայթ; ձեզ պետք է միայն rjmp: Հետևաբար, որոշ միկրոկոնտրոլերներ; ունենալ rjmp և ոչ jmp.org 0x0020; Timer0 overflow handler rjmp overflow_handler- ի հիշողության վայրը; գնացեք այստեղ, եթե տեղի է ունենում timer0- ի արտահոսքի ընդհատում; ============ Վերակայեք. ldi temp, 0b00000101 out TCCR0B, temp; ժամացույցի ընտրիչ բիթեր CS00, CS01, CS02 սահմանել 101; սա ժամաչափի հաշվիչը 0, TCNT0- ն դնում է FCPU/1024 ռեժիմի վրա; այնպես որ այն տիզում է պրոցեսորի հաճախականությամբ/1024 ldi ջերմաստիճանում, 0b00000001 տ. TIMSK0, ջերմաստիճան; սահմանել Timer Overflow Interrupt Enable (TOIE0) բիթը; Timer Interrupt Mask Register- ի (TIMSK0) sei; միացնել գլոբալ ընդհատումները `համարժեք« sbi SREG, I »clr temp out TCNT0, temp; սկզբնականացնել erամաչափը/հաշվիչը 0 sbi DDRD, 4; սահմանել PD4- ը ելքային; ======================; Mainրագրի հիմնական մարմինը ՝ թարթել ՝ sbi PORTD, 4; միացրեք LED- ը PD4- ի զանգի հետաձգման վրա; ուշացումը կլինի 1/2 վայրկյան cbi PORTD, 4; անջատել LED- ը PD4- ի զանգի հետաձգման վրա; ուշացումը կլինի 1/2 վայրկյան rjmp թարթում; loop back to the start delay: clr overflows; սահմանել արտահոսքերը 0 վայրկյան_հաշիվ `cpi գերհոսում, 30; համեմատել արտահոսքերի քանակը և 30 brne sec_count; մասնաճյուղ վերադառնալ դեպի sec_count, եթե ոչ հավասար ret; եթե 30 հեղեղ է տեղի ունեցել, վերադարձը թարթելու համար overflow_handler: inc overflows; ավելացնել 1 -ի գերհոսքերի փոփոխական cpi- ի արտահոսքերին, 61; համեմատել 61 brne PC+2; Countրագրի հաշվիչ + 2 (բաց թողնել հաջորդ տողը), եթե ոչ հավասար clr վարարումներ; եթե տեղի է ունեցել 61 արտահոսք, հաշվիչը զրոյական ռետիի է վերածել. վերադառնալ ընդհատումից

Ինչպես տեսնում եք, հիմա իմ մեկնաբանությունները մի փոքր ավելի կարճ են: Երբ մենք իմանանք, թե ինչ հրահանգներ են պարունակում հրահանգների հավաքածուն, մենք կարիք չունենք դա բացատրել մեկնաբանություններում: Մեզ մնում է միայն բացատրել, թե ինչ է կատարվում ծրագրի տեսանկյունից:

Մենք կքննարկենք, թե ինչ է անում այս ամենը մաս առ մաս, բայց նախ փորձենք գլոբալ հեռանկար ստանալ: Theրագրի հիմնական մարմինն աշխատում է հետևյալ կերպ.

Սկզբում մենք PORTD- ի բիթ 4 -ը դնում ենք «sbi PORTD, 4» թվով, սա 1 է ուղարկում PD4- ին, որը լարումը դնում է 5V- ի վրա այդ քորոցին: Սա կմիացնի LED- ը: Այնուհետև մենք անցնում ենք «հետաձգման» ենթածրագրին, որը հաշվում է 1/2 վայրկյան (մենք կբացատրենք, թե ինչպես է դա անում ավելի ուշ): Այնուհետև մենք վերադառնում ենք թարթելու և մաքրելու 4 բիթը PORTD- ում, որը PD4- ն սահմանում է 0V և, հետևաբար, անջատում է LED- ը: Հետո մենք հետաձգում ենք ևս 1/2 վայրկյան, այնուհետև նորից վերադառնում ենք թարթման սկզբին կրկին «rjmp blink» - ով:

Դուք պետք է գործարկեք այս կոդը և տեսեք, որ այն անում է այն, ինչ պետք է:

Եվ ահա դուք ունեք այն: Այս ամենը ֆիզիկապես անում է այս կոդը: Միկրոկոնտրոլերի ներքին մեխանիկան մի փոքր ավելի ներգրավված է, և այդ պատճառով մենք անում ենք այս ձեռնարկը: Այսպիսով, եկեք հերթով քննարկենք յուրաքանչյուր հատված:

Քայլ 4.. Org Assembler դիրեկտիվներ

Մենք արդեն գիտենք, թե ինչ են անում.nolist,.list,.include և.def assembler հրահանգները մեր նախորդ ձեռնարկներից, ուստի եկեք նախ նայենք դրանից հետո եկող 4 տողերի կոդերին.

.org 0x0000

jmp Վերակայել.org 0x0020 jmp overflow_handler

. Org- ի հայտարարությունը հավաքողին ասում է, թե որտեղ է «Memրագրի հիշողություն» բաժնում տեղադրել հաջորդ հայտարարությունը: Programրագրի գործարկման ընթացքում «Countրագրի հաշվիչը» (կրճատված է որպես ԱՀ) պարունակում է ընթացիկ տողի հասցեն: Այսպիսով, այս դեպքում, երբ համակարգիչը գտնվում է 0x0000- ում, այն կտեսնի «jmp Reset» հրամանը, որը բնակվում է այդ հիշողության վայրում: Պատճառն այն է, որ մենք ցանկանում ենք jmp Reset- ը տեղադրել այդ վայրում, այն է, որ երբ ծրագիրը սկսվում է, կամ չիպը վերակայվում է, համակարգիչը սկսում է այս վայրում կատարել կոդը: Այսպիսով, ինչպես տեսնում ենք, մենք պարզապես ասել ենք նրան, որ անմիջապես «անցնի» դեպի «Վերագործարկեք» պիտակով բաժինը: Ինչու՞ դա արեցինք: Դա նշանակում է, որ վերը նշված վերջին երկու տողերը պարզապես բաց են թողնվում: Ինչո՞ւ:

Դե, այստեղ ամեն ինչ հետաքրքիր է դառնում: Այժմ դուք ստիպված կլինեք բացել pdf դիտիչ ՝ ամբողջական ATmega328p տվյալների թերթիկով, որը ես մատնանշեցի այս ձեռնարկի առաջին էջում (այդ իսկ պատճառով «ձեզ պետք կգա» բաժնի 4 -րդ կետն է): Եթե ձեր էկրանը չափազանց փոքր է, կամ արդեն շատ պատուհաններ ունեք բացված (ինչպես ինձ մոտ է), կարող եք անել այն, ինչ ես եմ անում և տեղադրել այն Ereader- ի կամ ձեր Android հեռախոսի վրա: Դուք այն մշտապես կօգտագործեք, եթե պլանավորում եք գրել հավաքման կոդ: Ամենահետաքրքիրն այն է, որ բոլոր միկրոկոնտրոլերները կազմակերպվում են շատ նման ձևերով, ուստի երբ ընտելանաք տվյալների թերթեր կարդալուն և դրանցից ծածկագրելուն, գրեթե աննշան կլինի նույնը անել այլ միկրոկոնտրոլերի համար: Այսպիսով, մենք իրականում սովորում ենք, թե ինչպես օգտագործել բոլոր միկրոկոնտրոլերները ինչ -որ իմաստով և ոչ միայն atmega328p- ը:

Լավ, դիմեք տվյալների թերթի 18-րդ էջին և նայեք Նկար 8-2-ին:

Այսպես է ստեղծվում միկրոկառավարիչի Memրագրի հիշողությունը: Դուք կարող եք տեսնել, որ այն սկսվում է 0x0000 հասցեով և բաժանված է երկու բաժնի. դիմումի ֆլեշ հատված և բեռնման ֆլեշ հատված: Եթե հակիրճ հղում կատարեք 277-րդ աղյուսակ 27-14-րդ էջին, կտեսնեք, որ հավելվածի ֆլեշ հատվածը զբաղեցնում է 0x0000- ից մինչև 0x37FF- ի տեղերը, իսկ բեռնախցիկի բռնկման բաժինը զբաղեցնում է մնացած տեղերը 0x3800- ից մինչև 0x3FFF:

Ercորավարժություն 1. Քանի՞ տեղ կա memoryրագրի հիշողության մեջ: Այսինքն 3FFF- ը վերածել տասնորդականի և ավելացնել 1, քանի որ սկսում ենք հաշվել 0 -ով: Քանի որ հիշողության յուրաքանչյուր վայրը 16 բիթ (կամ 2 բայթ) լայնություն ունի, որքա՞ն է հիշողության բայթերի ընդհանուր թիվը: Այժմ փոխարկեք սա կիլոբայթների ՝ հիշելով, որ կիլոբայթում կա 2^10 = 1024 բայթ: Բեռնախցիկի բռնկման հատվածը 0x3800- ից անցնում է 0x37FF, քանի՞ կիլոբայթ է սա: Քանի՞ կիլոբայթ հիշողություն է մեզ մնում, որ օգտագործենք մեր ծրագիրը պահելու համար: Այսինքն, որքանո՞վ կարող է մեծ լինել մեր ծրագիրը: Ի վերջո, քանի՞ տող կոդ կարող ենք ունենալ:

Լավ, հիմա, երբ մենք ամեն ինչ գիտենք ֆլեշ ծրագրի հիշողության կազմակերպման մասին, եկեք շարունակենք.org հայտարարությունների մեր քննարկումը: Մենք տեսնում ենք, որ հիշողության առաջին վայրը 0x0000 պարունակում է մեր հրահանգը ՝ անցնել մեր այն հատվածին, որը մենք պիտակեցինք Վերագործարկեք: Այժմ մենք տեսնում ենք, թե ինչ է անում «.org 0x0020» հայտարարությունը: Այն ասում է, որ մենք ցանկանում ենք, որ հաջորդ տողի հրահանգը տեղադրվի 0x0020 հիշողության վայրում: Այն հրահանգը, որը մենք տեղադրել ենք այնտեղ, մեր կոդի մի հատվածի անցումն է, որը մենք մակնշել ենք «overflow_handler» … հիմա ինչու՞ ենք մենք պահանջելու, որ այս թռիչքը տեղադրվի հիշողության վայրում 0x0020: Դա պարզելու համար մենք դիմում ենք տվյալների թերթիկի 65-րդ էջին և հայացք նետում Աղյուսակ 12-6-ին:

Աղյուսակ 12-6-ը «Վերականգնել և ընդհատել վեկտորների» աղյուսակն է և այն ցույց է տալիս, թե կոնկրետ ուր կգնա ԱՀ-ն, երբ ստանա «ընդհատում»: Օրինակ, եթե նայեք Վեկտորի համար 1-ին, ընդհատման «աղբյուրը» «RESET» է, որը սահմանվում է որպես «External Pin, Power-on Reset, Brown-out Reset, and Watchdog system reset», եթե որևէ մեկը այդ բաները տեղի են ունենում մեր միկրոկառավարիչի հետ, համակարգիչը կսկսի մեր ծրագիրը կատարել ծրագրի հիշողության 0x0000 վայրում: Իսկ ի՞նչ կասեք մեր.org հրահանգի մասին: Դե, մենք հրաման ենք տեղադրել հիշողության վայրում 0x0020, և եթե նայեք ներքևի աղյուսակին, կտեսնեք, որ եթե տեղի ունենա erամաչափի/Counter0- ի արտահոսք (գալիս է TIMER0 OVF- ից), այն կկատարի այն, ինչ գտնվում է 0x0020 վայրում: Այսպիսով, երբ դա տեղի ունենա, ԱՀ -ն կանցնի այն տեղը, որը մենք մակնշել ենք «overflow_handler»: Թույն, ճիշտ? Մեկ րոպեից կտեսնեք, թե ինչու ենք մենք դա արել, բայց նախ եկեք ավարտենք ձեռնարկի այս քայլը մի կողմով:

Եթե ցանկանում ենք մեր կոդն ավելի կոկիկ և կոկիկ դարձնել, մենք իսկապես պետք է փոխարինենք այն 4 տողերը, որոնք այժմ քննարկում ենք, հետևյալով (տե՛ս էջ 66).

.org 0x0000

rjmp Վերագործարկեք; ԱՀ = 0x0000 reti; ԱՀ = 0x0002 reti; ԱՀ = 0x0004 reti; ԱՀ = 0x0006 reti; ԱՀ = 0x0008 reti; ԱՀ = 0x000A… reti; ԱՀ = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti; ԱՀ = 0x0030 reti; ԱՀ = 0x0032

Այսպիսով, եթե տվյալ ընդհատումը տեղի ունենա, այն պարզապես «reti» կլինի, ինչը նշանակում է «վերադառնալ ընդհատումից», և ուրիշ ոչինչ տեղի չունենա: Բայց եթե մենք երբեք «չակտիվացնենք» այս տարատեսակ ընդհատումները, ապա դրանք չեն օգտագործվի, և մենք կարող ենք ծրագրային կոդ դնել այս կետերում: Մեր ներկայիս «blink.asm» ծրագրում մենք միայն միացնելու ենք timer0- ի արտահոսքի ընդհատումը (և, իհարկե, վերակայման ընդհատումը, որը միշտ միացված է), ուստի մենք չենք անհանգստանա մյուսների հետ:

Այդ դեպքում ինչպե՞ս ենք «միացնում» timer0 գերհոսքի ընդհատումը: … Սա այս ձեռնարկի մեր հաջորդ քայլի թեման է:

Քայլ 5. Timամաչափ/հաշվիչ 0

Timամաչափ/հաշվիչ 0
Timամաչափ/հաշվիչ 0

Նայեք վերը նշված նկարին: Սա «ԱՀ» -ի որոշումների կայացման գործընթացն է, երբ ինչ -որ արտաքին ազդեցություն «ընդհատում» է մեր ծրագրի հոսքը: Առաջին բանը, որ անում է այն, երբ դրսից ազդանշան է ստանում, որ ընդհատում է տեղի ունեցել, դա ստուգում է ՝ արդյոք մենք դրել ենք «ընդհատման միացման» բիթը այդ տեսակի ընդհատումների համար: Եթե մենք չենք արել, ապա այն պարզապես շարունակում է կատարել մեր հաջորդ տողի ծածկագիրը: Եթե մենք սահմանել ենք այդ ընդհատման միացման բիթը (այնպես, որ այդ բիտում 0 -ի փոխարեն լինի 1), ապա այն կստուգի ՝ մենք միացրել ենք «գլոբալ ընդհատումները», թե ոչ, եթե ոչ, նորից կանցնի հաջորդ տողին: ծածկագրին և շարունակել: Եթե մենք նաև միացրել ենք գլոբալ ընդհատումները, ապա այն կգնա այդ տեսակի ընդհատումների Memրագրի հիշողություն (ինչպես ցույց է տրված Աղյուսակ 12-6-ում) և կկատարի այն հրամանը, որը մենք տեղադրել ենք այնտեղ: Այսպիսով, եկեք տեսնենք, թե ինչպես ենք մենք այս ամենը ներդրել մեր օրենսգրքում:

Մեր կոդի Reset պիտակավորված հատվածը սկսվում է հետևյալ երկու տողերով.

Վերակայել ՝

ldi ջերմաստիճան, 0b00000101 out TCCR0B, ջերմաստիճան

Ինչպես արդեն գիտենք, սա բեռնում է ջերմաստիճանում (այսինքն ՝ R16) անմիջապես հաջորդ համարին, որը 0b00000101 է: Այնուհետև այն գրում է այս թիվը TCCR0B կոչվող գրանցամատյանում ՝ օգտագործելով «դուրս» հրամանը: Ի՞նչ է սա գրանցամատյանը: Դե, եկեք անցնենք տվյալների թերթի 614 էջ: Սա աղյուսակի մեջտեղում է ՝ ամփոփելով բոլոր գրանցամատյանները: 0x25 հասցեում կգտնեք TCCR0B: (Այժմ դուք գիտեք, թե որտեղից է դուրս եկել «0x25, r16» տողը ՝ կոդի իմ չմեկնաբանված տարբերակում): Մենք վերևի կոդի հատվածով տեսնում ենք, որ մենք սահմանել ենք 0 -րդ և 2 -րդ բիթերը և մաքրել ենք մնացած բոլորը: Աղյուսակին նայելով կարող եք տեսնել, որ սա նշանակում է, որ մենք սահմանել ենք CS00 և CS02: Այժմ անցնենք տվյալների թերթի «8-բիթ ժամաչափ/հաշվիչ PWM- ով» կոչվող գլխին: Մասնավորապես, անցեք այդ գլխի 107 -րդ էջին: Դուք կտեսնեք «erամաչափի/հաշվիչ հսկողության գրանցամատյան B» (TCCR0B) գրանցամատյանի նույն նկարագրությունը, որը մենք հենց նոր տեսանք գրանցամատյանների ամփոփ աղյուսակում (այնպես որ կարող էինք անմիջապես գալ այստեղ, բայց ես ուզում էի, որ դուք տեսնեք, թե ինչպես օգտագործել ամփոփ աղյուսակները հետագա հղումների համար): Տվյալների թերթիկը շարունակում է նկարագրել այդ գրանցամատյանում բիթերից յուրաքանչյուրի նկարագրությունը և այն, ինչ նրանք անում են: Մենք առայժմ բաց կթողնենք այդ ամենը և էջը կդարձնենք Աղյուսակ 15-9: Այս աղյուսակը ցույց է տալիս «ockամացույցի ընտրության բիթ նկարագրությունը»: Այժմ նայեք ներքև այդ սեղանին, մինչև չգտնեք այն տողը, որը համապատասխանում է այն բիթերին, որոնք մենք պարզապես դրել ենք այդ գրանցամատյանում: Տողում գրված է `« clk/1024 (նախավաճառողից) »: Սա նշանակում է, որ մենք ցանկանում ենք, որ Timer/Counter0- ը (TCNT0) նշվի արագությամբ, որը պրոցեսորի հաճախականությունը բաժանված է 1024 -ի: Քանի որ մեր միկրոկոնտրոլերը սնվում է 16 ՄՀց բյուրեղային տատանումով, նշանակում է, որ այն արագությունը, որը կատարում է մեր պրոցեսորը ՝ Վայրկյանում 16 միլիոն հրահանգ: Այսպիսով, մեր TCNT0 հաշվիչի արագությունը 16 մլն/1024 = 15625 անգամ վայրկյանում է (փորձեք ժամացույցի տարբեր բիթերով և տեսեք, թե ինչ է տեղի ունենում. Հիշո՞ւմ եք մեր փիլիսոփայությունը): Եկեք 15625 թիվը հետագայում պահենք մեր մտքում և անցնենք ծածկագրի հաջորդ երկու տողերին.

ldi ջերմաստիճան, 0b00000001

sts TIMSK0, տեմպ

Սա սահմանում է գրանցամատյանի 0 -րդ բիթը, որը կոչվում է TIMSK0 և մաքրում է մնացած բոլորը: Եթե նայեք տվյալների թերթի 109 -րդ էջին, կտեսնեք, որ TIMSK0- ը նշանակում է «erամաչափ/հաշվիչի ընդհատման դիմակների գրանցում 0», իսկ մեր ծածկագիրը սահմանել է 0 -րդ բիթը, որը կոչվում է TOIE0, որը նշանակում է «erամաչափ/Counter0 Overflow Interrupt Enable»: … Այնտեղ! Հիմա տեսնում եք, թե ինչի մասին է խոսքը: Այժմ մենք ունենք «ընդհատման միացման բիթերի հավաքածու», ինչպես ցանկանում էինք վերևում գտնվող մեր նկարի առաջին որոշումից: Այսպիսով, այժմ մեզ մնում է միայն միացնել «գլոբալ ընդհատումները», և մեր ծրագիրը կկարողանա արձագանքել այս տիպի ընդհատումներին: Մենք շուտով միացնելու ենք գլոբալ ընդհատումները, բայց մինչ դա անելը կարող է ձեզ ինչ -որ բանով շփոթել:

Ամեն անգամ, երբ տեսնում եք, որ ես օգտագործում եմ այնպիսի հրահանգ, որը նախկինում չեք տեսել, առաջին բանը, որ դուք պետք է անեք, անցեք տվյալների թերթիկի 616 էջը: Սա «Հրահանգների հավաքածուի ամփոփում» է: Այժմ գտեք «STS» հրահանգը, որն ես օգտագործել եմ: Այն ասում է, որ այն վերցնում է մի շարք R գրանցամատյանից (մենք օգտագործել ենք R16) և «Պահել ուղղակիորեն SRAM- ում» գտնվելու վայրից k (մեր դեպքում տրված է TIMSK0): Այսպիսով, ինչու՞ մենք ստիպված էինք օգտագործել «sts» - ը, որը տևում է 2 ժամացույցի ցիկլ (տե՛ս աղյուսակի վերջին սյունակը) TIMSK0- ում պահելու համար, և մեզ անհրաժեշտ էր միայն «դուրս», որը տևում է ընդամենը մեկ ժամացույցի ցիկլ, TCCR0B- ում պահելու համար: Այս հարցին պատասխանելու համար մենք պետք է վերադառնանք մեր գրանցամատյանների ամփոփ աղյուսակին 614 -րդ էջում: Դուք տեսնում եք, որ TCCR0B գրանցամատյանը գտնվում է 0x25 հասցեում, բայց նաև (0x45): Սա նշանակում է, որ դա գրանցամատյան է SRAM- ում, բայց դա նաև որոշակի տեսակի գրանցամատյան է, որը կոչվում է «պորտ» (կամ i/o գրանցամատյան): Եթե նայեք հրահանգների ամփոփ աղյուսակին «դուրս» հրամանի կողքին, կտեսնեք, որ այն արժեքներ է վերցնում «աշխատանքային գրանցամատյաններից», ինչպիսիք են R16- ը և դրանք ուղարկում է ՊՈՌՏ: Այսպիսով, մենք կարող ենք օգտագործել «դուրս» -ը TCCR0B- ին գրելիս և ինքներս մեզ փրկել ժամացույցի ցիկլը: Բայց հիմա փնտրեք TIMSK0 գրանցամատյանում: Տեսնում եք, որ այն ունի 0x6e հասցե: Սա դուրս է նավահանգիստների տիրույթից (որոնք SRAM- ի միայն առաջին 0x3F վայրերն են), ուստի դուք պետք է հետ կանգնեք sts հրամանից օգտվելուց և դա անելու համար վերցրեք CPU ժամացույցի երկու ցիկլ: Խնդրում ենք կարդալ ծանոթագրություն 4 -ը `հրահանգների ամփոփ աղյուսակի վերջում, էջ 615 -ում հենց հիմա: Նաև նկատեք, որ մեր բոլոր մուտքային և ելքային պորտերը, ինչպես PORTD- ը, գտնվում են աղյուսակի ներքևում: Օրինակ ՝ PD4- ը 4-րդ բիթ է ՝ 0x0b հասցեով (այժմ տեսնում եք, թե որտեղից են առաջացել 0x0b- ի բոլոր իրերը իմ չմեկնաբանված ծածկագրում): լավ, արագ հարց. պատահում է Հիշեք մեր փիլիսոփայությունը: կոտրել այն! մի ընդունիր իմ խոսքը միայն իրերի համար:

Լավ, նախքան առաջ շարժվելը, մեկ րոպե անցեք տվյալների թերթի 19 -րդ էջին: Դուք տեսնում եք տվյալների հիշողության պատկերը (SRAM): SRAM- ում առաջին 32 գրանցամատյանները (0x0000- ից մինչև 0x001F) «ընդհանուր օգտագործման աշխատանքային գրանցամատյաններն» են R0- ից մինչև R31, որոնք մենք մշտապես օգտագործում ենք որպես փոփոխականներ մեր ծածկագրում:Հաջորդ 64 գրանցամատյաններն են մինչև 0x005f մուտքի/ելքի պորտերը (այսինքն ՝ այն, որոնց մասին մենք խոսում էինք, գրանցամատյանում դրանց կողքին առկա են այն փակագծերով հասցեները, որոնք կարող ենք օգտագործել «դուրս» հրամանը «sts»-ի փոխարեն) SRAM- ի հաջորդ բաժինը պարունակում է ամփոփ աղյուսակի բոլոր մյուս գրանցամատյանները `հասցեով 0x00FF, և վերջապես մնացածը ներքին SRAM է: Այժմ արագ, եկեք մի վայրկյան անցնենք էջ 12 -ին: Այնտեղ տեսնում եք «ընդհանուր օգտագործման աշխատանքային գրանցամատյանների» աղյուսակը, որը մենք միշտ օգտագործում ենք որպես մեր փոփոխականներ: Դուք տեսնում եք R0- ից R15 և R16- ից R31 թվերի միջև հաստ գիծը: Այդ տողն է պատճառը, որ մենք միշտ օգտագործում ենք R16- ը որպես ամենափոքրը, և ես դրան մի փոքր ավելի կանդրադառնամ հաջորդ ձեռնարկում, որտեղ մեզ նույնպես անհրաժեշտ կլինեն 16-բիթանոց անուղղակի հասցեների երեք գրանցամատյանները ՝ X, Y և Z: մտեք այդ ամենի մեջ, չնայած որ մեզ դա հիմա պետք չէ, և մենք բավականին խրվում ենք այստեղ:

Մեկ էջը հետ շրջեք դեպի տվյալների թերթի 11 -րդ էջը: Վերևից աջ կտեսնեք SREG գրանցամատյանի դիագրամ: Դուք տեսնում եք, որ այդ գրանցամատյանի 7 -րդ բիթը կոչվում է «ես»: Այժմ իջեք էջը և կարդացեք Bit 7 -ի նկարագրությունը… յա! Դա Global Interrupt Enable բիթն է: Դա այն է, ինչ մենք պետք է սահմանենք ՝ մեր վերևի գծապատկերում երկրորդ որոշումն ընդունելու և մեր ծրագրում ժամանակաչափի/հաշվիչի արտահոսքի ընդհատումները թույլ տալու համար: Այսպիսով, մեր ծրագրի հաջորդ տողը պետք է կարդա.

sbi SREG, I

որը SREG գրանցամատյանում սահմանում է «I» կոչվող բիթը: Այնուամենայնիվ, փոխարենը մենք օգտագործել ենք հրահանգը

սեյ

փոխարենը. Այս բիթը այնքան հաճախ է դրված ծրագրերում, որ նրանք պարզապես դա պարզեցնելու միջոց են պատրաստել:

Լավ! Այժմ մենք ստացել ենք արտահոսքի ընդհատումները, որպեսզի մեր «jmp overflow_handler» - ը կատարվի, երբ որևէ մեկը պատահի:

Նախքան շարժվելը, արագ նայեք SREG գրանցամատյանը (Կարգավիճակի գրանցամատյան), քանի որ այն շատ կարևոր է: Կարդացեք, թե ինչ է ներկայացնում դրոշներից յուրաքանչյուրը: Մասնավորապես, շատ հրահանգներ, որոնք մենք կիրառում ենք, մշտապես կարգավորում և ստուգում են այդ դրոշները: Օրինակ, հետագայում մենք կօգտագործենք «CPI» հրամանը, որը նշանակում է «անհապաղ համեմատել»: Նայեք այս հրահանգի հրահանգների ամփոփ աղյուսակին և նկատեք, թե քանի դրոշ է այն դնում «դրոշներ» սյունակում: Սրանք բոլորը SREG- ի դրոշներ են, և մեր ծածկագիրը դրանք սահմանելու և անընդհատ ստուգելու է: Շուտով կտեսնեք օրինակներ: Ի վերջո, կոդի այս հատվածի վերջին բիթը հետևյալն է.

clr ջերմաստիճան

դուրս TCNT0, ջերմաստիճան sbi DDRD, 4

Վերջին տողն այստեղ բավականին ակնհայտ է: Այն պարզապես սահմանում է PortD- ի Տվյալների ուղղման գրանցամատյանի 4 -րդ բիթը, ինչը հանգեցնում է PD4- ի ԵԼՔ:

Առաջինը փոփոխականի ջերմաստիճանը զրոյի է սահմանում, այնուհետև պատճենում է այն TCNT0 գրանցամատյանում: TCNT0- ը մեր Timամաչափ/Counter0- ն է: Սա զրոյի է դնում: Հենց որ համակարգիչը կատարի այս տողը, ժմչփը 0 կսկսվի զրոյից և կհաշվի յուրաքանչյուր վայրկյան 15625 անգամ: Խնդիրը սա է. TCNT0- ը «8-բիթանոց» գրանցամատյան է: Այսպիսով, ո՞րն է ամենամեծ թիվը, որը կարող է պահել 8-բիթանոց գրանցամատյանը: Դե 0b11111111 դա է: Սա 0xFF թիվն է: Ո՞րն է 255 -ը: Այսպիսով, տեսնում եք, թե ինչ է տեղի ունենում: Theամաչափը պտտվում է վայրկյանում 15625 անգամ, և ամեն անգամ, երբ այն հասնում է 255 -ի, այն «վարարում» է և նորից 0 -ի է վերադառնում: Zeroրոյի վերադառնալուն զուգահեռ այն ուղարկում է erամաչափի գերհոսքի ընդհատման ազդանշան: ԱՀ -ն ստանում է սա, և գիտե՞ք, թե ինչ է անում մինչ այժմ: Այո Այն գնում է Program Memory location 0x0020 և կատարում է այնտեղ գտած հրահանգը:

Հիանալի! Եթե դու դեռ ինձ հետ ես, ուրեմն դու անխոնջ սուպերհերոս ես: Շարունակենք…

Քայլ 6: Overflow Handler

Այսպիսով, եկեք ենթադրենք, որ ժմչփ/counter0 ռեգիստրը նոր է լցվել: Այժմ մենք գիտենք, որ ծրագիրը ստանում է ընդհատման ազդանշան և կատարում է 0x0020 ծրագիրը, որն ասում է Countրագրի հաշվիչին, համակարգչին անցնել «overflow_handler» պիտակի վրա:

overflow_handler:

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

Առաջին բանը, որ նա անում է, ավելացնում է «overflows» փոփոխականը (որը մեր անունն է ընդհանուր օգտագործման աշխատանքային գրանցամատյան R17), այնուհետև այն «համեմատում» է հեղեղումների բովանդակությունը 61. թվի հետ: երկու թվերը, և եթե արդյունքը զրոյական է, այն Z դրոշը դնում է SREG գրանցամատյանում (ես ձեզ ասացի, որ մենք անընդհատ կտեսնենք այս գրանցամատյանը): Եթե երկու թվերը հավասար են, ապա Z դրոշը կլինի 1, եթե երկու թվերը հավասար չեն, ապա դա կլինի 0:

Հաջորդ տողում գրված է «brne PC+2», ինչը նշանակում է «մասնաճյուղ, եթե ոչ հավասար»: Ըստ էության, այն ստուգում է Z դրոշը SREG- ում, և եթե դա մեկ չէ (այսինքն ՝ երկու թվերը հավասար չեն, եթե հավասար լինեին, զրո դրոշը դրված կլիներ) ԱՀ -ն ճյուղավորվում է դեպի PC+2, այսինքն ՝ բաց է թողնում հաջորդը: գծում և ուղիղ գնում դեպի «reti», որն ընդհատումից վերադառնում է այն տեղը, որտեղ այն գտնվում էր ծածկագրում, երբ ընդհատումը հասավ: Եթե brne հրահանգը զրոյական դրոշակի բիտում գտնի 1, այն չի ճյուղավորվի և փոխարենը պարզապես կշարունակի անցնել հաջորդ տողին, որը կլրվի վարարումներով ՝ այն վերականգնելով 0 -ի:

Ո՞րն է այս ամենի զուտ արդյունքը:

Դե, մենք տեսնում ենք, որ ամեն անգամ, երբ կա ժմչփի արտահոսք, այս կարգավորիչը մեկով ավելացնում է «վարարումների» արժեքը: Այսպիսով, «լցվել» փոփոխականը հաշվում է դրանց արտահոսքի քանակը դրանց առաջացման դեպքում: Երբ թիվը հասնում է 61 -ի, մենք այն զրոյի ենք վերածում:

Հիմա ինչու՞ աշխարհում դա անենք:

Տեսնենք: Հիշեք, որ մեր CPU- ի ժամացույցի արագությունը 16 ՄՀց է, և մենք այն «նախալրացրեցինք» TCCR0B- ի միջոցով, որպեսզի ժամաչափը հաշվի միայն վայրկյանում 15625 հաշվելու արագությամբ: Եվ ամեն անգամ, երբ ժամաչափը հասնում է 255 -ի, այն դուրս է գալիս: Այսպիսով, դա նշանակում է, որ այն վարարում է 15625/256 = 61,04 անգամ վայրկյանում: Մենք հետևում ենք մեր «փոփոխություններ» փոփոխականներով հեղեղների քանակին և այդ թիվը համեմատում ենք 61. -ի հետ: Այսպիսով, մենք տեսնում ենք, որ «արտահոսքերը» հավասար կլինեն 61 -ի ամեն վայրկյան մեկ անգամ: Այսպիսով, մեր կարգավորիչը «վայրէջքները» զրոյի կդնի վայրկյան մեկ անգամ: Այսպիսով, եթե մենք պարզապես վերահսկենք «արտահոսքերը» փոփոխականը և հաշվի առնենք, որ ամեն անգամ այն զրոյի վերածվելիս մենք իրական վայրկյան հաշվելու ենք (նկատի ունեցեք, որ հաջորդ ձեռնարկում մենք ցույց կտանք, թե ինչպես ստանալ ավելի ճշգրիտ միլիվայրկյանների ուշացում նույն կերպ, ինչպես աշխատում է Arduino- ի «հետաձգման» ռեժիմը):

Այժմ մենք «կարգավորել» ենք ժմչփի արտահոսքի ընդհատումները: Համոզվեք, որ հասկանում եք, թե ինչպես է դա աշխատում, և ապա անցեք հաջորդ քայլին, որտեղ մենք կօգտագործենք այս փաստը:

Քայլ 7: Հետաձգում

Այժմ, երբ մենք տեսանք, որ մեր ժամանակաչափի արտահոսքի ընդհատումների կարգավորիչը «overflow_handler» առօրյան ամեն վայրկյան մեկ անգամ զրոյական կդարձնի «overflows» փոփոխականը, մենք կարող ենք օգտագործել այս փաստը «հետաձգման» ենթածրագրի նախագծման համար:

Մեր ուշացման տակից նայեք հետևյալ ծածկագրին

հետաձգում:

clr- ը վարարում է վրկ.հաշիվ

Մենք պատրաստվում ենք այս ենթագիծը անվանել ամեն անգամ, երբ մեր ծրագրի հետաձգման կարիք ունենք: Աշխատանքի եղանակն այն է, որ սկզբում «հոսում» փոփոխականը զրոյի է դնում: Այնուհետև այն մտնում է «sec_count» պիտակով տարածք և համեմատում է 30 -ի արտահոսքը, եթե դրանք հավասար չեն, ապա այն ճյուղավորվում է դեպի sec_count պիտակը և նորից համեմատում, և նորից և այլն, մինչև վերջնականապես հավասարվեն (հիշեք, որ ամբողջ ժամանակ դա շարունակվում է մեր ժամանակաչափի վրա ընդհատումների կարգավորիչը շարունակում է մեծացնել փոփոխական արտահոսքերը, և դա փոխվում է ամեն անգամ, երբ մենք շրջում ենք այստեղ: Երբ վերջնական հոսքերը հավասար են 30 -ի, այն դուրս է գալիս շրջանակից և վերադառնում այնտեղ, որտեղից հետաձգում ենք անվանում. 1/2 վայրկյան ուշացում

Ercորավարժություն 2. Փոխեք overflow_handler ռեժիմը հետևյալի.

overflow_handler:

inc overflows reti

և գործարկել ծրագիրը: Արդյո՞ք ինչ -որ բան այլ է: Ինչո՞ւ կամ ինչո՞ւ ոչ:

Քայլ 8: Թարթիր:

Վերջապես, եկեք նայենք թարթելու ռեժիմին.

թարթել:

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

Սկզբում մենք միացնում ենք PD4- ը, այնուհետև մենք կանչում ենք մեր հետաձգման ենթածրագիրը: Մենք օգտագործում ենք rcall- ը այնպես, որ երբ համակարգիչը հասնի «ret» հայտարարության, այն կվերադառնա rcall- ին հաջորդող տող: Հետո ուշացման սովորական ընթացքը ձգձգում է 30 հաշվի համար, ինչպես մենք տեսանք, և դա գրեթե ուղիղ 1/2 վայրկյան է, այնուհետ անջատում ենք PD4- ը, հետաձգում ևս 1/2 վայրկյան, իսկ հետո նորից վերադառնում սկզբին:

Resultուտ արդյունքը թարթող լուսադիոդ է:

Կարծում եմ, որ այժմ կհամաձայնվեք, որ «թարթելը» հավանաբար հավաքման լեզվով լավագույն «բարև աշխարհ» ծրագիրը չէ:

Ercորավարժություններ 3. Changeրագրի տարբեր պարամետրերը փոխեք այնպես, որ LED- ը թարթվի տարբեր արագությամբ, ինչպես երկրորդը կամ վայրկյանը 4 անգամ և այլն: ercորավարժություն 4. Փոխեք այն այնպես, որ LED- ը միացված կամ անջատված լինի տարբեր ժամանակներում: Օրինակ ՝ 1/4 վայրկյան, ապա անջատված 2 վայրկյան կամ նման բան: ercորավարժություն 5. Փոխեք TCCR0B ժամացույցի ընտրված բիթերը 100 -ի, ապա շարունակեք բարձրանալ սեղանին: Ո՞ր կետում է այն տարբերվում մեր «բարև.ազմ» ծրագրից ՝ ձեռնարկ 1 -ից: iseորավարժություն 6 (ըստ ցանկության). Եթե ունեք այլ բյուրեղյա տատանումներ, օրինակ ՝ 4 ՄՀց կամ 13.5 ՄՀց կամ որևէ այլ բան, փոխեք ձեր 16 ՄՀց տատանողը: ձեր նոր սեղանի վրա և տեսեք, թե դա ինչպես է ազդում լուսադիոդի թարթման արագության վրա: Այժմ դուք պետք է կարողանաք ճշգրիտ հաշվարկ կատարել և ճշգրիտ կանխատեսել, թե ինչպես դա կազդի փոխարժեքի վրա:

Քայլ 9: Եզրակացություն

Ձեզանից մահմեդականներին, ովքեր մինչև այժմ հասան դրան, շնորհավորում եմ:

Ես գիտակցում եմ, որ բավականին դժվար է խաբելը, երբ դուք ավելի շատ կարդում և վեր եք նայում, քան աշխատում և փորձարկում եք, բայց հույս ունեմ, որ դուք սովորել եք հետևյալ կարևոր բաները.

  1. Ինչպես է աշխատում ծրագրի հիշողությունը
  2. Ինչպես է աշխատում SRAM- ը
  3. Ինչպես փնտրել գրանցամատյաններ
  4. Ինչպես փնտրել հրահանգներ և իմանալ, թե ինչ են նրանք անում
  5. Ինչպես իրականացնել ընդհատումներ
  6. Ինչպես է CP- ն կատարում կոդը, ինչպես է աշխատում SREG- ը և ինչ է տեղի ունենում ընդհատումների ժամանակ
  7. Ինչպես անել օղակներ և ցատկեր և ցատկել ծածկագրում
  8. Որքա՞ն կարևոր է կարդալ տվյալների թերթիկը:
  9. Երբ իմանաք, թե ինչպես անել այս ամենը Atmega328p միկրոկառավարիչի համար, դա կլինի տորթերի հետ կապված քայլարշավ ՝ սովորելու ձեզ հետաքրքրող ցանկացած նոր կարգավորիչ:
  10. Ինչպես փոխել պրոցեսորի ժամանակը իրական ժամանակի և օգտագործել այն հետաձգման ռեժիմներում:

Այժմ, երբ մենք ունենք բազմաթիվ տեսություններ, որոնք ի վիճակի են ավելի լավ ծածկագիր գրել և ավելի բարդ բաներ վերահսկել: Այսպիսով, հաջորդ ձեռնարկը մենք հենց այդպես էլ կանենք: Մենք կկառուցենք ավելի բարդ, ավելի հետաքրքիր, կշրջենք և կզարգացնենք այն զվարճալի եղանակներով:

Exորավարժություն 7. «Կոտրիր» ծածկագիրը տարբեր եղանակներով և տես, թե ինչ կլինի: Գիտական հետաքրքրասիրություն երեխա: Ուրիշ մեկը ճի՞շտ է լվանում սպասքը Այսինքն «avra -l blink.lst blink.asm» և հայացք գցեք ցուցակի ֆայլին: Լրացուցիչ վարկ. Չմեկնաբանված կոդը, որը ես տվեցի սկզբում և մեկնաբանված կոդը, որը մենք հետագայում կքննարկենք, տարբերվում են: Կոդի մեկ տող կա, որը տարբերվում է: Կարո՞ղ եք գտնել այն: Ինչու՞ այդ տարբերությունը նշանակություն չունի:

Հուսով եմ, որ դուք զվարճացել եք: Կհանդիպենք հաջորդ անգամ…

Խորհուրդ ենք տալիս: