Ձեր Arduino- ն վերածեք մագնիսական քարտի ընթերցողի: 9 քայլ (նկարներով)
Ձեր Arduino- ն վերածեք մագնիսական քարտի ընթերցողի: 9 քայլ (նկարներով)
Anonim

Բոլորը, կարծում եմ, օգտագործել են մագնիսական քարտի ընթերցող: Նկատի ունեմ ՝ ո՞վ է այս օրերին կանխիկ գումար տանում: Դրանք նույնպես դժվար չէ ձեռք բերել, և իմ ամենասիրված էլեկտրոնիկայի խանութ կատարած ճանապարհորդության ընթացքում ես գտա այս տղաներով լի աղբարկղը: Այսպիսով,… Իհարկե, ես վերցրեցի մեկը և բերեցի տուն ՝ տեսնելու, թե ինչպիսի իրեր կարող եմ անել դրա և AVR- ի հետ:

Այս հրահանգը ցույց կտա ձեզ, թե ինչպես միացնել Magtek մագնիսական քարտի ընթերցողը AVR- ին կամ Arduino/կլոնին և կարդալ տվյալները քարտի առաջին հետքից: Ամրացրեք ձեր տեղերը; մագնիսական քարտերի ընթերցողներն ունեն բիթերի բարձր արագություն:

Քայլ 1: Սարքավորումների ցուցակ

Ահա մի քանի բան, որոնք ձեզ հարկավոր են սկսելու համար:

  • Մագնիսական քարտի ընթերցիչ (Իմը Magetk 90 մմ երկկողմանի ընթերցող է. $ 5.00)
  • AVR, Arduino կամ կլոն (ATmega328p 4. 4.30 դոլար Mouser.com- ից
  • առանց զոդման տախտակ
  • ինչ -որ մետաղալար
  • գուցե վերնագիր, եթե ձեզ դուր է գալիս նման բան:
  • ինչ -որ բան կարդալ ձեր սերիական նավահանգիստը: Ես օգտագործում եմ AVR տերմինալը BattleDroids.net- ից

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

Քայլ 2. Ինքնակարգավորվող մագնիսական քարտերի ընթերցողներ

Մագնիսական քարտերի ընթերցողները «ինքնակարգավորվում են», այսինքն `նրանք ապահովում են ժամացույց, որը կոչվում է ստրոբ, որի դեմ միացված միկրոկառավարիչը կարող է համաժամացվել: Սա բարիք է: Դա նշանակում է, որ դուք չպետք է անհանգստանաք ժամացույցի ազդանշանի որոնման և ազդանշանի կենտրոնացման ժամանակացույցի մասին անմիջապես ժամացույցի զարկերակի վրա, և որևէ անհանգստացնող տատանում չլինի ժամացույցի ազդանշանի քաղցր տեղում: Սա իմաստ է ունենում, երբ մտածում ես քարտերի հարվածների մասին. Բոլորը սայթաքում են տարբեր տեմպերով, ոմանք ավելի դանդաղ, ոմանք ավելի արագ, քան մյուսները: Ինքնակարգավորումը նույնիսկ իմ քաղցր տատիկին հնարավորություն է տալիս օգտագործել իր քարտը ՝ առանց դաստակը կոտրելու: Հիշեցնում է, որ ես պետք է փոխեմ իր համար այն կարգավորումը, որը որոշում է, թե որքան ժամանակ է վավերական կտտոցների միջև կրկնակի սեղմում գրանցելու համար…:

Այս քարտի ընթերցողի տվյալները վավեր են 1.0 անգամ մեզանից, նախքան ստրոբը գծի վրա դնելը, այնպես որ անհանգստացեք «բիթ ժամանակի» մեջ մտնելու հետաձգման մասին: Երկկողմանի ընթերցողի համար, ինչպիսին ես օգտագործում եմ, կարդալու համար հասանելի են երկու տվյալների հետքեր: Այս «իբլու» -ում ես ցույց կտամ ընթերցումը առաջնային առաջին ուղուց `սկսելու համար: Կան հինգ կապեր, որոնք դուք պետք է կատարեք (չորսը, եթե դեմ չեք հրաժարվել ավելի նուրբ կարգավորված վերահսկողությունից ՝ ավելի քիչ I/O նավահանգիստների համար): Ստուգեք ստորև ներկայացված նկարը: Կարմիր մետաղալարն անցնում է +5 Վ -ի, իսկ սևը ՝ գետնին: Կանաչ մետաղալարն է /CARD_PRESENT; դեղին մետաղալարն է /STROBE, իսկ սպիտակ մետաղալարն է /DATA1: Ֆորվարդ շեղը (/) նշանակում է, որ տվյալները շրջված են: Signalածր ազդանշանը (այսինքն `0) կարդացվում է որպես մեկ կամ բարձր: Մյուս միակցիչները շագանակագույն են /STROBE2- ի համար և նարնջագույն /DATA2- ի համար: Մենք չենք օգտագործելու դրանք: Եթե ցանկանում եք, կարող եք մոռանալ /CARD_PRESENT- ի մասին: Տվյալների տողն իջնում է գլխի հոսքի շուրջ 17 պտույտներից հետո `ցույց տալու համար, որ քարտ կա (ասենք, պատահական աղմուկի փոխարեն, որը ձեր ընթերցողին ուղարկում է կեղծ տվյալներ) և օգտագործվում է վավերացնելու համար, որ ձեր ստացած տվյալները քարտի տվյալներն են և ոչ թափոն: Դուք կարող եք բաց թողնել այս կապը, եթե տվյալների հոսքում ստուգեք սկզբնական պահակակետը: Այդ մասին ավելի ուշ: Ինչպես տեսնում եք ստորև, ես օգտագործեցի ուղղանկյուն արական վերնագիր, որը միացված էր հացի տախտակին և դրան միացրեց իմ ընթերցողին: Ես /STROBE- ը միացրել եմ PIND2- ին (թվային կապիչ 2 -ը Arduino- ում), /CARD_PRESENT- ը PIND3- ին (նկարազարդման նպատակով) և /DATA1- ը PIND4- ին: Համոզվեք, որ միացնում եք քաշումներն այս կապում, որպեսզի ձեր կապումներն չլողան: Ես նաև փոխեցի իմ Arduino- ն Bare Bones AVR- ով, քանի որ ինձ դուր է գալիս, թե ինչպես է այն տեղավորվում հացահատիկի մեջ:

Քայլ 3. Մագնիսական քարտի հիմունքները

Մագնիսական քարտ կարդալու համար ձեզ անհրաժեշտ հիմնական գործառույթներն են. Տվյալներ Նախ, ես ձեզ կներկայացնեմ մի քանի մագնիսական քարտի հիմունքներ, որոնք դուք պետք է իմանաք, երբ սկսում եք գրել ձեր սեփական կոդը:

Մագնիսական քարտի ստանդարտներ

Մագնիսական քարտերը ստանդարտացված են ISO- ով ՝ հետևյալ փաստաթղթերում. 5 Հետագծի 3 -րդ տեղ. Այս տարբերությունների համար դուք ստիպված կլինեք ծրագրավորել: Ես պարզապես ունեի վարկային քարտ և ապահովագրական քարտ, ուստի ծրագրավորեցի այս տեսակների համար (որոնք երկուսն էլ պատահում են B ձևաչափով):

Քարտի ձևաչափեր

Կան մի քանի տարբեր ձևաչափեր մագնիսական քարտերի համար: A և B ձևաչափերը սովորական են, որոնցից B- ն ամենատարածվածն է, որը ես տեսել եմ, և որն ապահովված է այս ծածկագրում: Կարծում եմ, C- ից մինչև M- ի ձևաչափերը վերապահված են ISO- ին, իսկ N- ից մինչև ?? վերապահված են ինստիտուցիոնալ օգտագործման համար: Հետք 1 Ֆինանսական քարտերի համար առաջին հետքը գրանցվում է 210 դյույմ մեկ դյույմով և քարտի վերևի առաջին 0.110 դյույմն է: Տվյալները կոդավորված են որպես «քարտային տվյալներ» ՝ յուրաքանչյուր բնույթի համար 7 բիթ: Դա 6 բիթ է: կերպարը և մի փոքր հավասարության համար: track 79 ալֆան -թվային նիշ կա 1. Ֆիզիկական կարգը հետընթաց է: Այսինքն, տվյալները քարտի վրա գրված են հետընթաց (և, հետևաբար, ձեր որոնվածը կկարդա), ինչպես. հավասարությունը տարօրինակ է: Քարտի տվյալների ձևաչափն այսպիսին է.

[SS] [FC] [Հիմնական հաշիվ #] [FS] [Անուն] [FS] [Լրացուցիչ տվյալներ] [FS] [ES] [LRC] որտեղ ՝

SS Սկիզբ պահապան FC Ձևաչափի կոդ FS Դաշտի անջատիչ ES Վերջ պահակ LRC Երկայնական ավելորդության ստուգման նիշ Հետևեք մեկ SS = '%', FC = ձևաչափերից մեկին (շատ անգամներ կլինեն B), FS- ն հաճախ '', ES- ն '?' ' իսկ LRC- ի բնույթը սովորաբար '<' է, չնայած այն չափորոշիչներում նշված չէ: Բացի քարտի վրա հետ գրվելուց, տվյալները ունեն կենտ պարիտետային բիթ և 0x20 են ASCII- ից: Մենք կկարգավորենք դա, երբ մշակենք տվյալները: Հետք 2 Հետքը երկուսն ունի 0.110 "լայնություն և սկսվում է 0.110 քարտի վերևից: Նրա ձայնագրման խտությունը 75 բիթ / դյույմ է: Տվյալները 5 բիթ են մեկ նիշի համար և բաղկացած են միայն մոտ 40 թվային խորհրդանիշից: Դուք չպետք է հանդիպեք դրանց: տառեր այս ուղու վրա: Քարտի տվյալների ձևաչափը պետք է համապատասխանի այս կառուցվածքին

[SS] [առաջնային հաշիվ #] [FS] [լրացուցիչ տվյալներ | հայեցողական տվյալներ] [ES] [LRC]

Երկրորդ ուղու SS- ն ստորակետն է ՝ ';' իսկ FS- ն '=' Այս սուրբ գիտելիքներով ձեր գոտում, շարունակեք հաջորդ քայլերը `տեսնելու վերը նկարագրված ընթացակարգը իրականացնող կոդը:

Քայլ 4. Հայտնաբերել, երբ քարտը տեղափոխվում է

1. Հայտնաբերել, երբ քարտը պաշտոնապես սահեցվել է, կարելի է ստուգել /CARD_PRESENT քորոցը `պարզելու, թե արդյոք այն ցածր է: Բարեբախտաբար, սա իսկապես անհրաժեշտ չէ: Ավելի ուշ մենք ստուգելու ենք վավեր քարտը: Այլապես, դուք կարող եք կարդալ ձեր ստրոբի քորոցը ՝ տեսնելու համար, թե երբ են ստրոբները դրված քորոցի վրա, սակայն դա ձեզ զրոյական շատ զրոյական հաշիվներ կբերի: Ընթերցողը կուղարկի մոտ 60-70 առաջատար զրոներ `տեղեկացնելու համար, որ տվյալները պատրաստվում են ներկայացնել: Այնուամենայնիվ, մենք մտադիր ենք օգտագործել երկուական տվյալների բնույթը `որոշելու, թե երբ սկսել բիթերի գրանցումը: Առաջին ուղու համար պահակակետը (SS) տոկոսային նշանն է (%): Նրա երկուական արժեքը 0010 0101 է, ինչը նշանակում է, որ այն կպահվի (և կկարդա) որպես 1010 001 (դա 7 բիթ է, այնպես որ 8-րդ բիթը չի փոխանցվում): Այժմ, խորաթափանց ընթերցողը կնկատի, որ չնայած տվյալները հետ են, բայց դրանք չեն համապատասխանում երկուական ASCII արժեքին: Դա պայմանավորված է նրանով, որ այն 0x20 զեղչ է վեցանկյունից: % Խորհրդանիշը 0x25 է, իսկ 0100 0101 -ը ՝ 0x05: Քարտի տվյալները արժեքից հանվում են 0x20: Այդ մեկը, որը կախված է այնտեղ բարձր խայթոցից, տարօրինակ հավասարության բիթ է: Այն տեղադրված է այնպես, որ արժեքի մեջ կա կենտ թիվ «1»: Այսպիսով, քանի որ մենք գիտենք, որ վավեր քարտը միշտ կսկսվի այս մեկնարկային պահակակից, և քանի որ պարիտետային բիթը 1 է, ապա երբ մենք հայտնաբերում ենք առաջին բարձրից ցածր մակարդակի անցումը տվյալների քորոցի վրա, ապա մենք գիտենք, որ նոր ենք սկսել ստանալ սկսել պահապանը քարտից: Այժմ, դա միշտ չէ, որ ճշմարիտ է լինելու, և անխելք ծրագիր կլինի /ստուգել /CARD_PRESENT քարտը `պարզելու համար, թե արդյոք այն OWԱOWՐ է գնացել: SS- ի սկիզբը հայտնաբերելու ամենապարզ միջոցը /STROBE- ի ընկնող եզրին առաջացած արտաքին ընդհատման ստեղծումն է: Տվյալները վավեր են 1.0 մեզանից առաջ ՝ ընկնելու եզրից, այնպես որ, երբ դուք նմուշառում եք ընկնող եզրը, ապա գիտեք, որ կարող եք կարդալ /DATA1 փին և ստանալ վավեր արժեք: Ահա ձեր արտաքին ընդհատումը ստեղծելու կոդը, որը գործարկվել է ընկնելու եզրին:

voidInitInterrupt (void) {// Setup ընդհատում BSET (EIMSK, INT0); // արտաքին ընդհատման դիմակ BSET (EICRA, ISC01); // ընկնող եզր BCLR (EICRA, ISC00); // ընկնող եզր BSET (SREG, 7); // I-bit SREG- ում}

Իմ ընդհանուր ծրագրում, որը ես ներառում եմ իմ բոլոր ծրագրերում, կարելի է գտնել BSET և BCLR սահմանումները: Անդրադարձ կատարեք այդ ֆայլին, եթե բիտեր տեղադրելու վերաբերյալ հարցեր ունեք: Այժմ, երբ ընդհատումը գործարկվում է, մենք ուզում ենք /DATA1- ը (իմ CARD_DATA- ով սահմանված կոդով) նմուշ վերցնել և մի փոքր դնել ընդհանուր նշանակության IO գրանցամատյանում: Եթե մենք գտնվում ենք 7 -րդ բիթի վրա, ապա հանեք գրանցամատյանը որպես նշան մեր գլոբալ բուֆերում: Ես օգտագործում եմ GPIOR0 գրանցամատյան, քանի որ այն արագ մուտք ունի: Կեղծ կոդն այսպիսին է.

Դադարեցրեք 16-բիթ ժամաչափ Մաքրել ժամաչափը Եթե ՏՎՅԱԼՆԵՐԸ OWԱՐ են Սահմանել BIT = 1 ԳՐԱՆISՎԵԼ Նվազեցում BIT Սահմանել դրոշը, որպեսզի այլևս չշրջանցենք ՏՎՅԱԼՆԵՐԸ ԲԱՐՁՐԱ SetՈԹՅՈ isՆ Է BIT = 0 0 ԳՐԱՆISՎԵԼ Նվազեցում BIT Եթե BIT- ը 0 Ավելացնել բայթ բուֆերին Բարձրացման ինդեքս Վերագործարկեք BIT- ը

Եթե ինքներդ ձեզ հարցնում եք, թե ինչու է ավելացման փոխարեն նվազում, հիշեք, որ տվյալները հետ են, ուստի բիթերը գրանցելու փոխարեն, երբ դրանք ստանում ենք LSB- ից MSB, մենք դրանք պահում ենք MSB- ից LSB, որպեսզի ստիպված չլինենք հակադարձել բիթերը: ավելի ուշ տվյալների մշակման ժամանակ: Եթե իսկապես ցանկանայիք, կարող եք նաև 0x20 վեցանկյուն ավելացնել այստեղ, բայց քանի որ խոսքը այս ստրոբների վրա 5 -ի մասին է, ես նվազագույնի եմ հասցնում այս ընդհատվող ծառայության ռեժիմի մշակումը:

ISR (INT0_vect) {StopTimer (); ClearTimer (); եթե (! BCHK (PIND, CARD_DATA1)) // հակադարձ ցածր = 1 {BSET (GPIOR0, բիթ); -բիթ; bDataPresent = 1; } else if (bDataPresent) {BCLR (GPIOR0, բիթ); -բիթ; } if (բիթ <0) {buff [idx] = (char) GPIOR0; ++ idx; բիթ = 6; } StartTimer ();} Եթե ձեզ հետաքրքրում է, թե ինչի մասին է խոսքը ժամանակի մասին, դա նկարագրված է այն քայլում, որը որոշում է, թե երբ է քարտը թողել ընթերցողը:

Քայլ 5: Կարդացեք տվյալների հոսքը

Կարդացեք տվյալների հոսքը

Դե, ես արդեն ցույց տվեցի, թե ինչպես կարդալ տվյալները, քանի որ դա ընդհատման ծառայության ռեժիմի մի մասն է `մեր արտաքին եզրերի ընկնելու եզրին: Այլընտրանքային մեթոդը կլիներ դրոշ տեղադրել ISR- ում, իսկ հիմնական օղակում ՝ հարցնել դրոշը և կարդալ տվյալները այդ կերպ, բայց ես կարծում եմ, որ այն, ինչ ես ներկայացրել եմ, ավելի մաքուր է: Եղեք ձեր դատավորը և գրեք ձեր սեփականը, սակայն ձեր MCU- ն դա թույլ կտա: Ասել է թե `եկեք գնանք պարզելու, թե ինչպես կարելի է հայտնաբերել, երբ քարտը քաշում է Էլվիսին և դուրս է գալիս շենքից:

Քայլ 6. Բացահայտեք քարտը, որը թողնում է ընթերցողին

Հայտնաբերել, երբ քարտը անհետացել է

Պաշտոնապես, կարելի էր նմուշառել /CARD_PRESENT քորոցը `տեսնելու, թե արդյոք այն կրկին բարձրացել է, բայց մեզ հարկավոր չէ որևէ այլ մուտքի /ելք վերցնել: Այստեղ են հայտնվում այդ ժամաչափերը: Ամեն անգամ, երբ ընդհատումը կանչվում է, քանի որ մենք հայտնաբերել ենք /STROBE- ի եզրը, մենք կանգնեցնում ենք ժամաչափը, մաքրում ժամաչափի արժեքը և սկսում կարդալ: Երբ մենք ավարտում ենք կարդալը, մենք նորից սկսում ենք ժամաչափը: Կրկնեք սրտխառնոցը, կամ մինչև ժամաչափը հասնի որոշակի արժեքի: Դա նշանակում է, որ վերջին ընդհատումը կանչվել է և այլ տվյալներ չեն մուտքագրվել, ուստի մենք ենթադրում ենք, որ դա այն է և սկսում ենք մշակել մեր հավաքած տվյալները: Timամաչափերի համար մենք օգտագործում ենք TIMER1, այսինքն `16-բիթ ժամաչափ: Ես արտաքինից օգտագործում եմ 16 ՄՀց ռեզոնատոր իմ AVR- ի համար: Եթե դուք օգտագործում եք arduino, ապա, հավանաբար, դուք նույնպես: Այսպիսով, ես ընտրել եմ նախնական սակարկիչի արժեքը `1024, ինչը նշանակում է, որ ժամաչափը կավելանա ամեն (16, 000, 000 /1024) անգամ: Ասել է թե ՝ այն վայրկյանում «կխփի» 15, 625 անգամ: /CARD_PRESENT- ը կբարձրանա Բարձր ՝ նշելով, որ քարտը ընթերցողին թողել է մոտ 150ms վերջին տվյալների բիթից հետո: Սա իմանալով ՝ ես պարզապես որոշեցի ստուգել վայրկյանի յուրաքանչյուր 1/4 -ը: Դա այսպիսի տեսք կունենա.

(((F_CPU) / PRESCALER) / 4) որը, պարզվում է, մոտ 3900 է: Այսպիսով, երբ ժամաչափի հաշվիչը TCNT1- ը հասնում է 3900 -ի, ապա ես գիտեմ, որ այն անցել է մոտ 300ms, և ես կարող եմ բավականին ապահով եզրակացնել, որ քարտը հեռացել է ընթերցողից: Հեշտ

#սահմանել PRESCALER 1024#սահմանել CHECK_TIME ((F_CPU / PRESCALER) / 4) // 250 ms#սահմանել StartTimer () BSET (TCCR1B, CS10), BSET (TCCR1B, CS12) // 1024 prescaler#define StopTimer () BCLR (TCCR1, CS10), BCLR (TCCR1B, CS12)#սահմանել ClearTimer () (TCNT1 = 0) Դուք տեսել եք ISR- ում, որտեղ ժամաչափը գործարկվում է, կանգնում և մաքրվում յուրաքանչյուր ընդհատման ժամանակ: Այժմ, հիմնական հանգույցում մենք պարզապես ստուգում ենք ՝ արդյոք ժամաչափի հաշվիչը հասել է մեր նպատակային արժեքին, և եթե այո, ապա սկսել տվյալների մշակումը

(;;) {if (TCNT1> = CHECK_TIME) {

StopTimer (); ClearTimer (); ProcessData (); ReadData (); idx = 0; բիթ = 6; bDataPresent = 0; memset (& buff, 0, MAX_BUFF_SZ1); }} Այժմ անվտանգ է տվյալների մշակումը

կոդը ՝ ֆորմատավորում ՝

Քայլ 7: Տվյալների մշակում

Մշակել տվյալները

Մշակման փուլը բաղկացած է.

  • վավեր SS- ի ստուգում
  • հավասարության ստուգում
  • վերածվում է ASCII- ի
  • վավեր ES- ի առկայության ստուգում
  • LRC- ի ստուգում

Այստեղ ես չեմ անհանգստանում պարիտետը ստուգելով, քանի որ այդ բիթը պարզապես զրոյի եմ դրել: Ես նաև չեմ հաշվարկում LRC- ն այս փոքրիկ ձեռնարկի համար: Դա կլիներ մի բան, որը գուցե ցանկանար անել ավելի լիովին գիտակցված որոնվածը: Ահա վերը նշված քայլերը կատարող տվյալները (առանց վերը նշվածի): Գտեք այն ստորև ներկայացված պատկերում: Դա մեկնաբանված է և բավականին ինքնաբացատրիչ: Հատուկ նշում պարիտետի և ASCII- ի վերաբերյալ. Ես պարզապես մաքրում եմ պարիտետի բիթը (7 -րդ բիթ… այսինքն ՝ 1 ՝ դրա հետևում 6 զրո) և «քարտային տվյալներից» փոխարկելու համար արժեքին պետք է ավելացնել 0x20: Այդ մասին է խոսքը:

Քայլ 8: Տվյալների ցուցադրում

Displayուցադրել տվյալները

Էկրանը գնում է տերմինալային ծրագրի, որը ես գրել եմ հատուկ RS232 կամ USB- ի միջոցով AVR- ին միանալու համար: Isրագիրը կոչվում է AVR տերմինալ: ReadData () մեթոդը բավականին տգեղ է, և դուք խրախուսվում եք գտնել ավելի մաքուր լուծում, քան այն, ինչ ես գտա: AVR տերմինալում կա նաև գործառույթի ելք: Արդյունքն առաջին հերթին վերաբերում է առողջության ապահովագրության քարտին, իսկ երկրորդը `VISA քարտին: Կտտացրեք նկարի վերին ձախ անկյունում գտնվող - ին և ընտրեք բնօրինակ կամ մեծ պատկերը `այն ավելի լավ տեսնելու համար:

Քայլ 9: Կոդի ներբեռնում և փաթեթավորում

Այս ուսանելի հոդվածում ես քննարկեցի մագնիսական քարտերի ընթերցողների հիմունքները և ձեզ ցույց տվեցի մի քանի կոդ, որպեսզի կարողանաք ճիշտ ուղղությամբ սկսել մագնիսական քարտերից տվյալների կարդալը: Շատ ավելի շատ աշխատանք կարող է կատարվել, օրինակ ՝ 2 -րդ ուղու ընթերցումը և վերծանումը, LRC- ի հաշվարկը և յուրաքանչյուր բայթում կենտ հավասարության հաշվարկը: Ամբողջական աղբյուրի կոդը հասանելի է ներքևում ներբեռնման համար: Այն գրվել է AVR Studio 4.17 -ում: Հուսով եմ, որ ձեզ դուր եկավ այս ուսանելի ծրագիրը, և ինչպես միշտ, ես անհամբերությամբ սպասում եմ ցանկացած մեկնաբանության կամ առաջարկի: Ուրախ կոդավորում և AVR'ing:

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