/**************************************************************
   Schemat podłączeń programowanego układu

                 +----v----+
           MCLR [| 1     40|] 
                [| 2     39|] 
                [| 3     38|] RB5 -> DB4_LCD
                [| 4     37|] RB4 -> DB5_LCD
                [| 5     36|] RB3 -> DB6_LCD
impuls -> T0CKI [| 6     35|] RB2 -> DB7_LCD
                [| 7     34|] RB1 -> RS_LCD
                [| 8     33|] RB0 -> EN_LCD
                [| 9     32|] VDD
                [|10     31|] VSS
            VDD [|11     30|] 
            VSS [|12     29|] 
(20 MHz) / OSC1 [|13     28|]
         \ OSC2 [|14     27|]
      W1 -> RC0 [|15     26|] RC7 -> K4
      W2 -> RC1 [|16     25|] RC6 -> K3
      W3 -> RC2 [|17     24|] RC5 -> K2
      W4 -> RC3 [|18     23|] RC4 -> K1
                [|19     22|] 
                [|20     21|] 
                 +---------+
                 PIC16F877A

***************************************************************/

//definiujemy szybkość oscylatora dla funkcji __delay_
#define _XTAL_FREQ 20000000
#include <htc.h>
#include <stdlib.h>
#include <string.h>
//////////////////////////////////////
#define TRIS_RS_LCD   TRISBbits.TRISB1
#define TRIS_EN_LCD   TRISBbits.TRISB0
#define TRIS_DB4_LCD  TRISBbits.TRISB5
#define TRIS_DB5_LCD  TRISBbits.TRISB4
#define TRIS_DB6_LCD  TRISBbits.TRISB3
#define TRIS_DB7_LCD  TRISBbits.TRISB2

#define RS_LCD   PORTBbits.RB1
#define EN_LCD   PORTBbits.RB0
#define DB4_LCD  PORTBbits.RB5
#define DB5_LCD  PORTBbits.RB4
#define DB6_LCD  PORTBbits.RB3
#define DB7_LCD  PORTBbits.RB2

#include "lcd.h"
//////////////////////////////////////
#define TRIS_W1  TRISCbits.TRISC0
#define TRIS_W2  TRISCbits.TRISC1
#define TRIS_W3  TRISCbits.TRISC2
#define TRIS_W4  TRISCbits.TRISC3
#define TRIS_K1  TRISCbits.TRISC4
#define TRIS_K2  TRISCbits.TRISC5
#define TRIS_K3  TRISCbits.TRISC6
#define TRIS_K4  TRISCbits.TRISC7

#define PORT_W1  PORTCbits.RC0
#define PORT_W2  PORTCbits.RC1
#define PORT_W3  PORTCbits.RC2
#define PORT_W4  PORTCbits.RC3
#define PORT_K1  PORTCbits.RC4
#define PORT_K2  PORTCbits.RC5
#define PORT_K3  PORTCbits.RC6
#define PORT_K4  PORTCbits.RC7

#include "klawiatura.h"
//////////////////////////////////////
//oscylator 20 MHz (FOSC_HS)
//watchdog wyłączony (WDTE_OFF)
//wyłączone LVP (Low-Voltage ICSP Programming) (LVP_OFF)
__CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF);

char napis0[] = "Zacznij pomiar";	//14 znaków
char napis1[] = "Wynik:";			//6 znaków
char napis2[] = " Hz";				//3 znaki
char napisw[11];					//bufor wyniku
char kod, pomiar;					//zmienne pomocnicze
unsigned int wynik;					//zmienna wyniku pomiaru
volatile unsigned char ile_razy;	//zmienna inkrementowana podczas wywołania przerwania Timer1
unsigned long int obliczenia;		//liczba wyświetlana
unsigned long int wzor_iteracji;	//wzorcowa liczba iteracji
float wynik_f;

void main()
{
	ADCON1 = 0x06;				//wyłączenie linii analogowych 
                    			//(wszystkie linie cyfrowe)
	WlaczLCD();					//inicjalizacja wyświetlacza LCD
	WyswietlLCD(napis0, 14);	//wyświetl napis "Zacznij pomiar"
	Wlacz_klawiature();			//inicjalizacja portów klawiatury

	//konfiguracja modułu Timer0
	OPTION_REGbits.T0CS	= 1;	//źródło taktowania rejestru TMR0 zewnętrzne (T0CKI)
	OPTION_REGbits.T0SE = 0;	//inkrementacja zboczem narastającym
	OPTION_REGbits.PSA = 0;		//preskaler przypisany do modułu Timer0

	for(;;)						//pętla nieskończona
	{
		kod = Czekaj_na_klawisz();	//czekaj na klawisz :)
		kod--;						//zmniejsz kod znaku
		kod &= 0x07;				//pozostaw tylko 3 najmłodsze bity

		//ustaw preskaler modułu Timer0
		if(kod&0x04)
			OPTION_REGbits.PS2 = 1;
		else
			OPTION_REGbits.PS2 = 0;
		if(kod&0x02)
			OPTION_REGbits.PS1 = 1;
		else
			OPTION_REGbits.PS1 = 0;
		if(kod&0x01)
			OPTION_REGbits.PS0 = 1;
		else
			OPTION_REGbits.PS0 = 0;

		pomiar = 0;					//wyzerowanie sygnalizacji końca pomiaru				
		ile_razy = 0;				//przerwanie modułu Timer1 wywołane 0 razy
		INTCONbits.TMR0IF = 0;		//wyczyść flagę przerwania
		PIR1bits.TMR1IF = 0;		//wyczyść flagę przerwania
		TMR0 = 0;					//wyzerowanie licznika TMR0
		TMR1 = 0;					//wyzerowanie licznika TMR1
		PIE1bits.TMR1IE = 1;		//włącz przerwanie Timer1
		INTCONbits.TMR0IE = 1;		//włącz przerwanie modułu Timer0
		T1CONbits.TMR1ON = 1;		//włącz moduł Timer1
		INTCONbits.PEIE = 1;		//włączenie przerwań urządzeń peryferyjnych
		INTCONbits.GIE = 1;			//globalne włączenie przerwań		
		while(pomiar == 0);			//zaczekaj na koniec pomiaru

		T1CONbits.TMR1ON = 0;		//wyłącz moduł Timer1
		PIE1bits.TMR1IE = 0;		//włącz przerwanie Timer1
		INTCONbits.TMR0IE = 0;		//wyłącz przerwanie modułu Timer0
		INTCONbits.GIE = 0;			//globalne wyłączenie przerwań		
		
		//obliczenia pomocnicze
		obliczenia = 2560;
		wzor_iteracji = obliczenia<<kod;
		//obliczenie liczby wykonanych iteracji rejestru TMR1
		obliczenia = 0x10000;
		obliczenia = (obliczenia*ile_razy)+wynik;
		obliczenia = obliczenia - (ile_razy+1)*10;	//kalibracja (uwzględnienie błędów iteracji)
		//obliczenie wyniku
		wynik_f = (float)(wzor_iteracji)/(float)(obliczenia);
		wynik_f *= 1000000.0;
		obliczenia = (unsigned long int)wynik_f;
		//wyświetlenie wyniku
		ultoa(napisw, obliczenia, 10);		//konwersja wyniku w napis
		CzyscLCD();							//reset wyświetlacza
		WyswietlLCD(napis1, 6);				//wyświetl napis "Wynik"
		UstawKursorLCD(2, 1);				//wiersz 2 kolumna 1
		WyswietlLCD(napisw, strlen(napisw));//wyświetl wynik
		WyswietlLCD(napis2, 3);				//wyświetl napis " Hz"
	}
}

static void interrupt
knowania_przerwania(void)
{
	wynik = TMR1;				//kopiuj czas

	if(INTCONbits.TMR0IF == 1)	//przerwanie modułu Timer0
	{
		pomiar = 1;				//ustaw flagę prawidłowego końca pomiaru
		INTCONbits.TMR0IF = 0;	//wyczyść flagę przerwania
	}
	if(PIR1bits.TMR1IF == 1)	//przerwanie modułu Timer1
	{
		ile_razy++;
		PIR1bits.TMR1IF = 0;	//wyczyść flagę przerwania
	}
}
