პროექტი №14 – სინათლის სენსორი.

December 16, 2012

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

დაგვჭირდება:

პიეზო დინამიკი  (ან პიეზო დისკი) soiwoekw

ორკონტაქტიანი ტერმინალი             sfjwerf;;wre

ფოტო წინაღობა (1kΩ10kΩ)             lksjslkfj;werf

10kΩ წინაღობა                   lskjfwlekf

სქემის აწყობა.

როგორც ყოველთვის, გამოვაძროთ არდუინოდან USB კაბელი და ავაწყოთ ქვემოთ მოყვანილი სქემა.

ewjf;welkf;qwkf

სურ. 4-4. სქემა მე-14-ე პროექტისთვის – სინათლის სენსორი

ფრ–ს პოლარობა არ აქვს, ამიტომ სქემაში მისი ჩართვა უბრალო წინაღობის მსგავსია.

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

// Project 14 - სინათლის სენსორი
// პიეზო ელემენტი მიერთებულია მერვე გამომყვანზე (Pin 8)
int piezoPin = 8;
// ფრ მიერთებული №0 ანალოგურ გამომყვანზე (Aalog Pin 0)
int ldrPin = 0; 
int ldrValue = 0; // ფრ–დან მიღებული საწყისი სიდიდე
void setup() {
 // ცარიელია
}
void loop() {
  // ფრ–დან რაღაც მნიშვნელობის მიღება 
  ldrValue = analogRead(ldrPin); 
  // პიეზო ელემენტი გამოსცემს 1000ჰც სიხშირის ტონს
  tone(piezoPin,1000); 
  delay(25); // დალოდება 25 მილიწამით
  noTone(piezoPin); // ტონის შეწყვეტა
  delay(ldrValue); //ldrValue–ს ტოლი მილიწამით დაყოვნება
} 

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

ამ გაკვეთლის პროგრამული კოდი საკმაოდ მარტივია და ადვილად გასარჩევი. ამიტომ პრდაპირ

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

სქემის განხილვა.

ფოტო რეზიტორებს ამზადებენ კადმიუმ–სულფატის ფოტომგძნობიარე შენაერთისაგან ( CdS: Cadmium-Sulfide) და მათ აქვთ სხვადასხვა წინაღობა.

oiegjtwejf[we

სხვა და სხვა კონსტრუქციისის ფოტო რეზიტორები.

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

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

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

ამ გაკვეთილში გამოყენებულია მუდმივი 10kΩ სიდიდის წინაღობა და ცვლადი წინაღობა ფრ–ის სახით. ძაბვის დამყოფის სტანდარტული სქემა მოცემული ქვემოთ.

pgjsd[fjvsv

როგორც ნახაზიდან ჩანს, შემავალი ძაბვა(Vin) მოდებულია ორივე წინაღობაზე. ერთ რომელიმე წინაღობაზე მოსული, ანუ დაყოფილი ძაბვა კი იქნება ნაკლები და მას პირობითად დავარქვათ გამომავალი ძაბვა (Vout). ამ გამომავალი ძაბვის გამოსათვლელი ფორმულა ასეთია:
Vout = (R2/(R2+R1))x Vin

მაგ. თუ R1=R2=100Ω (ანუ =0.1kΩ) და შემავალი ძაბვა Vin=5ვ, მაშინ გამომავალი ძაბვა იქნება:

Vout= (0.1/(0.1+0.1))X5 = 2.5

თუ R1=R2=470Ω მაშინ:

 

Vout= (0.47/(0.47+0.47))X5 = 2.5ვ

იმ შემთხვევაში თუ R1=1kΩ და R2=500Ω მაშინ:

Vout= (0.5/(0.5+1))X5 = 1.66ვ

თუ R1=1kΩ და R2=2kΩ მაშინ

Vout= (2/(2+1))X5 = 3.33ვ

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

რადგან ჩვენს სქემაში გამოყენებულია მუდმივი 10kΩ წინაღობა და ფრ რომლის წინაღობა იცვლება 10kΩდან (სრული დაბნელება) 1kΩ–მდე (მაქსიმალური განათება), მაშინ გამომავალი ძაბვა და მისი შესაბამისი განათებულობის მნიშვნელობები მოცემულია ქვემოთ მოყვანილ ცხრილში.

R1

R2 (ფრ)

გამომავალი ძაბვა Vout

განათებულობა

10kΩ

100kΩ

4.54

სიბნელე

10kΩ

73kΩ

4.39

25%

10kΩ

45kΩ

4.09

50%

10kΩ

28kΩ

3.68

75%

10kΩ

10kΩ

2.5

მაქს. სიკაშკაშე


პროექტი № 13 – კაკუნის პეზო სენსორი

December 15, 2012

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

დაგვჭირდება

პიეზო დინამიკი     dporgkpsorkg

ორკონტაქტიანი ტერმინალი  'zkjsdv'kjav

შუქდიოდი  osidhugwoueirg

1Mწინაღობა   fuhgpsiug

* შეგიძლიათ პიეზო ელემენტის გამომყვანებს მიარჩილოთ 22 awg მავთული(იხ. გაკვეთლი 1, სურ. 2-8.) და ჩართოთ დაფაში, ან არდუინოში.

სქემის აწყობა.

opdisfvpejfv

სურ. 4-3. სქემა მე-13-ე პროექტისთვის – კანუნის პიეზო სენსორი

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

// Project 13 - კაკუნის პიეზო სენსორი
int ledPin = 9; // შუქდიოდი მე-9 გამომყვანზე
int piezoPin = 5; // პიეზო მიერთებულია მე-5 ანალოგურ გამომყვანზე
int threshold = 120; 
// სესორის საწყისი მინიშვნელობა 120 მის გააქტიურებამდე
int sensorValue = 0; // ცვლადი რომელიც ინახავს სენსსორიდან 
// მიღებული სიგნალის სიდიდეს 
float ledValue = 0; // შუქდიოდის ნათების სიდიდე.

void setup() {
   // ledPin განსაზღვრულია როგორ გამომავალი კონტაქტი
   pinMode(ledPin, OUTPUT);
   //პროგრამის გაშვებისას შუქდიოდი აინთება ორჯერ   
   digitalWrite(ledPin, HIGH); 
   delay(150); 
   digitalWrite(ledPin, LOW); 
   delay(150);
   digitalWrite(ledPin, HIGH); 
   delay(150); 
   digitalWrite(ledPin, LOW); 
   delay(150);
}

void loop() {
   sensorValue = analogRead(piezoPin);//სესორის მიშვნელობის მიღება
   if (sensorValue >= threshold) { 
      // თუ კაკუნია რეგისტრირებული, შუქდიოდი აინთოს მაქსიმუმადე
      ledValue = 255;
   }
   // ნათების სიდიდის გადაცემა შუქდიოზე
   analogWrite(ledPin, int(ledValue) );
   ledValue = ledValue - 0.05; // შუქდიოდი ჩაქრეს ნელა
   if (ledValue <= 0) { ledValue = 0;} 
   //ledValue ნულზე ნაკლები არ უნდა იყოს 
}

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

არდუონო დააფიქსირებს კაკუნს ან კრისტალზე მოდებულ დაწოლას. შუქდიოდი განათდება და დაიწყებს ნელა ჩაქრობას.

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

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

ზემოთ მოყვანილ კოდში ახალი არაფერია.

აქ გამოცხადებულია ცვლადები და მოცემულია კომენტარები:

int ledPin = 9; // შუქდიოდი მე-9 გამომყვანზე 
// პიეზო მიერთებულია მე-5 ანალოგურ გამომყვანზე
int piezoPin = 5; 
// სესორის საწყისი მინიშვნელობა მის გააქტიურებამდე
int threshold = 120; 
// ცვლადი რომელიც ინახავს სენსსორიდან მიღებული
// სიგნალის სიდიდეს
int sensorValue = 0; 
float ledValue = 0; //შუქდიოდის ნათების სიდიდე. 

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

void setup() {
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH); 
   delay(150); 
   digitalWrite(ledPin, LOW); 
   delay(150);
   digitalWrite(ledPin, HIGH); 
   delay(150); 
   digitalWrite(ledPin, LOW); 
   delay(150);
}

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

sensorValue = analogRead(piezoPin);

შემდეგ, პროგრამული კოდი ამოწმებს არის თუა არა მიღებული სიგნალის სიდიდე მეტი ან ტოლი (>=) ვიდრე threshold-თვის მინიჭებული საწყისი მნიშვნელობა.და თუ მეტი ან ტოლი მაშინ ledValue-ს მიენიჭება 255, რას არის PWM ტიპის №9(Pin 9) ციფრული კონტაქტზე გამომავალი ძაბვის მაქსიმალური სიდიდე.

if (sensorValue >= threshold) {
    ledValue = 255;
}

და ეს სიდიდე გადაეცემა PWM Pin 9-ს. რადგან ledValue არის float ტიპის, საჭიროა მისი გარდაქნა integer ტიპად, რადგან analogWrite ფუნქციისათვის დასაშვებია მხოლოდ integer ტიპის ცვლადები:

analogWrite(ledPin, int(ledValue) );

შემდეგ ledValue ცვლადი მნიშვნელობა მცირდება, მას თანდათან აკლდება 0,05

ledValue = ledValue – 0.05;

და შუქდიოდი ნელა ჩაქრება თუ არ დაფიქსირდა ახალი კაკუნი.

თუ საჭიროა შუქდიოდის უფრო სწრაფად ან უფრო ნელა ჩაქრობა, მაშიმ 0,05-ის მაგიერ უნდა ავიღოთ შესაბამისად უფრო დიდი ან მცირე მნიშვნელობა.


პროექტი №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).


პროექტი № 11 – პიეზო სირენა.

November 19, 2012

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

დაგვჭირდება:

პიეზო დისკი

კონტაქტები*

*ამ პროექტისთვის აუცილებელი არ არის. შეგიძლიათ პიეზო ელემენტის გამომყვანებს მიარჩილოთ 22 awg მავთული(იხ. გაკვეთლი 1, სურ. 2-8.) და ჩართოთ დაფაში, ან არდუინოში.

სქემის აწყობა.

სქემა მარტივია, განმარტებები საჭირო არ არის.

მხოლოდ ერთი: არდუინო უნდა იყოს გამორთული

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

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმეთ და ჩატვირთეთ არდუინოში.

// Project 11 – პიეზო სირენა

float sinVal;
int toneVal;
void setup() {
     pinMode(8, OUTPUT); 
}
void loop() {
     for (int x=0; x<180; x++) {
                   // გრადუსის გადაყვანა რადიანებში
         sinVal = (sin(x*(3.1412/180)));
                   // სინუსის მნიშვნელობიდან სიხშირის მიღება
         toneVal = 2000+(int(sinVal*1000));
         tone(8, toneVal);
         delay(2);
     }
}

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

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

ვაცხადებთ ორ ცვლადს:

 
float sinVal;
int toneVal;

float ტიპის ცვლადი sinVal ინახება სინუსის მნიშვნელობა რომელიც გამოიყენება ხმის მოსამატებლად და შესამცირებლად ისევე, როგორც მე–7 გაკვეთილში იცვლებოდა შუქდიოდის ნათება. toneVal ცვლადი იყენებს sinVal–ის მნიშვნელობებს და გარდაქმნის ჩვენთვის სასურველ სიხშირეში.

setup ფუნქციაში მე-8 კონტაქტი გამოცხადებულია როგორც გამომავალი.

 
void setup() {
     pinMode(8, OUTPUT);
}

მთავარ ციკლში, ჩასმულია for ციკლი 0 დან 179 ჩათვლით იმისათვის, რომ გამოვრიცხოთ სინუსის უარყოფითი მნიშვნელობები (იხ. გაკვეთილი 7):

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

გადავიყვანოთ x -ის გრადუსული ზომა რადიანებში (იხ. გაკვეთილი 7):

sinVal = (sin(x*(3.1412/180)));

მიღებული მნიშვნელობები გადავიყვანოთ სიხშირულ დიაპაზონად.

toneVal = 2000+(int(sinVal*1000));

2000-ს ემატება sinVal გამრავლებული 1000-ზე და ვღებულობთ 2000-3000ჰც დიაპაზონს

შემდეგ სტრიქონში გამოყენებულია tone() ბრძანება რომელიც გენერირებს და აგზავნის სიხშირეს პიეზო დინამიკზე:

tone(8, toneVal);

tone() ბრძანებას გადაეცემა ორი ან სამი პარამეტრი

tone(pin, frequency) – (კონტაქტი, სიხშირე)

tone(pin, frequency, duration) – (კონტაქტი, სიხშირე, ხანგრძლივობა)

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

ბოლო სტრიქონში ჩაწერილი გვაქვს 2 მილიწამიანი დაყოვნება, სიხშირის ახალ ცვლილებამდე.

პიეზო ელემენტი.

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

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


პროექტი №10 – Serial Monitor-ით მართული RGB ნათურა.

October 19, 2012

მერვე გაკვეთილის გარძელება.

დავუბრუნდეთ მერვე გაკვეთილში აწყობილ სქემას. ამ გაკვეთილში დაწვრილებით განვიხილავთ Serial Monitor-ის საშუალებით კომპიუტერიდან არდუინოსთან ურთიერთობას. კერძოდ კომპიუტერიდან მოვახდეთ ნათურის მართვას. ამ გაკვეთილში ასევე ვნახავთ თუ როგორ შეიძლება ტექსტური სტრიქონით მანიპულირება.

კოდის შეყვანა.

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმეთ და ჩატვირთეთ არდუინოში. (თქვენ რათქმაუნდა კოდს არ კრეფთ, არამედ copy, paste და პირდაპირ IDE-ში).

// Project 10 – Serial Monitor-ით მართული RGB ნათურა.

char buffer[18];
int red, green, blue;
int RedPin = 11;
int GreenPin = 10;
int BluePin = 9;
void setup()
{
   Serial.begin(9600);
   Serial.flush();
   pinMode(RedPin, OUTPUT);
   pinMode(GreenPin, OUTPUT);
   pinMode(BluePin, OUTPUT);
}

void loop()
{
   if (Serial.available() > 0) {
      int index=0;
      delay(100); // დაყოვნება, ბუფერმა რომ შეძლოს შევსება
      int numChar = Serial.available();

      if (numChar>15) {
         numChar=15;
      }

      while (numChar--) {
         buffer[index++] = Serial.read();
      }
      splitString(buffer);
   }
}

void splitString(char* data) {
   Serial.print("Data entered: ");
   Serial.println(data);
   char* parameter;
   parameter = strtok (data, " ,");
   while (parameter != NULL) {
      setLED(parameter);
      parameter = strtok (NULL, " ,");
   }
   // ტექსტის წაშლა და ბუფერის გაწმენდა
   for (int x=0; x<16; x++) {
      buffer[x]='';
   }
   Serial.flush();
}

void setLED(char* data) {
   if ((data[0] == 'r') || (data[0] == 'R')) {
      int Ans = strtol(data+1, NULL, 10);
      Ans = constrain(Ans,0,255);
      analogWrite(RedPin, Ans);
      Serial.print("Red is set to: ");
      Serial.println(Ans);
   }
   if ((data[0] == 'g') || (data[0] == 'G')) {
      int Ans = strtol(data+1, NULL, 10);
      Ans = constrain(Ans,0,255);
      analogWrite(GreenPin, Ans);
      Serial.print("Green is set to: ");
      Serial.println(Ans);
   }
   if ((data[0] == 'b') || (data[0] == 'B')) {
      int Ans = strtol(data+1, NULL, 10);
      Ans = constrain(Ans,0,255);
      analogWrite(BluePin, Ans);
      Serial.print("Blue is set to: ");
      Serial.println(Ans);
   }
}

როდესაც პროგრამას გაუშვებთ ვიზუალურად არაფერიც არ მოხდება. იმიტომ, რომ პროგრამა ელოდება თქვენს ბრძანებას. დააწკაპუნეთ IDE-ში შესაბამის პიქტოგრამაზე და გაუშვით Serial Monitor. ტექსტის ფანჯარაში შეიყვანეთ თითოეული R, G, და B შუქდიოდების ნათების შესაბამისი მნიშნელობები. შედეგად მივიღებთ რაღაც ჯამურ ფერს. მაგ. თუ ჩაწერთ მხოლოდ R255, მაშინ წითელი შუქდიოდი აინთება სრული სიკაშკაშით. თუ ჩაწერთ R255, G255, მაშინ ორივე, წითელი და მწვანე გაანათებს სრული სიკაშკაშით. ჩაწერეთ R127, G100, B255 შედეგად მიიღებთ მეწამულ-იასამნის ფერს. ჩაწერეთ r0, g0, b0 და სამივე შუქდიოდი ჩაქრება. ტექსტის შეყვანა შეიძლება ქვედა და ზედა რეგისტრშიც, ხოლო მნიშვნელობები კი უნდა იყოს [0; 255] დიაპაზონში. ([]კვადრატილი ფრჩხილები ნიშნავს, რომ 0 და 255 ამ დიაპაზონს ეკუთვნის.)

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

r255 b100
r127 b127 g127
G255, B0
B127, R0, G255

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

ამ გაკვეთილში პირველად განვიხილავთ ისეთ ახალ საკითხებს, როგორიცაა serial monitor -თან კავშირი, მაჩვენებლები (pointers), და სტრიქონის გამოყენება.

პირველ რასაც ვაკეთებთ, არის char (characters) ტიპის მასივის გამოცხადება, ტექსტის 18 სიმბოლოიანი სირგძის მითითებით.

char buffer[18];

შემდეგ ვაცხადებთ integer ტიპის წითელი, მწვანე, ლურჯი ფერის შესაბამის red, green, blue ცვლადებს და გამოყენებულ ციფრულ კონტაქტებს:

int red, green, blue;
int RedPin = 11;
int GreenPin = 10;
int BluePin = 9;

მომდევნო setup ფუნქციაში ვაცხადებთ სამ PWM გამომყვან კონტაქტს. მაგრამ ფუნქცია იწყება ბრძანებით Serial.begin:

void setup()
{
   Serial.begin(9600);
   Serial.flush();
   pinMode(RedPin, OUTPUT);
   pinMode(GreenPin, OUTPUT);
   pinMode(BluePin, OUTPUT);
}

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

Serial.flush ბრძანება საჭიროა, რომ გაიწმინდოს, წაშალოს ნებისმიერ სიმბოლო და serial monitor-ის ფანჯარა მზად იყოს არდუინოზე ბრძანებების გადასაცემად და იქედან ინფორმაციის მისაღებად.

მთავარ ციკლში გვაქვს ifპირობა:

if (Serial.available() > 0) {

რომელიც იყენებს რა Serial.available ბრძანებას, ამოწმებს ჩავწერეთ თუ არა ახლიდან რაიმე სიმბოლო serial monitor-ის ფანჯარაში. ხოლო თუ ჩაწერილია მაშინ შესრულდება if პირობისბლოკში{ } მოთავსებული კოდი:

if (Serial.available() > 0) {
   int index=0;
   delay(100); // დაყოვნება, ბუფერმა რომ შეძლოს შევსება
   int numChar = Serial.available();
   if (numChar>15) {
      numChar=15;
   }
   while (numChar--) {
      buffer[index++] = Serial.read();
   }
   splitString(buffer);
}

გამოვაცხადეთ integer ტიპის ცვლადი სახელად index თავდაპირველად ის ნულის ტოლია. ეს ცვლადი ღებულობს მნიშვნელობებს, რომელიც აღნიშნავს მაჩვენებლის (pointer) პოზიციას char ტიპის მასივში არსებულ რომელიღაც სიმბოლოზე.

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

რადგან სიმბოლოების სტრიქონის შეყვანის დროს Serial.available ფუნქცია მყისიერ ღებულობს ნულზე მეტი სიდიდის მონაცემებს, ამიტომ კოდის შემდგომ სტრიქონში მოთავსებული if ფუნქციას შეუძლია დაიწყოს თავისი კოდი შესრულება. ამიტომ, რომ არ იყოს delay(100) დაყოვნება, მაშინ , როგორც უკვე ავღნიშნეთ, შესაძლებელია delay()ისმომდევნო if პირობა ჩაითვალოს უკვე შესრულებულად და მოხდეს serial monitor-ის ფანჯარაში აკრეფილი სტრიქონის მხოლოდ საწყისი ნაწილის გადაცემა არდუინოში. რაც იქნება არასწორი.

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

თუ Serial Monitor-ში შეყვანილია

R255, G255, B255

მაშინ numChar მნიშვნელობა იქნება 17 და არა 16, იმიტომ, რომ ყოველი ტექსტის ბოლო არის უხილავი სიმბოლო სახელად NULL რომელიც ეუბნება არდუინოს რომ მიღწეულია სტრიქონის ბოლო.

შემდეგი if ამოწმებს არის თუ არა numChar მნიშვნელობა 15-ზე მეტი, და თუ მეტია, მაშინ მინიჭებს მას 15. ეს აუცილებელია იმისათვის, რომ მასივი char buffer[18]არ გადაივსოს.

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

while(expression) {
       // ოპერატორები
}

ჩვენს პროგრამაში ციკლი whileასე გამოიყურება:

while (numChar--) {
     buffer[index++] = Serial.read();
}

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

რადგან numChar წარმოადგენს Serial Monitor-ის ფანჯარაში შეყვანილი ტექსტური სტრიქონის სიგრძეს, ამიტომ while ციკლში მოთავსებული კოდი შესრულდება რამოდენიმეჯერ.

while ციკლში მოთავსებული კოდი არის:

buffer[index++] = Serial.read();

რომელიც Serial Monitor-ის ფანჯარაში შეყვანილი ტექსტური სტრიქონის თითოეულ სიმბოლოს მიაკუთვნებს ბუფერის მასივის თითოეულ ელემეტს. Serial.read() ბრძანება კითხულობს შემოსულ მიმდევრობით მონაცემებს, თითო ბაიტს ცილის თითო გავლაზე. შეყვანილი სიმბოლოებით სტრიქონული მასივის შევსების შემდეგ while ციკლი დმათვრდება მაშინ როდესაც numChar გახდება ნული.

while ციკლის შემდეგ მოდის შემდეგი სტრიქონი:

splitString(buffer);

რომელის არის splitString() ფუნქციის გამოძახება. ეს ფუნქცია კი ასე გამოიყურება:

void splitString(char* data) {
   Serial.print("Data entered: ");
   Serial.println(data);
   char* parameter;
   parameter = strtok (data, " ,");
   while (parameter != NULL) {
       setLED(parameter);
       parameter = strtok (NULL, " ,");
   }
   // ტექსტის წაშლა და ბუფერის გაწმენდა
   for (int x=0; x<16; x++) {
       buffer[x]='';
   }
   Serial.flush();
}

ეს ფუნქცია არ გვიბრუნებს მონაცემს, ეს ხდება იმის გამო, რომ ფუნქციის გამოძახების წინ დგას void. ჩვენ გადავეცით ფუნქციას პარამეტრი, char ტიპის ცვლადი, რომელიც ჩვეთვის არის მონაცემი. მაგრამ C და C++ პროგრამირების ენა არ გვაძლევს იმის უფლებას, რომ სიმბოლოების მასივი პირდაპირ გადავცეთ ფუნქციას. ამ შეზღუდვის დაძლევა, გვერდის ავლა შეიძლება მაჩვენებლის (pointer) გამოყენებით.

მაჩვენებლის, იგივე მიმთითებლის ნიშანია ვარსკვლავი * (char* data). დაწვრილებითი ინფორმაცია მითითებლების შესახებ შეგიძლიათ იხილოთ შესაბამის ლიტერატურაში ან მიმართოთ პროგრამისტებს.

ჩვენთვის კი საკმარისი ვიცოდეთ, რომ ცვლადების როგორც მითითებლის გამოცხადებით, ეს უკანასკნელი ხდება ცვლადი რომელიც მიუთითებს ანუ მიანიშნებს სხვა ცვლადზე. ჩვენ შეგვიძლია ან & სიმბოლოს გამოყენებით მივუთითოთ ის მისმართი მახსოვრობაში სადაც ინახება ცვლადი, ან ამ მისამართზე შენახული ცვლადის სიდიდე ანუ მნიშვნელობა *სიმბოლოს გამოყენებით. ასე შეგვიძლია ”მოვატყუოთ” სისტემა, რადგან C\C++ში ნებადართულია სიმბოლოების მასივის მაჩვენებლების გადაცემა ფუნქციისათვის.

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

საბოლოოდ და მოკლედ: გამოვიძახეთ რა splitString(), ჩვენ მას სრულად გადავეცით ბუფერში მყოფი სიმბოლოების მასივი,

splitString(buffer);

პირველი სტრიქონი ფუნქციაში არის:

Serial.print(“Data entered: “);

ამ გზით შეიძლება მონაცემების გადმოგზავნა არდუინოდან უკან, კომპიუტერში. აქ მოცემული print ბრძანება ბრჭყალებში მოთავსებულ ნებისმიერ სიმბოლოებს USB კაბელის საშუალებით აგზავნის უკან, კომპიუტერში რომელიც გამოჩნდება Serial Monitor-ის ფანჯარაში. ჩვენს შემთხვევაში ფანჯარაში გამოვა Data entered: . დააკვრდით, ორწერტილის შემდეგ არის შუალედი, ინტერვალი, რომელის შემდეგ გამოვა მომდევნო ტექსტი.

შემდეგი სტრიქონია:

Serial.println(data);

აქაც ადგილი აქვს მონაცემების გადაცემას არდუინოდან კომპიუტერზე. გადაიცემა char ტიპის ცვლადის data-ს მნიშვნელობები, რომლიც არის ბუფერში შენახული მონაცემების ასლი. მაგ. თუ თავიდან Serial Monitor-ის ფანჯრიდან არდუინოში გადაცემული იყო:

R255 G127 B56

მაშინ გახილული სტრიქონი

Serial.println(data);

კომპიუტერში, Serial Monitor-ის ფანჯარაში დააბრუნებს იგივე ტექსტს.

ასევე ყურადღება მიაქციეთ print ბრძანების ის ბოლოში lnს. println ბრძანება ნიშნავს Serial Monitor-ის ფანჯარაში ინფრომაციის გამოყვანას და ამის შემდეგ ახალ სტრიქონზე გადასვლას. განხვავებით print ბრძანებისგან, როდესაც ახალ სრიქონზე გადასვლა არ ხდება.

საბოლოოდ, ამ არი ბრძანების შემდეგ:

Serial.print("Data entered: ");
Serial.println(data);

ეკრანზე გამოვა ჯერ Data entered: შემდეგ კურსორი დარჩება ტექსტის ბოლოს იმავე სტრიქონზე, ერთი ინტერვალით მარჯვნივ გადასული. შემდეგ, მეორე ბრძანება გამოიყვანს არდუინოზე ადრე გადაგზავნილ ტექსტს და მხოლოდ ამის შემდეგ გადავა კურსორი ახალ სტრიქონზე.

მომდევნო სტრიქონი ქმნის char ტიპის მოცემების ცვლადს სახელად parameter

Char* parameter;

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

შემდეგი ბრძანებაა strtok, რომელიც საკმაოდ სასრგებლოა ტექსტთან სამუშაოდ.

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

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

parameter = strtok (data, ” ,”);

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

მაგ. თუ შეყვანილი იყო სტრიქონი:

R127 G56 B98

მაშინ parameter მიიღებს მნიშნელობას:

R127

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

შემოგვაქს while ციკლი, სადაც მითითებულია პირობა, რომ parameter არ არის ცარიელი, ანუ სტიქონი ბოლომდე არ არის დამუშავებული:

while (parameter != NULL) {

ამავე ციკლში ვიძახებთ მეორე ფუნქციას:

setLED(parameter);

(რომლის მუშაობას მოგვიანებით განვიხილავთ). შემდეგ parameter ცვლადს ვიყენებთ ტექსტის დარჩენილ ნაწილში მომდევნო შუალედის ან მძიმის მოსაძებნად. ამისათვის strtok-ს გადავცემთ NULL პარამეტრს შემდეგნაირად:

parameter = strtok (NULL, ” ,”);

რომელიც მიუთითებს strtok ბრძანებას გაარძელოს მოქმედება ბოლო გაჩერების ადგილიდან.

ფუნქციის შემდეგი ნაწილი:

char* parameter;
parameter = strtok (data, " ,");
while (parameter != NULL) {
      setLED(parameter);
      parameter = strtok (NULL, " ,");
}

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

განხილული splitString() ფუნქციის დარჩენილი ნაწილი ბუფერულ მასის ავსებს NULL სიდიდით, რომელიც ხორციელდება \0 სიმბოლოთი, ხოლო შემდეგ, გაწმენდს მიდევრობითი ბუფერს მონაცემებისაგან, ამის შემდეგ ბუფერი მზად იქნება ახალი მოცემების მისაღებად.

// ტექსტის წაშლა და ბუფერის გაწმენდა

for (int x=0; x<16; x++) {
    buffer[x]='';
}
Serial.flush();

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

მაგ. თუ ჩავწერეთ:

G125 B55

მაშინ splitString() ფუნქცია მას დაყოფს ორ დამოუკიდებელ ნაწილად :

G125

B55

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

დავუბრუნდეთ setLED() ფუნქციას:

void setLED(char* data) {
    if ((data[0] == 'r') || (data[0] == 'R')) {
       int Ans = strtol(data+1, NULL, 10);
       Ans = constrain(Ans,0,255);
       analogWrite(RedPin, Ans);
       Serial.print("Red is set to: ");
       Serial.println(Ans);
    }
    if ((data[0] == 'g') || (data[0] == 'G')) {
       int Ans = strtol(data+1, NULL, 10);
       Ans = constrain(Ans,0,255);
       analogWrite(GreenPin, Ans);
       Serial.print("Green is set to: ");
       Serial.println(Ans);
    }
    if ((data[0] == 'b') || (data[0] == 'B')) {
       int Ans = strtol(data+1, NULL, 10);
       Ans = constrain(Ans,0,255);
       analogWrite(BluePin, Ans);
       Serial.print("Blue is set to: ");
       Serial.println(Ans);
    }
}

როგორც ვხედავთ ეს ფუნქციაშეიცავს სამ მსგავს if პირობას. განვიხილოთ მათგან ერთი:

if ((data[0] == 'r') || (data[0] == 'R')) {
   int Ans = strtol(data+1, NULL, 10);
   Ans = constrain(Ans,0,255);
   analogWrite(RedPin, Ans);
   Serial.print("Red is set to: ");
   Serial.println(Ans);
}

if პირობა ამოწმებს, რომ ტექსტის ნაწილში data[0] პირველი სიმბოლო არის ასო r ან R. C და C++ განასხვავებს ქვედა და ზედა რეგისტრებს. r და R ასოების არჩევისათვის გამოიყენება ლოგიკური ბრძანება OR(ან), რომლის სიმბოლოა ||.

თუ პირველი სიმბოლო არის r ან R, მაშინ if პირობამ ”იცის”, რომ გვინდა შევცვალოთ წითელი შუქდიოდის ნათება და ის შესრულბს შესაბამის კოდს. ამისათვის ვაცხადებთ int ტიპის ლოკალურ ცვლადს Ans (გამოყენება მხოლოდ შუქდიოდის პარამეტრის შესაცვლელად) და ვიყენებთ strtol (Stringდან long integer-ზე) ბრძანებას იმისათვის, რომ გარდავქმნათ R(r) -ის შემდეგ შეყვანილი სიმბოლოები integer ტიპად. strtol ბრძამებას აქვს სამი პარამეტრი. პირველი, იმ სიმბოლოების ერთობლიობა რომელის უნდა გადაეცეს მას. მეორე, მაჩვენებელი(pointer) integer-ის შემდგომ მყოფ სიმბოლოზე(მაგრამ არ ვიყენებთ, რადგან, ჩვენ უკვე დავყავით სიმბოლოების მწკრივი strtok ბრძანების გამოყენებით და ამიტომ ან შემთხვევაში გადავცემთ NULL სიმბოლოა), და თვლის სისტემა, ჩვენს შემთხვევაში ათობითი, რაზეც მითუთითებს მესამე პარამეტრი 10.

მოკლედ რომ ვთქვათ, შემოვიღეთ integer ტიპის ცლადი, გადავეცით მას R-ის შემდეგ ჩაწერილი მნიშვნელობა, შემდეგ constrain ბრძანებით დავადგინეთ, რომ Ans იცვლება [0 ; 255] შუალედში. ამის შემდეგ analogWrite ბრძანებით წითელი შუქდიოდის კონტაქტს გადავეცით Ans მნიშნელობა. ხოლო შემდეგ Serial.print ბრძანებით Serial Monitor-ის ფანჯარაში გავაგზავნეთ Red is set to:და Ans მნიშვნელობა. დანარჩენი ორი if-ის მოქმედება კი განხილულის იდენტურია.

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

№№11,12,13, და 14 გაკვეთილებში განვიხილავთ პიეზო ელემენტის გამოყენებას.


პროექტი № 9 – ღია ცეცხლის ეფექტი

October 17, 2012
დაგვჭირდება:
წითელი შუქდიოდი                       
2 ცალი ყვითელი შუქდიოდი       
3 ცალი რეზისტორი                         

სქემის აწყობა.

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

სურ. 3-6.

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

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმეთ და ჩატვირთეთ არდუინოში.

// პროექტი № 9 – ღია ცეცხლის ეფექტი

int ledPin1 = 9;
int ledPin2 = 10;
int ledPin3 = 11; 
void setup()
{
    pinMode(ledPin1, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    pinMode(ledPin3, OUTPUT);
} 
void loop()
{
    analogWrite(ledPin1, random(120)+135);
    analogWrite(ledPin2, random(120)+135);
    analogWrite(ledPin3, random(120)+135);
    delay(random(100));
}

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

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

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

int ledPin1 = 9;
int ledPin2 = 10;
int ledPin3 = 11;

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

pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);

პროგრამის მთავარი ციკლი აგზავნის შემთხვევით მნიშვნელობებს [0;120]; და დამატებული 130(მაქსიმალური ნათების მისაღებად) PWM ტიპის კონტაქტებზე 9, 10, and 11:

analogWrite(ledPin1, random(120)+135);
analogWrite(ledPin2, random(120)+135);
analogWrite(ledPin3, random(120)+135);

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

delay(random(100));

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


პროექტი №8 – RGB ნათურა

October 16, 2012

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

დაგვჭირდება:

შუქდიოდები: წითელი, მწვანე, ლურჯი და 3 ცალი 150-200Ω წინაღობა

 

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

სქემის აწყობა.

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

სურ. 3-4.

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

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმეთ და ჩატვირთეთ არდუინოში.

float RGB1[3];
float RGB2[3];
float INC[3]; 
int red, green, blue;
int RedPin = 11;
int GreenPin = 10;
int BluePin = 9; 
void setup()
{
  randomSeed(analogRead(0));
  RGB1[0] = 0;
  RGB1[1] = 0;
  RGB1[2] = 0; 
  RGB2[0] = random(256);
  RGB2[1] = random(256);
  RGB2[2] = random(256);
}

void loop()
{
  randomSeed(analogRead(0));

  for (int x=0; x<3; x++) {
      INC[x] = (RGB1[x] - RGB2[x]) / 256; 
  }

  for (int x=0; x<256; x++) {
      red = int(RGB1[0]);
      green = int(RGB1[1]);
      blue = int(RGB1[2]);

      analogWrite (RedPin, red);
      analogWrite (GreenPin, green);
      analogWrite (BluePin, blue);
      delay(100);

      RGB1[0] -= INC[0];
      RGB1[1] -= INC[1];
      RGB1[2] -= INC[2];
  }

  for (int x=0; x<3; x++) {
      RGB2[x] = random(556)-300;
      RGB2[x] = constrain(RGB2[x], 0, 255);
      delay(1000);
  }

}

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

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

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

პროექტში სამი შუქდიოდის მაგიერ შეიძლება გამოიყენოთ ერთი ე.წ. RGB შუქდიოდი(უფრო კარგი ეფექტი მიიღება)  ოთხი გამომყვანით. აქედან ერთი გამომყვანი არის ან საერთო ანოდი ან საერთო კათოდი. ხოლო დანარჩენი სამი – კი შესაბამისი ფერის გამომყვანი.

თუ RGB -ს მნიშვნელობა არის 255, 0, 0 მაშინ ვღებულობთ წითელს. თუ 0, 255, 0 მაშინ მწვანეს და თუ 0, 0, 255 – ლურჯს. სიკაშკაშის ცვლილების გარეშე, სამი ძირითადი ფერის მხოლოდ ჩართვა (ON) ან გამორთვით (OFF), მიღებული ყველ შესაძლო ფერების ჩამონათვალი მოცემული ქვემოთ მოყვანილ ცხრილში და სურათზე.

წითელი მწვანე ლურჯი მიღებული ფერი
255 0 0 წითელი
0 255 0 მწვანე
0 0 255 ლურჯი
255 255 0 ყვითელი
0 255 255 ცისფერი
255 0 255 მეწამული
255 255 255 თეთრი

RGB შუქდიოების მხოლოდ ჩართვით(ON) ან გამორთვით(OFF) მიღებული ფერები.

შუქდიოდების სიკაშკაშის ცვლილების PWM მეთოდის გამოყენებით, როდესაც RGB -ს თითოეული მნიშვნელობა და შესაბამისად ფერი იცვლება 0 255 დიაპაზონში, შეგვიძლია დამატებით მივიღოთ 16777216 ფერი (256x256x256).

პროგრამული კოდი იწყება float ტიპის მასივის და integer ტიპის ცვლადების გამოცხადებით. რომლებიც გამოიყენებიან increment და RGB-სმნიშვნელობებისათვის:

float RGB1[3];
float RGB2[3];
float INC[3];

int red, green, blue;

setup ფუნქციაში გვაქვს, randomSeed(analogRead(0));

randomSeed ბრძანების საშუალებით ხდება შემთხვევითი(random), სინამდვილეში კი ფსევდო-შემთხვევითი (pseudo-random) რიცხვების გენერირება. კომპიუტერის ჩიპს არ შეუძლია ჭეშმარიტად შემთხვევითი რიცხვების გენერირება, ამისათვის ის მიმართავს თავის მახსოვრობას ან სხვადასხვა მნიშვნელობების ცხრილს და მიღებულ მნიშვნელობებს იყენებს როგორც ფსევდო-შემთხვევით მნიშნელობებს. Seed-ის გამოყენებით, (რაც აქ ნიშნავს საწყის, პირველწყაროს), ჩვენ მივუთითებთ კომპიუტერს თუ საიდან უნდა იქნეს აღებული ან ათვლილი შესაბამისი მნიშვნელობები. შვენს პროექტში randomSeed მიმართავს ანალოგურ კონტაქს ნომრით 0 (Analog Pin 0). რადგან ამ Analog Pin 0ზე არაფერი არ არის მიერთებული, მაზე ყოველთვის წარმოქმნება ელექტრო ”ხმაური”, ფლუქტუაცია, გნებავთ შიგნიდან ან გარედან ინდუცირებული ანალოგური სიგნალი. მას შემდეგ რაც მითითებულია შემთხვევითი სიგნალოს წყარო, შეიძლება ისეთი ფუნქციის შექმნა რომელიც გამოიყენებს random()-ს. შევთანხმდეთ, რომ სიმარტივისთვის, ფსევდო შემთხვევითი რიცხვის მაგიერ, გამოვიყენოთ ტერმინი შემთხვევითი რიცხვი.

ასევე გვაქვს ორი, სამ-სამ ელემეტიანი მასივი სადაც ინახება RGB-ს მნიშვნელობები. RGB1 შეიცავს RGB -ის იმ მნიშნელობებს რომლებიც განსაზღვრავენ შუქდიოდების საწყის ნათებას, ამ შემთხვევაში ყველ არის 0 ან off):

RGB1[0] = 0;
RGB1[1] = 0;
RGB1[2] = 0;

RGB2 მასივი წარმოადგენს RGB-ს შემთხვევით მნიშვნელობებს რომლებიც გამოიყენებიან შუქდიოდების სიკაშკაშის ცვლილებისათვის:

RGB2[0] = random(256);
RGB2[1] = random(256);
RGB2[2] = random(256);

აქ, მასივის ელემეტებს მიენიჭება შემთხვევითი რიხვები, 0 დან 255-ის ჩათვლით, სულ 256 მნიშვნელობა რაც ფრჩხილებშია მითითებული 256.

მაგალითისთვის თუ random() ფუნქციაში ჩავწერთ (გადავცემთ) 1000, მაშინ random(1000)დაგვირუნებს მნიშვნელობებს 0 დან 999-ის ჩათვლით. ხოლო თუ ჩავწერთ ორ პარამეტრს random(10,100)მაშინ დაგვიბრუნდება შემთხვევითი რიცხვები [10 ; 99]. ამ მაგალითებიდან ჩანს, რომ ზედა ზღვარს ყოველთვის აკლდება 1.

პროგრამის მთავარ ციკლში (loop), ვამოწმებთ RGB-ს საწყის და ბოლო მნიშნელობებს და ვარკვევთ, თუ ბიჯის(increment) რა მნიშვნელობა არის საჭირო, რომ გადავიდეთ ერთი მიშვნელობიდან მეორეზე 256 ბიჯის გავლით (PWM-ის მნიშვნელობები უნდა იყოს 0255 დიაპაზონში). ეს კეთდება შემდეგნაირად:

for (int x=0; x<3; x++) {
INC[x] = (RGB1[x] - RGB2[x]) / 256; 
}

ამ for ციკლს გამოყავს INCის (increment-ის პირველი სამი ასო) მნიშვნელობები R, G and B არხებისთვის. კაშკაშის განმსაზღვრელ ორ მნიშნელობას შორის სხვაობა იყოფა 256.

შემდეგი for ცკილი

for (int x=0; x<256; x++) {
    red = int(RGB1[0]);
    green = int(RGB1[1]);
    blue = int(RGB1[2]);

    analogWrite (RedPin, red);
    analogWrite (GreenPin, green);
    analogWrite (BluePin, blue);

    delay(100);

    RGB1[0] -= INC[0];
    RGB1[1] -= INC[1];
    RGB1[2] -= INC[2];
}

გამოითვლის წითელ, მწვანე და ლურჯი ფერის შესაბამის მნიშვნელობებს RGB1 მასივში; გადასცემს ამ მნიშვნელობებს ციფრულ 9, 10 და 11 კონტაქტებს, გამოაკლებს ინკრემეტის ბიჯს და გაიმეორებს ამ პროცეს 256-ჯერ. შედეგად შემთხვევითი ფერი მდორედ გადავა, გადაედინება სხვა შემთხვევით ფერში. ინკრემეტის ბიჯებს შორისი 100მლწმ დაყოვნება delay(100)იძლევა ფერების შენელებულ და თანაბარ ცვლილებას. ამ დაყოვნების შეცვლა შეიძლება პროგრამულად delay()– ში არგუმენტის ცვლილებთ, ან მე-6 გაკვეთილში აღწერილი პოტენციომეტრის გამოყენებით,.

შემთხვევითი ფერების 256-ჯერ შეცვლის შემდეგ, RGB1 მასივში აღმოჩნდება RGB2 მასივის ტოლი ან თითქმის ტოლი მნიშნელობები. ამის თავიდან აცილების მიზნით პროგრამის ბოლოში არის ახალი for ციკლი:

for (int x=0; x<3; x++) {
    RGB2[x] = random(556)-300;
    RGB2[x] = constrain(RGB2[x], 0, 255);
    delay(1000);
}

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

გავიხილოთ თუ როგორ მუშაობს constrain()(შეზღუდვა, პირობის შემოღება) ფუნქცია. მოცემული ფუნქცია იყენებს სამ პარამეტრს x, a, და b, სადაც x არის შესაზღუდი სიდიდე, a არის შეზღუდვის ქვედა ზღვარი, ხოლო b წარმოადგენს ზედა ზღვარს. constrain() ფუნქცია ამოწმებს არის თუ არა x მნიშვნელობა მოქცეული [a; b] შუალედში. თუ x <a, მაშინ ფუნქცია დაგვიბრუნებს a-ს; თუ x>b, მაშინ ფუნქცია დაგვიბრუნებს b-ს. თუ x მოქცეულია [a; b] შუალედში მაშინ ფუნქცია დააბრუნებს x-ის მიმდინარე მიშვნელობას.

ჩვენს შემთხვევაში, თუ constrain(RGB2[x], 0, 255)ფუნქციის RGB2[x]არგუმენტის მნიშვნელობა მოქცეულია [0; 255] დიაპაზონში, მისი მნიშვნელობა გადაეცემა PWM კონტაქტს. ხოლო უარყოფითი მნიშვნელობები იქნება იგნორირებული.

გაგრძლება იხ. გაკვეთილი №10.


პროქტი№7 – შუქდიოდის ცვალებადი სიკაშკაშე, პულსირება.

September 16, 2012

თუ წინა გავეთილებში მხოლოდ შუქდიდის ჩართვა-გამორთვით ვიყავით დაკავებულები, ამჯერად შევეცადოთ შევცვალოთ მისი ნათების სიკაშკაშე.

დაგვჭირდება:

შუქდიოდი, (იყოს მწვანე)  

150-200Ω წინაღობა              

სქემის აწყობა 

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

სურ. 3-3.  სქემა, პულსირებადი შუქდიოდი

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

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმეთ და ჩატვირთეთ არდუინოში.
// int ტიპის ცვლადი სახელად ledPin 
// (კონტაქტის № რომელზეც მიერთებულა შუქდიოდი)
int ledPin = 11; 
// float ტიპის ცვლადი სახელად 
// sinVal (შინაარსი: სინუსის მნიშვნელობა)
float sinVal; 
// int ტიპის ცვლადი სახელად ledVal 
// (შინაარსი: შუქდიოდის კაშკაშის მნიშვნელობა)
int ledVal; 

void setup() { 
 pinMode(ledPin, OUTPUT);//ledPin=11 კონტაქტი არის გამომსვლელი
}
void loop() {
 for (int x=0; x<180; x++) { // კუთხის ზრდა 10 ბიჯით
       /*შემდეგ სტრიქონში ხდება კუთხის გრადუსული 
       ზომის გადაყვანა რადიანებში და შესაბამისი სინუსის გამოთვლა */
       sinVal = (sin(x*(3.1412/180)));
   ledVal = int(sinVal*255);//მიღებული სინუსის გადაეცემა ledVal-ს
       // ledVal-ის გადაცემა გამომსვლელ კონტაქტზე
       analogWrite(ledPin, ledVal);
   delay(25); // დაყოვნება 25 მილიწამით
   }
}

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

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

ზემოთ მოყვანილი პროგრამული კოდი მარტივია, მაგრამ აუცილებელია ზოგიერთი განმარტების გაკეთება. გამოსასვლელი კონტაქტისთვის შემოვიღეთ int ტიპის ცავლადი ledPin. სინუსის გამოსათვლელად float ტიპის ცვლადი. ხოლო  №11 PWM გამომსვლელ კონტაქტზე გადასაცემად კი int ტიპის ცვლადი ledVal.

იდეა მდგომარეობს იმაში, რომ სიკაშკაშის ცვლილებისათვის გამოვიყენოთ სინუსის ფუნქციის თვისება მიიღოს მნიშვნელობები (0; 1; 0) შუალედში, როდესაც არგუმენტი იცვლება 00 გრადუსიდან 1800 გრადუსამდე (1800-3600 არ გვჭირდება რადგან ამ შუალედში სინუსი უარყოფითია).

სინუსის გამოსათვლელად საჭიროა გრადუსული ზომის გადაყვანა რადიანებში x*(3.1412/180).

(ერთი შეხედვით რა საჭიროა ჯერ გრადუსული ზომის აღება და მერე მისი გადაყვანა რადიანებში, არ ჯობდა პირდაპირ რადიანები აგვეღო? არ ჯობდა იმიტომ, რომ გრადუსული ზომისთვის ინკრემენტი for (int x=0; x<180; x++) მარტივია). მიღებულ sinVal მნიშვნელობას ვამრავლებთ 255-ზე და ვღებულობთ ledVal-ს მნიშვნელობებს 0 დან 255 მაქსიმუმამდე. თან float ტიპის sinVal გარდაიქმნება int ტიპად შემდეგ გამოცხადებით:int()

ledVal = int(sinVal*255);

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

ამის შემდეგ, მიღებული მნიშვნელობები გადაეცემა №11 ციფრულ PWM კონტაქტს.

analogWrite(ledPin, ledVal);

მაგრამ, როგორ გადაეცემა ანალოგური სიგნალი ციფრულ კონტაქტს? თუ დავაკვირდებით არდუინოს დაფას, ვნახავთ, რომ №3, 5, 6, 9, 10 და 11 კონტაქტებს აწერია PWM. ეს კონტაქტები იმით განსხვავდება სხვა, მხოლოდ ციფრული კონტაქტებისაგან, რომ მათ დამატებით შეუძლიათ გამოიყვანონ PWM ტიპის სიგნალი.

ახლა განვიხილოთ თუ რას წარმოადგენს PWM (Pulse Width Modulation). ეს მეთოდი გულისხმობს ანალოგური სიგნალის მოქმედების მსგავსი ეფექტის მიღებას ციფრული სიგნალით. ამ დროს მართკუთხა ციფრული სიგალის ხანგრძლივობის ცვლილებით (სურათი ქვემოთ) ხდება ანალოგური სიგნალის კოდირება-იმიტაცია. არდუინო თავის PWM კონტაქტებზე აგზავნის 0 და 5ვ სიდიდის იმპულსებს 500ჰც სიხშირით. ამ იმპულსების, ანუ ჩართვა-გამორთვის კომბინაციები ახდენენ ანალოგური სიგალის 0-დან 5ვ-მდე ცვლილების იმიტაციას. კომბინაციები კი ნიშნავს თუ როგორია თანაფარდობა ჩართული მდგომარების ჯამურ ხანგრძლივობასა და გამორთული მდგომარების ჯამურ ხანგრძლივობას შორის.

მაგალითად: №11 ციფრულ PWM კონტაქტზე analogWrite()-ის საშუალებით 0-გადაცემის შემთხვევაში, ჩართული მდგომარეობის ანუ ძაბვის მიწოდების ხანგრძლივობა იქნება ნული, ანუ სამუშაო ციკლის 0%. იმავე კონტაქტზე 64-ის გადაცემის შემთხვევაში (რაც შეადგენს 255-ის ≈25%(25,1)) №11 ციფრულ PWM კონტაქტზე 5ვ ძაბვა მიწოდებული იქნება დროის 25% განმავლობაში და გამორთული 75% განმავლობაში. 191-ის გადაცემის დროს კი დროის ≈75% (74,9) ჩართული და გამორთული ≈25%. ხოლო 255-ის გადაცემის დროს სრული 100% ჩართული. საბოლოოდ იქმნება ილუზია, რომ შეგვიძლია ციფრული გამომსველელი კონტაქტზე მოვახდინოთ ანალოგური სიგნალის სიმულირება

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


პროექტი №6 – ინტერაქტიული ”მორბენალი” ნათება

September 11, 2012

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

მე-5 პროექტზე დასამატებლად დაგვჭირდება :

4,7KΩ ან ცოტათი მეტი წინაღობის პოტენციომეტრი (მაგ. 5,1)

 

სქემის აწყობა

სურ. 3-2. მე-6 პროექტის სქემა.

 გამოვრთოთ არდუინოდა მე-5 პროექტის სქემას დავამატოთ პოტენციომეტრი. რომლის ერთი კიდურა გამომყვანი მიერთებულია  არდუინოს +5ვოლტიან კონტაქტზე, მეორე კიდურა გამომყვანი მიერთებულია ”მიწაზე”, ხოლო შუა გამომყვანი ანუ ცოცია – კი არდუინოს №2 ანალოგურ კონტაქტზე.

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

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

byte ledPin[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
int ledDelay;
int direction = 1;
int currentLED = 0;
unsigned long changeTime;
int potPin = 2; // პონტენციომეტრისთვის შემავალი კონტაქტის დანიშვნა

void setup() {
  for (int x=0; x<10; x++) { 
      pinMode(ledPin[x], OUTPUT); 
  }
  changeTime = millis();
}

void loop() {
 ledDelay = analogRead(potPin); // პოტენციომეტრის მნიშვნელობის წაკითხვა
 if ((millis() - changeTime) > ledDelay) {
    changeLED(); changeTime = millis();
 }
}
void changeLED() {
  for (int x=0; x<10; x++) { 
      digitalWrite(ledPin[x], LOW);
  }
  digitalWrite(ledPin[currentLED], HIGH);
  currentLED += direction;
  if (currentLED == 9) {
     direction = -1;
  }
  if (currentLED == 0) {
     direction = 1;
  }
}

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

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

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

int potPin = 2; ამ სტრიქონს განსაკუთრებული ახსნა არ უნდა, პოტერციომეტრი მიერთებულია №2 ანალოგურ კონტაქტთან. ledDelay = analogRead(potPin); // პოტენციომეტრის მნიშვნელობის წაკითხვა ამ სტრიქონის საშუალებით ვკითხულობთ ანუ ვღებულობთწინაღობის მნიშვნელობებს №2 კონტაქტიდან analogRead ბრძანების გამოყენებით. არდუინოს აქვს ექვსი (დამოკიდებულია არდუინოს მოდელზე) ანალოგური შემავალ/გამომავალი კონტაქტი ანალოგურიდან ციფრულში 10ბიტიანი გადამყვანით(analog to digital convertor). რაც ნიშნავს, რომ ანალოგურ კონტაქტს შეუძლია წაიკითხოს შემავალი 0-დან 5 ვოლტამდე ძაბვა როგორც integer ტიპის მნიშვნელობები 0დან(ანუ 0 ვოლტიდან) 1023მდე(ანუ 5 ვოლტამდე). რაც გვაძლევს შემდეგ გარჩევისუნარობას: 5ვოლტი / 1024 ერთეულზე (რადგან 0-იც შედის სათვალავში)ანუ 0,0049 ვოლტი (4,9მილივოლტი)ერთ ერთეულზე. (5/1024=0,00488281250.0049 პრაქტიკული თვალსაზრისით თამამად შეგვიძლია ვთქვათ = 0,0049) პოტენციომეტრიდან მიღებული ანუ წაკითხული მნიშვნელობები პირდაპირ მიენიჭება ledDelay ცვლადს და საბოლოოდ ვღებულობთ დაყოვნებას 0-დან 1023 მილიწამამდე. ledDelay = analogRead(potPin); ციფრული კონტაქტებისაგან განსხვავებით, ანალოგურ კონტაქს არ ჭირდება წინასწარ გასაზღრვრა შემავალია ის თუ გამომავალი. ledDelay = analogRead(potPin); რადგან, ამ სტრიქონს მუდმივად აკონტროლებს მთავარი ციკლი void loop(), ჩვენ მხოლოდ ისღა დაგვრჩენია ვატრიალოთ პოტენციომეტრის სახელური.

პოტენციომეტრის მიკლე აღწერა

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


პროექტი №5 – ”მორბენალი” ნათება

September 10, 2012

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

დაგვჭირდება:

1) 10 ცალი შუქდიოდი

2) 10 ცალი 150-200Ω  რესისტორი

სქემის აწყობა.

 ყურადღებით დააკვირდით და გამორთულ არდუინოზე ააწყვეთ ქვემოთ მოყვანილი სქემა.

სურ. 3-1.

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

აკრიფეთ ქვემოთ მოყვანილი კოდი, შეამოწმენეთ და ჩატვირთეთ არდუინოში.

// პროექტი №5 - ”მორბენალი” შუქდიოდები
// byte ტიპის მასივი სახელად ledPin რომლის
byte ledPin[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
//შემადგენელი ელემენტებია იმ კონტაქტების
//ნომრები რომლებზეც შუქდიოდებია მიერთებული 
// int ტიპის ცვლადი სახელად ledDelay, შეცვლის დაყოვნება მლწმ-ში
int ledDelay(65); 
int direction = 1;//int ტიპის ცვლადი სახელად direction
int currentLED = 0;// int ტიპის ცვლადი სახელად currentLED
//unsigned long ტიპის ცვლადი სახელად changeTime
unsigned long changeTime;
void setup() {
// კონტაქტების გადაყვანა გამოსვლის რეჟიმში
  for (int x=0; x<10; x++) { 
      pinMode(ledPin[x], OUTPUT); 
  }
  changeTime = millis();
}

void loop() {
//თუ ბოლო შეცვლიდან გასულია ledDelay მლწმ   
   if ((millis() - changeTime) > ledDelay) { 
      changeLED();
      changeTime = millis();
   }
}
void changeLED() {
  for (int x=0; x<10; x++) { // ყველ შუქდიოდის გამორთვა
      digitalWrite(ledPin[x], LOW);
  }
  // მიმდინარე შუქდიოდის ჩართვა
  digitalWrite(ledPin[currentLED], HIGH); 
  currentLED += direction; // direction-ით მატება
  // შეიცვალოს მიმართულება direction თუ გავედით ბოლოში
  if (currentLED == 9) {
      direction = -1;
  }
  if (currentLED == 0) {
      direction = 1;
  }
}

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

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

პირველი სტრიქონი

byte ledPin[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13};

არის მონაცემთა მასივი, გამოცხადებული byte ტიპის ცვლადის საშუალებით, სახელად ledPinმასივი არის ცვლადების (გნებავთ მნიშვნელობების) ერთობლიობა, ნაკრები, ჯგუფი, სიმრავლე. მასივის შემადგენელი ელემენტების გამოძახება, გამოყენება, წვდომა ხდება მათი ინდექსის ანუ რიგითი ნომრის საშუალებით. ჩვენი მასივი შედგემა 10 ელემეტისაგან, მნიშვნელობისაგან, წევრისაგან (კონტაქტების ნომრები 4-დან 13-ის ჩათვლით). მიუხედავად იმისა, რომ ჩვენ ინტუიციურად მიჩვეული ვართ თვლა დავიყოთ 1-დან, მასივის გამოყენების შემთხვევაში კი საქმე სხაგვარად არის, ამიტომ დაიმახსოვრეთ : მასივის ელემენტების ნუმერაცია იწყება 0-დან. რაც იმას ნიშნავს, რომ პირველი ელემენტის ინდექსი არის 0, მეორე ელემენტის ინდექსი არის 1, მესამე ელემენტის ინდექსი 2 და ა.შ. ამიტომ ჩვენი მასივის ელემენტების ინდექსებია: 0, 1, 2, 3, 4, 5, 6 ,7, 8 და 9. მაგალითად: არდუინოს მე-6 კონტაქტის ანუ მასივის მე-3 ელემენტის გამოძახება ჩაიწერება ასე: ledPin[2]. მე-10 კონტაქტის ანუ მასივის მე-7 ელემენის გამოძახება კი ასე ledPin[6].

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

byte ledPin[10];

ხოლო ელემენტები მიგვენიჭებინა მოგვიანებით.

დავუბრუნდეთ ისევ ჩვენს პროგრამას. მთავარ ციკლში, თუ შუქდიოდების ბოლო ნათებიდან გასულია ledDelay ცვლადში მოცემული დრო მილიწამებში, მაშინ გამიოძახება ფუნქცია changeLED()

void changeLED() {
// ყველ შუქდიოდის გამორთვა
for (int x=0; x<10; x++) { 
    digitalWrite(ledPin[x], LOW);
}

digitalWrite(ledPin[currentLED], HIGH); // მიმდინარე შუქდიოდის ჩართვა

currentLED += direction; // direction-ის ტოლი სიდიდით მატება

// შეიცვალს მიმართულება direction თუ გავედით ბოლოში

if (currentLED == 9) {direction = -1;}

if (currentLED == 0) {direction = 1;}

}

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

შემდეგ ამ ცვლადს ემატება direction. რადგან direction-ის მნიშვნელობა შეიძლება იყოს ან1, ცვლადის მნიშვნელობა გაიზრდება (+1) ან შემცირდება (currentLED +(-1)) ერთით.

ამ ფუქციაში არის შუქდიოდების მწკრივის ბოლოში გასვლის შემოწმების if პირობა.  თუ მიღწეულია მწკრივის ბოლო მაშინ იცვლება ცვლადის ”მიმართულება” ანუ ნათების გადაადგილების, ”სრიალის” მიმართულება.

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

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