#include <main-proteus.h>
#byte PORTB         =0xF81 //Ορισμός των θυρών με την θέση τους στην μνήμη.
#byte PORTC         =0xF82
#byte PORTD         =0xF83
//Δηλώσεις μεταβλητών
int8  des=0;       //Μεταβλητή που χρησιμοποιείται από την πόρτα C για να ενεργοποιεί
      // έναν κάθε φορά από τους ενδείκτες 1, 2, 3 αποστέλλοντας με την σειρά λογικό 1
      // στις βάσεις των τρανζίστορ που συνδέουν τις καθόδους των τριών ενδεικτών 
      // προς την γη.

int16 tenthseconds,tenthseconds_stop=0; //Με την μεταβλητή tenthseconds μετράμε δέκατα 
                  //του δευτερολέπτου.
                // Την μεταβλητή tenthseconds_stop την χρησιμοποιούμε για
                // να αποθηκεύσουμε την τιμή του χρόνου όταν ο 
                //ακροδέκτης RD0 μεταβεί από 0 σε 1.
int8 counter;      // μεταβλητή για να μετράμε 20 διακοπές που συμβαίνουν κάθε 5 ms
         //κάθε 20 διακοπές έχει περάσει ένα δέκατο του δευτερολέπτου(=100 ms)
int1 start=0;       // Η μεταβλητή start γίνεται 1 όταν ξεκινήσει ο μετρητής και παραμένει για πάντα 1
int1 stop=0;       // Η μεταβλητή stop παίρνει την τιμή 1 όταν γίνει RD0=1
                 // Τότε σταματάει να μεταφέρεται η τρέχουσα τιμή του μετρητή στους ενδείκτες.
                 // Οι ενδείκτες για stop =1 εμφανίζουν την τιμή κατά την στιγμή 
                //μετάβασης του RD0 από 0 σε 1. Δηλαδή όταν stop=1 "παγώνουν" οι ενδείκτες.
int8 table[16] ={ 0b00111111,   //Πίνακας με του κώδικες για εμφάνιση σε ενδείκτη 7 τομέων
                        0b00000110,   //των ψηφίων 0, 1, 2, … 9, … F.
                             0b01011011, 
                             0b01001111, 
                             0b01100110, 
                             0b01101101, 
                             0b01111101, 
                             0b00000111, 
                             0b01111111, 
                             0b01101111, 
                             0b01110111, 
                             0b01111100, 
                             0b00111001, 
                             0b01011110, 
                             0b01111001, 
                             0b01110001};  
int8 dig[3] = {1,2,4}; // πίνακας με τις τιμές  0000 0001, 0000 0010, 0000 0100 για ενεργοποίηση
             // από τους ακροδέκτες της πόρτας C με την σειρά ενός κάθε φορά από 
            // τους τρεις ενδείκτες κοινής καθόδου. Εφαρμόζονται 5 V στην βάση του 
            //αντίστοιχου τρανζίστορ και αυτό έρχεται στον κόρο συνδέοντας την κοινή
            //κάθοδο του ενδείκτη προς την γη.
// Δήλωση συναρτήσεων
void timer0_int(void);
void init (void);
// Κύρια συνάρτηση
void main()
{
      init();  //ρουτίνα αρχικοποίησης με αρχικές τιμές
   
     while (TRUE){    
   if ((INPUT(PIN_D0)==0) && (start==0)){   //Αυτή η συνθήκη ισχύει στο ξεκίνημα όταν RD0=0
                  // και start=0
   start=1;                  // Στο ξεκίνημα γίνετα start=1 και δεν αλλάζει ποτέ.
         }
   else if(start == 1 && INPUT(PIN_D0) == 1){             //Αυτό συμβαίνει όταν γίνει RD0=1
                    stop = 1; // Αν η μεταβλητή stop είναι 1 
                                  // οι ενδείκτες δεν εμφανίζουν 
                      // την τρέχουσα τιμή χρόνου αλλά
                     // εμφανίζουν την τιμή χρόνου κατά την                     // προηγούμενη στιγμή μετάβασης
                     // του ακροδέκτη RD0 από 0 σε 1
                  }
                  else {         //Αυτό συμβαίνει όταν RD0=0
                     stop = 0;  //Οι ενδείκτες εμφανίζουν την
                           // τρέχουσα τιμή χρόνου. 
                                }         
      }     //κλείνει η while
}           //κλείνει η main
// Ορισμός συναρτήσεων 
#INT_TIMER0 HIGH   // Διακοπή με μεγάλη προτεραιότητα από τον Timer0
void timer0_int(void){
      int16 mon,dec,eka;  // Μεταβλητές για αποθήκευση μονάδων, δεκάδων, εκατοντάδων
      counter--; // Κάθε 20 * 5 msec  = 0,1 sec 
            // Διακοπές συμβαίνουν κάθε 5 ms. O counter παίρνει την αρχική τιμή 20
           // Κάθε 20 διακοπές έχουν περάσει 20Χ5ms=100ms=0,1 s.
      if (counter == 0){  // κάθε φορά που μηδενίζεται ο counter έχουν περάσει 0,1 s
            if (start == 1){ //Αν τρέχει ο μετρητής 
            tenthseconds++; // αυξάνεται  κατά 1 κάθε 0,1 sec(=20 διακοπές)
                                       }
            counter = 20; //αν γίνουν 20 διακοπές, δηλαδή counter=0
                         //ο μετρητής διακοπών ξαναπαίρνει την τιμή 20
            if (tenthseconds > 999){              // Ο μετρητής μετά την τιμή 999
                     tenthseconds = 0;  // ξαναπαίρνει την τιμή 0.
                              }              
            }
      if (stop == 0){                        
                   tenthseconds_stop = tenthseconds;   // Όταν είναι stop=0(δηλαδή RD0=0)    
                            //αποθηκεύεται συνεχώς η τρέχουσα
                            //τιμή του μετρητή στην
                            // μεταβλητή seconds_stop. 
                           // Η ένδειξη του μετρητή θα τρέχει
                            // Όταν γίνει stop=1(δηλαδή RD0=1) η μεταβλητή 
                            //tenthseconds κρατάει σταθερά την τιμή 
                                       //που είχε κατά την στιγμή της μετάβασης
                           //του ακροδέκτη RD0 από 0 σε 1
                           // Επομένως όταν RD0=1 η ένδειξη θα παραμένει
                           // παγωμένη(σταθερή)
                  }               
          eka = (int8) (tenthseconds_stop /100);    //Υπολογισμός των εκατοντάδων του μετρητή
          dec = (int8) ((tenthseconds_stop - (100*eka))/10); //Υπολογισμός των δεκάδων του
                           // μετρητή
          mon = (int8) (tenthseconds_stop - (100 * eka) -(10 * dec)); //Υπολογισμός των μονάδων 
                                           // του μετρητή
          set_timer0(5536); // Αρχική τιμή του timer0 για να έχουμε διακοπές κάθε 5 ms
         des = ++des%3;  //Μεταβλητή des παίρνει τις τιμές 0, 1, 2, 0, 1, 2 ,0, 1, 2,…
            //%3 σημαίνει modulo 3(υπόλοιπο διαίρεσης με το 3)
      PORTC = dig[des]; //Η πόρτα C παίρνει τιμές 0000 0001, 0000 0010, 0000 0100,…
               // δηλαδή τις τιμές 1, 2, 4, 1, 2, 4 ,… από τον πίνακα dig 
             //Η πόρτα C επιλέγει σε ποιος ενδείκτης θα ανάψει.
// Εμφάνιση μονάδων, δεκάδων, εκατοντάδων στους ενδείκτες
      if (des==0){                                //PORTC=0000 0001(=dig[0]), επιλογή ενδείκτη μονάδων
         PORTB = table[mon]; //Αν des=0 ενεργοποιείται ο ενδείκτης των μονάδων
                        //PORTC=0000 0001(=dig[0])
                       }         
      if (des==1){                         //PORTC=0000 0010(=dig[1]), επιλογή ενδείκτη δεκάδων
         PORTB = table[dec]; //Αν des=1 ενεργοποιείται ο ενδείκτης των δεκάδων
                                                }            
      if (des==2){                         //PORTC=0000 0010(=dig[2]), επιλογή ενδείκτη εκατοντάδων
         PORTB = table[eka]; //Αν des=2 ενεργοποιείται ο ενδείκτης των εκατοντάδων
                      //PORTC=0000 0100(=dig[2])
         }               
}                     
// Συνάρτηση αρχικοποίησης
void init (void){
   set_tris_b(0x00);        // Καθορισμός της πόρτας Β ως έξοδος
    set_tris_c(0x00);        // Καθορισμός της πόρτας C ως έξοδος
    set_tris_d(0x0f);        // Καθορισμός της πόρτας C ως έξοδος
    PORTB = 0;           //Αρχική τιμή πόρτας Β
    PORTC = 0;          // Αρχική τιμή πόρτας C
    counter = 20;          // Αρχική τιμή του counter
    tenthseconds = 0;    //Αρχική τιμή μετρητή δεκάτων δευτερολέπτου
    tenthseconds_stop = 0; //Αρχική τιμή της μεταβλητής tenthseconds_stop
    start=0; //κατά την εκκίνηση start=0. Στην συνέχεια γίνεται 1 και παραμένει πάντα 1
    stop=0; //αρχική τιμή μεταβλητής stop=0, δηλαδή ο μετρητής εμφανίζεται στους ενδείκτες.
    des =0; //αρχική τιμή μεταβλητής που χρησιμοποιείται για επιλογή ενδείκτη από την θύρα C
   SETUP_TIMER_0(T0_INTERNAL | T0_DIV_1 ); //Ρύθμιση prescaler=1
   set_timer0(5536);                             //  Αρχική τιμή του  timer για διακοπές κάθε 5 ms
          enable_interrupts(INT_TIMER0);  // Ενεργοποίηση της διακοπής του timer0
          enable_interrupts(GLOBAL);         // Ενεργοποίηση του γενικού                                           // διακόπτη των διακοπών
            
      }         // κλείνει η αγκύλη της init()

