// Πληροφορίες
// Το παρακάτω είναι μια παλμογεννήτρια το οποίο δημιουργεί ένα αναλογικό κύμα μέσω PWM (Pulse Width Modulation)
// που βασίζεται σε ένα ημιτονοειδή μοτίβο (sine wave)
//Η επιθυμητή συχνότητα του ημιτόνου είναι καθορισμένη στην παράμετρο frequency του κώδικα
//Αυτό σημαίνει ότι το ημιτονικό κύμα θα επαναλαμβάνεται 500 φορές το δευτερόλεπτο ή 500 Hz.
//Ο αριθμός των βημάτων (resolution) καθορίζει πόσα σημεία θα περιλαμβάνει το κύμα σε μια πλήρη περίοδο (ένα κύκλο του ημιτόνου)
//Η διάρκεια κάθε βήματος υπολογίζεται από την καθυστέρηση που υπάρχει στο τέλος του βρόχου loop()
// Το 1000000 είναι το πλήθος των μικροδευτερολέπτων σε 1 δευτερόλεπτο (1.000.000 μs)
// άρα Delay= (1000000) / (500×50) = 40 μικροδευτερόλεπτα , κάθε βήμα διαρκεί 40 μsec
// Η συχνότητα του ημιτόνου θα είναι 500 Hz με 50 βήματα, πράγμα που σημαίνει ότι κάθε 40 μικροδευτερόλεπτα (η διάρκεια του βήματος) παράγεται ένα νέο σημείο στην κυματομορφή
// άρα για να κατασκευάσουμε κύμα με f=500hz θέλουμε
// 1) Κάθε περίοδος να έχει 50 βήματα
// 2) κάθε βήμα να απέχει απο το προηγούμενο 40 μsec
// Προφανώς μπορούμε να το αλλάξουμε και να βάλουμε περισσότερα βήματα
//Πατάμε Simulation και μετά απο 2 δευτερλεπτα πατάμε PAUSE , σώνει ένα αρχείο
//Ανοίγουμε το παρακάτω Online tool και το κάνουμε drag and drop εκει.
//https://vc.drom.io/
/*
------------------Περίληψη της δομής:
Η συνάρτηση setup() εκτελείται μία φορά όταν ξεκινά το πρόγραμμα στον μικροελεγκτή.
Στο εσωτερικό της, υπάρχει ένας βρόχος for που υπολογίζει τις τιμές του ημιτόνου για κάθε βήμα (δλδ μια θέση στον πίνακα sineWave[]).
------------------Περίμετροι του πίνακα sineWave[]:
Το sineWave[] είναι ένας πίνακας τύπου byte που θα αποθηκεύσει τις τιμές του ημιτόνου για κάθε βήμα. Στην αρχή, τα στοιχεία του πίνακα δεν έχουν τιμές.
Το resolution (που είναι 50 στην περίπτωσή μας) καθορίζει πόσα βήματα θα περιλαμβάνει μία πλήρης περίοδος του ημιτόνου. Δηλαδή, ο πίνακας sineWave[] θα έχει 50 τιμές ημιτόνων απο 0 - 2π .
// το βήμα μεταξύ των 50 τιμών είναι σταθερό και υπολογίζεται ¨: Βημα γωνίας = 2π/50 = 0.12566ακίνια , δλδ περίπου 7.2 μοίρες παίρνουμε μια τιμή ημιτόνου.
// Αν θέλουμε πιο ακριβής αναπαράσταση πρέπει να αυξήσουμε τον αριθμό των βημάτων αλλά προσοχή στο ότι είναι πλακέτα που το computing ειναι περιορισμένο.
------------------Ο βρόχος for:
Ο βρόχος for (int i = 0; i < resolution; i++) ξεκινά με την τιμή του i να είναι 0 και συνεχίζει μέχρι το i να φτάσει στο resolution - 1. Αυτό σημαίνει ότι εκτελείται 50 φορές (αν το resolution είναι 50).
Για κάθε τιμή του i, υπολογίζεται το αντίστοιχο σημείο της κυματομορφής του ημιτόνου.
Υπολογισμός του ημιτόνου: Η τιμή του ημιτόνου υπολογίζεται με την εξής μαθηματική συνάρτηση:
------------------sineWave[i] = offset + amplitude * sin(2 * PI * i / resolution);
sin(): Η συνάρτηση sin() υπολογίζει την τιμή του ημιτόνου για μία γωνία. Η γωνία που παρέχεται είναι σε ακτίνια, όχι σε μοίρες.
2 * PI * i / resolution: Εδώ υπολογίζουμε τη γωνία που αντιστοιχεί στο βήμα i. Ο τύπος 2 * PI * i / resolution δημιουργεί ένα πλήρη κύκλο (όταν το i κυμαίνεται από 0 έως resolution - 1), διαιρώντας τον κύκλο σε ίσα μέρη.
2 * PI αντιπροσωπεύει την πλήρη γωνία ενός κύκλου σε ακτίνια (περίπου 6.283 ακτίνια).
Ο πλήρης κύκλος (η ολοκληρωμένη περιστροφή γύρω από το κέντρο του κύκλου) έχει γωνία 2π ακτίνια. Αυτό σημαίνει ότι, για να κάνουμε μία πλήρη περιστροφή γύρω από τον κύκλο, η γωνία πρέπει να αυξηθεί κατά 2π ακτίνια (που είναι περίπου 6.283 ακτίνια).
Αν το σκεφτείς με πιο απλά λόγια:
Η γωνία 0 ακτίνια αντιστοιχεί στην αρχική θέση (στην "εκκίνηση" του κύκλου).
Η γωνία π/2 ακτίνια (περίπου 1.570 ακτίνια) είναι το 1/4 του κύκλου (ή 90 μοίρες).
Η γωνία π ακτίνια (περίπου 3.1416 ακτίνια) είναι το 1/2 του κύκλου (ή 180 μοίρες).
Η γωνία 3π/2 ακτίνια (περίπου 4.712 ακτίνια) είναι το 3/4 του κύκλου (ή 270 μοίρες).
Η γωνία 2π ακτίνια (περίπου 6.283 ακτίνια) είναι το 1 πλήρες κύκλο (ή 360 μοίρες).
i / resolution: Διαχωρίζει τον κύκλο σε 50 τμήματα (αν το resolution είναι 50). Έτσι, κάθε τιμή του i αντιστοιχεί σε ένα σημείο της κυματομορφής.
amplitude: Το πλάτος του ημιτόνου. Αν το amplitude = 127, αυτό σημαίνει ότι το πλάτος του κύματος είναι 127(μεγιστο το 255)
offset: Η μετατόπιση της κυματομορφής. Αν το offset = 128, το ημιτονικό κύμα δεν κυμαίνεται γύρω από το μηδέν, αλλά γύρω από το 128 (γι' αυτό το κύμα είναι πάντα θετικό και έχει εύρος από 0 έως 255).
Έτσι, για κάθε βήμα i, υπολογίζεται το ημιτονοειδές κύμα, προσαρμοσμένο με το offset και το πλάτος ώστε να αποθηκεύεται στον πίνακα sineWave[i]
*/
// Ορισμός της θύρας για την έξοδο PWM
const int pwmPin = 9; // Θύρα PWM (αναλογική έξοδος) για σύνδεση με το κύκλωμα
// Ο αριθμός των βημάτων της κυματομορφής (π.χ. πόσα σημεία να περιλαμβάνει η κυματομορφή)
const int resolution = 10; //δοκίμασε με 50/100/200 τι παρατηρείς?
// Αριθμός βημάτων για ένα πλήρες κύμα (μικρότερη τιμή δίνει πιο ακριβές κύμα, μεγαλύτερη πιο τραχύ)
// Το μέγεθος του πλάτους (amplitude) της κυματομορφής, το οποίο αντιστοιχεί στη μέγιστη τιμή του κύματος (προσαρμόζεται από 0 έως 255)
const int amplitude = 127; // Πλάτος του κύματος (το μέγιστο είναι 255, αλλά εμείς το περιορίζουμε για το PWM)
// Το μετατόπισμα (offset) που προστίθεται στο κύμα για να το κεντράρουμε γύρω από το 128 (μετατοπίζει το κύμα για να είναι θετικό)
const int offset = 128; // Μετατόπιση του κύματος (στην περίπτωση αυτή, γύρω από το 128 για κεντραρισμένο κύμα)
// Συχνότητα του ημιτόνου (πόσες φορές το δευτερόλεπτο θα επαναλαμβάνεται το κύμα)
const int frequency = 500; // Επιθυμητή συχνότητα του ημιτόνου (σε Hz)
// Πίνακας που περιέχει τα δεδομένα της κυματομορφής (ημιτόνιο) για την αναπαραγωγή μέσω PWM
byte sineWave[resolution]; // Πίνακας για την αποθήκευση των τιμών του ημιτόνου
void setup() {
// Υπολογισμός των τιμών του ημιτόνου για κάθε βήμα
for (int i = 0; i < resolution; i++) {
// Υπολογισμός της τιμής της συνάρτησης του ημιτόνου για κάθε βήμα
// Κάνουμε προσαρμογή στις τιμές του ημιτόνου ώστε να ταιριάζουν με τις τιμές PWM (0-255)
sineWave[i] = offset + amplitude * sin(2 * PI * i / resolution);
}
}
void loop() {
static int index = 0; // Ο δείκτης που μας λέει ποιο σημείο του ημιτόνου να δείξουμε αυτή τη στιγμή
// Εμφανίζουμε την τρέχουσα τιμή του ημιτόνου στην έξοδο PWM
analogWrite(pwmPin, sineWave[index]);
// Αυξάνουμε το δείκτη για να δείξουμε το επόμενο σημείο στην κυματομορφή
// Επαναφορά του δείκτη όταν φτάσουμε στο τέλος του πίνακα (δημιουργεί περιοδικότητα)
index = (index + 1) % resolution;
// Ο χρόνος καθυστέρησης για να επιτευχθεί η επιθυμητή συχνότητα του ημιτόνου
// Η καθυστέρηση υπολογίζεται με βάση τον αριθμό των βημάτων και τη συχνότητα του κύματος
delayMicroseconds(1000000 / (frequency * resolution));
}