Τίτλος προγράμματος
;*********************************************************************
; *
; The Countdown timer processing *
; *
;Author : Seiichi Inoue Ελληνική απόδοση : Παναγιώτης Πανταζόπουλος *
;*********************************************************************
Ψευδοεντολές LIST &
INCLUDE
list p=pic16f84a
include p16f84a.inc
Ο τύπος του μικροεπεξεργαστή δηλώνεται με την
ψευδοεντολή List.
Με το αρχείο p16f84a.inc
και με την ψευδοεντολή Include, εισάγονται στον κώδικα σας έτοιμες
αντιστοιχίες ονομάτων με καταχωρητές, κ.λ.π Εάν
χρησιμοποιείτε το include αρχείο της Microchip, κατά την μεταγλώττιση
θα σας εμφανίζεται ένα μήνυμα προειδοποίησης σχετικά με τους
καταχωρητές TRISA και TRISB. Για να αποφύγετε την εμφάνιση του
μηνύματος αυτού μπορείτε να κάνετε την παρακάτω τροποποίηση.
Τα include αρχεία συνήθως βρίσκονται στον
κατάλογο:
c:\Program
Files\Mplab\p16f84a.inc
; P16F84A.INC Standard Header File, Version 2.00'(Διόρθωση)
TRISA EQU H'0085' -> H'0005'
TRISB EQU H'0086' -> H'0006'
Μπορείτε επίσης να χρησιμοποιήσετε την
ψευδοεντολή ERRORLEVEL για να απενεργοποιήσετε την
εμφάνιση του μηνύματος.
Διαμόρφωση μικροεπεξεργαστή
Με το Configuration
Word
ενημερώνεται
ο
Assembler για τις
ρυθμίσεις των ‘σημαιών’ διαμόρφωσης του μικροεπεξεργαστή όπως, αν θα
χρονίζει με κρύσταλλο, αν θα ενεργοποιήσουμε το Watchdog
timer, αν θα
προστατεύσει το πρόγραμμα από αντιγραφή κ.λ.π .
__config _hs_osc & _wdt_off & _pwrte_on & _cp_off
Το Configuration Word μπορείτε να το δηλώσετε μέσα από
το λογισμικό της συσκευής προγραμματισμού, ή να δηλωθεί αυτόματα
χρησιμοποιώντας την ψευδοεντολή CONFIG.
Παρατηρήστε πώς υπάρχουν δύο underscore (Κάτω παύλες),
πριν από την ψευδοεντολή.
Ορισμός ονομάτων
(Ετικετών)
;**************** Label Definition ********************
Σε αυτό
το σημείο ‘βαφτίζουμε’ τους ελεύθερους προς χρήση καταχωρητές του
μικροεπεξεργαστή και ότι άλλο χρειαζόμαστε, με ονόματα που θα μπορούμε
να θυμόμαστε κατά την διάρκεια γραφής του προγράμματος
.
Η κατάσταση κάθε τμήματος των
Display για την απεικόνιση των αριθμών ορίζεται με της ψευδοεντολές
EQU.
Στον πίνακα που ακολουθεί φαίνεται η
κατάσταση των τμημάτων για κάθε αριθμό.
|
|
'0' : Αναμμένο, '1' :
Σβησμένο. |
 |
 Επάνω
όψη |
|
a |
b |
c |
d |
e |
f |
g |
| 0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
| 1 |
1 |
0 |
0 |
1 |
1 |
1 |
1 |
| 2 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
| 3 |
0 |
0 |
0 |
0 |
1 |
1 |
0 |
| 4 |
1 |
0 |
0 |
1 |
1 |
0 |
0 |
| 5 |
0 |
1 |
0 |
0 |
1 |
0 |
0 |
| 6 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
| 7 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
| 8 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
| 9 |
0 |
0 |
0 |
0 |
1 |
0 |
0 | |
Λειτουργία γρήγορης
εξομοίωσης
;************** Debugging mode setting ****************
;Για γρηγορότερη εξομοίωση το Ελληνικό ερωτηματικό, ";" της επόμενης εντολής πρέπει να διαγραφεί.
;#define _debug
Υπάρχει τρόπος με ένα κολπάκι κατά την μεταγλώττιση, να
παρακάμπτονται οι υπορουτίνες χρόνου, για πιο γρήγορο έλεγχο του
προγράμματος με την λειτουργία της εξομοίωσης. Με αυτό το 'κόλπο' οι
τιμές των μετρητών, κ.λ.π, ορίζονται έτσι ώστε ο εξομοιωτής να εκτελεί
τις υπορουτίνες χρόνου μόνο μία φορά. Στο παράδειγμα μας για να γίνει
αυτό χρησιμοποιείται η ετικέτα '_debug', και οι ψευδοεντολές
'#ifdef, #else, #endif και #ifndef. Για λεπτομέρειες, δηλαδή πώς
γίνεται, κάντε κλικ στο: "Εξομοίωση
χρονόμετρου".
Εκκίνηση
προγράμματος
;**************** Program Start ***********************
Μετά το
Power
on ο
μικροεπεξεργαστής αρχίζει να εκτελεί τις εντολές που έχει αποθηκευμένες
στην μνήμη του από την διεύθυνση μηδέν ‘Address
0’. Σε
περίπτωση που χρησιμοποιούμε Interrupts
η
εκτέλεση των εντολών αρχίζει από την διεύθυνση τέσσερα.
Λειτουργία
αρχικοποίησης
;**************** Initial Process *********************
Λειτουργία αναμονής χρονόμετρου (Timer
stand-by)
;************* Timer stand-by Process *****************
Λειτουργία εκκίνησης & αντίστροφης
μέτρησης του χρονόμετρου
;************** Timer start Process *******************
Η παρακάτω λειτουργία γίνεται όταν πατηθεί το μπουτόν
εκκίνησης και αρχίσει η αντίστροφη χρονομέτρηση.
Ενεργοποιείται το ρελέ και
ανάβει το LED ένδειξης του χρονόμετρου.
Ορίζονται τις τιμές των
μετρητών.
Για να υπάρχει ακρίβεια στη μέτρηση, πρέπει τα
νούμερα του χρονόμετρου να αλλάζουν ακριβώς κάθε
δευτερόλεπτο. Για τον υπολογισμό των τιμών που
πρέπει να έχουν οι μετρητές (TMR0, Prescaler & Multipliers),
ακολουθείστε την παρακάτω διαδικασία ή χρησιμοποιείστε το πρόγραμμα
Pic
Timer.
| Συχνότητα
ταλαντωτή |
: |
Για το παράδειγμα είναι 10-MHz |
| Τιμή προδιαιρέτη
(prescaler). |
: |
Ορίστηκε η τιμή 256. για να γίνεται μία αύξηση των
πολλαπλασιαστών κάθε 256 υπερχειλίσεις
(overflow interrupt) του TMR0 |
| Τιμή έναρξης TMR0 |
: |
Ορίστηκε η τιμή που δίνει την μικρότερη απόκλιση
κατά την μέτρηση του δευτερόλεπτου.( 213 αυξήσεις ) Η τιμή έναρξης του TMR0 βγαίναι από την αφαίρεση,
256-213=43. |
| Τιμή
πολλαπλασιαστών |
: |
Για την προσέγγιση του δευτερόλεπτου με το
μικρότερο σφάλμα πρέπει ο πολλαπλασιαστής να πάρει την τιμή
46. |

| Ο χρόνος για το δευτερόλεπτο υπολογίζεται με την
ακόλουθη διαδικασία.
(Εάν θέλετε απόλυτη ακρίβεια χρησιμοποιήστε
κρύσταλλο 3,2768MHz και τροποποιήστε ανάλογα τις ρουτίνες
χρόνου).
| Χρόνος |
= (4/συχνότητα ταλαντωτή) x προδιαιρέτη x
αυξήσεις TMR0 x φορές πολλαπλασιαστή |
|
= 0.4 x 10-6 x 256 x 217 x
45 |
|
= 0.999936
Δευτερόλεπτα |
Εάν
για παράδειγμα χρησιμοποιήσετε κρύσταλλο 4.19MHz και TMR0=186,
πολλαπλασιαστή=22, το αποτέλεσμα θα ήταν χρόνος ίσος με 1.000049642
δευτερόλεπτα. Για μέτρηση 99 λεπτών το σφάλμα
(απόκλιση) είναι -20 δευτερόλεπτα (το χρονόμετρο μηδενίζει πιο
γρήγορα). Ενώ για μέτρηση ενός δευτερόλεπτου η απόκλιση είναι
0.003367 δευτερόλεπτα.
Με τις τιμές, κρύσταλλο 10MHz, TMR0=213, και
πολλαπλασιαστή=46, το σφάλμα για μέτρηση 99 λεπτών είναι μόνο 1
δευτερόλεπτο.
| Χρόνος |
= (4/συχνότητα ταλαντωτή) x προδιαιρέτη x
αυξήσεις TMR0 x φορές παλλαπλασιαστή |
|
= 0.4 x 10-6 x 256 x 213 x
46 |
|
= 1.0033152
Δευτερόλεπτα |
Η τιμή εκκίνησης του χρονομετρητή (TMR0) είναι
εκείνη που βγαίνει από την αφαίρεση του αριθμού των αυξήσεων που
πρέπει να κάνει πρίν υπερχειλίσει, από το σταθερό αριθμό
256. 256-213=43(2Bh)
Για απόλυτο χρόνο ενός δευτερόλεπτου, πρέπει να
βάλετε κρύσταλλο 3,2768MHz, προδιαιρέτη=256, TMR0=200,
πολλαπλασιαστή=16
| Χρόνος |
= (4/συχνότητα ταλαντωτή)
x προδιαιρέτη x αυξήσεις TMR0 x φορές
παλλαπλασιαστή |
|
= 1.220703125 x
10-6 x 256 x 200 x 16 |
|
= 1,0000
Δευτερόλεπτα |
|
Απεικόνιση χρόνου
;************** LED Control Subroutine ****************
Ο χρόνος μετριέται με την βοήθεια καταχωρητών. Το
περιεχόμενο αυτών των καταχωρητών απεικονίζεται στα LED Display επτά
τμημάτων, με την εξής σειρά :
Δεκάδες λεπτών, Μονάδες λεπτών, : δεκάδες δευτερόλεπτων,
Μονάδες δευτερόλεπτων.
Μετατροπή BCD σε κώδικα επτά τμημάτων
(7 segment data)
;******* Change BCD to 7segment data Subroutine *******
Γίνεται μετατροπή των δυαδικά κωδικοποιημένων
δεκαδικών αριθμών, σε κώδικα επτά τμημάτων και απεικόνιση τους μέσο της
PORTB στα LED Display.
Υπορουτίνα χρόνου, 1 μιλισεκόντ
(millisecond)
;************* 1msec Timer Subroutine *****************
Όπως προαναφέρθηκε, η PORTB διαβάζει ή οδηγεί
περισσότερα από ένα υλικά, πχ. τους διακόπτες BCD, το μπουτόν εκκίνησης
(start), τα LED Display. Τα τρανζίστορ που χρησιμοποιούνται στο κύκλωμα
για να συνδέουν το κάθε υλικό με την PORTB, για να αλλάξουν κατάσταση
(από αγωγιμότητα σε αποκοπή και αντίστροφα), χρειάζονται κάποια
μικροσεκοντ (εξαρτάται από τα χαρακτηριστικά των τρανζίστορ). Με
χρονισμό 10MHz ο PIC εκτελεί κάθε εντολή σε 0,4μSec, συνεπώς για να
προλαβαίνουν τα τρανζίστορ να αλλάζουν κατάσταση πρέπει να υπάρχει και η
ανάλογη χρονική καθυστέρηση. Προσοχή χρειάζεται σε αυτό το σημείο γιατί
εάν ο χρόνος αυτός είναι μεγάλος τότε τα LED Display θα φαίνονται σαν να
τρεμοσβήνουν.
Στην περίπτωση του διαβάσματος
ενός υλικού, εκτελείται πρώτα η καθυστέρηση του ενός μιλισεκόντ (1mSec),
και μετά γίνεται η ανάγνωση της κατάστασης του υλικού που επιλέχτηκε.
Στην περίπτωση της οδήγησης, το υλικό οδηγείται μετά την
καθυστέρηση.
Εάν δεν συνδεσμολογήσετε το
κύκλωμα είναι πολύ δύσκολο να καταλάβετε με την χρήση του εξομοιωτή την
χρησιμότητα της καθυστέρησης του ενός μιλισεκόντ (1mSec). Επομένως ποτέ
μην ξεχνάτε πως πρέπει να υπολογίζεται και τον χρόνο ανταπόκρισης των
υλικών.
Λειτουργία διακοπής
(Interruption)
;************ Begin Interruption Process **************
Όταν υπάρξει διακοπή της ροής του προγράμματος,
η υπορουτίνα αυτή, αποθηκεύει τα περιεχόμενα των W και STATUS στους
καταχωρητές w_save , s_save και επιβεβαιώνει ότι έγινε η διακοπή
από υπερχείλιση του TMR0 με ανάγνωση του ψηφίου
TOIF.
Λειτουργία τερματισμού διακοπής
(Interruption)
;************ END of Interruption Process **************
Μόλις ολοκληρωθεί η ρουτίνα διακοπής (interruption), ο
μετρητής προγράμματος επιστρέφει και εκτελεί τον κώδικα από το σημείο
που είχε σταματήσει όταν συνέβη η διακοπή. Το περιεχόμενο του καταχωρητή STATUS επαναφέρεται πρώτα και μετά
του W.
Για την επαναφορά του W, πρέπει να ακολουθήσετε την εξής
διαδικασία:
Επειδή το περιεχόμενο του STATUS αλλάζει εάν επαναφέρετε
το W με την εντολή MOVF, η επαναφορά πρέπει να γίνει με την χρήση
της εντολής SWAPF, έτσι το περιεχόμενο που μόλις πριν επαναφέρθηκε στον
STATUS παραμένει αναλλοίωτο. Παρατηρήστε πώς για την επαναφορά του W η
εντολή SWAPF χρησιμοποιείται δύο φορές. Η ρουτίνα
κλείνει με την εντολή RETFIE, η οποία επαναφέρει το τον μετρητή
προγράμματος (Program counter) στο σημείο που ήταν πριν την διακοπή,
επίσης κάνει '1' (ενεργοποιεί) το ψηφίο GIE του καταχωρητή
INTCON.
Υπερχείλιση χρονομετρητή TMR0 (time
out)
;*********** Time-out interruption Process ************
Αυτή η ρουτίνα εκτελείται κάθε φορά που
υπερχειλίζει ο TMR0. Την μέτρηση του χρόνου κάθε
ένα δευτερόλεπτο κάνει ο χρονομετρητής TMR0, με μέγιστο χρόνο (για
χρονισμό 10MHz) δίχως πολλαπλασιαστές τα 26,214 mSec. Για να μετρηθεί λοιπόν ένα δευτερόλεπτο, μετριούνται οι
υπερχειλίσεις του TMR0.
Λειτουργία αντίστροφης μέτρησης
(Countdown)
;************* Timer Countdown Process ***************
Αυτή η ρουτίνα εκτελείτε κάθε
δευτερόλεπτο. Πρώτα ελέγχει τον μετρητή των
μονάδων των δευτερόλεπτων εάν είναι 0, στην περίπτωση που είναι
μηδέν, επειδή υπάρχει η πιθανότητα να έχει γίνει υπερχείλιση του TMR0,
άρα και διακοπή, ελέγχει όλους τους μετρητές για να δεί εάν έχουν
μηδενιστεί "Τέλος χρόνου". Για να καταλάβει ο PIC ότι ένας μετρητής έχει
μηδενίσει ή όχι, διαβάζει το περιεχόμενο του με την εντολή,
movf
και ελέγχει το ψηφίο
Z
bit του καταχωρητή STATUS. Εάν το ψηφίο Ζ (Zero) είναι σε
λογικό '1' το περιεχόμενο του μετρητή είναι μηδέν.
Κατά την εκτέλεση της αντίστροφης
μέτρησης, ελέγχονται τα περιεχόμενα των μετρητών και στην περίπτωση
που κάποιος γίνει μηδέν αμέσως επαναφέρεται με τον μέγιστο για αυτόν
αριθμό. Για παράδειγμα, ο μεγαλύτερος αριθμός για τον μετρητή των
δεκάδων των λεπτών, είναι το 5 ενώ για τον μετρητή των μονάδων των
λεπτών είναι το 9.
Τέλος
κώδικα
;********************************************************
; END of Count Down Timer processing
;********************************************************
end
Στο τέλος του κώδικα πάντα πρέπει να υπάρχει η
ψευδοεντολή END, προσέξτε εάν λείπει δεν θα γίνει η
μεταγλώττιση.

|