პროექტი №12 – პიეზო პლეერი.

November 24, 2012

ამ გაკვეთილში გავაკეთოთ პიეზო პლეიერი. გამოვიყენოთ მე-11 გაკვეთილის სქემა.

პროგრამული კოდი

ქვემოთ მოყვანილი კოდი გადაიტანეთ ID-ში.

// Project 12 - პიეზო პლეერი. 
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define WHOLE 1
#define HALF 0.5
#define QUARTER 0.25
#define EIGHTH 0.125
#define SIXTEENTH 0.0625


int tune[] = { NOTE_C4, NOTE_C4, NOTE_C4, NOTE_C4, 
NOTE_C4, NOTE_B3, NOTE_G3, NOTE_A3, NOTE_C4, 
NOTE_C4, NOTE_G3, NOTE_G3, NOTE_F3, NOTE_F3, 
NOTE_G3, NOTE_F3, NOTE_E3, NOTE_G3, NOTE_C4, 
NOTE_C4, NOTE_C4, NOTE_C4, NOTE_A3, NOTE_B3, 
NOTE_C4, NOTE_D4};

float duration[] = { EIGHTH, QUARTER+EIGHTH, SIXTEENTH,
QUARTER, QUARTER, HALF, HALF, HALF, QUARTER, QUARTER, 
HALF+QUARTER, QUARTER, QUARTER, QUARTER, QUARTER+EIGHTH, 
EIGHTH, QUARTER, QUARTER, QUARTER, EIGHTH, EIGHTH, 
QUARTER, QUARTER, QUARTER, QUARTER, HALF+QUARTER};

int length;
void setup() {
    pinMode(8, OUTPUT);
    length = sizeof(tune) / sizeof(tune[0]);
}
void loop() {
     for (int x=0; x<length; x++) {
         tone(8, tune[x]);
         delay(1500 * duration[x]);
         noTone(8);
     }
     delay(5000);
}

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

კოდის განხილვა.

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

#define PI 3.14159265358979323846264338327950288419716939937510

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

მეორე მაგალითი:

#define TRUE 1
#define FALSE 0

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

კიდევ ერთი მაგალითი: დავუშვათ დაგვჭირდა რაღაც ტაბლოს გარჩევის უნარიანობის განსაღვრა სიდიდით 8 x 32. მოსახერხებელი ტაბლოს, გნებავთ დიპლეის სიმაღლის (height) და სიგანის (width) განმსაზღვრელი დირექტივები ჩავწეროთ ასე:

#define DISPLAY_HEIGHT 8
#define DISPLAY_WIDTH 32

ამ დირექტივის შემდეგ, პროგრამულ კოდში სადაც საჭრო იქნება და რამდეგჯერაც საჭირო ინება უბრალოდ ჩავწერთ DISPLAY_HEIGHT და DISPLAY_WIDTH ვიდრე მშრალ ციფრებს.

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

ამ პროექტში ჩვენ შევქმენით define directive-ების სია ნოტების დასახელებებით და შესაბამისი სიხშირეების მითითებით. სიაში პირველი ნოტი არის C3 და მისის სიხშირეა 131ჰც.

ნოტების შემდგომი ხუთი define directive არის ნოტების ხანგრძლივობა შესაბამისი მნიშვნელობები: მთელი ნოტა, ნახევარი, მეოთხედი. მერვედი და მეთექვსმეტედი. ეს მნიშვნელობები გამოიყენება თითოეული ნოტის ჟღერადობის ხანგრძლივოდის გამოსათვლელად მილიწამებში. მაგ მეოთხედი ნოტისთვის:

1500 x QUARTER = 375 milliseconds

ამ ორი define directive შემდეგ მოდის int ტიპის tune[] მასივი,რომელშიც ჩაწერილია მელოდია ანუ ნოტების თანმიმდევრობა:

int tune[] = { NOTE_C4, NOTE_C4, NOTE_C4, NOTE_C4,
NOTE_C4, NOTE_B3, NOTE_G3, NOTE_A3, NOTE_C4, NOTE_C4, 
NOTE_G3, NOTE_G3, NOTE_F3, NOTE_F3, NOTE_G3, NOTE_F3,
NOTE_E3, NOTE_G3, NOTE_C4, NOTE_C4, NOTE_C4, NOTE_C4, 
NOTE_A3, NOTE_B3, NOTE_C4, NOTE_D4};

შემდეგია float ტიპის duration[ ] მასივი. ამ მასივში მოცემულია მელოდიის თითოეული ნოტის ხანგრძლივობა:

float duration[] = { EIGHTH, QUARTER+EIGHTH, 
SIXTEENTH, QUARTER, QUARTER, HALF, HALF, 
HALF, QUARTER, QUARTER, HALF+QUARTER, QUARTER,
QUARTER, QUARTER, QUARTER+EIGHTH, EIGHTH, 
QUARTER, QUARTER, QUARTER, EIGHTH, EIGHTH,
QUARTER, QUARTER, QUARTER, QUARTER, 
HALF+QUARTER};

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

შემდეგია int ტიპის ცვლადი სახელად length

int length;

რომელიც გამოიყენება მასივის სიგრძის(ანუ თითოეული ნოტის ”სიგრძის”) გამოსათვლელად და შესანახად.

setup()ში მოცემული სტრიქონით მე-8 კონტაქტი არის გამომავალი:

pinMode(8, OUTPUT);

sizeof() ფუნქციის გამოყენებით გამოვითვლით მასივში მოცემული ნოტების რაოდენობას და გადავცემთ მას length ცვლადს.

length = sizeof(tune) / sizeof(tune[0]);

sizeof ფუნქცია აბრუნებს მისთვის გადაცემული(ფრჩხილებში მოთავსებული) პარამეტრის ბაიტების რაოდენობას. (არდუინოში integer ტიპს გამოყოფილი აქვს 2 ბაიტი, ბაიტი კი შედგება 8 ბიტისაგან). ჩვენი მელოდია შედგება 26 ნოტისაგან, ანუ tunes[]მასივი შეიცავს26 ელემენტს. მთელი მასივის ზომა ბაიტებში იქნება:

sizeof(tune)

გავყოფთ ამ მიღებულ სიდიდეს ერთი ელემენტის ზომაზე ბაიტებში:

sizeof(tune[0])

მივიღებთ lengthის სიდიდეს:

26 / 2 = 13

ასეთი გამოთვლა მოსახერხებელია იმ შემთხვევაში თუ ერთ მელოდიას შევცვლით მეორე მელოდიით, მაშინ length გამოითვლის ახალ მელოდიაში არსებული ნოტების რაოდენობას.

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

მთავარ ციკლში მოცემულია for ციკლი, რომელიც შესრულდება იმდენჯერ რამდენი ნოტიც დავთვალეთ lengthის საშუალებით

for (int x=0; x<length; x++) {

მე-8 გამომავალ კონტაქტს გადაეცემა tune[] მასივში მოცემულინოტები .

tone(8, tune[x]);

თითიეული ნოტის გაიჟღერებს

delay(1500 * duration[x]);

მილიწამის განმავლობაში.

საბაზისო 1500 მილიწამი გამრავლებულია ნოტის ხანგრძლივობაზე (მაგ 1500*0,25 მეოთხედი ნოტისთვის და 0,125-ზე მერვედი ნოტისთვის)

მომდევნო ნოტის გაჟღერებამდე გამომავალ კონტაქტს ეგზავნება ბრძანება:

noTone(8);

გასაგებია, რომ ეს ნიშნავს სიგნალის შეწყვეტას.

ეს ბრძანება საჭიროა იმისათვის, რომ ყოველი ნოტი გაჟღერდეს ინდივიდუალურად არ მივიღოთ რაღაც ერთი გრძელი გადაბმული მელოდია.

ბოლოს, for ციკლის დასრულების შემდეგ, მელოდიის შემდგომ გამეორებამდე დგას 5 წამიანი დაყოვნება:

delay(5000);

შემდეგ გაკვეთილში გავარჩევთ კაკუნის, ვიბრაციის სენსორს (Knock Sensor).