Μακροεντολές Arduino: Ένας πλήρης οδηγός για να τις κατακτήσετε με παραδείγματα

  • Οι μακροεντολές στο Arduino σάς επιτρέπουν να βελτιστοποιήσετε τον κώδικα και τη μνήμη πριν από τη μεταγλώττιση.
  • Η χρήση #define σάς επιτρέπει να δημιουργείτε προσαρμοστικές συναρτήσεις, σταθερές και δομές.
  • Οι προηγμένες μακροεντολές σάς επιτρέπουν να συνενώνετε αναγνωριστικά και να έχετε πρόσβαση στο PROGMEM.
  • Η πειθαρχημένη χρήση μακροεντολών βελτιώνει την αποτελεσματικότητα χωρίς να θυσιάζεται η αναγνωσιμότητα.

Arduino Cores Zephyr OS beta-1

Arduino έχει φέρει επανάσταση στον κόσμο των ηλεκτρονικών χάρη στην ευκολία με την οποία μπορούν να δημιουργηθούν λειτουργικά πρωτότυπα και έργα. Ωστόσο, για όσους θέλουν να κάνουν τον προγραμματισμό τους ένα βήμα παραπέρα και να βελτιστοποιήσουν τους πόρους, να διατηρήσουν τον κώδικα καθαρό και να αποκτήσουν αποτελεσματικότητα, μακροεντολές γίνει βασικό εργαλείο.

Σε αυτό το άρθρο θα βουτήξουμε βαθιά στη χρήση του μακροεντολές στο Arduino: τι είναι, πώς χρησιμοποιούνται, πλεονεκτήματα και περιορισμοί τους. Και αυτό θα το κάνουμε συλλέγοντας τις πιο περιεκτικές και χρήσιμες πληροφορίες από τους καλύτερους πόρους που διατίθενται στο διαδίκτυο, ξαναγραμμένες με σαφή και σύγχρονο τρόπο για να είναι πραγματικά πρακτικοί.

Τι είναι οι μακροεντολές στο Arduino;

Οι μακροεντολές είναι οδηγίες προεπεξεργαστή σε C/C++ που σας επιτρέπουν να αντικαταστήσετε κείμενο πριν τη μεταγλώττιση του κώδικα. Αντί να εκτελεί εντολές όπως μια παραδοσιακή συνάρτηση, μια μακροεντολή λειτουργεί αντικαθιστώντας τμήματα του κειμένου προέλευσης, το οποίο έχει άμεσο αντίκτυπο στον τρόπο δημιουργίας του τελικού δυαδικού κώδικα.

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

Βασικό παράδειγμα: ένας ορισμός σαν #define LED_PIN 13 προκαλεί την αυτόματη αντικατάσταση όλων των κωδικών LED_PIN με 13 πριν από τη σύνταξη.

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

Πλεονεκτήματα της χρήσης μακροεντολών

Η εφαρμογή μακροεντολών σε έργα Arduino μπορεί να προσφέρει μια σειρά από συγκεκριμένα οφέλη:

  • Βελτιώστε την αναγνωσιμότητα κώδικα: Με την επαναχρησιμοποίηση συμβολικών ονομάτων, είναι ευκολότερο να κατανοήσουμε τον σκοπό κάθε στοιχείου.
  • Βελτιστοποίηση απόδοσης: Με τη μη δημιουργία κλήσεων συναρτήσεων, οι μακροεντολές μπορούν να εκτελούν λειτουργίες πιο γρήγορα.
  • Μειώστε τη χρήση RAM: ιδιαίτερα χρήσιμο σε πίνακες με περιορισμένους πόρους, όπως το Arduino UNO.
  • Επιτρέπει προσαρμογές υπό όρους: Είναι δυνατή η μεταγλώττιση διαφορετικών τμημάτων κώδικα ανάλογα με τον τύπο της πλακέτας Arduino που χρησιμοποιείται.

Βασικές μακροεντολές: Χρήση #define

Διευθυντικός #καθορίζω Είναι το πιο χρησιμοποιημένο. Χρησιμοποιείται και για τα δύο ορίστε σταθερές τιμές ως προς το δημιουργήστε αυτόματες λειτουργίες με έγχυση κατά τον χρόνο της προκατασκευής.

Παράδειγμα 1: Ορίστε μια καρφίτσα

#define PINLED 13

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

void loop() {
  digitalWrite(PINLED, HIGH);
  delay(500);
  digitalWrite(PINLED, LOW);
  delay(500);
}

Παράδειγμα 2: Μακροεντολή ως ενσωματωμένη συνάρτηση

int itemCounter = 0;
#define COUNT_ITEM() do { itemCounter++; } while(0)

void setup() {
  Serial.begin(9600);
  COUNT_ITEM();
  COUNT_ITEM();
}

void loop() {
  Serial.println(itemCounter);
}

Όπως μπορείτε να δείτε, η χρήση του μοτίβου do { … } while(0) διασφαλίζει ότι η μακροεντολή συμπεριφέρεται με ασφάλεια ακόμη και αν χρησιμοποιείται σε δομές υπό όρους.

## τελεστής και συνένωση μακροεντολών

Ο τελεστής ## είναι ένα ισχυρό εργαλείο προεπεξεργαστή. που επιτρέπει τη συνένωση αναγνωριστικών. Αυτό είναι πολύ χρήσιμο όταν θέλετε να δημιουργήσετε ονόματα μεταβλητών δυναμικά.

Πρακτικό παράδειγμα:

#define GENERAR_VARIABLE(no) \
  int var##no = no;

void setup() {
  GENERAR_VARIABLE(3); // crea int var3 = 3
}

Σημαντική προειδοποίηση: Αυτός ο χειριστής δεν είναι εξίσου συμβατός με όλα τα μοντέλα πλακέτας Arduino. Για παράδειγμα, μπορεί να λειτουργεί καλά σε Uno ή Esplora, αλλά να αποτύχει σε Mega. Επίσης, δεν μπορείτε να τοποθετήσετε τη δημιουργία μακροεντολών σε άλλες μακροεντολές χρησιμοποιώντας απευθείας το ##.

Μακροεντολές και εξοικονόμηση μνήμης

Ένα από τα βασικά πλεονεκτήματα της χρήσης μακροεντολών στο Arduino είναι το εξοικονόμηση μνήμης RAM. Το Arduino έχει περιορισμένη χωρητικότητα, επομένως η φόρτωση συμβολοσειρών κειμένου απευθείας στη μνήμη RAM μπορεί να γίνει σημαντικό πρόβλημα.

Μια προηγμένη τεχνική για να αποφευχθεί αυτό περιλαμβάνει τη χρήση FORCE_INLINE και φόρτωση συμβολοσειρών από τη μνήμη προγράμματος (PROGMEM):

#include <HardwareSerial.h>
#define MYSERIAL Serial
#define FORCE_INLINE __attribute__((always_inline)) inline

FORCE_INLINE void printFromFlash(const char *str) {
  char ch = pgm_read_byte(str);
  while (ch) {
    MYSERIAL.write(ch);
    ch = pgm_read_byte(++str);
  }
}

#define SERIAL_LOG(x) (MYSERIAL.print(x))
#define SERIAL_LOGLN(x) (MYSERIAL.println(x))

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

Μακροεντολές σε συνδυασμό με λειτουργίες

Οι μακροεντολές μπορούν επίσης να διευκολύνουν την κλήση συναρτήσεων δυναμικά, με βάση έναν τύπο που μεταβιβάζεται ως παράμετρος. Ένα σαφές και αρκετά γραφικό παράδειγμα είναι:

#define FUNC_LENTA(tipo) \
  { funcion_##tipo##_lenta(); }

#define FUNC_RAPIDA(tipo) \
  { funcion_##tipo##_rapida(); }

void funcion_caminar_lenta() {
  Serial.println("Andando despacio");
}

void funcion_caminar_rapida() {
  Serial.println("Andando rápido");
}

void setup() {
  Serial.begin(9600);
  FUNC_LENTA(caminar);
}

void loop() {
  FUNC_RAPIDA(caminar);
}

Χάρη στον τελεστή ## και τις μακροεντολές, μπορούμε να αποφύγουμε την επανάληψη δομών και να συγκεντρώσουμε τη δυναμική λογική..

Μακροεντολές με παραμέτρους εξόδου

Είναι επίσης δυνατή η χρήση μακροεντολών για την ενθυλάκωση μικρών αντικειμένων ή μετατροπών:

#define BOOL_OUT() (bool){false}
#define NUM_OUT(a,b) (float){a+b}
#define STR_OUT(msg) (String){msg}

void loop() {
  Serial.println(BOOL_OUT());
  Serial.println(NUM_OUT(1.2, 3.4));
  Serial.println(STR_OUT("Mensaje"));
}

Καλές πρακτικές και προφυλάξεις με μακροεντολές

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

Μερικοί βασικοί κανόνες για την αποφυγή προβλημάτων:

  • Αποφύγετε τα περιττά κενά ή τα σπασίματα των γραμμών εντός της μακροεντολής.
  • Μην συμπεριλάβετε σχόλια μέσα σε πολύπλοκες μακροεντολές που χρησιμοποιούν πολλές γραμμές.
  • Χρησιμοποιήστε μοναδικά ονόματα ή με προθέματα (όπως το όνομα του έργου) για την αποφυγή διενέξεων.
  • Αντικαταστήστε τις μακροεντολές με πραγματικές σταθερές ή συναρτήσεις όποτε είναι δυνατόν. Η σύγχρονη C++ επιτρέπει καθαρότερες, ασφαλέστερες εναλλακτικές λύσεις.

Από την άλλη πλευρά, η υπερβολική χρήση μακροεντολών μπορεί να μειώσει τη σαφήνεια του κώδικα. Ο στόχος πρέπει να είναι η βελτίωση της αποτελεσματικότητας και της αρθρωτής δομής χωρίς να διακυβεύεται η συντηρησιμότητα.

Οδηγίες υπό όρους και προσαρμοστική σύνταξη

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

Χαρακτηριστικό παράδειγμα:

#ifdef ARDUINO_MEGA
  #define LEDPIN 53
#else
  #define LEDPIN 13
#endif

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

Εσωτερικές μακροεντολές μεταγλωττιστή

Ο προεπεξεργαστής GCC για AVR (που χρησιμοποιείται στο Arduino) περιλαμβάνει πολλούς ειδικές μακροεντολές που παρέχουν πληροφορίες συστήματος, πολύ χρήσιμο κατά την ανάπτυξη:

  • __ΓΡΑΜΜΗ__: τρέχων αριθμός γραμμής.
  • __ΑΡΧΕΙΟ__: όνομα του τρέχοντος αρχείου.
  • __TIME__ και __DATE__: ώρα και ημερομηνία συλλογής.
  • __func__: όνομα της τρέχουσας συνάρτησης.

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

Οι μακροεντολές προσφέρουν έναν ισχυρό και ευέλικτο τρόπο δομής έργων Arduino. Σας επιτρέπουν να ορίσετε σταθερές, εξοικονόμηση μνήμης, προσαρμόστε τον κώδικα ανάλογα με το περιβάλλον εκτέλεσης και να δημιουργήσετε επαναχρησιμοποιήσιμα μπλοκ χωρίς διπλότυπες γραμμές. Φυσικά, απαιτούν πειθαρχία, σαφήνεια και γνώση για την αποφυγή λεπτών σφαλμάτων ή απώλειας αναγνωσιμότητας. Όταν εφαρμόζονται σωστά, αποτελούν ανεκτίμητο πλεονέκτημα για μεσαίους και προχωρημένους προγραμματιστές.


Γίνε ο πρώτος που θα σχολιάσει

Αφήστε το σχόλιό σας

Η διεύθυνση email σας δεν θα δημοσιευθεί. Τα υποχρεωτικά πεδία σημειώνονται με *

*

*

  1. Υπεύθυνος για τα δεδομένα: Miguel Ángel Gatón
  2. Σκοπός των δεδομένων: Έλεγχος SPAM, διαχείριση σχολίων.
  3. Νομιμοποίηση: Η συγκατάθεσή σας
  4. Κοινοποίηση των δεδομένων: Τα δεδομένα δεν θα κοινοποιούνται σε τρίτους, εκτός από νομική υποχρέωση.
  5. Αποθήκευση δεδομένων: Βάση δεδομένων που φιλοξενείται από τα δίκτυα Occentus (ΕΕ)
  6. Δικαιώματα: Ανά πάσα στιγμή μπορείτε να περιορίσετε, να ανακτήσετε και να διαγράψετε τις πληροφορίες σας.