Encoder Magnus 21 კავშირის დიაგრამა. ენკოდერის დაკავშირება PIC მიკროკონტროლერთან. მონაცემთა გამომავალი ტიპის მიხედვით, ენკოდერები იყოფა ორ დიდ ჯგუფად

საჩვენებელი პროექტის განსახორციელებლად დაგვჭირდება:

  • 24-პოზიციიანი შიფრატორი;
  • 16 LED (3 მმ);
  • LED დრაივერი A6276;
  • მიკროკონტროლერი PIC18F2550.

ენკოდერი არის ციფრული მოწყობილობების მართვის თანამედროვე და ორიგინალური ელემენტი და გარეგნულად ის ცვლადი რეზისტორების მსგავსია (იხ. სურათი ქვემოთ). ამ კონტროლის კიდევ ერთი სახელია კუთხის სენსორი, ბრუნვის სენსორი. ლილვის ბრუნვას თან ახლავს დაწკაპუნება, მაგალითად 24 დაწკაპუნება რევოლუციაზე. კოდირს აქვს 3 გამომავალი - A, B, C და გამოიყენება ციფრულ მოწყობილობებში მონაცემების სწრაფად შესატანად. ზოგიერთ მოდელს აქვს ჩაშენებული ღილაკი, რომელიც გააქტიურებულია ენკოდერის ლილვის დაჭერით (დამატებულია სხვა გამოსავალი).

შიფრატორის მუშაობის პრინციპი

ერთი დაწკაპუნებით მობრუნებისას, მაგალითად, მარჯვნივ, კონტაქტი A+C ჯერ იკეტება, შემდეგ B+C. ამ დაწკაპუნებით ლილვის მობრუნებისას, კონტაქტები იხსნება იმავე თანმიმდევრობით. ლილვის სხვა მიმართულებით მობრუნებისას იცვლება C კონტაქტით დახურვის თანმიმდევრობა, ე.ი. მარცხნივ მოხვევისას ჯერ B+C, შემდეგ A+C იკეტება.

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

სქემატური დიაგრამა

ენკოდერის პინები A და B დაკავშირებულია მიკროკონტროლერის RB4 და RB5 პორტებთან, ენკოდერის პინი C დაკავშირებულია მიწასთან. აღსანიშნავია, რომ ასაწევი რეზისტორები უნდა იყოს დაკავშირებული A და B ქინძისთავების სიგნალის ხაზებთან. შემთხვევითი არ არის, რომ ენკოდერი დაკავშირებულია მიკროკონტროლერის მითითებულ I/O ხაზებთან: ჯერ ერთი, B პორტს აქვს ჩაშენებული ასაწევი რეზისტორები და არ გვიწევს გარე შეერთება, მეორეც, მიკროკონტროლერის B პორტი. აქვს ძალიან სასარგებლო ფუნქცია - "interrupt-on-change" - შეფერხება დონის შეცვლით, რაც საშუალებას მოგვცემს დავაკვირდეთ კოდირების მდგომარეობას.

16 ჩვეულებრივი 3 მმ LED-ები გამოიყენება შეყვანის მონაცემების ვიზუალიზაციისთვის და ისინი განთავსდება დაბეჭდილი მიკროსქემის დაფაზე დამონტაჟებული ენკოდერის გარშემო. LED-ები დაკავშირებულია A6276 ჩიპთან.

A6276 ჩიპი არის LED დრაივერი 16-ბიტიანი სერიული შეყვანით. დრაივერი შეიცავს 16-ბიტიან CMOS ცვლის რეგისტრს, ასოცირებულ ჩამკეტებს და დრაივერებს LED-ების სამართავად და შეუძლია მართოს მეტი LED-ები, ვიდრე მიკროკონტროლერი იძლევა საშუალებას. გარდა ამისა, დრაივერის კონტროლი შესაძლებელია SPI ინტერფეისის საშუალებით, რაც კიდევ უფრო ამცირებს გამოყენებული I/O ხაზების რაოდენობას და ხდის პროექტს მასშტაბურს.

ჩვენი პრობლემის გადასაჭრელად მიკროკონტროლერის პროგრამა შედარებით მარტივია. არსებობს 3 ოპერაციული რეჟიმი (ინფორმაციის შეყვანა) და გამოხმაურება:

  • 360° პოზიციონირების რეჟიმი - ამ რეჟიმში LED-ები მიუთითებენ ენკოდერის ამჟამინდელ „პოზიციაზე“, მომხმარებელს შეუძლია მარცხნივ და მარჯვნივ მოაბრუნოს ენკოდერის ლილვი ნებისმიერი კუთხით;
  • "მოცულობის/დონის" რეჟიმი - ამ რეჟიმში, LED-ები მიუთითებენ მიმდინარე მნიშვნელობას შეყვანის დიაპაზონის მინიმალურ და მაქსიმალურ დონეებს შორის (როგორც ხმის დონე აუდიო მოწყობილობებში);
  • 3-პოზიციური მბრუნავი გადართვის რეჟიმი - ამ რეჟიმში არის მხოლოდ სამი ასარჩევი პოზიცია, რომელსაც მომხმარებელი ირჩევს ენკოდერის ლილვის მარცხნივ/მარჯვნივ შებრუნებით.

პროექტის დემონსტრირება

ჩამოტვირთვები

განთავსებულია ZIP არქივი პროექტით MPLAB გარემოში და წყარო კოდი Hitech C-ში, ასევე ბეჭდური მიკროსქემის დაფის მიკროსქემის დიაგრამა და ტოპოლოგია.

ენკოდერი უბრალოდ ციფრული ბრუნვის კუთხის სენსორია, მეტი არაფერი.

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

თუ ყველაფერი მარტივია აბსოლუტური კოდირებით, მაშინ დამატებითი კოდირებით არის სირთულეები. როგორ დავამუშავოთ?

ორი სიგნალი A და B გამოდის ენკოდერიდან, ფაზაში 90 გრადუსით გადაადგილებული, ასე გამოიყურება:

ოპტიკურში შეიძლება იყოს ორი ფანარი და ორი ფოტოდიოდი, რომლებიც ანათებენ დისკზე სლოტებით (ბურთიანი მაუსი, დიახ. ეს არის ის).

მექანიკური დაკავშირებულია საკმაოდ მარტივად: ცენტრალური მიწასთან, ორი გარე (არხი) დაჭიმულ პორტებთან. იმისთვის, რომ უსაფრთხოდ ვიყო, დავაკავშირე გარე ამომყვანი. საბედნიეროდ, ყველაფერი რაც მე უნდა გავაკეთო არის რამდენიმე გადამრთველის დაწკაპუნება:


ოპტიკური უკავშირდება ოპტოსენსორის ტიპს, როგორც წესი, არის ორი საერთო ანოდით.

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

მეთოდი მარტივია:
მოდით ჩავანაცვლოთ ნულები და ერთი, სიგნალის დონის შესაბამისად და ჩავწეროთ კოდის თანმიმდევრობა:


A:0 0 1 1 0 0 1 1 0 0 1 1 0
B:1 0 0 1 1 0 0 1 1 0 0 1 1

თუ A და B გადადიან კონტროლერის ერთსა და იმავე პორტში (მაგალითად, A=PB0 B=PB1), მაშინ როდესაც ვატრიალებთ ენკოდერს, ვიღებთ ცვალებად კოდს:

11 = 3
10 = 2
00 = 0
01 = 1
11 = 3

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

გაწურულია კილოჰერცზე ნაკლები. იმათ. საჭიროა მისი გამოკითხვა დაახლოებით 1000 ჯერ წამში. თქვენ შეგიძლიათ გააკეთოთ ეს კიდევ უფრო იშვიათად, ეს უფრო საიმედო იქნება შესაძლო ჭექა-ქუხილის თვალსაზრისით. ახლა, სხვათა შორის, თითქმის არ არის ხრაშუნა, მაგრამ შორს არის ის ფაქტი, რომ არ იქნება მოგვიანებით, როდესაც მოწყობილობა ფხვიერი გახდება.

თავად კვლევა უნდა იყოს სასრული მდგომარეობის მანქანის სახით. იმათ. გვაქვს არსებული მდგომარეობა და ორი შესაძლო შემდეგი.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 // ეს დავალება უნდა შესრულდეს ყოველ მილიწამში. // EncState გლობალური ცვლადი u08 -- წინა კოდირების მდგომარეობა // EncData გლობალური ცვლადი u16 -- Encoder counting register void EncoderScan(void) ( u08 ახალი; ახალი = PINB & 0x03 ; // აიღეთ მიმდინარე მნიშვნელობა // და შეადარე ძველს // იმის მიხედვით, თუ რომელი მიმართულება შეიცვალა, ვამატებთ // ან შეამცირეთ დათვლის რეგისტრიშეცვლა (EncState) ( შემთხვევა 2: (თუ (ახალი == 3) EncData++; თუ (ახალი == 0) EncData--; შესვენება;) შემთხვევა 0: (თუ (ახალი == 2) EncData++; თუ (ახალი == 1 ) EncData-- შესვენება ) შემთხვევა 1 : (თუ (ახალი == 0) EncData++; თუ (ახალი == 3) EncData--; შესვენება; (ახალი == 2 ) EncData-- ) ) EncState = ახალი; // დაწერეთ ახალი მნიშვნელობა // წინა მდგომარეობა SetTimerTask(EncoderScan, 1); // გადატვირთეთ დავალება დისპეჩერის ტაიმერის საშუალებით }

// ეს დავალება უნდა შესრულდეს ყოველ მილიწამში. // EncState გლობალური ცვლადი u08 -- ენკოდერის წინა მდგომარეობა // EncData გლობალური ცვლადი u16 -- ენკოდერის მთვლელი რეგისტრაცია void EncoderScan(void) ( u08 New; New = PINB & 0x03; // აიღეთ მიმდინარე მნიშვნელობა // და შეადარე ძველს // იმის მიხედვით, თუ რომელი მიმართულება შეიცვალა, ვამატებთ // ვამცირებთ დათვლის რეგისტრის გადამრთველს(EncState) ( შემთხვევა 2: ( if(New == 3) EncData++; if(New == 0) EncData--; break; ) შემთხვევა 0: ( if(ახალი == 2) EncData++; if(ახალი == 1) EncData--; შესვენება; ) შემთხვევა 1: (if(ახალი == 0) EncData++; if(ახალი == 3) EncData- -; შესვენება 3: (if(New == 1) EncData++; if(New == 2) EncData--; break; (EncoderScan,1 / / გადატვირთეთ დავალება დისპეჩერის ტაიმერის საშუალებით)

რატომ დავამატე ასეთი დიდი ცვლადი მრიცხველის ქვეშ? ორი მთელი ბაიტი? დიახ, მთელი საქმე იმაშია, რომ ჩემს ენკოდერს, იმპულსების გარდა, ტაქტილური დაწკაპუნებაც აქვს. 24 პულსი და 24 დაწკაპუნება რევოლუციაზე. და ჩემი ლოგიკით, თითო იმპულსზე ოთხი მდგომარეობის ცვლილებაა, ე.ი. სრული პერიოდი არის 3201_3201_3201 და ერთი დაწკაპუნება იძლევა 4 დაყოფას, რაც მახინჯია. ასე რომ, ვითვლი 1024-მდე და შემდეგ ვყოფ ოთხზე გადანაცვლებით. გამომავალი არის ერთი დაწკაპუნებით - ერთი მონიშვნა.

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

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

ასე რომ თქვენ შეგიძლიათ გამოიყენოთ შეფერხებები უპრობლემოდ. შემდეგ კი ყველაფერი წარმოუდგენლად მარტივი ხდება. ჩვენ ვაკონფიგურირებთ მხოლოდ ერთ შეწყვეტას გარე სიგნალისთვის. მაგალითად, ჩვენ ვაკონფიგურირებთ INT0-ს ისე, რომ ტრიგერი აღმოჩნდეს ამომავალ კიდეზე. და ჩვენ ვაწვდით A არხს INT0-ს.


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

და INT0 შეფერხების დამმუშავებელში ჩვენ ვამოწმებთ B არხს მეორე პინით და შემდეგ ყველაფერი ელემენტარულია!

თუ არის მაღალი დონე, ვამატებთ +1-ს, თუ დაბალია, -1-ს ვამატებთ ჩვენს დამთვლელ რეესტრს. ეს სამი სტრიქონიანი კოდია, ძალიან მეზარება მისი დაწერა.

რა თქმა უნდა, ამ მეთოდის მიმაგრება შეგიძლიათ მექანიკურ ენკოდერზეც. მაგრამ აქ დაგჭირდებათ INT0 შეფერხებების გამორთვა რამდენიმე მილიწამით. და არავითარ შემთხვევაში არ უნდა გააკეთოთ ეს დამმუშავებელში.

ანტი-debounce შეფერხების ალგორითმი ასე გამოიყურება:

  • შეიყვანეთ INT0 დამმუშავებელი
  • ჩვენ ვიგრძენით მეორე არხი
  • +1 ან -1
  • აკრძალულია ადგილობრივად INT0
  • ჩვენ დავაყენეთ მოვლენა ტაიმერზე, რომელიც საშუალებას აძლევს INT0-ს რამდენიმე მილიწამში
  • გავიდა დამჭერიდან

რთული? არა, არ არის რთული. Მაგრამ რატომ? მარტივი გამოკითხვის გაკეთება, როგორც ზემოთ აღინიშნა, უფრო ადვილია და არ იყოს დამოკიდებული შეწყვეტის ქინძისთავებზე. თუმცა, მფლობელი ჯენტლმენია.

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

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

უპირველეს ყოვლისა, არსებობს რამდენიმე ტიპის შიფრატორი, რომელიც განხილულია ამ სტატიაში, არის მექანიკური ინკრემენტული. Pec12-4220f-s0024 გამოიყენებოდა როგორც ტესტის სუბიექტი. გარეგნულად ის ცვლადი რეზისტორს ჰგავს, მაგრამ რეზისტორისგან განსხვავებით არ აქვს შემზღუდველი, ე.ი. შეუძლია დაუსრულებლად ტრიალი ნებისმიერი მიმართულებით.

ასეთი მოწყობილობის შედეგი არის ბინარული გრეის კოდი. მისი მიღება შესაძლებელია ფეხების მდგომარეობის ანალიზით, რომლებზეც მოდის პულსი ენკოდერიდან.

ახლა მოდით შევხედოთ ყველაფერს უფრო დეტალურად. ელექტრულად შედგება 2 ღილაკისაგან ჩაკეტვის გარეშე, როცა მოხვევას ვიწყებთ მორიგეობით მუშაობენ - ჯერ ერთი, მერე მეორე. იმის მიხედვით, თუ რომელი მიმართულებით ვატრიალებთ, ერთ-ერთი ღილაკი ადრე თუ გვიან ირთვება. იმისათვის, რომ გაიგოთ, რა მდგომარეობაშია ეს ღილაკები, პორტის ფეხები (რომელზეც არის დაკავშირებული ენკოდერი) უნდა გაიყვანოთ "+" კვების წყარომდე.

დაშლილ ენკოდერზე ფართობის 1/3 ეკუთვნის პირველ კონტაქტს, 1/3 მე-2 კონტაქტს, მყარი ფართობი საერთოა. როდესაც მოცურების კონტაქტები მოხვდება იზოლირებულ ადგილებში (შავი), ისმის დაწკაპუნების ხმა. ამ მომენტში, ენკოდერი სტაბილურ მდგომარეობაშია, როდესაც ორივე ღილაკი ღიაა. პორტის ფეხებზე იქნება ჟურნალის ერთეულები (მდგომარეობა 11).

როგორც კი რაიმე მიმართულებით ვიწყებთ ბრუნვას, ერთ-ერთი კონტაქტი მიწასთან იკეტება. ჟურნალი 0 გამოჩნდება ამ ფეხზე, ჟურნალი 1 კვლავ გამოჩნდება მეორე ფეხიზე (მდგომარეობა 01). თუ გავაგრძელებთ ბრუნვას, log0 (მდგომარეობა 00) გამოჩნდება მეორე ფეხიზე. შემდეგი, კონტაქტი პირველ ფეხზე ქრება (მდგომარეობა 10) და საბოლოოდ ენკოდერი უბრუნდება სტაბილურ მდგომარეობას (11). იმათ. თითო დაწკაპუნებით ხდება 4 მდგომარეობის ცვლილება. დროის დიაგრამა ასე გამოიყურება:

საპირისპირო მიმართულებით მობრუნებისას იდეა იგივე რჩება, ჯერ მხოლოდ მეორე ფეხი დაიხურება.

თუ ამ მდგომარეობებს ორობით სისტემაში ჩავწერთ და გადავიყვანთ ათწილადად, მივიღებთ შემდეგ თანმიმდევრობას (ერთი მიმართულებით ბრუნვისთვის):
11=3
01=1
00=0
10=2

საპირისპირო მიმართულებით ბრუნვისას:
11=3
10=2
00=0
01=1

ახლა რჩება იმის გაგება, თუ როგორ უნდა დამუშავდეს ეს მნიშვნელობები. ვთქვათ, ენკოდერი დაკავშირებულია B0 და B1 პორტის პინებთან. ჩვენ უნდა წავიკითხოთ ეს ფეხები. არსებობს საკმაოდ ჭკვიანი გზა, მაგრამ ჯერ უნდა გავიგოთ ლოგიკური და (&) ოპერაცია.

შედეგი ერთის ტოლი იქნება მხოლოდ იმ შემთხვევაში, თუ ორივე რიცხვი 1-ის ტოლია, ე.ი. 1&1 ოპერაციის შედეგი იქნება 1-ის ტოლი. ამიტომ 1&0=0, 0&0=0, 0&1=0.

ლოგიკური და დაგვეხმარება მთელი პორტიდან მხოლოდ ის ფეხების იზოლირებაში, რომლებიც გვაინტერესებს. იმათ. ოპერაცია x=0b00000011 & PINB; საშუალებას მოგვცემს „x“ ცვლადში წავიკითხოთ პირველი ორი ფეხის მდგომარეობა, მიუხედავად იმისა, თუ რა არის დარჩენილ ფეხებზე. რიცხვი 0b00000011 შეიძლება გარდაიქმნას თექვსმეტობით 0x3-ად.

ახლა ჩვენ გვაქვს ყველა საჭირო ცოდნა firmware-ის დასაწერად. დავალება: გაზარდეთ/შეამცირეთ Vol ცვლადი ენკოდერის გამოყენებით, აჩვენეთ შედეგი LCD ეკრანზე.

#შეიცავს int NewState, OldState, Vol, upState, downState; #asm .equ __lcd_port= 0x12 ; PORTD #endasm #include #შეიცავს შეწყვეტა [TIM1_COMPA] void timer1_compa_isr(void) ( NewState= PINB & 0b00000011 ; if (NewState!= OldState) ( გადართვა (OldState) ( შემთხვევა 2 : ( if (NewState == 3 ) ზევით (NewState == 3 ) ზევით (NewState ==N+Tew) წყვეტი შესვენება 3: (თუ (NewState == 1) upState++; if (NewState == 2) downState++; break; // შეყვანის/გამოსვლის პორტების ინიციალიზაცია// პორტი B ინიციალიზაცია // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // სახელმწიფო7=T მდგომარეობა6=T მდგომარეობა5=T მდგომარეობა4=T მდგომარეობა3=T მდგომარეობა2=T მდგომარეობა1=P მდგომარეობა0=P PORTB= 0x03 ; DDRB= 0x00 ; // Timer/Counter 1 ინიციალიზაცია// საათის წყარო: სისტემის საათი // საათის მნიშვნელობა: 1000,000 kHz // რეჟიმი: CTC top=OCR1A // OC1A გამომავალი: Discon. // OC1B გამომავალი: Discon. // ხმაურის დამცავი: გამორთულია // Input Capture on Falling Edge // ტაიმერი 1 Overflow შეწყვეტა: გამორთულია // Input Capture Interrupt: გამორთულია // შეადარეთ მატჩის შეწყვეტა: ჩართული // შედარება B მატჩის შეწყვეტა: გამორთულია TCCR1A= 0x00 ; TCCR1B= 0x0A; TCNT1H= 0x00 ; TCNT1L= 0x00 ; ICR1H= 0x00 ; ICR1L= 0x00 ; OCR1AH= 0x03; OCR1AL= 0xE8 ; OCR1BH= 0x00 ; OCR1BL= 0x00 ; // ტაიმერი(ები)/მრიცხველ(ებ)ი შეწყვეტის(ებ)ის ინიციალიზაცია TIMSK= 0x10 ; // Global enable interrupts #asm("sei") lcd_init(8) ; while (1) ( if (upState >= 4) ( Vol++; upState = 0 ; ) if (downState >= 4 ) ( Vol--; downState = 0 ; ) sprintf (lcd_buf, "vol=%d" , Vol) lcd_gotoxy(0, 0); )

#შეიცავს int NewState,OldState,Vol,upState,downState; #asm .equ __lcd_port=0x12 ;PORTD #endasm #include #შეიცავს შეწყვეტა void timer1_compa_isr(void) ( NewState=PINB & 0b00000011; if(NewState!=OldState) ( switch(OldState) ( case 2: ( if(NewState == 3) upState++; if(NewState!=OldState = ) შემთხვევა 0: ( if(NewState == 2) upState++; if(NewState == 1) downState++; break; ) case 1: ( if(NewState == 0) upState++; if(NewState == 3) downState++; break; ) შემთხვევა 3: (if(NewState == 1) upState++; if(NewState == 2) downState++; break; ) OldState=NewState TCNT1L=0x00; შეყვანის/გამოსვლის პორტების ინიციალიზაცია // B პორტის ინიციალიზაცია // Func7=Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4 =T State3=T State2=T State1=P State0=P PORTB=0x03 // Timer/Counter 1 ინიციალიზაცია // საათის წყარო: სისტემის საათი // საათის მნიშვნელობა: 1000,000 kHz // რეჟიმი: CTC top=OCR1A // OC1A; გამომავალი: Discon // OC1B გამომავალი: Discon // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // შედარება Match Interrupt: ჩართული // შედარება. B მატჩის შეწყვეტა: გამორთულია TCCR1A=0x00; TCCR1B=0x0A; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x03; OCR1AL=0xE8; OCR1BH=0x00; OCR1BL=0x00; // ტაიმერი(ები)/მრიცხველ(ებ)ი შეფერხ(ებ)ის ინიციალიზაცია TIMSK=0x10; // Global enable interrupts #asm("sei") lcd_init(8); while (1) ( if (upState >= 4) ( Vol++; upState = 0; ) if (downState >= 4) ( Vol--; downState = 0; ) sprintf(lcd_buf,"vol=%d",Vol) lcd_gotoxy(0,0); )

დაზუსტების მიზნით: ტაიმერი 1 კონფიგურირებულია 1000-ჯერ წამში გასროლისთვის, ხაზით NewState=PINB & 0b00000011; ჩვენ ვკითხულობთ B პორტის 0 და 1 ქინძისთავების მდგომარეობას. if(NewState!=OldState) თუ მდგომარეობა არ შეცვლილა, მაშინ არ არის როტაცია.
თუ მდგომარეობა შეიცვალა, გადამრთველის კონსტრუქცია განსაზღვრავს თუ რა მიმართულებით შესრულდა ბრუნვა, ამის მიხედვით იზრდება downState (მარცხნივ) ან upState (მარჯვნივ) ცვლადის მნიშვნელობა.

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

ენკოდერი არის ნივთი, რომელიც ჰგავს ცვლადი რეზისტორის, მაგრამ, ამ უკანასკნელისგან განსხვავებით, მას არ აქვს შეზღუდვები და შეუძლია ნებისმიერი მიმართულებით უსასრულოდ ბრუნვა. შიფრატორის გამოყენებით, ძალიან მოსახერხებელია ყველა სახის ეკრანზე მენიუს ორგანიზება, ერთი „დაჭერილი“ ენკოდერი (ანუ თუ მას შეუძლია მუშაობა ღილაკის სახით) იდეალურია ერთგანზომილებიანი ციკლური მენიუს ორგანიზებისთვის.

არსებობს ორი სახის ენკოდერი: აბსოლუტური - დაუყოვნებლივ გამოსცემს ბრუნვის კუთხის კოდს და ინკრემენტული - გამოსცემს პულსებს ბრუნვის დროს. ამ უკანასკნელისთვის მიკროკონტროლერი პასუხისმგებელი უნდა იყოს იმპულსების დათვლასა და ბრუნვის კუთხეებად გადაქცევაზე.

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

მიუხედავად იმისა, რომ ქსელში უამრავი ინფორმაციაა პროგრამირების ენკოდერების შესახებ, ისევე როგორც ამისათვის მზა ბიბლიოთეკები, ისინი ყველა გარკვეულწილად ზედმეტად რთულია (IMHO) - მდგომარეობის გამოკითხვა ჩვეულებრივ ხორციელდება როგორც სასრული მდგომარეობის მანქანა, გადამრთველის სახით. ბლოკი ჩასმული if-ებით, რაც გარკვეულწილად რთული გამოიყურება (განსაკუთრებით მაშინ, როცა ასამბლერშია დაწერილი). მიუხედავად იმისა, რომ განხორციელება შეიძლება უფრო მარტივი იყოს.

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


აქ A და B არის კონტაქტები, რომლებზეც მიკროკონტროლერი დაამუშავებს დონეებს. მოძრავი კონტაქტი ხურავს მათ მიწასთან, თუ ისინი არ მოხვდებიან მის ხვრელებში. გაითვალისწინეთ, რომ ფიგურაში ნაჩვენებია მხოლოდ ოთხი ხვრელი სიმარტივისთვის. სინამდვილეში, ასეთი ხვრელები კიდევ ბევრია (კიდევ ერთხელ, გაიხსენეთ ბურთის მაუსი და როგორ გამოიყურება მისი ოპტიკური საჭე). ტერმინალები A და B იწევს რეზისტორებით მიწოდების ძაბვამდე. შედეგად, როდესაც ბრუნავს, მიიღება ზემოთ მოცემულ ფიგურაში ნაჩვენები დიაგრამები.

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

ამრიგად, გამოდის, რომ კოდირების მიმდინარე მდგომარეობა აღწერილია ორბიტიანი მნიშვნელობით. მაგრამ ამჟამინდელი მდგომარეობა თავისთავად ატარებს მცირე სასარგებლო ინფორმაციას და ბრუნვის გასაანალიზებლად ის უნდა განიხილებოდეს წინა მდგომარეობის მნიშვნელობასთან ერთად. და ეს წყვილი უკვე ნათლად განსაზღვრავს სახელურის ბრუნვის მიმართულებას. მოხერხებულობისთვის ავიღოთ ოთხბიტიანი რიცხვი, რომლის ორი ყველაზე მნიშვნელოვანი ბაიტი შეიცავს A და B კონტაქტების წინა მდგომარეობას, ხოლო ორი ყველაზე დაბალი ბაიტი შეიცავს მიმდინარეებს.

ხოლო საათის ისრის საწინააღმდეგოდ ბრუნვისას

ორობითი ათწილადი
1110 14
0001 1
0010 2
0111 7

ახლა ენკოდერის ბრუნვის მიმართულების განსაზღვრის ალგორითმი ძალიან მარტივია: ჩვენ ვიღებთ მნიშვნელობას და ვადარებთ ჯდება თუ არა ის ერთ-ერთ ნაკრებში (2, 4, 11, 13) და (1, 7, 8, 14). თუ კი, მაშინ გვაქვს შემობრუნება შესაბამისი მიმართულებით. წინააღმდეგ შემთხვევაში, ლილვი ან საერთოდ არ ბრუნავდა, ან ისე სწრაფად ტრიალებდა, რომ გამოტოვებდა რამდენიმე მდგომარეობას (თუ ეს ხშირად ხდება, მაშინ უნდა იფიქროთ შტატის კენჭისყრის სიხშირის გაზრდაზე), ან მოხდა კონტაქტების „ამობრუნება“. მიზეზში ჩაღრმავების გარეშე, ყველა სხვა მნიშვნელობის უსაფრთხოდ იგნორირება შეიძლება.

მაგალითად, განვიხილოთ ენკოდერის მოქმედება AVR მიკროკონტროლერთან ერთად:


აქ დასაკავშირებლად გამოიყენება ATMega8 მიკროკონტროლერის PB პორტის ორი დაბალი რიგის პინი. წყვილი რეზისტორები ამ ხაზებს მიჰყავს მიწოდების ძაბვამდე (რადგან Atmega-ს შიდა რეზისტორები აქ შეიძლება არ იყოს საკმარისი სტაბილური მუშაობისთვის), დამონტაჟებულია წყვილი კონდენსატორები იმპულსური ხმაურის ჩასახშობად.

ასეთი კავშირის სქემისთვის შეგიძლიათ დახაზოთ შემდეგი განხორციელება C-ში:

სტატიკური uint8_t encoderGetVal() ( დაბრუნება PINB & 3; ) სტატიკური uint8_t encoderGetCode() ( სტატიკური uint8_t წინა; uint8_t val = encoderGetVal(); uint8_t კოდი = (წინა<< 2) | val; prev = val; return code; } static void encoderInit() { DDRB &= ~0b11; PORTB |= 0b11; encoderGetCode(); } void onEncoderEvent(bool direction); void encoderCheck() { uint8_t code = encoderGetCode(); if (code == 1 || code == 7 || code == 8 || code == 14) { onEncoderEvent(true); } else if (code == 2 || code == 4 || code == 11 || code == 13) { onEncoderEvent(false); } }

კოდი წარმოუდგენლად მარტივია - რამდენიმე თუ და არანაირი სასრული მდგომარეობის მანქანა. encoderInit() ფუნქცია გამოიძახება დასაწყისში პორტის ინიციალიზაციისა და საწყისი მნიშვნელობის დასამახსოვრებლად. EncoderCheck() ფუნქცია გამოიძახება მოვლენის ციკლში (main()-ში ან ტაიმერით). onEncoderEvent(bool) დამმუშავებელი გამოიძახება, როდესაც ენკოდერი ბრუნავს და მიიღებს ბრუნვის მიმართულების დროშას.

მაგრამ არის ერთი მნიშვნელოვანი მომენტი: ენკოდერი სენსიტიური ნივთია და თუ ცდილობთ, მაგალითად, მენიუს ნავიგაციის მოვლენების ამ გზით დამუშავებას, მაშინ ენკოდერის ღილაკის მცირე შებრუნებაც კი არაერთხელ გამოიძახებს onEncoderEvent() დამმუშავებელს, როგორც. რის შედეგადაც მენიუს კურსორი შემდეგ /წინა ელემენტზე გადასვლის ნაცვლად დაუყოვნებლივ გაფრინდება სიის ბოლოს/საწყისში. თქვენ შეგიძლიათ დაარეგულიროთ ენკოდერის მგრძნობელობა encoderCheck() ზარის სიხშირის შეცვლით (ჩვეულებრივ, ოპტიმალური სიხშირეა ~ 10 ჰც). ამ შემთხვევაში, encoderGetCode() მეთოდი უნდა გამოიძახოთ რაც შეიძლება ხშირად, რათა ყოველთვის ჰქონდეს კონტაქტების ბოლო მდგომარეობის მიმდინარე მნიშვნელობა (სიხშირით სადღაც 100 ჰც-მდე).

ასამბლერში ეს კოდი შეიძლება ასე გამოიყურებოდეს:

EQU encoder_port PORTB .EQU encoder_pin PINB .EQU encoder_ddr DDRB .DSEG .ORG SRAM_START sEncoderPrev: .BYTE 1 ... .CSEG .ORG $0000 ... Encoder_init: cbi encoder,1 encoderrd_ 0 s bi encoder_port, 1 r0-ში, encoder_pin andi r0, 3 sts sEncoderPrev, r0 ... Encoder_check lds ZL, sEncoderPrev lsl ZL lsl ZL r0-ში, encoder_pin andi r0, 3 sts sEncoderPrev, r0 ან ZL, r0; 1 7 8 14 -> საათის ისრის მიმართულებით cpi ZL, 1 breq Encoder_clockwise cpi ZL, 7 breq Encoder_clockwise cpi ZL, 8 breq Encoder_საათის ისრის მიმართულებით cpi ZL, 14 breq Encoder_საათის ისრის მიმართულებით ; 2 4 11 13 -> საათის ისრის საწინააღმდეგოდ cpi ZL, 2 breq Encoder_counterclockwise cpi ZL, 4 breq Encoder_counterwhise cpi ZL, 11 breq Encoder_counterwise cpi ZL, 13 breq Encoder_countercodercodercodercone rj. ; აქ არის საათის ისრის ბრუნვის დამმუშავებლის კოდი; Encoder_საწინააღმდეგო ისრის მიმართულებით: ; ; აქ არის საათის ისრის საწინააღმდეგო როტაციის დამმუშავებლის კოდი; Interval_enc_done.

ოპერაციული პრინციპი, კავშირის დიაგრამა და ბიბლიოთეკის წყარო კოდი ინკრემენტულ ენკოდერთან მუშაობისთვის უკვე განვიხილეთ ერთ-ერთ სტატიაში. დღეს ჩვენ ვისაუბრებთ ენკოდერის პრაქტიკულ გამოყენებაზე. მაგალითად, მე ავირჩიე კვადრატული ტალღის გენერატორის პროგრამა 1 - 100 ჰც ოპერაციული სიხშირის დიაპაზონით. თავდაპირველი გეგმა ითვალისწინებდა დიაპაზონს 1 - 1000 ჰც, მაგრამ პრაქტიკაში აღმოჩნდა, რომ ათასი მნიშვნელობის გავლა დამღლელი იყო კოდირებითაც კი.

მომზადება

შექმენით ახალი პროექტი ცარიელ სამუშაო სივრცეში

პროექტი > ახალი პროექტის შექმნა…

შაბლონი ტიპი C > მთავარი

დააკოპირეთ ბიბლიოთეკის წყაროს ფაილები ენკოდერთან მუშაობისთვის პროექტის საქაღალდეში
encoder.h და encoder.c

ჩვენ ვუკავშირდებით encoder.c ფაილს ჩვენს პროექტს
მაუსის მარჯვენა ღილაკი სამუშაო სივრცის ფანჯარაში და მენიუში, რომელიც იხსნება დამატება > ფაილების დამატება...

დააკოპირეთ ფაილი bits_macros.h პროექტის საქაღალდეში.


სათაურის ფაილების ჩათვლით

main.c ფაილის დასაწყისში ვწერთ შემდეგ სტრიქონებს
#შეიცავს
#შეიცავს
#include "encoder.h"
#include "bits_macros.h"

პროექტის პარამეტრების დაყენება

პროექტი > ოფციები

მიკროკონტროლის ტიპი
ზოგადი პარამეტრები > სამიზნე > პროცესორის კონფიგურაცია > ATMega8535

სათაურის ფაილებში განსაზღვრული ბიტების სახელების გამოყენების დაშვება
ზოგადი ოფციები > სისტემა > ბიტის დაცვის ჩართვა...

კოდის ოპტიმიზაცია ზომისთვის
C/C++ შემდგენელი > ოპტიმიზაცია > ზომა მაღალი

გამომავალი ფაილის ტიპი
Linker > Output File შეამოწმეთ ნაგულისხმევი გადახურვა და შეცვალეთ გაფართოება ექვსკუთხედზე
Linker > Format > სხვა აირჩიეთ Intel Standard

დააწკაპუნეთ OK. შეინახეთ პროექტი და სამუშაო ადგილი.
ახლა ჩვენ გვაქვს ცარიელი პროექტი დაკავშირებული ბიბლიოთეკით და მითითებული პარამეტრებით.

დავალება

გააკეთეთ მიკროკონტროლერმა შექმნას კვადრატული ტალღა 1-დან 100 ჰც-მდე სიხშირით. სიხშირის მნიშვნელობა უნდა დაყენდეს კოდირების გამოყენებით. შიფრატორის ერთი პოზიციით შემობრუნება უნდა შეესაბამებოდეს გენერატორის სიხშირის ცვლილებას 1 ჰც-ით.

დიაგრამა ჩვენი მაგალითისთვის

LED უკავშირდება პინს, რომელზედაც წარმოიქმნება მეანდრი, რათა როგორმე მაინც ნახოთ პროგრამის შედეგი. ნაკლებად სავარაუდოა, რომ ბევრ ადამიანს ხელთ ჰქონდეს ოსცილოსკოპი.

პროგრამის ალგორითმი

კვადრატული ტალღის სიგნალი წარმოიქმნება 16-ბიტიანი ტაიმერის T1 გამოყენებით, რომელიც მუშაობს CTC რეჟიმში - გადატვირთეთ, როდესაც ემთხვევა. მიკროკონტროლერის ფლეშ მეხსიერება ინახავს მასივს, რომელიც შეიცავს მუდმივას საჭირო სიხშირის თითოეული მნიშვნელობისთვის. pTimerValue ცვლადი გამოიყენება მასივის ელემენტებზე წვდომისთვის. ტაიმერის T1 შეფერხებებში მუდმივის მნიშვნელობა იკითხება და იწერება შედარების რეგისტრში.

სიგნალის გენერირებისთვის გამოიყენება პინი PD5 (OC1A). მას აქვს ალტერნატიული ფუნქციები - მას შეუძლია შეცვალოს თავისი მდგომარეობა საპირისპიროდ, თუ მთვლელი და შედარების რეგისტრი ტოლია.

მთავარ პროგრამაში, უსასრულო while მარყუჟში, მიკროკონტროლერი გამოკითხავს ენკოდერის ბუფერს და, მისი მნიშვნელობიდან გამომდინარე, ამცირებს ან ზრდის pTimerValue ცვლადს.

მთავარის დასაწყისში არის კოდი პერიფერიული მოწყობილობებისა და აუცილებელი ცვლადების ინიციალიზაციისთვის.

პროგრამის სტრუქტურა

სიცხადისთვის მე გამოვხატე პროგრამის სტრუქტურა დიაგრამის სახით.

ეს არის ტიპიური სტრუქტურა მარტივი პროგრამების შესაქმნელად. შეფერხებები ბუნებრივად ხდება მარყუჟის შემთხვევით წერტილებში.

  • ინიციალიზაცია.
  • უსასრულო მარყუჟი (ე.წ. superloop), რომელშიც ელოდება მოვლენას, ჩვეულებრივ, კენჭისყრის დროშების ან რაიმე სახის ბუფერის სახით.
  • პერიფერიული მოწყობილობების პარალელური მუშაობა, რომელიც იწვევს შეფერხებებს. ისინი აწარმოებენ ზოგიერთ კოდს (სასურველია მოკლე) და აყენებენ დროშებს.

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

მუდმივების გაანგარიშება ტაიმერი T1

გამოვთვალოთ მუდმივის მნიშვნელობა 1 ჰც სიხშირისთვის. მსგავსი გამოთვლა უკვე მივეცი, მაგრამ მისი დამახსოვრება სასარგებლო იქნება

მიკროკონტროლერის საათის სიხშირეა 16 MHz (იხ. დიაგრამა). ტაიმერის პრესკალერის ფაქტორი არის 256. ის საშუალებას გაძლევთ მიიღოთ შეფერხებები ნებისმიერი სიხშირით ჩვენი დიაპაზონიდან.

ერთი ტაიმერის ტიკის პერიოდი ტოლი იქნება 1/(16 MHz/ 256) = 16 μs

პინ PD5-ზე უნდა მივიღოთ სიგნალი 1 ჰც სიხშირით. პინი ცვლის თავის მდგომარეობას ტაიმერის ყოველი შეფერხებისთვის, რაც ნიშნავს, რომ შეფერხების სიხშირე უნდა იყოს 2-ჯერ მეტი. ჩვენი შემთხვევისთვის - 2 ჰც.

რამდენი ტაიმერი ჯდება 2 ჰერცში? (1/2 Hz)/16 μs = 31250
ეს არის სასურველი მუდმივი.

დარჩენილი მნიშვნელობები გამოითვლება იმავე გზით. ამისთვის ჩვეულებრივ Excel-ს ვიყენებ.


მიღებულ მნიშვნელობებს ვათავსებთ მასივში

__ ფლეში ხელმოუწერელი ინტ timerValue =
{

შეინახეთ ცალკე ფაილში – timer_value.h და დააკავშირეთ main.c ფაილთან

#include "timer_value.h"

დიახ, თქვენ კვლავ უნდა დაამატოთ რამდენიმე მუდმივი ამ ფაილს

#define MAX_TIM_VALUE 99
#define MIN_TIM_VALUE 0

მოდით დავრწმუნდეთ, რომ სწორად გამოვთვალეთ ტაიმერის მუდმივები. მოდით გავუშვათ იგი. პროგრამის კოდი იქნება ასეთი.

//AVR პროგრამირება C-ში

//ვებგვერდი 10.17.09
#შეიცავს
#შეიცავს
#include "encoder.h"
#include "bits_macros.h"
#include "timer_value.h"

//ინდექსი მასივის ელემენტებზე წვდომისთვის
არასტაბილური ხელმოუწერელი char pTimerValue = 0;

ინტმთავარი ( ბათილად )
{
//ტაიმერის ინიციალიზაცია T1
TCNT1 = 0;
TCCR1A = (0<TCCR1B = (0<

//დააყენეთ PD5 პინი გამოსავალზე
SetBit (PORTD, PD5);
SetBit (DDRD, PD5);

//არაფრის გაკეთება გაუთავებელ ციკლში
ხოლო(1);
დაბრუნების 0;
}

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

მრიცხველის რეესტრის გადატვირთვა
TCNT1 = 0;

T1 ტაიმერის კონფიგურაციის რეგისტრების ინიციალიზაცია.
TCCR1A = (0<TCCR1B = (0<

სადაც ბიტები WGM13, WGM12, WGM11, WGM10 ადგენენ ტაიმერის მუშაობის რეჟიმს - CTC,
CS12, CS11, CS10 – განსაზღვრეთ ტაიმერის პრესკალერის კოეფიციენტი –256,

COM1A1, COM1A0 - განსაზღვრეთ PD5(OC1F) პინის ქცევა - ამ შემთხვევაში, ტაიმერის სიგნალზე დაყრდნობით, ის შეცვლის თავის მდგომარეობას საპირისპიროდ.


დააწყვეთ შესატყვისი რეგისტრი საწყის მნიშვნელობამდე.
OCR1A = timerValue;

ჩვენ ვადგენთ პროგრამას და ვტვირთავთ მიკროკონტროლერში. LED უნდა ციმციმდეს 1 ჰც სიხშირით.
პროგრამაში შეფერხებები არ არის. PD5 პინის მანიპულირება არ ხდება. თუმცა, LED ციმციმებს!

პროგრამა

ახლა თქვენ უნდა "დააბრუნოთ" ენკოდერი ამ პროგრამაზე. მოდით დავაყენოთ პარამეტრები სათაურის ფაილში encoder.h - პორტი და ქინძისთავები, რომლებთანაც დაკავშირებულია ენკოდერი, მუდმივების მნიშვნელობები.


#define PORT_Enc PORTA
#define PIN_Enc PINA
#define DDR_Enc DDRA
#define Pin1_Enc 2
#define Pin2_Enc 1

#define RIGHT_SPIN 0x01
#define LEFT_SPIN 0xff

სათაური შეიცავს სამი ფუნქციის პროტოტიპებს. გავიხსენოთ მათი მიზანი.

void ENC_InitEncoder(void)აკონფიგურირებს მიკროკონტროლერის ქინძისთავებს, რომლებზეც ენკოდერი დაკავშირებულია შესასვლელთან. ეს ფუნქცია უნდა გამოიძახოთ main-ის დასაწყისში.


void ENC_PollEncoder(void)– გამოკითხავს კოდირს ერთხელ, აანალიზებს მიმდინარე და წინა მდგომარეობას და წერს შესაბამის მუდმივებს (RIGHT_SPIN და LEFT_SPIN) ბუფერში. ეს ფუნქცია დაჯდება T0 ტაიმერის შეფერხებაში.


ხელმოუწერელი სიმბოლო ENC_GetStateEncoder(void)– აბრუნებს კოდირების ბუფერის შიგთავსს. თუ როტაცია ერთი პოზიციით არ იყო დაფიქსირებული, ფუნქცია დააბრუნებს 0-ს, თუ როტაცია დაფიქსირდა, ფუნქცია დააბრუნებს შესაბამის მუდმივ მნიშვნელობას. ეს გაასუფთავებს ბუფერულ მნიშვნელობას. ეს ფუნქცია გამოიძახება მთავარ პროგრამაში - while ციკლში.


ჩვენ ვაფართოვებთ ჩვენს პროგრამას. თქვენ შეგიძლიათ სცადოთ ამის გაკეთება საკუთარ თავს.

//AVR პროგრამირება C-ში
//ენკოდერის გამოყენების მაგალითი
//ვებგვერდი 10.17.09

#შეიცავს
#შეიცავს
#include "encoder.h"
#include "bits_macros.h"
#include "timer_value.h"

#define TCNT0_const 253
#define TCCR0_const 5

არასტაბილური ხელმოუწერელი char pTimerValue = 0;

ინტმთავარი ( ბათილად )
{
ENC_InitEncoder();

//ტაიმერის ინიციალიზაცია t0
TCNT0 = TCNT0_const;
TCCR0 = TCCR0_const;

//ტაიმერის ინიციალიზაცია t1
TCNT1 = 0;
TCCR1A = (0<TCCR1B = (0<OCR1A = timerValue;

//ტაიმერის შეფერხებების ჩართვა
//t0 - გადადინებით, t1 - დამთხვევით

TIMSK = (1<

//დააყენეთ PD5 გამოსავალზე
SetBit (PORTD, PD5);
SetBit (DDRD, PD5);

__ჩართვა_შეწყვეტა ();
ხოლო (1){
//ინკოდერის ბუფერის შიგთავსის წაკითხვა
//წაკითხვის შემდეგ იწმინდება

ხელმოუწერელი სიმბოლო stateEnc = ENC_GetStateEncoder();

//თუ ცარიელი არ არის
თუ(stateEnc != 0)(
//ბრუნვის მიმართულების განსაზღვრა და timerValue ცვლადის შეცვლა
თუ(stateEnc == RIGHT_SPIN)(
თუ(pTimerValue == MAX_TIM_VALUE) pTimerValue = MIN_TIM_VALUE;
სხვა pTimerValue++;
}
თუ(stateEnc == LEFT_SPIN) (
თუ(pTimerValue == MIN_TIM_VALUE) pTimerValue = MAX_TIM_VALUE;
სხვა pTimerValue--;
}
}
}
დაბრუნების 0;
}

//ენკოდერის გამოკითხვა
#პრაგმა ვექტორი=TIMER0_OVF_vect
__გააწყვეტინეთბათილად ტაიმერი0_ovf_my( ბათილად)
{
TCNT0 = TCNT0_const;
ENC_PollEncoder();
}

#პრაგმა ვექტორი=TIMER1_COMPA_vect
__გააწყვეტინეთ ბათილად timer1_compa_my( ბათილად)
{
//შედარების რეგისტრის მნიშვნელობის განახლება
OCR1A = timerValue;
}

როგორც ჩანს, ყველაფერი გასაგები უნდა იყოს.
კოდის ნაწილი, რომელიც ცვლის pTimerValue-ს მნიშვნელობას, ასევე შეიძლება დაიწეროს ასე:

თუ(stateEnc != 0) (
pTimerValue = pTimerValue + stateEnc;
თუ(pTimerValue == (MAX_TIM_VALUE + 1)) pTimerValue = MIN_TIM_VALUE;
სხვა თუ(pTimerValue == (MIN_TIM_VALUE - 1)) pTimerValue = MAX_TIM_VALUE;
}

როდესაც ენკოდერი ბრუნავს მარჯვნივ, pTimerValue ემატება 1-ს, ანუ იზრდება.

ენკოდერის მარცხნივ მობრუნებისას, pTimerValue ემატება 0xff, რაც უდრის 1-ის გამოკლებას. ეს იგივე ოპერაციაა, მაგრამ შედეგი არის ზუსტად საპირისპირო.



გაქვთ შეკითხვები?

შეატყობინეთ შეცდომას

ტექსტი, რომელიც გაეგზავნება ჩვენს რედაქტორებს: