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

AVR Assembler ձեռնարկ 2: 4 քայլ
AVR Assembler ձեռնարկ 2: 4 քայլ

Video: AVR Assembler ձեռնարկ 2: 4 քայլ

Video: AVR Assembler ձեռնարկ 2: 4 քայլ
Video: Areg's Time - Tarva Eghanakner | Տարվա Եղանակներ 2024, Հուլիսի
Anonim
AVR Assembler ձեռնարկ 2
AVR Assembler ձեռնարկ 2

Այս ձեռնարկը «AVR Assembler Tutorial 1» -ի շարունակությունն է

Եթե դուք չեք անցել ձեռնարկ 1 -ը, ապա պետք է դադարեցնեք և առաջինը դա անեք:

Այս ձեռնարկում մենք կշարունակենք մեր ուսումնասիրությունը Arduino's- ում օգտագործվող atmega328p- ի հավաքման լեզվի ծրագրավորման վերաբերյալ:

Ձեզ հարկավոր կլինի.

  1. տախտակ Arduino կամ պարզապես սովորական Arduino, ինչպես ձեռնարկ 1 -ում
  2. մի LED
  3. 220 օմ դիմադրություն
  4. սեղմիչ կոճակ
  5. միացնող լարեր `ձեր հացահատիկի վրա միացում կազմելու համար
  6. Instruction Set Manual: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Տվյալների թերթ ՝ www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

Իմ ձեռնարկների ամբողջական հավաքածուն կարելի է գտնել այստեղ ՝

Քայլ 1: Շղթայի կառուցում

Շրջանի կառուցում
Շրջանի կառուցում

Նախ անհրաժեշտ է կառուցել միացում, որը մենք ուսումնասիրելու ենք այս ձեռնարկում:

Ահա դրա միացման եղանակը.

PB0 (թվային կապիչ 8) - LED - R (220 օհմ) - 5V

PD0 (թվային կապիչ 0) - սեղմիչ - GND

Կարող եք ստուգել, որ ձեր LED- ն ճիշտ կողմնորոշված է ՝ այն PB0- ի փոխարեն միացնելով GND- ին: Եթե ոչինչ չի պատահում, շրջեք կողմնորոշումը, և լույսը պետք է վառվի: Այնուհետեւ նորից միացրեք այն PB0- ին եւ շարունակեք: Նկարը ցույց է տալիս, թե ինչպես է միացված իմ տախտակի արդուինոն:

Քայլ 2. Հավաքման օրենսգրքի գրառում

Համագումարի օրենսգրքի գրառում
Համագումարի օրենսգրքի գրառում

Գրեք հետևյալ կոդը pushbutton.asm կոչվող տեքստային ֆայլում և կազմեք այն avra- ով, ինչպես դա արեցիք ձեռնարկ 1 -ում:

Ուշադրություն դարձրեք, որ այս ծածկագրում մենք ունենք բազմաթիվ մեկնաբանություններ: Ամեն անգամ, երբ հավաքողը տեսնում է ստորակետ, նա բաց կթողնի գծի մնացած մասը և կանցնի հաջորդ տողին: Programրագրավորման լավ պրակտիկա է (հատկապես հավաքման լեզվով) ՝ ձեր ծածկագիրը խիստ մեկնաբանելու համար, որպեսզի հետագայում դրան վերադառնալիս իմանաք, թե ինչ էիք անում: Ես պատրաստվում եմ շատ բաներ մեկնաբանել առաջին մի քանի ձեռնարկներում, որպեսզի մենք հստակ իմանանք, թե ինչ է կատարվում և ինչու: Հետագայում, երբ մենք մի փոքր ավելի լավը դառնանք հավաքման կոդավորման մեջ, ես մի փոքր ավելի մանրամասնորեն կմեկնաբանեմ բաները:

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

; գրել է ՝ 1o_o7; ամսաթիվ ՝ 2014 թ. հոկտեմբերի 23; **********************************

.համարանիշ

. ներառել "m328Pdef.inc".list.def temp = r16; նշանակել աշխատանքային գրանցամատյան r16 որպես temp rjmp Init; առաջին տողը կատարված է

Սկիզբ:

սեր ջերմաստիճան; ջերմաստիճանի բոլոր բիթերը սահմանել 1 -ի: դուրս DDRB, ջերմաստիճան; Տվյալների ուղղության մուտքի/ելքի վրա 1 -ի սահմանում; գրանցվել PortB- ի համար, որը DDRB է, սահմանում է դա. կապը ՝ որպես ելք, 0 -ն այդ կապը կդնի որպես մուտքագրում. այստեղ, PortB- ի բոլոր կապումներն ելքեր են (սահմանել 1) ldi temp, 0b11111110; բեռնել «անմիջական» համարը ջերմաստիճանի գրանցամատյանում. եթե դա պարզապես ld լիներ, ապա երկրորդ վեճը. փոխարենը պետք է լինի հիշողության վայր ՝ DDRD, temp; mv ջերմաստիճանը DDRD- ին, արդյունքում ստացվում է, որ PD0- ը մուտքագրված է. իսկ մնացածը ելքեր են ՝ clr ջերմաստիճան; ջերմաստիճանի բոլոր բիթերը սահմանվում են 0 -ից դուրս PortB, temp; սահմանել PortB- ի բոլոր բիթերը (այսինքն ՝ կապում) 0V ldi ջերմաստիճանի վրա, 0b00000001; բեռնել անմիջական թիվը PortD, temp; ջերմաստիճանը տեղափոխել PortD: PD0- ն ունի ձգման դիմադրություն; (այսինքն ՝ սահմանվել է 5 Վ), քանի որ այն ունի այդ բիտում 1; մնացածը 0 -ից 0V են:

Հիմնական:

ջերմաստիճանում, PinD; PinD- ն պահում է PortD վիճակը, պատճենեք սա ջերմաստիճանում; եթե կոճակը միացված է PD0- ին, դա կլինի. 0, երբ կոճակը սեղմվում է, 1 հակառակ դեպքում. PD0- ն ունի ձգման դիմադրություն, որը սովորաբար 5V- ից դուրս է PortB, ջերմաստիճան; ուղարկում է 0 -ի և 1 -ի վերը կարդացված տվյալները PortB; սա նշանակում է, որ մենք ուզում ենք LED- ն միացված լինի PB0- ին, երբ PD0- ը OWԱՐ է, այն PB0- ն դնում է LOW- ի և շրջում; LED- ի վրա (քանի որ LED- ի մյուս կողմն է. միացված է 5V- ին, և դա PB0- ն կդարձնի 0V, այնպես որ հոսանքը կհոսի) rjmp Main; հանգույցները վերադառնում են Main- ի մեկնարկին

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

Վերոնշյալ ծածկագիրը կազմելուց հետո այն պետք է բեռնեք միկրոկոնտրոլերի վրա և տեսեք, որ այն աշխատում է: Կոճակը սեղմելիս LED- ը պետք է միանա, իսկ հետո բաց թողնելուց հետո նորից անջատվի: Ես ցույց տվեցի, թե ինչ տեսք ունի նկարում:

Քայլ 3. Օրենսգրքի տող առ տող վերլուծություն

Ես բաց կթողնեմ այն տողերը, որոնք ընդամենը մեկնաբանություններ են, քանի որ դրանց նպատակը ինքնին հասկանալի է:

.համարանիշ

.ընդգրկել «m328Pdef.inc». ցանկը

Այս երեք տողերը ներառում են այն ֆայլը, որը պարունակում է գրանցամատյան և Bit սահմանումներ այն ATmega328P- ի համար, որը մենք ծրագրավորում ենք:. Nolist հրամանը հավաքողին ասում է, որ այս ֆայլը չներառի pushbutton.lst ֆայլում, որը այն արտադրում է այն հավաքելիս: Անջատում է ցուցակման տարբերակը: Ֆայլը ներառելուց հետո մենք նորից միացնում ենք ցուցակման տարբերակը ՝.list հրամանով: Պատճառն այն է, որ մենք դա անում ենք, քանի որ m328Pdef.inc ֆայլը բավականին երկար է, և մենք իսկապես կարիք չունենք այն տեսնել ցուցակի ֆայլում: Մեր հավաքողը, avra- ն, ինքնաբերաբար չի ստեղծում ցուցակի ֆայլ, և եթե մենք կցանկանայինք, մենք կհավաքվեինք ՝ օգտագործելով հետևյալ հրամանը.

avra -l pushbutton.lst pushbutton.asm

Եթե դա անեք, այն կստեղծի pushbutton.lst անունով ֆայլ, և եթե ուսումնասիրեք այս ֆայլը, ապա կգտնեք, որ այն ցույց է տալիս ձեր ծրագրի ծածկագիրը ՝ լրացուցիչ տեղեկությունների հետ միասին: Եթե նայեք լրացուցիչ տեղեկատվությանը, ապա կտեսնեք, որ տողերը սկսվում են C- ով. Որին հաջորդում է հարաբերական հասցեն այն վեցանկյունում, որտեղ ծածկագիրը տեղադրված է հիշողության մեջ: Ըստ էության, այն սկսվում է 000000 -ին `առաջին հրամանով և այնտեղից ավելանում է յուրաքանչյուր հաջորդ հրամանով: Հիշողության հարաբերական տեղից հետո երկրորդ սյունակը հրամանի վեցանկյուն կոդն է, որին հաջորդում է հրամանի փաստարկի վեցանկյուն կոդը: Listանկի ֆայլերը հետագայում կքննարկենք հետագա ձեռնարկներում:

.def ջերմաստիճան = r16; նշանակել աշխատանքային գրանցամատյան r16 որպես ջերմաստիճան

Այս տողում մենք օգտագործում ենք «.def» հավաքողի դիրեկտիվը `« temp »փոփոխականը սահմանելու համար որպես r16« աշխատանքային գրանցամատյան »: Մենք կօգտագործենք ռեգիստր r16- ը որպես այն համարը, որը պահում է այն թվերը, որոնք մենք ցանկանում ենք պատճենել տարբեր նավահանգիստներում և գրանցամատյաններում (որոնց ուղղակիորեն գրել հնարավոր չէ):

Ercորավարժություն 1. Փորձեք կրկնօրինակ համարը պատճենել անմիջապես նավահանգստում կամ հատուկ գրանցամատյանում, ինչպիսին է DDRB- ը և տեսեք, թե ինչ է տեղի ունենում, երբ փորձում եք հավաքել ծածկագիրը:

Գրանցամատյանը պարունակում է տեղեկատվության բայթ (8 բիթ): Ըստ էության, դա սովորաբար SR- փականների հավաքածու է, որոնցից յուրաքանչյուրը «բիթ» է և պարունակում է 1 կամ 0. Մենք կարող ենք դա քննարկել (և նույնիսկ կառուցել) ավելի ուշ այս շարքում: Ձեզ կարող է հետաքրքրել, թե ինչ է «աշխատանքային գրանցամատյանը» և ինչու ենք ընտրել r16- ը: Մենք դա կքննարկենք ապագա ձեռնարկում, երբ սուզվենք չիպի ներքին մասերի ճահճի մեջ: Առայժմ ես ուզում եմ, որ դուք հասկանաք, թե ինչպես անել այնպիսի բաներ, ինչպիսիք են ծածկագիրը գրելը և ֆիզիկական սարքավորումների ծրագրավորումը: Այնուհետև դուք կունենաք այդ փորձի վերաբերյալ հղումների շրջանակ, որը միկրոկառավարիչի հիշողությունը և գրանցման հատկությունները դյուրին կդարձնի: Ես գիտակցում եմ, որ ներածական դասագրքերի և քննարկումների մեծ մասը դա անում են հակառակը, բայց ես գտել եմ, որ որոշ ժամանակ առաջ տեսախաղ խաղալ նախքան ձեռնարկի ընթերցումը գլոբալ տեսանկյունից իմանալը շատ ավելի հեշտ է, քան առաջինը ձեռնարկը կարդալը:

rjmp Init; առաջին տողը կատարված է

Այս տողը «հարաբերական թռիչք» է «Init» պիտակի վրա և իրականում այստեղ անհրաժեշտ չէ, քանի որ հաջորդ հրամանը արդեն Init- ում է, բայց մենք այն ներառում ենք ապագա օգտագործման համար:

Սկիզբ:

սեր ջերմաստիճան; ջերմաստիճանի բոլոր բիթերը սահմանել 1 -ի:

Init պիտակից հետո մենք կատարում ենք «set register» հրամանը: Սա գրանցման «տեմպ» -ի բոլոր 8 բիթերը (որոնք հիշում եք, որ r16 է) դնում է 1 -ի: Այսպիսով, ջերմաստիճանը այժմ պարունակում է 0b11111111:

դուրս DDRB, ջերմաստիճան; Data Direction I/O գրանցամատյանում մի փոքր սահմանելով 1

; PortB- ի համար, որը DDRB է, սահմանում է այդ կապը որպես ելք; 0 -ը այդ կապը կդնի որպես մուտքագրում. այստեղ, PortB- ի բոլոր կապումներն ելքեր են (սահմանվում է 1)

DDRB (Data Direction Register for PortB) գրանցամատյանը պատմում է, թե PortB- ի որ կապերն են (այսինքն ՝ PB0- ից PB7) նշվում են որպես մուտքագրում, իսկ որոնք `ելք: Քանի որ մենք ունենք PB0 կապը միացված մեր LED- ին, իսկ մնացածը `ոչ մի բանի, մենք բոլոր բիթերը կդնենք 1 -ի, այսինքն` դրանք բոլորը ելքեր են:

ldi ջերմաստիճան, 0b11111110; բեռնել «անմիջական» համարը ջերմաստիճանի գրանցամատյանում

; եթե դա պարզապես ld լիներ, ապա երկրորդ փաստարկը կլիներ. պետք է լինի հիշողության վայր

Այս տողը բեռնում է 0b11111110 երկուական թիվը ջերմաստիճանի գրանցամատյանում:

դուրս DDRD, ջերմաստիճան; mv ջերմաստիճանը DDRD- ին, արդյունքում ստացվում է, որ PD0- ն մուտքագրում է և

; մնացածը արդյունքներ են

Այժմ մենք PortD- ի համար տվյալների ուղղման գրանցամատյանը սահմանում ենք ջերմաստիճանից, քանի որ ջերմաստիճանը դեռ պարունակում է 0b11111110, մենք տեսնում ենք, որ PD0- ն կնշանակվի որպես մուտքագրման քորոց (քանի որ ծայրամասում կա 0), իսկ մնացածը նշանակված են որպես ելքեր, քանի որ կան 1 -ը այդ կետերում:

clr ջերմաստիճան; ջերմաստիճանի բոլոր բիթերը սահմանվում են 0 -ի վրա

դուրս PortB, ջերմաստիճան; սահմանեք PortB- ի բոլոր բիթերը (այսինքն ՝ կապում) 0 Վ

Սկզբում մենք «մաքրում ենք» գրանցման ջերմաստիճանը, ինչը նշանակում է, որ բոլոր բիթերը զրոյի են հասցնում: Այնուհետև այն պատճենում ենք PortB գրանցամատյանում, որը 0V է սահմանում այդ բոլոր կապում: Bրոյը PortB բիթի վրա նշանակում է, որ պրոցեսորը կպահի այդ կապը 0 Վ -ի վրա, բիթի վրա մեկին կհանգեցնի, որ այդ քորոցը սահմանվի 5 Վ -ի:

Ercորավարժություն 2. Օգտագործեք բազմաչափ ՝ ստուգելու համար, թե արդյոք PortB- ի բոլոր կապումներն իրականում զրո են: Արդյո՞ք ինչ -որ տարօրինակ բան է կատարվում PB1- ի հետ: Anyանկացած գաղափար, թե ինչու դա կարող է լինել: (նման է վարժություն 4 -ի ստորև, ապա հետևեք ծածկագրին …) ercորավարժություն 3. Հեռացրեք վերը նշված երկու տողերը ձեր ծածկագրից: Արդյո՞ք ծրագիրը դեռ ճիշտ է աշխատում: Ինչո՞ւ:

ldi ջերմաստիճան, 0b00000001; բեռնել անմիջական համարը ջերմաստիճանին

դուրս PortD, ջերմաստիճան; ջերմաստիճանը տեղափոխել PortD: PD0- ը 5V- ում է (ունի ձգման դիմադրություն); քանի որ այն ունի 1 բիտում մնացածը 0V են: Exորավարժություն 4. Հեռացրեք վերը նշված երկու տողերը ձեր ծածկագրից: Արդյո՞ք ծրագիրը դեռ ճիշտ է աշխատում: Ինչո՞ւ: (Սա տարբերվում է վարժություն 3 -ից վերևում: Տեսեք կապի գծապատկերը: Ո՞րն է PD0- ի կանխադրված DDRD կարգավորումը: (Տե՛ս տվյալների թերթիկի 90 -րդ էջը

Սկզբում մենք «անմիջապես բեռնում ենք» 0b00000001 թիվը ջերմաստիճանի վրա: «Անմիջական» մասը այնտեղ է, քանի որ մենք ուղիղ թիվ ենք բեռնում ջերմաստիճանում, այլ ոչ թե ցուցիչ դեպի հիշողության վայր, որը պարունակում է բեռնման համարը: Այդ դեպքում մենք պարզապես կօգտագործեինք «ld», այլ ոչ թե «ldi»: Այնուհետև մենք այս թիվը ուղարկում ենք PortD, որը PD0- ն սահմանում է 5 Վ, իսկ մնացածը ՝ 0 Վ:

Այժմ մենք կապումներն ենք դրել որպես մուտք կամ ելք, և մենք նրանց սկզբնական վիճակները դրել ենք որպես 0V կամ 5V (OWԱOWՐ կամ ԲԱՐՁՐ) և այժմ մենք մտնում ենք մեր ծրագրի «հանգույց»:

Հիմնական ՝ ջերմաստիճանում, PinD; PinD- ն պահպանում է PortD վիճակը, պատճենեք սա ջերմաստիճանում

; եթե կոճակը միացված է PD0- ին, ապա դա կլինի. a 0, երբ կոճակը սեղմվում է, 1 հակառակ դեպքում ՝ PD0- ն ունի ձգման ռեզիստոր, այն սովորաբար 5 Վ լարման դեպքում է

Գրանցամատյանը PinD- ն պարունակում է PortD կապերի ընթացիկ վիճակը: Օրինակ, եթե 5V լարը կցեցիք PD3- ին, ապա հաջորդ ժամացույցի ցիկլում (որը տեղի է ունենում 16 միլիոն անգամ վայրկյանում, քանի որ միկրոկառավարիչը միացված է մինչև 16 ՄՀց ժամացույցի ազդանշանին) PinD3 բիթը (PD3- ի ներկա վիճակից) կդառնա 1 -ը 0. -ի փոխարեն: Այսպիսով, այս տողում մենք պատճենում ենք կապանքների ընթացիկ վիճակը ջերմաստիճանում:

դուրս PortB, ջերմաստիճան; ուղարկում է 0 -ի և 1 -ի վերը կարդացված տվյալները PortB- ին

; սա նշանակում է, որ մենք ուզում ենք LED- ը միացված լինի PB0- ին, այնպես որ; երբ PD0- ն OWԱՐ է, այն PB0- ը կդարձնի LOW և կդարձնի; LED- ի վրա (LED- ի մյուս կողմը միացված է. 5V- ին, և դա PB0- ը կդարձնի 0V, այնպես որ ընթացիկ հոսքերը)

Այժմ մենք PinD- ի կապերի վիճակն ուղարկում ենք PortB ելքին: Արդյունավետորեն դա նշանակում է, որ PD0- ն 1 -ը կուղարկի PortD0- ին, եթե կոճակը սեղմված չէ: Այդ դեպքում, քանի որ կոճակը միացված է գետնին, այդ կապը կլինի 0V- ում, և այն 0 -ը կուղարկի PortB0- ին: Այժմ, եթե նայեք սխեմայի սխեմային, 0V- ը PB0- ում նշանակում է, որ LED- ը կփայլի, քանի որ դրա մյուս կողմը 5V է: Եթե մենք չենք սեղմում կոճակը, այնպես որ 1 -ը ուղարկվում է PB0- ին, դա կնշանակի, որ մենք ունենք 5V PB0- ում և նաև 5V LED- ի մյուս կողմում, ուստի պոտենցիալ տարբերություն չկա, և հոսանք չի հոսելու, և այսպես LED- ը չի լուսավորվի (այս դեպքում դա LED է, որը դիոդ է, և հոսանքը հոսում է միայն մեկ ուղղությամբ ՝ անկախ ամեն ինչից):

rjmp Հիմնական; loops back to Start

Այս հարաբերական ցատկումը մեզ վերադարձնում է դեպի մեր հիմնական ՝ պիտակը և նորից ստուգում ենք PinD- ը և այլն: Յուրաքանչյուր 16 միլիոներորդական վայրկյանում ստուգեք, արդյոք կոճակը սեղմվում է և համապատասխանաբար կարգավորում PB0- ն:

Ercորավարժություն 5. Փոփոխեք ձեր ծածկագիրը, որպեսզի ձեր LED- ը PB0- ի փոխարեն միացված լինի PB3- ին և տեսեք, որ այն աշխատում է: 6որավարժություն 6. 5 LED- ի փոխարեն ձեր LED- ը միացրեք GND- ին և համապատասխանաբար փոփոխեք ձեր ծածկագիրը:

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

Այս ձեռնարկում մենք հետագայում ուսումնասիրեցինք ATmega328p- ի հավաքման լեզուն և սովորեցինք, թե ինչպես վերահսկել LED- ը սեղմման կոճակով: Մասնավորապես, մենք սովորեցինք հետևյալ հրամանները.

ser գրանցամատյանը գրանցիչի բոլոր բիթերը դնում է 1 -ի վրա

clr ռեգիստրը գրանցիչի բոլոր բիթերը դնում է 0 -ի

գրանցամատյանում i/o գրանցամատյանը պատճենում է համարը i/o ռեգիստրից դեպի աշխատանքային գրանցամատյան

Հաջորդ ձեռնարկում մենք կքննարկենք ATmega328p- ի կառուցվածքը և դրանում պարունակվող տարբեր գրանցամատյանները, գործողությունները և ռեսուրսները:

Նախքան այս ձեռնարկների շարունակելը ես կսպասեմ և կտեսնեմ հետաքրքրության մակարդակը: Եթե կան մի շարք մարդիկ, ովքեր իրականում հաճույք են ստանում, թե ինչպես են միկրոպրոցեսորի համար ծրագրեր ծածկագրում հավաքման լեզվով, ապա ես կշարունակեմ և կկառուցեմ ավելի բարդ սխեմաներ և կօգտագործեմ ավելի ուժեղ կոդ:

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