Wednesday, August 13, 2014

პინების მანიპულაცია

port-control-register-overview.png

ეს არის პირველი ტუტორიალი, რომლის მთავარი მიზანია AVR-ის 8 ბიტიანი მიკროკონტროლერები. ამ ტუტორიალში ვისაუბრებ მიკრო კონტროლერის პორტების ოპერაციებზე და მათ პროგრამულ მანიპულაციაზე.

პირველად იყო რეგისტრი (იხილეთ ლინკი), და სანამ ამ ტუტორიალს ბოლომდე წაიკითხავდეთ, გთხოვთ, რომ გაიგოთ რას წარმოადგენს ეს ელექტრონული ერთეული. მოკლედ, რომ ვთქვათ რეგისტრი არის მეხსიერების ერთეული მთავარ პროცესორთან. ამიტომ შესაძლებელია მისი სწრაფი და საჭიროებისამებრ ხშირად წაკითხვა. ეს რეგისტრები პირადაპირ კავშირშია ცენტრალური პროცესორის მოქმედების ხასიათთან. წარმოვიდგენოთ რეგისტრი, როგორც “ყუთების” მასივი, როგორც ქვემოთ, სურათზეა, ნაჩვენებიRegister-B.jpg
ეს სურათი არის ერთ-ერთი მაგალით, რომელიც აღებულია სურათზე მითითებული საიტიდან. როგორც ხედავთ ამ “ყუთების” დანომვრა იწყება მარჯვნიდან მარცხნივ, შესაბამისად ყველაზე პირველ ბიტს ეწოდება LSB - Least Significant Bit, ხოლო ყველაზე ბოლოს - მარცხენა ბიტს MSB - Most Significant Bit. ამ კონცეპტში რომ უკეთესად გაერკვიოთ შემოვიღოთ რამდენიმე შეთანხმება: 0b პრეფიქსი ნიშნავს, რომ 0b ის შემდეგ მოცემული რიცხვი წარმოადგენს რიცხვს ორობით სისტემაში, ხოლო 0x პრეფიქსის შემდგომ დაწერილი რიცხვი, შესაბამისად, თექვსმეტობითში. პრეფისქსის გარეშე დაწერილი რიცხვები ჩვეულებრივ ათობით სისტემას მიეკუთხვნებიან. მაგალითისთვის ავიღოთ X = 0b0110 0111 რომელიც ათობით სისტემაში გადაყვანისას (ორობითიდან) არის 103. ჩვენ თუ შევცვლით LSB-ს, მივიღებთ Y = 0b0110 0110, რომელიც ათობითში არის 102 და საკმაოდ ახლოს არის A ცვლადის მნიშვნელობასთან. მოდით შევცვალოთ MSB. მივიღებთ  Z = 0b1110 0111, რომლიც 231-ის ტოლია. სწორედ ამიტომ არის რომ LSB ბიტის შეცვლა ნაკლებ მნიშვნელოვანია ვიდრე MSB-სა, რომლის ცვლილება საკმაოდ დიდ სახე სხვაობებს გვაძლევს (Z).

რეგისტრებთან მიმართებაში, ასევე მნიშვნელოვანია ის ფაქტი, რომ თითოეულ მათგანს გააჩნია სახელი, ხოლო მის ყოველ ბიტსაც გააჩნია თავისი ინდივიდუალური დასახელება. მაგალითისთვის ავიღოთ ADCSRA რეგისტრი
ADCSRA.png
რომელიც შედგება 8 ბიტისგან. დააკვირდით, რომ თითოეულ ბიტს გააჩნია საწყისი მნიშვნელობა და, როგორც აღვნიშნე, ინდივიდუალური სახელი. თუ დავწერ შემდეგ ხაზს IDE-ში

ADCSRA = 0b01000111;

ეს იმას ნიშნავს, რომ რეგისტრში შესაბამისად დაიწერება 1 იანები ნულიანების ადგილას, ხოლო სადაც ნულიანები არ შეგვიცვლია უცვლელი დარჩება. ეს ყველაფერი შესაძლებელია ასევე გაკეთდეს მოცემული კოდითაც.

ADCSRA = (1<<ADCS) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
ADCSRA = 0x47;

ასევე მეორე ხაზში მითითებულია თექვსმეტობითში გადაყვანილი მნიშვნელობა, რაც იგივეა რაც 0b01000111. აქვე დავამატებ, რომ თუ თქვენთვის უცნობია “<<” ან “|” “ნიშანი”, რომელიც ოპერატორს წარმოადგენს C/C++-ში, მაშინ იხილეთ ეს ტუტორიალი.

ასე, რომ, ვფიქრობ ზოგადი წარმოდგენა მაინც შეგექმნათ, როგორ არიან რეგისტრები მოწყობილი მიკრო კონტროლერში. შესავალ / გამოსავალის გასაკონტროლებლად ახლა გავარჩევ სამ რეგისტრს

1) DDRx - Data Direction Register
2) PORTx - Pin Output Register
3) PINx - Pin Input Register

DDRx რეგისტრი
მიკრო კონტროლერზე I / O პინები შეიძლება იყოს ან შესავალი ან გამოსავალი, მაგრამ საჭიროა, რომ მათ იცოდნენ ამის შესახებ, სასურველი შედეგის მისაღებად. ასევე აქვე თუ ვნახავთ AtMega328 პინებს შევამჩნევთ, რომ გვაქვს PB, PC და PD გამოსასვლელები, რომლებსაც ცალკე საკუთარი ნომრები აქვთ.

pinmap.jpg
თუ ავიღებთ PB პინებს, ვნახავთ, რომ ის სულ 8 ცალია, ასევე PD-იც. წარმოვიდგინოთ, ახლა რომ ეს ყველაფერი დაკავშირებულია რეგისტრთან, რომლშიც შეგვიძლია რაღაც მნიშვნელობების ჩაწერა, რაც მიკრო კონტროლერს ეტყვის თუ რომელი პინი უნდა იყოს შესავალი და გამოსავალი (სიგნალის). სწორედ ‘x’ (DDRx, PORTx, PINx)  წარმოადგენს ჩვენს შემთხვევაში B ან D რეგისტრს. მაგალითისთვის განვიხილოთ შემდეგი კოდი, რომლის თითოეული ხაზი ერთმანეთის ექვივალენტურია

DDRB = 0b10110001;
DDRB = 0xB1;
DDRB = (1<<0) | (1<<4) | (1<<5) | (1<<7);

ეს იმას ნიშნავს, რომ ყველა პინი, რომლის სახელია PBn, სადაც n იცვლება ნულიდან შვიდამდე, ჩაიწერა 0b10110001 მნიშვნელობა. ახლა გეტყვით ეს ორობითი კოდი რას წარმოადგენს მიკრო კონტროლერისთვის.

ყოველი 1-იანი არის გასასვლელი
ყოველი 0-იანი არის შესავალი

ანუ თუ გადავთარგმნით, PB0, PB4, PB5, PB7 არის გამოსასვლელი პინები, ხოლო დანარჩენი შესავალი, რადგან ნულებია მათი მნიშვნელობა.

იმ პინებს, რომლებიც არიან მარკირებულები როგორც შესასვლელები, აქვთ უნარი წაიკითხონ ძაბვა, მოდებული მათ პინზე და აღიქვან ის როგორც ლოგიკური ერთიანი, თუ მეტია ეს ძაბვა მათ გამხსნელ ძაბვაზე, ან ნულიანი თუ ნაკლებია მოდებული ძაბვა გამხსნელ ძაბვაზე. ზოგადად, გამხსნელი ძაბვა არის VCC/2 ვოლტი, ანუ კვების ძაბვის ნახევარი. მეორე მხრივ კი პინები რომლებიც მარკირებულები არიან როგორც გამოსასვლელები უნარი აქვთ მიიღონ ლოგიკური ერთიანის ან ნულიანის მდგომარეობა, შესაბამისად მათზე ძაბვა გაუტოლდეს VCC (კვების ძაბვა) ან ნულს.

PORTx რეგისტრი
მას შემდეგ რაც განვსაზღვრავთ პინების სტატუსს, საჭიროა მათზე გავანახლოთ ინფორმაცია, ანუ თუ პინი მარკირებულია როგორც გამოსასვლელი, მაშინ საჭიროა გამოსასვლელი არხის მართვა, ანუ პინზე “ჩავწეროთ” ან მაღალი ან დაბალი მნიშნვნელობის ძაბვა, იგივე ლოგიკური 1 ან 0. ამისთვის ვიყენებთ PORTx რეგისტრს. შესაბამისად როდესაც DDRx ით მოვნიშნეთ გამოსასვლელები, იმავე პინებზე შეგვიძლია ლოგიკური მდგომარეობის შეცვლა PORTx რეგისტრით. რაც იმას ნიშნავს, რომ თუ პინების B რეგისტრში პინები, რომელთა ნომრებია 0, 4, 5, 7 (PB0, PB3, PB4, PB7) მათთან შესაძლებელია გამოყენებულ იქნას PORTB რეგისტრის მანიპულაცია, ხოლო დანარჩენ პინების შემთხვევაში ამ რეგისტრის გამოყენება სულ სხვა შედეგს მოგვცემს, რასაც მოგვიანებით განვიხილავ. მაგალითისთვის ავიღოთ შემდეგი კოდის ნაწილი, რომელიც PB0 და PB4 პინს ანიჭებს ლოგიკური 1-იანის მდგომარეობას.

PORTB = 0b00010001;

ახლა ზოგს შეიძლება ეჭვი გაუჩნდეს, რადგან მათი აზრით თუ PB0 და PB4 პინებს მივმართავთ უნდა ყოფილიყო შემდეგი კოდი,

1. PORTB = 0b10001000;
2. PORTB = 0b10010000;

ამ ორი პუნქტიდან არც ერთი არ არის სწორი, რადგან ათვლა იწყება მარჯვნიდან მარცხნივ, ანუ ყველაზე მარჯვენა ბიტი შეესაბამება მენულე პინს, ხოლო ყველაზე მარცხენა მეშვიდეს (1). ამის გარდა ათვლა იწყება ნულიდან და არა ერთიდან, როგორც ვართ ძირითადად მიჩვეულები (2).

რაც ზემოთ განვიხილეთ მოგცემთ პატარა ვიდეო დემოს, რომელიც ნათლად დაგარწმუნებთ ამ ყველაფრის მოქმედებაში და მოგიხსნით ყველანარი შეკითხვის და ეჭვს, რომელიც დაკავშირებულია ამ ყველაფერთან. პირველ რიგში დაგვჭირდება ქვემოთ მოცემული სურათზე კარგად დაკვირვება, რადგან ამ ყველაფრისთვის გამოვიყენებთ არდუინოს და რადგანაც არდუინოზე არის მოთავსებული atmega328P-PU მიკროპროცესორი უნდა ვიცოდეთ პინების რუკა, რადგან არდუინოზე პინების რეალური სახელწოდებები არ არის სწორედ აღნიშნული - სიმარტივისთვის

arduino_pin_mapping.jpg
მე ვაპირებ ვიდეოსთვის გამოვიყენო მეცხრე პინი, რომელიც B რეგისტრის მეორე წევრია. ამისთვის კი გამოვიყენებ შემდეგ კოდს, რომელიც არდუინოს IDE ში არის დაწერილი.

#include <util/delay.h>
#define LED 1

void setup()
{
 DDRB = 0b00000010;
 //DDRB = (1<<LED);
}

void loop()
{
 PORTB = (1<<LED);
 _delay_ms(100);
 PORTB = (0<<LED);
 _delay_ms(100);
}





ეს ვიდეო კი კოდის დემონსტრაციაა, სადაც PB1 ზე შეერთებულია LED და შეერთებულია მიწასთან 100ომიანი რეზისტორით, LED ისა და მიკრო პროცესორის უსაფრთხოდ გამოყენების მიზნით. ახლა კი დრო დადგა წავიკითხოთ თუ როგორ ხდება მიკრო კონტროლერის პინებე ინფორმაციის წაკითხვა. მანამდე კი ვნახოთ ერთი ოპერაცია / ტექნიკა, რომლის დახმარებითაც შეგვიძლია ჩავრთოთ pull-up რეზისტორები, რომლებიც AVR ის მიკროკონტროლერების ჩაშენებული თვისებაა. ეს ტექნიკა მდგომარეობს შემდგომში. დავუშვათ გვაქვს ხაზი, რომელსაც ვკითხულობთ, და გვინდა, რომ ამ ხაზზე უნდა დავიჭიროთ დაბალი სიგნალი, ანუ როდესაც ხაზზე მოდებულია ნული, ხოლო როდესაც სიგნალი არ არის არ იყოს განურჩეველი მდგომარეობა და ხაზზე იყოს რაღაც მუდმივი და სანდო სიგნალი, რომელიც დაბალი ვერ იქნება, ამიტომ უნდა იყოს მაღალი. ამას კი უზრუნველყოფს pull-up რეზისტორები, რომლებიც სტანდარტულად გათიშულია. სქემატური ნახაზი კი ქვემოთ არის მოცემული.

pull-up-resistor.png
აქ ერთადერთი განსხვავება ის არის, რომ R1 რეზისტორი შეიძლება იქნას პროგრამულად ჩართული, სურვილისამებრ და მოთავსებულია მიკრო კონტროლერის შიგნით. pull-up რეზისტორების გასააქტიურებლად ვნახოთ კოდი

 DDRB = 0b00000010; //PB1 არის გამოსასვლელი, დანარჩენი შესასვლელი
PORTB = 0b10000000; //ეს კოდი PB7 ზე ააქტიურებს pull-up რეზისტორს

ამ კოდით შეგვიძლია ვიმსჯელოთ, რომ თუ პინი მონიშნულია, როგორც შესასვლელი და მასში ვწერთ ლოგიკურ ერთიანს, რაც, ერთი შეხედვით დაუშვებელია, რადგან ეს ოპერაცია მხოლოდ მათთვის არის განკუთვნილი, რომელი პინიც გამოსასვლელია. მეორე მხრივ კი, ეს სულ სხვა რაღაცას აკეთებს - რთავს pull-up რეზისტორს. ახლა კი გადავინაცვლოთ მიკრო კონტროლერის პინების წაკითხვაზე და ინფორმაციის დამუშავებაზე.

PINx რეგისტრი
PINx რეგისტრი იღებს ინფორმაციას მიკრო კონტროლერის პინებიდან. დავუშვათ მიკრო კონტროლერის პროგრამულ მეხსიერებაში შესრულდა შემდეგი კოდი

DDRB = 0b11111110; //PB0 მონიშნულია შესასვლელად
PORTB = 0b00000000;

ახლა რადგან PB0 არის მონიშნული როგორც შესასვლელად, ჩვენი სურვილია, რომ წავიკითხოთ PB0 ზე მოსული ინფორმაცია. ამისთვის კი უნდა მივმართოთ რეგისტრს, რომელშიც ინახება და ახლდება ინფორმაცია B პინების რეგისტრის შესახებ. შევამოწმოთ თუ PB0 ზე გვაქვს ლოგიკური 1-იანი და PB1 ზე მიერთებულ LED ავაციმციმოთ.

if (PINB == 0b0000001)
Blink();
void Blink()
{
LED = 0;
PORTB = (1<<LED);
 _delay_ms(100);
 PORTB = (0<<LED);
 _delay_ms(100);
}

აქ ვრჩები პორტზე ოპერაციების მიმოხილვას და იმედია, რომ საინტერესო ტუტორიალი გამოვიდა. მიუხედავად იმისა, რომ ინფორმაცია დამწყებისთვის ბევრია, ეს ყველაფერი არ არის.

No comments:

Post a Comment