# Συζήτηση Κυκλωμάτων > Ψηφιακά Κυκλώματα > Μικροελεγκτές >  >  Χρονόμετρο σε μικροελενκτή PIC18F1320

## bxenos

Λόγω της περιορισμένης βιβλιογραφίας σε PIC18 σειρά μικροελενκτών στα ελληνικά, αποφάσισα να γράψω ένα παράδειγμα για τον μικροελενκτή PIC18F1320 με γλώσσα C.

Το παράδειγμα αφορά ένα χρονόμετρο με 6 οθόνες 7τμημάτων led και χρειάζεται ελαχιστά περιφερειακά εξαρτήματα.

Η γλώσσα στην οποία έχει γίνει το πρόγραμμα είναι η C.

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

Θα ήταν ισως χρήσιμο αν κάποιος ήθελε να γράψει το ίδιο προγραμμα για άλλον μικροελενκτη (π.χ. pic16f84a) με basic,c ή assembly ώστε να υπάρχει δυνατότητα για κάποιον που ξεκινά να επιλέξει με τι θελει να ασχοληθει.

To πρόγραμμα αποτελειται απο δυο αρχεια στην C:
το ένα το έχω ονομάσει 
IRQ.C και έχει το interrupt μετρησης δευτερολεπτων, τα fuses και τις αρχικές παραμετροποιησεις ακιδων, register και μεταβλητών προγράμματος
Το δεύτερο είναι το MAIN.C που έχει τον κώδικα του χρονομέτρου και την αποτύπωση στις οθόνες.

Για να κάνεται compile πρέπει να έχετε MPLAB και MCC18 (download δωρεάν απο Microchip). Δημιουργείτε νεό project για τον PIC18F1320 και εισάγεται τα δυο αρχεια .C που δίνω και το 18F1320.LKR (απο τον φάκελο \MCC18\LKR).

Παρακαλώ αν κάποιος έχει να αναφέρει ή να ρωτήσει κάτι, να μην κάνει QUOTE και τον κώδικα των αρχειων και έχουμε "σεντονια" ολόκληρα σε quote.




```
//clock: main.c

/*
	ρολόι με 6 οθόνες led 7 τμημάτων κοινής ανόδου
	μικροελενκτης: pic18f1320
	γλώσσα προγραμματισμού: C
	κρυσταλλος: δεν χρησιμοποιειται
	άλλα υλικά: 
			πυκνωτές για decoupling 22μF/16V και 100nF στην τροφοδοσία του μικροελενκτη
			αντιστάσεις συνδεσης ακίδων μικροελενκτή με A,B,C,D,E,F,G,DP οθόνων 8 * 150Ωμ
			6 τρανζίστορ bc547 για σύνδεση των ανόδων των οθονών 
	συνδεσμολογία:
	ολες οι οθόνες έχουν συνδεδεμένα τα τμήματα
		 	A στην ακίδα 	RB7 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			Β		RB6 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			C		RB0 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			D		RB4 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			E		RB5 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			F		RB2 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			G		RB3 του μικροελενκτη μέσω αντιστασης 150 Ωμ
			DP		RB1 του μικροελενκτη μέσω αντιστασης 150 Ωμ
	τα τρανζιστορ συνδεονται ως εξης:
			όλοι οι εκπομποί στα +5V,
			συλλέκτης ενός τρανζίστορ στην άνοδο της 1ης οθόνης και βάση στο RA7
			συλλέκτης ενός τρανζίστορ στην άνοδο της 2ης οθόνης και βάση στο RA6
			συλλέκτης ενός τρανζίστορ στην άνοδο της 3ης οθόνης και βάση στο RA0
			συλλέκτης ενός τρανζίστορ στην άνοδο της 4ης οθόνης και βάση στο RA1
			συλλέκτης ενός τρανζίστορ στην άνοδο της 5ης οθόνης και βάση στο RA2
			συλλέκτης ενός τρανζίστορ στην άνοδο της 6ης οθόνης και βάση στο RA3

	σημειώσεις:
		αυτό το προγραμμα αποτελεί ένα απλο παράδειγμα χρήσης 6 οθόνων 7 τμημάτων (led)
        για χρονόμετρο (μετρά ωρες,λεπτα,δευτερόλεπτα). 
	Χρησιμοποιεί τον εσωτερικό κρύσταλλο του μικροελενκτη και χρειάζεται ελάχιστα εξωτερικά εξαρτήματα.
	Δεν εκμεταλεύεται πληρως την φωτεινότητα των οθονών, ώστε να μην υπερφορτώσει τις ακίδες της PORTB.

        άσκηση (προγραμματισμου) 1: να γίνει μετατροπή στον κώδικα, για να 
					μετρά λεπτα,δευτερολεπτα,εκατοστα στις οθόνες
	άσκηση (ηλεκτρονικών) 2: να τροποποιηθεί το κύκλωμα (και το software αν απαιτείται) 
					ώστε να εκμεταλέυεται την μέγιστη φωτεινότητα των
					οθονών
*/

#include <p18f1320.h>
#include <delays.h>

#define A	PORTBbits.RB7
#define B	PORTBbits.RB6
#define C	PORTBbits.RB0
#define D	PORTBbits.RB4
#define E	PORTBbits.RB5
#define F	PORTBbits.RB2
#define G	PORTBbits.RB3
#define DP	PORTBbits.RB1

#define LED0	PORTAbits.RA7
#define LED1	PORTAbits.RA6
#define LED2	PORTAbits.RA0
#define LED3	PORTAbits.RA1
#define LED4	PORTAbits.RA2
#define LED5	PORTAbits.RA3

extern unsigned char sec_count;	//ορισμένο στο irq.c
void init(void);		//ορισμένο στο irq.c

unsigned char h,m,s;

void inc_hour(void){
	h++;
	if(h >= 24){
		h = 0;
	}
}

void inc_min(void){
	m++;
	if(m >= 60){
		m = 0;
		inc_hour();
	}
}

void inc_sec(void){
	s++;
	if(s >= 60){
		s = 0;
		inc_min();
	}
}

void show_digit(int digitNo,int num){
//digitNo = 0 το πρωτο αριστερα, 1 το δευτερο,... 5 το τελευταιο δεξια
	//ενεργοποιησε το τρανζιστορ της οθονης

	//πρωτα απενεργοποιησε ολα τα τρανζιστορ για να μην
	//τυπωσουμε κατα λαθος σε δυο οθονες
	LED0 = LED1 = LED2 = LED3 = LED4 = LED5 = 1;

	//σβησε και τις παυλιτσες
	A = B = C = D = E = F = G = DP = 1;

	//και αμέσως μετα ενεργοποιησε την οθονη που θελουμε
	switch(digitNo){
		case 0:
			LED0 = 0;
			break;
		case 1:
			LED1 = 0;
			break;
		case 2:
			LED2 = 0;
			break;
		case 3:
			LED3 = 0;
			break;
		case 4:
			LED4 = 0;	
			break;
		case 5:
			LED5 = 0;
	}

	//ενεργοποιουμε και τις παυλίτσες που θέλουμε
	switch(num){
		case 0:
			A = B = C = D = E = F = 0;
			break;
		case 1:
			B = C = 0;
			break;
		case 2:
			A = B = G = E = D = 0;
			break;
		case 3:
			A = B = C = D = G = 0;
			break;
		case 4:
			F = B = G = C = 0;
			break;
		case 5:
			A = F = G = C = D = 0;
			break;
		case 6:
			A = F = E = D = C = G = 0;
			break;
		case 7:
			A = B = C = 0;
			break;
		case 8:
			A = B = C = D = E = F = G = 0;
			break;
		case 9:
                	G = F = A = B = C = D = 0;
			break;
	}
	{
		//περιμενε λίγο με αναμενη την οθόνη
		ClrWdt();
		Delay100TCYx(20);
	}
}

void show_time(void){
	show_digit(0, h / 10);
	show_digit(1, h % 10);

	show_digit(2, m / 10);
	show_digit(3, m % 10);

	show_digit(4, s / 10);
	show_digit(5, s % 10);
}

void main(void){
	init();	//tmr0,uart,i/o init

	h = m = s = 0;

	while(1)
	{
		//περίμενε 1 δευτερολεπτο
		if(sec_count > 0){			
			sec_count--;
			//αυξησε ένα δευτερολεπτο
			inc_sec();
		}	

		//εμφάνισε την ώρα
		show_time();

		//καθυσηχασε τσοπανοσκυλο
		ClrWdt();
	}
}
```





```
//@(#)irq.c

#include <p18f1320.h>

//Oscillator Selection bits:
#pragma config OSC 	= INTIO2
#pragma config FSCM 	= ON	//OFF
#pragma	config IESO 	= OFF
#pragma config PWRT 	= ON
#pragma config BOR 	= ON
#pragma config BORV 	= 42	//brown out protect at 4,2V
#pragma config WDT 	= ON	//WatchDog timer on
#pragma config WDTPS 	= 64	//long WDT period
#pragma config MCLRE 	= OFF
#pragma config STVR 	= OFF
#pragma	config LVP	= OFF
#pragma config CP0 	= ON
#pragma config CP1 	= ON
#pragma config CPB 	= ON
#pragma config CPD 	= OFF
#pragma config WRT0	= OFF
#pragma config WRT1 	= OFF
#pragma config WRTB 	= OFF
#pragma config WRTC 	= OFF
#pragma config WRTD 	= OFF
#pragma	config DEBUG 	= OFF
#pragma config EBTR0	= OFF
#pragma config EBTR1	= OFF
#pragma config EBTRB	= OFF

static unsigned	t0c1;

unsigned char	sec_count,
		msec_count;


void low_isr_handler(void);
void high_isr_handler(void);

#pragma code low_vector=0x18
void interrupt_at_low_vector(void){
	_asm goto low_isr_handler _endasm
}

#pragma code high_vector=0x08
void interrupt_at_high_vector(void){
	_asm goto high_isr_handler _endasm
}

#pragma interruptlow low_isr_handler
#pragma interruptlow high_isr_handler
#pragma code /* return to the default code section */

void high_isr_handler(void){//HighInt:	;handles tmr0
	if(INTCONbits.TMR0IF){
		msec_count++;
		TMR0H = (0xffff-2000) / 256u;
		TMR0L = 0x0f + ((0xffff-2000u) % 256) + 2;
		if(++t0c1 == 1000u){
			t0c1 = 0;
			sec_count++;
		}
		INTCONbits.TMR0IF = 0;
	}
}

void low_isr_handler(void){
}

void init(void){
	ClrWdt();
	//osc config
	OSCCONbits.IDLEN 	= 0;
	OSCCONbits.IRCF2 	= 1;//8Mhz internal
	OSCCONbits.IRCF1	= 1;
	OSCCONbits.IRCF0	= 1;
	
	RCONbits.IPEN		= 1;//enable priorities in irq

	//tmr0 config
	T0CONbits.TMR0ON	= 1;//start timer0
	T0CONbits.T08BIT	= 0;//16 bit timer
	T0CONbits.T0CS		= 0;//instruction counter
	T0CONbits.PSA		= 1;//prescaler not allow
	T0CONbits.T0PS0		= 1;//prescaler
	T0CONbits.T0PS1		= 0;//1:4
	T0CONbits.T0PS2		= 0;
	
	INTCON2bits.TMR0IP	= 1;	//tmr0 high priority
	INTCONbits.TMR0IE	= 1;	//enable timer 0 interrupt
	
	//other inits
	ADCON1			= 0x7f;	//all pins dig io
	
	INTCON2bits.NOT_RBPU	= 0;	//port b pulls ups enable
	TRISB 			= 0x00;	//all outputs
	TRISA 			= 0x00;	//all outputs (except MCLR pin)

	//vars init
	t0c1 			= 0;
	sec_count = msec_count	= 0;
	
	//enable interrupts (high and low priority)
	INTCONbits.GIEH		= 1;
	INTCONbits.GIEL		= 1;
}
```

----------


## fmav

Το πρόβλημα με τη C είναι ότι δεν μπορείς να γνωρίζεις πως και κυρίως με πόσες εντολές θα μεταφραστεί ένα κομμάτι κώδικα. Αυτό σε εφαρμογές χρονισμού είναι κρίσιμο.
Προγραμματίζεται ο timer να δίνει interrupt μετά από 1msec για παράδειγμα. Όταν περάσει το 1 msec μπαίνει στη ρουτίνα interrupt και ξαναρυθμίζει τον timer ξανά στο 1msec. Όμως αν δεν ληφθεί υπόψη ο χρόνος που πέρασε από την στιγμή που ενεργοποιήθηκε ο interrupt μέχρι τη στιγμή που θα ξαναρχικοποιηθεί ο timer, τότε μεταξύ δύο interrupts δεν θα έχουμε ακριβώς ένα msec, αλλά κάτι παραπάνω. Σε assembly αυτός ο χρόνος μπορεί να υπολογιστεί (μετράμε τους κύκλους εντολής και τους αφαιρούμε από τη ρύθμιση του timer), όμως σε C αυτό δεν μπορεί να γίνει.

Από ό,τι πρόχειρα είδα στον κώδικά σου δεν λαμβάνεις υπόψη αυτόν το χρόνο. Άρα το ρολόι θα τρέχει λίγο πιο αργά, απ' όσο θα έπρεπε. 
Ο πιο σωστός τρόπος για μέτρηση χρόνου είναι με τη χρήση του capture/compare module που έχουν οι PIC.

----------


## bxenos

> Από ό,τι *πρόχειρα* είδα στον κώδικά σου δεν λαμβάνεις υπόψη αυτόν το χρόνο. Άρα το ρολόι θα τρέχει λίγο πιο αργά, απ' όσο θα έπρεπε.



 ξαναδές το καλύτερα, εκεί είναι ο κώδικας:



```
TMR0L = 0x0f + ((0xffff-2000u) % 256) + 2;
```


Στην περίπτωση του interrupt λόγω των ελάχιστων εντολών *(0χ0f)* που θα βάλει ο μεταγλωτιστης στο "εκτελέσιμο" αρχείο, κάνεις μια μέτρηση με το stopwatch ή κοιτάς το assembly και μετράς πόσες εντολές ξέφυγες (προσθέτεις και τις *2* tcy για αδράνεια όταν πειράζεις τον tmr0).

Αντι για capture-compare προτιμώ να μην πειράζω τον tmr0 καθόλου και να έχω απείραχτο το tmr0 στα φυσιολογικά του τελειώματα (δηλαδή κάθε 256 tcy), αλλά αν έβαζα το interrupt να εκτελειται κάθε 1 / 7812,5sec (οπότε ένα irq διάρκειας 7812 και ένα 7813) θα ήταν πιο δυσνόητο για κάποιον που ξεκινά

----------


## fmav

Όντως το έχεις λάβει υπόψη.

Όμως είναι αυτό που σου έλεγα, ο κάθε compiler C φτιάχνει διαφορετικό κώδικα, οπότε κάθε φορά θα πρέπει να αναθεωρείται η ρύθμιση του νέου timer. Επίσης τι γίνεται αν στον main κώδικα υπάρχουν σημεία όπου κόβονται τα interrupts; Αν συμβεί να μηδενιστεί ο Timer πάνω σε ένα τέτοιο κόψιμο του interrupt, τότε θα πρέπει να ληφθούν υπόψη και οι επιπλέον κύκλοι, μέχρι να μπορέσει να μπει στο interrupt. Αυτό όμως δεν μπορεί να γίνει γιατί είναι τελείως τυχαίο γεγονός.

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

----------


## bxenos

> Όμως είναι αυτό που σου έλεγα, ο κάθε compiler C φτιάχνει διαφορετικό κώδικα, οπότε κάθε φορά θα πρέπει να αναθεωρείται η ρύθμιση του νέου timer. Επίσης τι γίνεται αν στον main κώδικα υπάρχουν σημεία όπου κόβονται τα interrupts;



Σωστοί οι προβληματισμοί σου και σ'ευχαριστώ για τη συμετοχή σου, όμως υπάρχουν και άλλες λύσεις:

για το αν έχει γίνει disable τα irq και έχει προχωρήσει το tmr0l υπάρχει λύση με κάτι σαν:



```
TMR0L += ((0xffff-2000u) % 256) + 2;
```


 το οποίο μπορεί να γίνει ανεξάρτητο και απο το πιον compiler έχουμε και τι κώδικα φτιάχνει.

Πάντως και για τα δύο αυτά θέματα που αναφέρεις, αν δεν πειράζουμε τις tmr0 μεταβλητές δεν υπάρχει κανένα πρόβλημα. 

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

Αν θέλεις γράψε ένα εναλλακτικό irq.c με χρήση CCP για να υπάρχει σαν επιπλεόν αναφορά.

----------


## gsmaster

Δεν ξέρω για άλλους compiler αλλά στον CCS που χρησιμοποιώ σου βγάζει ένα αρχείο .lst όπου μπορείς να δεις ακριβώς κάθε εντολή της C πως μεταφράζεται σε assembly, και να υπολογίσεις ότι θες. Λογικά θα ισχύει και για άλλους compiler.

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

----------


## bxenos

> στον CCS που χρησιμοποιώ σου βγάζει ένα αρχείο .lst... Λογικά θα ισχύει και για άλλους compiler.
> 
> Πάντα υπάρχει και η άλλη δυνατότητα, να γράψεις ένα κομμάτι κώδικα, κατευθείαν σε assembly οπότε το κάνεις όπως θες εσύ.



πράγματι και ο mcc18 παράγει .lst. Μπορείς και assembly να γράψεις.

Συνοψίζω λοιπόν για timer ακριβείας:
α) απόδοση τιμής στα TMR0 με συνψηφισμό της καθυστέρισης. Μειονέκτημα η αλλαγη compiler θέλει επανέλεγχο.

β) χρηση CCP (capture and compare module)

γ) μη χρηση δυνατότητας απόδοσης τιμής σε TMR0.

δ) χρήση της 


```
TMR0L += adjust;
```


 μορφής απόδοσης τιμής.

ε) γράψιμο assembly για τα interrupt (που είναι και συχνή τακτική, ειδικά όταν μας νοιάζει η ταχύτητα).

Να επισημάνω ότι έχω κάποιες ακόμα παρατηρήσεις στον κώδικα, π.χ.: 
1) η μη χρήση volatile προσδιοριστικού για τις μεταβλητές που επιρεάζονται στο interrupt (αλλά βγάζει πολυ παχύ κώδικα η χρήση τους και λόγω της επιζητούμενης απλότητας το παρέλληψα)
2) δεν έγινε η χρήση κοινών case στην αποτύπωση ψηφείων (π.χ. το 8 είναι 0 + G, θα μπορούσε ο κώδικας του case 8 να είναι μικρότερος...)

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

----------


## bxenos

Παραθέτω οδηγίες χρήσης του MPLAB εργαλείου ανάπτυξης, όπως αυτό μου παραδόθηκε απο καθηγητή του 14ου εσπερινού ΕΠΑΛ/ΤΕΕ Ηλεκτρονικών στον Ευκλείδη (Παπαναστασίου 13) στη Θεσσαλονίκη. 

mplab_c_οδηγίες.pdf

----------


## bxenos

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

*Το πρόγραμμα* παρέχεται έτοιμο εδώ.

*Που και πως θα γράψουμε το πρόγραμμα;* εδώ. 
Πρώτα πρέπει να κατεβάσετε τα δωρεάν προγράμματα της Microchip, 
το MPLAB IDE Integrated Development Environmentκαι την C for PIC 18 Evaluation version.

*Λίστα με τα υλικά:*
6 τρανζίστορ bc5576 οθόνες 7 τμημάτων led, κοινής ανόδου8 αντιστάσεις 220Ωμ8 αντιστάσεις 56Ωμ1 μικροελενκτής PIC18F1320 I/P1 ηλεκτρολυτικός πυκνωτής 220μF/16V1 σταθεροποιητής 78L051 ζένερ 5,6V/0,5Watt

Διαφοροποιήσεις απο την αρχική λίστα με τα υλικά (στο πρώτο μήνυμα):
Έχει προστεθεί το ζένερ 5,6V μόνο σαν προστασία απο υπερτάσεις (κατά τους πειραματισμούς μας) ώστε να μην στείλουμε κατα λάθος περισσότερο απο 5V στο μικροελενκτή απο το τροφοδοτικό μας. 
Για τον ίδιο λόγο έχει τοποθετηθεί και ο σταθεροποιητής 78L05 ο οποίος έχει δύο πλεονεκτήματα: α) είναι μικρός και τα "ποδαράκια" του χωρούν στις τρύπες στο project/break/raster board (ή όπως αλλιώς το ξέρετε) και β) έχει περιορισμό ρεύματος αρκετά μικρό (οπότε είναι πολύ πιθανό να μας συγχωρήσει ο μικροελενκτής αν κάνουμε λάθος συνδέσεις πάνω του).και φωτό:
x1.jpg
DSC00286.jpg

_Οι φωτογραφίες τραβήχτηκαν στο προαναφερθέν ΕΠΑΛ/ΤΕΕ απο κατασκευή των μαθητών του τμήματος ηλεκτρονικών._

----------


## bxenos

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

----------


## thodoris1975

Βρε παιδιά που είναι το κύκλωμα ?

----------

GeorgeVita (01-09-13)

----------


## klik

Στα σχόλια στον κώδικα, στο 1ο μήνυμα.





> ...ρολόι με 6 οθόνες led 7 τμημάτων κοινής ανόδου
>     μικροελενκτης: pic18f1320
>     γλώσσα προγραμματισμού: C
>     κρυσταλλος: δεν χρησιμοποιειται
>     άλλα υλικά: 
>             πυκνωτές για decoupling 22μF/16V και 100nF στην τροφοδοσία του μικροελενκτη
>             αντιστάσεις συνδεσης ακίδων μικροελενκτή με A,B,C,D,E,F,G,DP οθόνων 8 * 150Ωμ
>             6 τρανζίστορ bc547 για σύνδεση των ανόδων των οθονών 
>     συνδεσμολογία:
> ...



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

7-seg1.gif


κάτι σαν το παραπάνω δηλαδή, αλλά με 6 οθόνες, 6 τρανζίστορ, χωρις κρύσταλλο

----------

GeorgeVita (01-09-13)

----------


## GeorgeVita

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



Τι έγραψες τώρα!
Εχω φτιάξει μια "οθόνη" με 6x 7seg-LED και δεν ήξερα τι να ανάψω σε αυτήν!
(επιπλέον μικρή αλλαγή γιατί περιέχει 6x*NPN* τρανζίστορ και όλες τις αντιστάσεις)

----------


## klik

Σωστός, προσθέτεις και 6 inputs (θα τροφοδοτούνται μέσω αντίστασης από τα 6 τρανζίστορς) και θα διαβάζονται από την ακίδα RA5 (που είναι μόνο input), για buttons ή άλλης μορφής inputs και είσαι έτοιμος για ότι εφαρμογή μέτρησης/απαρίθμησης θέλεις.

----------

