Мазмұны:

AVR Assembler оқулығы 3: 9 қадамдары
AVR Assembler оқулығы 3: 9 қадамдары

Бейне: AVR Assembler оқулығы 3: 9 қадамдары

Бейне: AVR Assembler оқулығы 3: 9 қадамдары
Бейне: Lesson 2: Getting Arduino Software and using Documentation for SunFounder Arduino Kit | SunFounder 2024, Шілде
Anonim
AVR Assembler оқулығы 3
AVR Assembler оқулығы 3

№3 оқулыққа қош келдіңіз!

Жұмысты бастамас бұрын мен философиялық ой айтқым келеді. Осы оқулықтарда біз құрастыратын схемалар мен кодпен тәжірибе жасаудан қорықпаңыз. Сымдарды ауыстырыңыз, жаңа компоненттер қосыңыз, компоненттерді шығарыңыз, код жолдарын өзгертіңіз, жаңа жолдар қосыңыз, жолдарды жойыңыз және не болатынын көріңіз! Кез келген нәрсені бұзу өте қиын, ал егер сіз оны бұзсаңыз, кімге қажет? Біз қолданатын ештеңе, соның ішінде микроконтроллер, өте қымбат емес және істің қалай сәтсіздікке ұшырайтынын көру әрқашан тәрбиелік мән береді. Келесіде не істеуге болмайтынын біліп қана қоймай, ең бастысы, неге бұлай жасамау керектігін білесіз. Егер сіз маған ұқсайтын болсаңыз, бала кезіңізде сізде жаңа ойыншық болған кезде, көп ұзамай оны бөлшектеп алғаннан кейін, оның дұрыс таңдалғанын көрдіңіз бе? Кейде ойыншық қалпына келмейтін зақыммен аяқталды, бірақ маңызды емес. Баланың қызығушылығын ойыншықтар сынғанша ашуға мүмкіндік беру оны ыдыс жуғыш машинаның орнына ғалымға немесе инженерге айналдырады.

Бүгін біз өте қарапайым тізбекті қосамыз, содан кейін теорияға аздап енеміз. Кешіріңіз, бірақ бізге құрал қажет! Мен мұны 4 -оқулықта толтырамыз деп уәде беремін, онда біз әлдеқайда күрделі схеманы жасаймыз және нәтиже керемет болады. Дегенмен, бұл оқулықтардың барлығын орындау әдісі өте баяу, ойланатын түрде. Егер сіз жай ғана жыртсаңыз, тізбекті құрсаңыз, кодты көшіріп, қойсаңыз және оны іске қоссаңыз, ол жұмыс істейді, бірақ сіз ештеңе білмейсіз. Әр жол туралы ойлану керек. Кідірту. Эксперимент. Ойлап табу. Егер сіз мұны осылай жасасаңыз, онда 5 -ші оқулықтың соңында сіз керемет материалдарды құрудан бас тартасыз және сізге қосымша сабақ қажет емес. Әйтпесе, сіз үйренуден және жасаудан гөрі жай қарап отырсыз.

Қалай болғанда да, философия жеткілікті, бастайық!

Бұл оқулықта сізге қажет:

  1. сіздің прототип тақтасы
  2. жарық диоды
  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 - жарық диоды - 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 out 0x26, r16 sbi 0x0a, 0x04 sbi 0x0b, 0x04 b: 0x04 b: sbi 0x04 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 -қадам: Blink.asm

Міне, біз бүгін талқылайтын код:

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

; жазған: 1o_o7; күні:; нұсқа: 1.0; файл келесі түрде сақталады: blink.asm; AVR үшін: atmega328p; сағат жиілігі: 16 МГц (міндетті емес); **********************************; Бағдарлама функциясы: ---------------------; светодиодты жыпылықтау арқылы секундтарды есептейді;; PD4 - жарық диоды - R (330 ом) - GND;; --------------------------------------.nolist.include «./m328Pdef.inc».list; ===============; Декларациялар:.def temp = r16.def толып кетуі = r17.org 0x0000; жад (ДК) қалпына келтіру өңдегішінің орналасуы rjmp Қалпына келтіру; jmp 2 cpu циклін құрайды, ал rjmp құны тек 1; сондықтан 8к байттан артық секіру қажет болмаса; сізге тек rjmp қажет. Сондықтан кейбір микроконтроллерлер; rjmp және jmp емес.org 0x0020; Timer0 толтыру өңдегішінің жад орны rjmp overflow_handler; timer0 толып кетуі орын алса, осында өтіңіз; ============= Reset: ldi temp, 0b00000101 TCCR0B, temp; CS00, CS01, CS02 Clock Selector Bits 101 параметрлерін орнатыңыз; бұл таймер Counter0, TCNT0 FCPU/1024 режиміне қояды; сондықтан ол CPU freq/1024 ldi temp, 0b00000001 sts TIMSK0, temp; таймердің асып кетуін тоқтатуды қосу (TOIE0) битін орнатыңыз; таймердің үзіліс маскасының тізілімі (TIMSK0) sei; жаһандық үзілістерді қосу - «sbi SREG, I» clr temp out TCNT0, temp; таймерді/есептегішті 0 sbi DDRD, 4 -ке инициализациялау; PD4 шығуға орнатыңыз; =====================; Бағдарламаның негізгі бөлігі: жыпылықтау: sbi PORTD, 4; PD4 қоңырауды кешіктіру кезінде жарықдиодты қосыңыз; кідіріс 1/2 секунд cbi болады PORTD, 4; PD4 қоңырауды кешіктірудегі жарықдиодты өшіру; кідіріс 1/2 секунд rjmp жыпылықтайды; цикл басталу кідірісіне оралады: clr толып кетеді; толып кетулерді 0 sec_count мәніне орнатыңыз: cpi толып кетуі, 30; толып кетулер мен 30 секундтық есепті салыстыру; ret_ тең емес болса, sec_count -қа қайту; егер 30 толып кетуі жыпылықтауға оралса overflow_handler: inc overflows; толып кетулерге айнымалы cpi overflows 1 қосыңыз, 61; 61 brne PC+2 -мен салыстыру; Counter + 2 бағдарламасы (келесі жолды өткізіп жіберіңіз) тең болмаса clr толып кетеді; егер 61 толып кетсе, есептегішті нөлдік ретке келтіріңіз; үзілістен оралу

Көріп отырғаныңыздай, менің түсініктемелерім қазір сәл қысқаша. Нұсқаулықтар жиынындағы қандай командалар екенін білген соң, түсініктемелерде оны түсіндірудің қажеті жоқ. Біз тек бағдарламаның тұрғысынан не болып жатқанын түсіндіруіміз керек.

Біз мұның барлығын бөлшектеп талқылайтын боламыз, бірақ алдымен жаһандық перспективаны алуға тырысайық. Бағдарламаның негізгі бөлігі келесідей жұмыс істейді.

Алдымен біз PORTD 4 битін «sbi PORTD, 4» арқылы орнатамыз, бұл PD4 -ке 1 жібереді, ол кернеуді 5В кернеуге қояды. Бұл жарық диодты қосады. Содан кейін біз 1/2 секундқа есептелетін «кешіктіру» кіші бағдарламасына өтеміз (мұны кейінірек түсіндіреміз). Содан кейін біз PORTD -де PD4 -ті 0В -ге орнататын 4 -ші жыпылықтауға және тазартуға ораламыз, сондықтан жарық диодты өшіреміз. Содан кейін біз тағы 1/2 секундқа кешіктіреміз, содан кейін «rjmp blink» арқылы жыпылықтаудың басына қайта ораламыз.

Сіз бұл кодты іске қосуыңыз керек және ол қажет нәрсені істейтінін көруіңіз керек.

Ал сізде бар! Бұл код физикалық түрде жасайды. Микроконтроллердің ішкі механикасы сәл көбірек қатысады, сондықтан біз бұл оқулықты жасаймыз. Сондықтан әр тарауды кезекпен талқылайық.

4 -қадам:.org Assembler директивалары

Біз алдыңғы оқулықтардан.nolist,.list,.include және.def ассемблер директивалары не істейтінін білеміз, сондықтан алдымен кодтың 4 жолын қарастырайық:

.org 0x0000

jmp.org 0x0020 jmp overflow_handler қалпына келтіру

. Org операторы ассемблерге «Бағдарламалық жадта» келесі операторды қайда қою керектігін айтады. Сіздің бағдарламаңыз орындалған кезде «Бағдарлама есептегіші» (ДК ретінде қысқартылған) орындалатын ағымдағы жолдың адресін қамтиды. Бұл жағдайда компьютер 0x0000 болғанда, ол жадта «jmp қалпына келтіру» пәрменін көреді. Jmp Reset -ті бұл жерге қоюды қажет ететін себебіміз, бағдарлама басталғанда немесе чип қалпына келтірілгенде, компьютер осы жерде кодты орындай бастайды. Көріп отырғанымыздай, біз оған «Қалпына келтіру» деп аталатын бөлімге бірден «секіруді» айттық. Біз неге олай жасадық? Бұл жоғарыдағы соңғы екі жолды өткізіп жіберуді білдіреді! Неге?

Міне, бұл жерде заттар қызықты болады. Енді сізге осы оқулықтың бірінші бетінде көрсеткен ATmega328p толық деректер кестесі бар pdf қарау құралын ашу қажет болады (сондықтан «сізге қажет» бөлімінің 4 тармағы). Егер сіздің экран тым кішкентай болса немесе сізде тым көп терезелер ашылса (менде де солай), мен жасайтын нәрсені істеп, оны Ereader немесе Android телефонына қоюға болады. Егер сіз құрастыру кодын жазуды жоспарласаңыз, сіз оны үнемі қолданасыз. Керемет нәрсе - барлық микроконтроллерлер ұқсас түрде ұйымдастырылған, сондықтан сіз деректер кестелерін оқуға және олардан кодтауға үйреніп алғаннан кейін, басқа микроконтроллер үшін де дәл осылай жасау оңай емес деп ойлайсыз. Біз шын мәнінде барлық микроконтроллерлерді қалай қолдануға болатынын үйреніп жатырмыз, тек atmega328p.

Жарайды, мәліметтер парағының 18-бетіне өтіп, 8-2-суретті қараңыз.

Микроконтроллердегі Бағдарлама жады осылайша орнатылады. Сіз оның 0x0000 адресінен басталатынын және екі бөлімге бөлінгенін көре аласыз; қосымшаның жарқыл бөлімі мен жүктеудің жарқыл бөлімі. Егер сіз 277-беттегі 27-14-кестеге қысқаша сілтеме жасасаңыз, онда қосымшаның жарқыл бөлімі 0x0000-ден 0x37FF-ге дейінгі орындарды алатынын, ал жүктеудің жарқыл бөлімі 0x3800-ден 0x3FFF-ке дейінгі қалған орындарды алатынын көресіз.

1 -жаттығу: Бағдарлама жадында қанша орын бар? Яғни 3FFF -ті ондық санау жүйесіне түрлендіріп, 0 -де санауды бастағаннан бері 1 -ді қосыңыз. Әр жад орны 16 биттік (немесе 2 байт) ені болғандықтан, жадтың жалпы байт саны қанша? Енді килобайтта 2^10 = 1024 байт бар екенін есте сақтап, оны килобайтқа түрлендіріңіз. Жүктеу флэшінің бөлімі 0x3800 -ден 0x37FF -ге дейін барады, бұл неше килобайт? Бағдарламаны сақтау үшін бізге қанша килобайт жады қалды? Басқаша айтқанда, біздің бағдарлама қаншалықты үлкен болуы мүмкін? Ақырында, бізде қанша код жолдары болуы мүмкін?

Жарайды, енді біз флэш -бағдарламаның жадысын ұйымдастыру туралы білетін болсақ,.org мәлімдемелерін талқылауды жалғастырайық. Біз 0x0000 жадының бірінші орналасуында «Қалпына келтіру» деп аталатын біздің бөлімге өту жөніндегі нұсқаулықты қамтитынын көреміз. Енді біз «.org 0x0020» мәлімдемесі не істейтінін көреміз. Онда келесі жолдағы нұсқаулық 0x0020 жад орнына орналастырылғанын қалаймыз дейді. Біз берген нұсқаулықта біздің кодта «overflow_handler» деп белгіленген бөлімге өту бар … енді неге біз бұл секіруді 0x0020 жад орнына қоюды талап етеміз? Мұны білу үшін біз мәліметтер кестесіндегі 65-бетке қараймыз және 12-6-кестені қараймыз.

12-6-кесте-«Векторларды қалпына келтіру және үзу» кестесі, онда ДК «үзіліс» алған кезде қайда баратынын дәл көрсетеді. Мысалы, егер сіз 1-ші векторлық нөмірге қарасаңыз, үзілістің «көзі»-«RESET», ол «Сыртқы түйін, қуат қосуды қалпына келтіру, қоңыр күйді қалпына келтіру және қарауыл жүйесін қалпына келтіру» ретінде анықталады. Мұндай жағдайлар біздің микроконтроллерде болады, ДК біздің бағдарламаны 0x0000 бағдарламалық жадында орындай бастайды. Біздің.org директивасы туралы не деуге болады? Біз 0x0020 жадына пәрмен қойдық, егер сіз кестеге қарасаңыз, егер таймер/Counter0 толып кетсе (TIMER0 OVF -тен келеді), ол 0x0020 орнындағы нәрсені орындайтынын көресіз. Сондықтан бұл орын алған кезде, ДК біз «overflow_handler» деп белгіленген жерге секіреді. Салқын, дұрыс па? Неліктен біз мұны істегенімізді бір минуттан кейін көресіз, бірақ алдымен оқулықтың бұл қадамын шетке қарай аяқтайық.

Егер біз өзіміздің кодты ұқыпты және ұқыпты еткіміз келсе, біз қазір талқылап жатқан 4 жолды төмендегілермен ауыстыруымыз керек (66 -бетті қараңыз):

.org 0x0000

rjmp қалпына келтіру; ДК = 0x0000 рети; ДК = 0x0002 рети; ДК = 0x0004 рети; ДК = 0x0006 рети; ДК = 0x0008 рети; ДК = 0x000A… реті; PC = 0x001E jmp overflow_handler: PC = 0x0020 рети: PC = 0x0022… reti; ДК = 0x0030 рети; ДК = 0x0032

Осылайша, егер үзіліс орын алса, ол тек «рети» болады, бұл «үзілістен қайту» дегенді білдіреді және басқа ештеңе болмайды. Бірақ егер біз бұл үзілістерді ешқашан «қоспай» қойсақ, онда олар қолданылмайды және біз бағдарламалық кодты осы жерлерге қоя аламыз. Біздің қазіргі «blink.asm» бағдарламасында біз timer0 толып кетуін ғана қосамыз (және, әрине, әрқашан қосылатын қалпына келтіру үзілісі), сондықтан біз басқалармен алаңдамаймыз.

Біз timer0 толып кетуін қалай «қосамыз»? … бұл біздің оқулықтағы келесі қадамымыздың тақырыбы.

5 -қадам: Таймер/Есептегіш 0

Таймер/есептегіш 0
Таймер/есептегіш 0

Жоғарыдағы суретке қараңыз. Бұл «компьютердің» шешім қабылдау процесі, егер кейбір сыртқы әсерлер біздің бағдарламаның ағымын «үзсе». Сырттан үзіліс орын алғандығы туралы сигнал алған кезде істейтін бірінші нәрсе - бұл үзілістің осы түріне «үзілісті қосу» битін орнатқанымызды тексеру. Егер бізде жоқ болса, онда ол келесі код жолын орындауды жалғастырады. Егер біз осы үзілістің рұқсат ету битін орнатқан болсақ (сол жерде 0 орнына 1 болатын болса), онда біз «жаһандық үзілістерді» қосқанымызды немесе қоспағанымызды тексереміз, егер ол болмаса, ол келесі жолға өтеді. кодты енгізіңіз және жалғастырыңыз. Егер біз жаһандық үзілістерді де қосқан болсақ, онда ол үзілістің осы түрінің Бағдарламалық жадына өтеді (12-6-кестеде көрсетілгендей) және біз онда берілген кез келген команданы орындайды. Осының бәрін біздің кодексте қалай енгізгенімізді көрейік.

Біздің кодтың таңбаланған бөлімі келесі екі жолдан басталады:

Қалпына келтіру:

ldi temp, 0b00000101 TCCR0B, температура

Біз білетіндей, бұл температураға (яғни R16) бірден келесі нөмірді жүктейді, бұл 0b00000101. Содан кейін бұл нөмір TCCR0B деп аталатын реестрге «шығу» пәрмені арқылы жазылады. Бұл регистр дегеніміз не? Деректер кестесінің 614 бетіне көшейік. Бұл барлық регистрлерді қамтитын кестенің ортасында. 0x25 мекен -жайында сіз TCCR0B таба аласыз. (Енді сіз кодтың түсіндірілмеген нұсқасында «0x25, r16» сызығы қайдан шыққанын білесіз). Біз жоғарыдағы код сегменті бойынша 0 -ші және 2 -ші биттерді орнатып, қалғандарын тазартқанымызды көреміз. Кестеге қарап, бұл CS00 мен CS02 орнатылғанын білдіреді. Енді деректер парағындағы «8-разрядты таймер/PWM бар Counter0» деп аталатын тарауға көшейік. Атап айтқанда, сол тараудың 107 -бетіне өтіңіз. Сіз «Таймер/Есептегіштерді бақылау регистрі B» (TCCR0B) регистрінің дәл осы сипаттамасын көресіз, біз оны реестрдің жиынтық кестесінде көрдік (сондықтан біз осында келуіміз мүмкін еді, бірақ мен жиынтық кестелерді қалай қолдану керектігін көргім келді) болашақ анықтама үшін). Деректер парағы сол регистрдегі әрбір битке және олар не істейтініне сипаттама беруді жалғастырады. Біз мұның бәрін өткізіп жібереміз және бетті 15-9 кестеге айналдырамыз. Бұл кестеде «Сағат таңдайтын биттік сипаттаманы» көрсетеді. Енді біз осы тізілімде біз орнатқан биттерге сәйкес келетін жолды тапқанша, сол кестеге қараңыз. Жолда «clk/1024 (алдын ала есептегіштен)» деп жазылған. Бұл дегеніміз, біз Timer/Counter0 (TCNT0) жиілігі 1024 -ке бөлінген жиілікпен жүруін қалаймыз. Біздің микроконтроллер 16 МГц кристалды осциллятормен қоректендірілгендіктен, бұл біздің процессордың нұсқауларды орындайтын жылдамдығын білдіреді. Секундына 16 миллион нұсқаулық. Біздің TCNT0 есептегішінің жылдамдығы секундына 16 миллион/1024 = 15625 рет болады (әр түрлі сағаттық биттерді қолданып көріңіз және не болатынын көріңіз - біздің философияны есте сақтаңыз ба?). Кейінірек 15625 санын санамызда сақтап, кодтың келесі екі жолына көшейік:

ldi temp, 0b00000001

sts TIMSK0, температура

Бұл TIMSK0 деп аталатын регистрдің 0 -битін орнатады және қалғандарын тазартады. Деректер кестесіндегі 109 -бетті қарасаңыз, TIMSK0 «таймер/есептегіштің үзіліс маскасының тіркелімі 0» дегенді білдіреді, ал біздің код «таймер/есептегіштен асып кетуді қосу» дегенді білдіретін TOIE0 деп аталатын 0 -ші битті орнатқанын көресіз. … Ана жерде! Енді сіз мұның не туралы екенін көресіз. Бізде жоғарыдағы суреттегі бірінші шешімнен қалағанымыздай, «үзілісті қосу биттік жиынтығы» бар. Енді біз тек «жаһандық үзілістерді» қосуымыз керек, және біздің бағдарлама мұндай үзілістерге жауап бере алады. Біз жаһандық үзілістерді жақында қосамыз, бірақ бұған дейін сізді бір нәрсе шатастыруы мүмкін.. неге мен «sts» пәрменін TIMSK0 регистріне әдеттегі «шығу» орнына көшіру үшін қолдандым?

Сіз мені көргенде, сіз бұрын көрмеген нұсқаулықты қолданасыз, бірінші кезекте деректер кестесіндегі 616 бетке өту керек. Бұл «Нұсқаулықтар жиынтығының қысқаша мазмұны». Енді мен қолданған «STS» нұсқауын табыңыз. Ол R регистрінен (біз R16 қолдандық) және «SRAM -ге тікелей сақтау» k орнынан нөмірді алатынын айтады (біздің жағдайда TIMSK0 береді). Неліктен біз TIMSK0 -де сақтау үшін 2 сағаттық циклді (кестенің соңғы бағанын қараңыз) алатын «sts» қолдануға тура келді және бізге тек TCCR0B -те сақтау үшін тек бір сағаттық циклді алатын «шығу» қажет болды? Бұл сұраққа жауап беру үшін біз 614 -беттегі реестрдің жиынтық кестесіне оралуымыз керек. Сіз TCCR0B регистрі 0x25 адресінде, сонымен қатар (0x45) орналасқанын көресіз бе? Бұл дегеніміз, бұл SRAM -дағы регистр, бірақ бұл сонымен қатар «порт» (немесе енгізу -шығару регистрі) деп аталатын регистрдің белгілі бір түрі. Егер сіз «шығу» командасының жанындағы нұсқаулықтардың жиынтық кестесіне қарасаңыз, ол R16 сияқты «жұмыс регистрлерінен» мәндерді қабылдап, оларды ПОРТҚА жіберетінін көресіз. Сонымен, біз TCCR0B -ке жазған кезде «шығуды» қолданып, сағат циклін сақтай аламыз. Бірақ енді тіркеу кестесінен TIMSK0 іздеңіз. Сіз оның 0x6e мекен -жайы бар екенін көресіз. Бұл порттардың диапазонынан тыс (олар тек SRAM -дың 0x3F орналасуы), сондықтан сіз sts пәрменін қолдануға және оны орындау үшін процессордың екі сағаттық циклін қабылдауға қайта оралуыңыз керек. Дәл қазір 615 беттегі нұсқаулық жиынтық кестесінің соңындағы 4 ескертуді оқыңыз. Сондай -ақ, PORTD сияқты барлық кіріс және шығыс порттары кестенің төменгі жағында орналасқанын ескеріңіз. Мысалы, PD4-0x0b адресіндегі 4 разряд (енді сіз түсініктеме берілмеген кодта барлық 0x0b материалдары қайдан шыққанын көресіз!).. жарайды, жылдам сұрақ: сіз «sts» -ті «out» -ға өзгерттіңіз бе және не болғанын көрдіңіз бе? болады? Біздің философияны ұмытпаңыз! сындыр! жай ғана менің сөзімді қабылдамаңыз.

Жарайды, біз көшпес бұрын, бір минут ішінде мәліметтер кестесіндегі 19 -бетке өтіңіз. Сіз деректер жадының (SRAM) суретін көресіз. SRAM -дағы алғашқы 32 регистр (0x0000 -ден 0x001F -ке дейін) - бұл R0 -ден R31 -ге дейінгі «жалпы мақсаттағы жұмыс регистрлері», біз әрқашан кодта айнымалы ретінде қолданамыз. Келесі 64 регистр-бұл 0x005f дейінгі енгізу-шығару порттары (яғни, біз айтатындар, тіркеу кестесінде олардың жанында жақшасыз мекенжайлары бар, оларды «sts» орнына «out» пәрменін қолдана аламыз) Соңында SRAM келесі бөлімінде 0x00FF мекенжайына дейінгі жиынтық кестедегі барлық басқа регистрлер бар, ал қалған бөлігі ішкі SRAM. Енді тезірек, бір секундқа 12 -бетке жүгінейік. Онда біз әрқашан айнымалы ретінде қолданатын «жалпы мақсаттағы жұмыс регистрлері» кестесін көресіз. Сіз R0 -ден R15 -ке дейінгі сандар арасындағы қалың сызықты көресіз бе? Міне, сондықтан біз әрқашан R16-ды ең кіші ретінде қолданамыз, мен келесі оқулықта оған аздап толығырақ тоқталамын, мұнда бізге 16 биттік X, Y және Z жанама мекен-жай регистрлері қажет болады. бұған әлі де кіріңіз, өйткені бізге қазір қажет емес және біз мұнда батып бара жатырмыз.

Мәліметтер парағының бір бетін 11 -бетке кері аударыңыз. Сіз жоғарғы оң жақта SREG регистрінің диаграммасын көресіз бе? Сіз бұл регистрдің 7 -биті «Мен» деп аталатынын көресіз. Енді бетті төмен түсіріп, Bit 7 сипаттамасын оқыңыз. Алақай! Бұл Global Interrupt Enable биті. Жоғарыдағы диаграммадағы екінші шешімді қабылдау үшін және біздің бағдарламада таймер/есептегіштердің толып кетуіне жол беру үшін дәл осылай орнатуымыз керек. Біздің бағдарламаның келесі жолы келесідей болуы керек:

sbi SREG, мен

ол SREG регистрінде «I» деп аталатын битті орнатады. Дегенмен, біз нұсқаулықты қолдандық

сей

оның орнына Бұл бит бағдарламаларда жиі орнатылады, сондықтан олар мұны қарапайым жолмен жасады.

Жақсы! Енді бізде «jmp overflow_handler» орын алған кезде орындалатындай толып кетуге дайын үзілістер бар.

Көшпес бұрын, SREG регистріне (күй регистрі) жылдам қараңыз, себебі бұл өте маңызды. Әр жалаушаның нені білдіретінін оқыңыз. Атап айтқанда, біз қолданатын көптеген нұсқаулар бұл жалауларды үнемі орнатады және тексереді. Мысалы, кейінірек біз «CPI» пәрменін қолданатын боламыз, ол «бірден салыстыру» дегенді білдіреді. Осы нұсқаулықтың қысқаша кестесін қараңыз және «жалаушалар» бағанында қанша жалауша орнатылғанына назар аударыңыз. Мұның бәрі SREG -дегі жалаушалар және біздің код оларды реттеп, үнемі тексеріп отырады. Сіз жақын арада мысалдарды көресіз. Соңында кодтың осы бөлімінің соңғы биті:

clr temp

TCNT0, temp sbi DDRD, 4

Мұнда соңғы жол өте айқын. Бұл PDD -нің шығуына әкелетін PortD үшін деректер бағыты регистрінің 4 -ші битін ғана орнатады.

Біріншісі айнымалы температураны нөлге орнатады, содан кейін оны 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 нұсқаулығының жұмыс әдісі - ол жай ғана азайтады. екі сан, ал егер нәтиже нөлге тең болса, ол S белгісінің регистрінде Z белгісін орнатады (мен сізге бұл регистрді үнемі көретінімізді айттым). Егер екі сан тең болса, онда Z белгісі 1 болады, егер екі сан тең болмаса, онда ол 0 болады.

Келесі жолда «brne PC+2» жазылады, бұл «тең болмаса филиал» дегенді білдіреді. Негізінде ол SREG ішіндегі Z жалаушасын тексереді және егер ол бір емес болса (яғни екі сан тең емес, егер олар тең болса, нөлдік жалауша орнатылады) ДК PC+2 -ге таралады, яғни ол келесіден өтеді сызық және тура «рети» -ге өтеді, ол үзілістен үзіліс келген кезде кодтағы кез келген жерге оралады. Егер brne нұсқауы нөлдік жалаушадан 1 -ді тапса, ол тармақталмайды және оның орнына келесі жолға жалғасады, ол clr overflows оны 0 қалпына келтіреді.

Осының барлығының таза нәтижесі қандай?

Біз таймердің толуы болған сайын, бұл өңдегіш «толып кету» мәнін бір есе арттыратынын көреміз. Сонымен, «толып кету» айнымалысы толып кету санын олардың пайда болуымен есептейді. Нөмір 61 -ге жеткенде біз оны нөлге қайтарамыз.

Енді біз неге әлемде осылай жасаймыз?

Қарайық. Еске сала кетейік, біздің процессордың сағат жылдамдығы 16 МГц және біз оны TCCR0B көмегімен «алдын ала масштабтадық», осылайша таймер секундына 15625 рет есептеледі. Ал таймер 255 санына жеткен сайын ол толып кетеді. Демек, бұл секундына 15625/256 = 61,04 рет асып түседі. Біз «толып кету» айнымалысы арқылы толып кету санын қадағалап отырамыз және бұл санды 61 -мен салыстырамыз. Осылайша біз «толып кету» секундына 61 рет болатынын көреміз! Біздің өңдеуші секундына бір рет «толып кетуді» нөлге қайтарады. Егер біз айнымалы «толып кетулерді» бақылайтын болсақ және оның нөлге қайта оралғанын ескеретін болсақ, біз нақты уақыт режимінде секунд сайын санап шығатын едік (келесі оқулықта біз дәлірек болу жолын көрсететінін ескеріңіз). миллисекундтарда кідіріс Arduino «кешіктіру» процедурасы сияқты жұмыс істейді).

Енді біз таймердің толып кетуін «өңдедік». Бұл қалай жұмыс істейтінін түсінгеніңізге көз жеткізіңіз, содан кейін біз бұл фактіні қолданатын келесі қадамға өтеміз.

7 -қадам: Кешіктіру

Енді біз таймердің толып кетуін «overflow_handler» реттегіші «толып кетулер» айнымалысын секундына нөлге қоятынын көрдік, біз бұл фактіні «кешіктіру» ішкі бағдарламасын жасау үшін қолдана аламыз.

Біздің кешігуімізден келесі кодты қараңыз: белгісі

кешігу:

clr overlocs sec_count: cpi толып кетуі, 30 brne sec_count ret

Біз бұл бағдарламаны кешіктіру қажет болған сайын шақырамыз. Жұмыс әдісі - бұл алдымен «толып кетулер» айнымалысын нөлге орнатады. Содан кейін ол «sec_count» деп аталатын аймаққа кіреді және 30 -мен толып кетулерді салыстырады, егер олар тең болмаса, олар sec_count белгісіне таралады және қайтадан теңестірілмейінше қайтадан және т.б.мен салыстырады (бұл уақыттың барлық уақытта болатынын ұмытпаңыз) біздің таймерде үзіліс өңдегіші айнымалы толып кетулерді ұлғайтуды жалғастыруда, сондықтан біз осында айналған сайын өзгеріп отырады. Толып кету 30 -ға тең болғанда, ол циклден шығады және біз кешіктіру деп аталатын жерге қайтып оралады: таза нәтиже - бұл 1/2 секундқа кешіктіру

2 -жаттығу: overflow_handler процедурасын келесіге өзгертіңіз:

overflow_handler:

Inc reti толтырады

және бағдарламаны іске қосыңыз. Басқа нәрсе бар ма? Неге?

8 -қадам: Жыпылықта

Соңында жыпылықтау тәртібін қарастырайық:

жыпылықтау:

sbi PORTD, 4 rcall кешіктіру cbi PORTD, 4 rcall кешіктіру rjmp жыпылықтау

Алдымен біз PD4 қосамыз, содан кейін біз кешіктірудің ішкі бағдарламасын шақырамыз. Біз rcall -ды қолданамыз, осылайша ДК «ret» мәлімдемесіне жеткенде, ол rcall -дан кейінгі жолға оралады. Содан кейін кешіктіру тәртібі біз көргендей толып кететін айнымалының 30 есебін кешіктіреді және бұл шамамен 1/2 секунд, содан кейін біз PD4 өшіреміз, тағы 1/2 секунд кешіктіреміз, содан кейін қайтадан басына ораламыз.

Нәтиже - жыпылықтайтын жарық диоды!

Менің ойымша, енді сіз «жыпылықтау» ассемблер тіліндегі ең жақсы «сәлем әлемі» бағдарламасы емес екеніне келісесіз деп ойлаймын.

3 -жаттығу: Бағдарламаның әр түрлі параметрлерін светодиоды әр түрлі жылдамдықпен секундына 4 рет жыпылықтайтындай етіп өзгертіңіз. 4 -жаттығу: Жарық диоды әр түрлі уақытқа қосылатын және өшетін етіп өзгертіңіз. Мысалы, 1/4 секундқа қосылады, содан кейін 2 секундқа өшіріледі немесе 5 -жаттығу: TCCR0B сағатын таңдау биттерін 100 -ге өзгертіңіз, содан кейін үстелге көтерілуді жалғастырыңыз. 1 -оқулықтағы біздің «hello.asm» бағдарламасынан қай уақытта айырмашылығы болмайды? 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» және тізім файлына қараңыз. Қосымша несие: Мен басында айтқан түсініктеме берілмеген код пен кейінірек талқыланатын түсініктеме коды ерекшеленеді! Әр түрлі кодтың бір жолы бар. Сіз таба аласыз ба? Неліктен бұл айырмашылық маңызды емес?

Сіз көңілді болды деп үміттенемін! Келесі кездескенше…

Ұсынылған: