Σε αυτή τη σειρά άρθρων, θα παρουσιάσουμε τη γλώσσα προγραμματισμού C, πάνω στους μικροελεγκτές AVR. Η γλώσσα C, αντικατέστησε την γλώσσα Assembly, σε εφαρμογές με τους μικροϋπολογιστές AVR για διάφορους λόγους. Ο πιο σημαντικός λόγος είναι ότι, ο χρήστης μπορεί να γράφει κώδικα σε επίπεδο αρκετά υψηλότερο από εκείνο της γλώσσας Assembly, με αποτέλεσμα την αυξημένη παραγωγικότητα.
Ένα πρόγραμμα σε C, ανεξάρτητα από το μέγεθος του, αποτελείται από συναρτήσεις και μεταβλητές. Μια συνάρτηση περιέχει εκφράσεις που ορίζουν την λειτουργία που θα εκτελεστεί. Μια έκφραση μπορεί να είναι μια δήλωση ή εκχώρηση ή μια σειρά πράξεων ή η κλήση μιας συνάρτησης ή έλεγχος και διακλάδωση. Κάθε έκφραση θα πρέπει να τελειώνει με ένα ελληνικό ερωτηματικό. Ένα πρόγραμμα στη C πρέπει υποχρεωτικά να περιέχει μια και μόνο μια συνάρτηση main με την οποία ξεκινά η εκτέλεση του προγράμματος.
Ένα πρώτο παράδειγμα είναι το ακόλουθο:
#include <avr\io.h>
int main(void)
{
DDRA=0xFF;
PORTA=0x1F;
while(1);
}
Με την πρώτη γραμμή του προηγούμενου προγράμματος , ο μεταγλωττιστής συμπεριλαμβάνει το οριζόμενο αρχείο κεφαλίδας στην αρχή του κώδικα που δημιουργεί και αυτό ανάλογα από τον μικροελεγκτή που χρησιμοποιείται. Αυτή η γραμμή περιέχεται στην αρχή κάθε C προγράμματος που γράφουμε για τον μικροελεγκτή AVR. Όταν χρησιμοποιούμε το Microchip IDE για να δημιουργήσουμε την εφαρμογή που θέλουμε, ο χρήστης θα πρέπει να ορίσει τον συγκεκριμένο μικροελεγκτή που θα χρησιμοποιήσει και έτσι αυτή η πρώτη γραμμή, εισάγεται αυτόματα στο πρόγραμμα μας από το σύστημα.
Για τον μικροελεγκτή που δηλώνουμε, το αρχείο κεφαλίδας περιέχει τους ορισμούς και τα ονόματα όλων Ι/Ο καταχωρητών (SFR καταχωρητές ειδικών λειτουργιών) οι οποίοι είναι υπεύθυνοι για τον έλεγχο περιφερειακών, θυρών εισόδου – εξόδου, τους χρονιστές, τις διακοπές, τον καταχωρητή κατάστασης καθώς και τα bit που εισάγονται στο πρόγραμμα, έτσι ώστε ο χρήστης να χρησιμοποιεί συμβολικά ονόματα για να αναφέρεται σ’αυτά.
Η δεύτερη γραμμή main είναι εκεί όπου ο κώδικας αρχίζει να εκτελείται. Ο κώδικας της συνάρτησης τοποθετείται μέσα σε ένα ζεύγος από άγκιστρα {} αμέσως μετά το όνομα της. Όπως θα δούμε παρακάτω η λέξη void δηλώνει ότι η κλήση της συνάρτησης δεν παίρνει κανένα όρισμα.
Στη τέταρτη γραμμή, εκχωρείται η τιμή 0xFF στον Ι/Ο καταχωρητή DDRA που εδώ ορίζει ότι όλοι οι ακροδέκτες διαμορφώνονται σαν έξοδοι. Στην πέμπτη γραμμή εκχωρείται η τιμή 0x1F στον Ι/Ο καταχωρητή PORTA και αυτό έχει σαν αποτέλεσμα να θέσει τους αντίστοιχους ακροδέκτες της θύρας Α σε κατάσταση ON ή OFF. Στην περίπτωση που έχουμε συνδέσει LED στις εξόδους, αυτά ανάβουν ή είναι σβηστά ανάλογα με τις αντίστοιχες τιμές των bits της PORTA.
Η έκτη γραμμή είναι ένας ατέρμων βρόγχος που προκαλεί τον μικροελεγκτή να σταματήσει εκεί για πάντα.
Σημείωση: τα κενά διαστήματα, οι χαρακτήρες στηλοθέτη (tab) και οι αλλαγές γραμμής δεν λαμβάνονται υπόψη από τον μεταγλωττιστή της C. Έτσι το προηγούμενο πρόγραμμα θα μπορούσε να γραφεί ισοδύναμα ως εξής:
#include <avr\io.h >
void main ( void) {
DDRA=0xFF;
PORTA= 0x1F;
while ( 1);
}
Παρά την άνω ελευθερία γραφής, θα πρέπει να υιοθετήσουμε κανόνες γραφής που κάνουν τα προγράμματα μας πιο ευανάγνωστα και κατανοητά.
Χρήση σχολίων
Ένα σωστά γραμμένο πρόγραμμα θα πρέπει να συμπεριλαμβάνει τη χρήση σχολίων μέσα στον κώδικα, με σκοπό να τον κάνει πιο ευανάγνωστο και κατανοητό. Τα σχόλια μπορούν να περιλαμβάνουν οποιοδήποτε μήνυμα και αρχίζουν με το ζεύγος χαρακτήρων /* και τελειώνουν με το ζεύγος χαρακτήρων */. Ένα παράδειγμα χρήσης σχολείων είναι το ακόλουθο:
/* Το πρώτο μου πρόγραμμα
1 Δεκεμβρίου 2024 */
#include <avr\io.h> /*συμπερίληψη βιβλιοθήκης*/
void main(void)
{
DDRA=0xFF; /* θέτει όλους τους ακροδέκτες της θύρας Α σε κατάσταση εξόδου*/
PORTA=0x1F; /* θέτει τα πινς 0,1,2,3,4 σε κατάσταση ΟΝ και τα υπόλοιπα σε OFF*/
while(1); /*ατέρμον βρόγχος*/
}
Στην τελευταία έκδοση της C εισάγεται μια νέα μορφή σχολείων, των σχολίων γραμμής, όπου τα σχόλια γραμμής ξεκινούν με δυο καθέτους // και τελειώνουν στο τέλος της γραμμής. Ακολουθεί ένα παράδειγμα:
// Το πρώτο μου πρόγραμμα
// 1 Δεκεμβρίου 2024
#include <avr\io.h> //συμπερίληψη βιβλιοθήκης
void main(void)
{
DDRA=0xFF; // θέτει όλους τους ακροδέκτες της θύρας Α σε κατάσταση εξόδου
PORTA=0x1F;// θέτει τα πινς 0,1,2,3,4 σε κατάσταση ΟΝ και τα υπόλοιπα σε OFF
while(1); //ατέρμον βρόγχος
}
Η έννοια της μεταβλητής
Μια μεταβλητή είναι ένα «κελί» στη θέση μνήμης, που έχει ένα όνομα και κρατά μια τιμή. Πριν χρησιμοποιηθεί μια οποιαδήποτε μεταβλητή, πρέπει πρώτα να δηλωθεί. Στην πρόταση της δήλωσης ενημερώνουμε τον μεταγλωττιστή της C για το όνομα και τον τύπο της μεταβλητής. Ο τύπος μιας μεταβλητής ορίζει πως η CPU θα χειριστεί την μεταβλητή.
Οι βασικοί τύποι μεταβλητών της C είναι τέσσερις:
char Μεταβλητή χαρακτήρα. Για αποθήκευση ενός χαρακτήρα.
int Ακέραια μεταβλητή. Για αποθήκευση ενός ακέραιου αριθμού.
float Μεταβλητή πραγματικού αριθμού. Για αποθήκευση ενός πραγματικού αριθμού κινητής υποδιαστολής.
double Μεταβλητή πραγματικού αριθμού διπλής ακριβείας. Για την αποθήκευση πραγματικού αριθμού κινητής υποδιαστολής, με μεγαλύτερη ακρίβεια στα δεκαδικά ψηφία.
Για παράδειγμα στο ακόλουθο παράδειγμα κώδικα, δηλώνονται τέσσερις μεταβλητές με ονόματα a, b, c,d και m
#include <avr\io.h>
void main(void)
{
char a; // Μεταβλητή τύπου χαρακτήρα
int b, c; // Μεταβλητή τύπου ακεραίου
float n; // Μεταβλητή τύπου πραγματικού αριθμού
double m; // Μεταβλητή τύπου πραγματικού αριθμού διπλής ακριβείας
}
Κατά τη δήλωση μιας μεταβλητής, γίνεται ταυτόχρονα δέσμευση του ανάλογου χώρου μνήμης. Για παράδειγμα η πρόταση:
int b;
Αναγκάζει τον μεταγλωττιστή να δεσμεύσει τον κατάλληλο αποθηκευτικό χώρο, που σε αυτή την περίπτωση δεσμεύει χώρο για ένα ακέραιο αριθμό και να του δίνει το όνομα b.
Τα ονόματα των μεταβλητών καθώς και άλλων οντοτήτων της C όπως συναρτήσεις, δομές κ.ά. λέγονται αναγνωριστικά και θα πρέπει να ακολουθούν συγκεκριμένους κανόνες: Τα ονόματα τους θα πρέπει να αποτελούνται από χαρακτήρες, αριθμούς και τον χαρακτήρα υπογράμμισης «_» και ο πρώτος χαρακτήρας του αναγνωριστικού θα πρέπει να είναι γράμμα.
Στη γλώσσα C γίνεται διάκριση πεζών και κεφαλαίων. Για παράδειγμα η μεταβλητή cat είναι διαφορετική από την Cat. Επίσης, όλες οι εντολές και συναρτήσεις βιβλιοθήκης της C γράφονται με πεζούς χαρακτήρες.
Ανάθεση τιμής σε μεταβλητή
Μπορούμε να αναθέσουμε μια τιμή σε μεταβλητή χρησιμοποιώντας τον τελεστή ανάθεσης ίσον (=)
int a;
char c;
float d;
a=5;
c=’B’;
d=35.25;
Στις τελευταίες γραμμές του παραπάνω κώδικα, ο τελεστής = καταχωρίζει την τιμή που υπάρχει στα δεξιά του, στη μεταβλητή που υπάρχει στα αριστερά του.
Αρχικές τιμές μεταβλητών
Στην πρόταση δήλωσης μιας μεταβλητής, μπορούμε να της αναθέσουμε ταυτόχρονα μια τιμή. Π.χ.
int a=10, b;
float d=2.65, k;
char c=’G’;
Εδώ δηλώνουμε τις μεταβλητές a, b, d, k και c με τους αντίστοιχους τύπους, ενώ αποδίδουμε αρχικές τιμές στις a, d και c τις τιμές 10, 2.65 και ‘J’ αντίστοιχα.
Μεταβλητές μόνο για ανάγνωση
Στη γλώσσα C έχουμε την δυνατότητα να δηλώνουμε μια μεταβλητή και να της δίνουμε αρχική τιμή, χωρίς να μπορούμε στην συνέχεια να αλλάζουμε το περιεχόμενο της. Μια τέτοια μεταβλητή δηλώνεται όπως και οι υπόλοιπες αλλά προσθέτουμε μπροστά από τον τύπο της το προσδιοριστικό const Π.χ.
const int m=10;
const float d = 9.25;
Στις παραπάνω προτάσεις δηλώνουμε δυο μεταβλητές μόνο για ανάγνωση και συγκεκριμένα τις m και d τύπου int και float με αρχικές τιμές 10 και 9.25 αντίστοιχα. Σε αυτές τις μεταβλητές δεν μπορούμε να αναθέσουμε αργότερα άλλες τιμές. Σημείωση: όταν δηλώνουμε μια μεταβλητή const (μόνο για ανάγνωση) πρέπει απαραιτήτως να της δίνουμε αρχική τιμή.
Σταθερές
Η σταθερά είναι μια τιμή όπως ένας αριθμός ή χαρακτήρας με την ιδιότητα ότι δεν μεταβάλλεται κατά την διάρκεια εκτέλεσης του κώδικα. Μια σταθερά έχει τύπο όπως char, int, float ή double. Για παράδειγμα, π.χ οι αριθμοί 9, -25, -1 είναι σταθερές τύπου int, ενώ π.χ. οι 23.78, 6.01 είναι τύπου double ενώ σταθερά χαρακτήρα είναι ένας χαρακτήρας μέσα σε μονά εισαγωγικά, π.χ ‘Β’
Δυαδικοί τελεστές
Η γλώσσα C μας επιτρέπει να χειριζόμαστε τις πληροφορίες σε επίπεδο bit. Αυτές οι πράξεις γίνονται με τους δυαδικούς τελεστές πάνω σε ακεραίους γραμμένους σε δυαδική μορφή. Όλοι οι δυαδικοί τελεστές (bitwise) εκτός από τον τελεστή ~ έχουν δυο μέλη, ένα αριστερό και ένα δεξιό. Τα μέλη αυτά πρέπει να είναι ακέραιες παραστάσεις, δηλαδή να αποδίδουν ακέραιες τιμές.
& (bitwise AND) Εκτελεί την πράξη AND στα αντίστοιχα bit των δυο μελών.
0&0 → 0
0&1 → 0
1&0 → 0
1&1 → 1
Παράδειγμα:
179 & 153 → 145 10110011
& 10011001
--------
10010001
| (bitwise OR) Εκτελεί την πράξη OR στα αντίστοιχα bit των δυο μελών.
0|0 → 0
0|1 → 1
1|0 → 1
1|1 → 1
Παράδειγμα:
179 | 153 → 187 10110011
| 10011001
--------
10111011
^ (bitwise XOR) Εκτελεί την πράξη XOR στα αντίστοιχα bit των δυο μελών. Το αποτέλεσμα είναι 1 όταν μόνο ένα από τα δυο μέλη έχει τιμή 1, σε κάθε άλλη περίπτωση το αποτέλεσμα είναι 0.
0^0 → 0
0^1 → 1
1^0 → 1
1^1 → 1
Παράδειγμα:
179 ^ 153 → 42 10110011
^ 10011001
--------
00101010
~ (συμπλήρωμα)
Αντιστρέφει τα bit του μέλους.
~0 → 1
~1 → 0
Παράδειγμα
~179 = 76 ~10110011 = 01001100
Τελεστές ολίσθησης “<<” και “>>”
<< (ολίσθηση αριστερά) μέλος-Α << μέλος-Β Μετακινεί προς τα αριστερά όλα τα bit του μέλους – Α τόσες θέσεις όση η τιμή του μέλους – Β. Σε κάθε μετατόπιση προς τα αριστερά το αριστερότερο bit χάνεται και το δεξιότερο bit παίρνει την τιμή 0.
>> (ολίσθηση δεξιά) μέλος-Α >> μέλος-Β Μετακινεί προς τα δεξιά όλα τα bit του μέλους – Α τόσες θέσεις όση η τιμή του μέλους – Β. Σε κάθε μετατόπιση προς τα δεξιά το δεξιότερο bit χάνεται και το αριστερότερο bit παίρνει την τιμή 0.