Εφαρμογή φωτός αναπνοής LED με χρήση του μικροελεγκτή 51

Jun 11, 2026 Αφήστε ένα μήνυμα

[Εισαγωγή]


Η τεχνολογία μικροελεγκτών είναι μια απαραίτητη βασική τεχνολογία στον σύγχρονο βιομηχανικό αυτοματισμό, την ηλεκτρονική, την ηλεκτρική μηχανική και το Διαδίκτυο των Πραγμάτων (IoT). Καθώς οι ζωές μας γίνονται όλο και πιο έξυπνες, η τεχνολογία μικροελεγκτών έχει διεισδύσει σχεδόν σε κάθε πτυχή της καθημερινότητάς μας, όπως σε έξυπνες κουζίνες ρυζιού, έξυπνα ηχεία και πολλά άλλα.


Έχοντας αυτό κατά νου, η σειρά άρθρων "Επανεκμάθηση του 51 μικροελεγκτή" στοχεύει να βοηθήσει τους αρχάριους να ξεκινήσουν με την τεχνολογία μικροελεγκτών. Θα ξεκινήσουμε με την απλούστερη εργασία-ανάβοντας ένα μόνο LED-και σταδιακά θα προχωρήσουμε στην υλοποίηση μονάδων όπως τα χειριστήρια κουμπιών, η οθόνη LCD1602, οι αισθητήρες θερμοκρασίας DS18B20 και DS1302 και η επικοινωνία μεταξύ δύο μικροελεγκτών. Θα καλύψουμε επίσης πρωτόκολλα επικοινωνίας υλικού όπως UART, I²C και SPI. Συνδυάζοντας αυτές τις έννοιες με τεχνικές προγραμματισμού C, θα χρησιμοποιήσουμε πραγματικά{10}}παγκόσμια έργα μηχανικής για να απεικονίσουμε προσεγγίσεις προγραμματισμού, δίνοντάς σας τη δυνατότητα να εφαρμόσετε ευέλικτα δείκτες και δομές C για να επιτύχετε αρθρωτό προγραμματισμό.


Τώρα, ας επιστρέψουμε στο κύριο θέμα: χρήση ενός μικροελεγκτή 51 για τον έλεγχο ενός LED και τη δημιουργία ενός εφέ αναπνευστικού φωτός.

 

[Πώς λειτουργούν τα φώτα αναπνοής]


Ας ρίξουμε πρώτα μια ματιά στο πώς λειτουργεί ένα εφέ φωτός αναπνοής.
Ένα αναπνευστικό φως σταδιακά φωτίζεται και μετά σταδιακά εξασθενεί, επαναλαμβάνοντας αυτόν τον κύκλο με τρόπο που μοιάζει με την αναπνοή. Ωστόσο, δεδομένου ότι οι ακίδες ενός μικροελεγκτή μπορούν να εξάγουν μόνο ένα 1 (on) ή ένα 0 (off), πώς μπορεί να επιτευχθεί ένα αποτέλεσμα σταδιακής μετάβασης;
Αυτό οφείλεται στην επιμονή της όρασης στα μάτια μας. Όταν κοιτάμε κάτι, η εικόνα που σχηματίζεται από τα μάτια μας παραμένει για 0,04 δευτερόλεπτα (αυτή η εικόνα βρέθηκε στο διαδίκτυο).
Αν υπολογίσουμε με βάση τα 0,04 δευτερόλεπτα, αυτό ισούται με 40 ms. Επομένως, όταν το LED ανάβει και σβήνει για 20 ms το καθένα, φαίνεται στο ανθρώπινο μάτι σαν να είναι συνεχώς αναμμένο.

图片

Είναι το αποτέλεσμα ενός LED που αναβοσβήνει για 20 ms και σβήνει για 20 ms το ίδιο με το να παραμένει αναμμένο συνεχώς;

 

Χαχα, σίγουρα είναι διαφορετικό. Όταν το φως εναλλάσσεται μεταξύ ενεργοποίησης και απενεργοποίησης κάθε 20 χιλιοστά του δευτερολέπτου, το εφέ που βλέπουμε είναι πιο αμυδρό από ό,τι όταν παραμένει αναμμένο συνεχώς. Αν υποθέσουμε ότι η φωτεινότητα ενός συνεχώς αναμμένου φωτός είναι 100%, τότε η φωτεινότητα ενός φωτός που εναλλάσσεται μεταξύ ενεργοποίησης και απενεργοποίησης κάθε 20 χιλιοστά του δευτερολέπτου είναι 50%. Με βάση αυτό, μπορούμε να ρυθμίσουμε τη φωτεινότητα του LED.

图片

 

Σε αυτό το σημείο, μπορούμε να ρυθμίσουμε τη φωτεινότητα του LED (ρυθμίζοντας τη διάρκεια του υψηλού επιπέδου εντός του κύκλου των 40ms). Αυτή είναι η αρχή πίσω από τη γνωστή-μέθοδο ελέγχου φωτεινότητας PWM (Διαμόρφωση πλάτους παλμού) και η ρύθμιση της διάρκειας του υψηλού επιπέδου ισοδυναμεί με τη ρύθμιση του κύκλου λειτουργίας (δηλαδή, η διάρκεια του υψηλού επιπέδου διαιρούμενη με τον συνολικό κύκλο: 20/40=50%).


Εδώ, ο πιο σημαντικός παράγοντας είναι αυτός ο κύκλος λειτουργίας. Για παράδειγμα, εάν η περίοδος είναι 20 ms, με το LED να εναλλάσσεται μεταξύ 10 ms αναμμένο και 10 ms σβηστό, η αντιληπτή φωτεινότητα εξακολουθεί να είναι 50% (δηλαδή, ο κύκλος λειτουργίας είναι 10/20=50%).

Στη συνέχεια, ας δούμε πώς εφαρμόζεται αυτό στο πρόγραμμα.

 

[Υλοποίηση Προγράμματος]


Ενεργοποίηση LED
Αρχικά, ας ξεκινήσουμε ενεργοποιώντας ένα LED και, στη συνέχεια, θα εφαρμόσουμε σταδιακά ένα εφέ αναπνοής φωτός. Το υλικό που θα χρησιμοποιήσουμε είναι το εξής:

Συμβούλιο Ανάπτυξης ZeroOne Training Development Board Microcontroller
Μοντέλο μικροελεγκτή STC89C52
Διεπαφή LED Καρφίτσα P4^4
图片

 

Από το σχηματικό, μπορούμε να δούμε ότι το LED είναι συνδεδεμένο στον ακροδέκτη P4^4 του μικροελεγκτή. Όταν ο μικροελεγκτής βγάζει 1, το LED ανάβει. όταν βγάζει 0, το LED σβήνει. Επομένως, το πρόγραμμα για την ενεργοποίηση ενός LED είναι αρκετά απλό, όπως φαίνεται παρακάτω:

info-299-230

 

 

Το πρόγραμμα για την ενεργοποίηση ενός LED είναι αρκετά απλό. Είμαι σίγουρος ότι όλοι ξέρουν πώς να το κάνουν.
 

Ρύθμιση φωτεινότητας LED


Στη συνέχεια, θα εφαρμόσουμε μια συνάρτηση που μας επιτρέπει να προσαρμόσουμε τη φωτεινότητα (δηλαδή, να προσαρμόσουμε τον κύκλο λειτουργίας), ως εξής:

info-400-538


 

Καθορίστε μια στατική μεταβλητή `duty_cycle` για την αποθήκευση του κύκλου λειτουργίας. Όταν το "flag" είναι 1, ο κύκλος λειτουργίας αυξάνεται σταδιακά στο 255, στη συνέχεια ορίστε το "flag" σε 0 και το "duty_cycle" μειώνεται σταδιακά από 255 σε 0. Επαναλάβετε αυτόν τον κύκλο.
Χαχα, σε αυτό το σημείο, μπορεί να νομίζετε ότι το αναπνευστικό φως λειτουργεί ήδη, αλλά δεν είναι. Αν δεν με πιστεύετε, δοκιμάστε μόνοι σας τον παραπάνω κώδικα.

Πού ακριβώς είναι λοιπόν το πρόβλημα;


Το πρόβλημα έγκειται στην άμεση κλήση μας στη συνάρτηση ρύθμισης φωτεινότητας -set_led_luminance()`. Αυτή η λειτουργία χρειάζεται 40 ms για να ολοκληρωθεί ένας κύκλος, που σημαίνει ότι ο κύκλος λειτουργίας δεν μπορεί να αλλάξει κατά τη διάρκεια αυτών των 40 ms. Διαφορετικά, η ρύθμιση φωτεινότητας δεν θα λειτουργήσει. Ας ρίξουμε μια άλλη ματιά στη συνάρτηση «breath_led». Μετά από κάθε κλήση στο `set_led_luminance()` για να ορίσετε τον κύκλο λειτουργίας, αλλάζει αμέσως την τιμή του "duty_cycle" χωρίς να περιμένει 40 ms.


Σε αυτό το σημείο, πρέπει να προσθέσουμε ένα χρονοδιακόπτη λογισμικού για να ενημερώσουμε την τιμή «κύκλος_λειτουργίας» μετά την πάροδο 40 ms. Το τροποποιημένο πρόγραμμα έχει ως εξής:

info-495-656

 

 

Σημείωση: Η διάρκεια του χρονοδιακόπτη πρέπει απλώς να είναι μεγαλύτερη από 40 ms (που σημαίνει ότι η τιμή του `s_breathCounter` πρέπει να είναι μεγαλύτερη από 255), αλλά είναι καλύτερο να τη ρυθμίσετε σε πολλαπλάσιο του κύκλου. Για παράδειγμα, αν ο κύκλος μας είναι 255 (δηλαδή, 256 τιμές από 0 έως 255), μπορούμε να τον ορίσουμε σε διπλάσια τιμή: 256 * 2 - 1=511 (δηλ. 512 τιμές από 0 έως 511).
Και να το έχετε-το φως αναπνοής μας ολοκληρώθηκε! Δεν είναι απλό; (* ̄︶ ̄)

 

Ακολουθεί η σημερινή ενότητα μπόνους.

Παρόλο που έχουμε επιτύχει το εφέ αναπνοής, ο κώδικας δεν είναι αρκετά συνοπτικός ή κομψός-χρησιμοποιεί ένα σωρό προτάσεις if και else. Ας δούμε αν μπορούμε να το απλοποιήσουμε περαιτέρω.

Αρχικά, ας απλοποιήσουμε αυτό το τμήμα της συνάρτησης set_led_luminance(), όπως φαίνεται στο παρακάτω σχήμα.
 

图片

 

Πριν το απλοποιήσουμε αυτό, ας καλύψουμε μια γρήγορη συμβουλή σχετικά με το C: τη λειτουργία bitwise AND.

info-600-117

 

Από αυτό, γνωρίζουμε ότι είτε είναι 1 είτε είναι 0, η εκτέλεση μιας λειτουργίας bitwise AND με 0 έχει ως αποτέλεσμα 0.

Είτε είναι 1 είτε 0, η εκτέλεση μιας λειτουργίας bitwise AND με 1 έχει ως αποτέλεσμα την αρχική τιμή.

Για ευκολία, χρησιμοποιούμε δεκαεξαδικό συμβολισμό (με πρόθεμα "0x"). Για παράδειγμα, το 0xff αντιστοιχεί στο 255 σε δεκαδικό. Επομένως,

 

Όταν ένας αριθμός μικρότερος ή ίσος του 0xff είναι ΚΑΙ με 0xff, το αποτέλεσμα είναι ο ίδιος ο αριθμός, όπως φαίνεται παρακάτω

info-534-63

 

 

Τι θα συμβεί αν εκτελέσετε μια λειτουργία AND μεταξύ ενός αριθμού μεγαλύτερου από 0xff και 0xff;

info-551-63

Το αποτέλεσμα είναι το υπόλοιπο όταν αυτός ο αριθμός διαιρείται με το (0xff + 1) (δηλαδή, το αποτέλεσμα εξακολουθεί να είναι μεταξύ 0 και 0xff).
Με αυτήν τη λειτουργία bitwise AND, ο παραπάνω κώδικας μπορεί να απλοποιηθεί

info-550-64

 

 

Με αυτόν τον τρόπο, η τιμή του s_Counter θα είναι πάντα εντός του εύρους από 0x00 έως 0xff.
Ομοίως, το χρονόμετρο λογισμικού στην παραπάνω λειτουργία breath_led μπορεί επίσης να απλοποιηθεί ως εξής:

info-389-353

Στη γραμμή 3, το 0x1ff είναι 511 σε δεκαδικό. Η συνθήκη είναι αληθής όταν η τιμή του s_breathCounter είναι (0x1ff+1) ή 512, επειδή το 512 & 0x1ff=0. Το θαυμαστικό πριν υποδηλώνει μια λειτουργία NOT (για την ακρίβεια, η συνθήκη πληρούται όταν η τιμή του `s_breathCounter` είναι ένα πολλαπλάσιο του ορισμού της ανάγκης 5. `s_breathCounter` Ελπίζω ότι αυτή η εξήγηση είναι σαφής-σκέψου το καλά). Εάν πληρούται η προϋπόθεση, ο κύκλος λειτουργίας αρχίζει να αυξάνεται ή να μειώνεται.


Αλλά το εύρος του κύκλου λειτουργίας δεν είναι από 0 έως 255; Γιατί η γραμμή 5 γίνεται επίσης 0x1ff (511); Μην ανησυχείτε-κοιτάξτε τη γραμμή 8. Αφαιρούμε ξανά 0xff, οπότε το εύρος του κύκλου λειτουργίας παραμένει από 0 έως 255.


Οι γραμμές 7–10 σημαίνουν: Όταν «κύκλος_λειτουργίας > (0xff)», δηλαδή 256–511, η αφαίρεση του 0xff ισοδυναμεί με αύξηση από το 1 στο 255, οπότε η φωτεινότητα αυξάνεται σταδιακά.


Όταν duty_cycle<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.


Χαχα, νομίζατε ότι τελείωσε η απλοποίησή μας;

 

Όχι, όχι, όχι

Στην πραγματικότητα, οι γραμμές 7 έως 10 θα μπορούσαν να απλοποιηθούν ακόμη περισσότερο. Εδώ είναι χρήσιμη η συνάρτηση απόλυτης τιμής.

Τι; Γιατί να χρησιμοποιήσετε τη συνάρτηση απόλυτης τιμής;

 

Κοιτάξτε τη γραμμή 10: Το 0xff - duty_cycle ισοδυναμεί με duty_cycle - 0xff και, στη συνέχεια, λάβετε την απόλυτη τιμή. Εντάξει, εδώ είναι ο απλοποιημένος κώδικας:

set_led_luminance(ABS(duty_cycle - (0xff)));

 

 

Η συνάρτηση μακροεντολής για τη λήψη της απόλυτης τιμής είναι η εξής

#define ABS(N) ((N) < 0 ? -(N) : (N))

 

Τέλος, έχω συμπεριλάβει ολόκληρο τον απλοποιημένο κώδικα παρακάτω

 

info-562-684

Τι πιστεύεις; Δεν είναι απλό; (* ̄︶ ̄)

Αποστολή ερώτησής

whatsapp

Τηλέφωνο

Ηλεκτρονικό ταχυδρομείο

Εξεταστική