/**************************************************************
   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
                [| 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|]
                [|15     26|] 
                [|16     25|] 
                [|17     24|] 
     SCL <- SCL [|18     23|] SDA <-> SDA
                [|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"

//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[] = "Wcisnij S1";
char napis1[] = "Trwa pomiar...";
char napis2[] = "Wynik:";
char napisw[11];

//definiujemy zmienne dbając o to, 
//by znalazły się w banku 0
volatile unsigned long int czas @ 0x40;
volatile unsigned long int czas_wzorcowy @ 0x44;
volatile unsigned int wypelniacz @ 0x3E;

void main()
{
	ADCON1 = 0x06;				//wyłączenie linii analogowych 
                    			//(wszystkie linie cyfrowe)
	TRISDbits.TRISD2 = 1;		//linia RD2 wejściowa (linia pomiaru)
	TRISCbits.TRISC0 = 1;		//linia RC0 wejściowa (przycisk S1)
	TRISAbits.TRISA5 = 0;		//linia RA5 wyjściowa (dioda D1)
	PORTAbits.RA5 = 0;			//dioda zgaszona

	WlaczLCD();					//inicjalizacja wyświetlacza LCD
	UstawKursorLCD(1, 4);		//wiersz 1 kolumna 3
	WyswietlLCD(napis0, 10);	//wyświetl napis

	for(;;)						//pętla nieskończona
	{	
		while(PORTCbits.RC0 == 1);//oczekiwanie na klawisz

		CzyscLCD();				//reset wyświetlacza
		UstawKursorLCD(1, 2);	//wiersz 1 kolumna 2
		WyswietlLCD(napis1, 14);//wyświetl napis

		//wyzerowanie zmiennych
		czas = 0;							
		czas_wzorcowy = 59999;	//czas pomiaru = 1 minuta

		//wykonaj pomiar
		#asm
		#include <caspic.h>
			//ustaw bank dla portu D (bank 0)
			banksel (PORTD)
			//tu rozpoczyna się pętla główna	
			petla:
			//sprawdź stan linii RD2
			btfsc	PORTD, 2	
			//jeśli linia jest ustawiona
			//pomiń inkrementację czasu
			goto	bez_inkrementacji_czasu
			//inaczej inkrementuj zmienną czas
			incf	_czas, f
			btfsc	STATUS, 2
			incf	_czas+1, f
			btfsc	STATUS, 2
			incf	_czas+2, f
			btfsc	STATUS, 2
			incf	_czas+3, f
			nop
			nop
			//sygnalizacja poprawności działania układu
			bcf		PORTA, 5	//zgaś diodę, gdy jasno
			goto	dekrementuj_czas_wzorcowy
			bez_inkrementacji_czasu:
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			nop
			//sygnalizacja poprawności działania układu
			bsf		PORTA, 5	//zaświeć diodę, gdy ciemno
			dekrementuj_czas_wzorcowy:			
			//Wypełniacz czasu :)
			//Bez tego kodu pętla trwa 25 cykli maszynowych.
			//Wypełnienie brakujących 4975 cykli maszynowych
			//daje w sumie 5000 cykli maszynowych,
			//czyli 1 milisekundę.
			////początek wypełniacza
			movlw	0x3					//W = 0x3
			movwf	_wypelniacz+1		//W -> wypelniacz[1]
			movlw	0x3B				//W = 0x3D
			movwf	_wypelniacz			//W -> wypelniacz[0]
			movlw	1					//W = 1
			petla_wypelniacza:
				subwf	_wypelniacz, f	//odejmij od bajtu 0. wartość z rejestru W
				btfss	STATUS, 0		//pomiń nast. instrukcję, jeśli nie było pożyczki
				subwf	_wypelniacz+1, f//odejmij od R0 wartość z rejestru W
				btfsc	STATUS, 0		//pomiń nast. instrukcję, jeśli była pożyczka
				goto	petla_wypelniacza	
			nop
			nop
			nop	
			////koniec wypełniacza
			movlw	1					//W = 1
			subwf	_czas_wzorcowy, f	//odejmij od bajtu 0. wartość z rejestru W
			btfss	STATUS, 0			//pomiń nast. instrukcję, jeśli nie było pożyczki
			subwf	_czas_wzorcowy+1, f	//odejmij od bajtu 1. wartość z rejestru W
			btfss	STATUS, 0			//pomiń nast. instrukcję, jeśli nie było pożyczki
			subwf	_czas_wzorcowy+2, f	//odejmij od bajtu 2. wartość z rejestru W
			btfss	STATUS, 0			//pomiń nast. instrukcję, jeśli nie było pożyczki
			subwf	_czas_wzorcowy+3, f	//odejmij od R0 wartość z rejestru W
			btfsc	STATUS, 0			//pomiń nast. instrukcję, jeśli była pożyczka
			goto	petla			
		#endasm		

		PORTAbits.RA5 = 0;					//zgaś diodę po zakończeniu pomiaru
		//wyświetlenie wyniku
		ultoa(napisw, czas, 10);			//konwersja wyniku na napis
		CzyscLCD();							//reset wyświetlacza
		WyswietlLCD(napis2, 6);				//wyświetl napis
		UstawKursorLCD(1, 7);				//wiersz 1 kolumna 7			
		WyswietlLCD(napisw, strlen(napisw));//wyświetl wynik
		UstawKursorLCD(2, 4);				//wiersz 2 kolumna 4
		WyswietlLCD(napis0, 10);			//wyświetl napis
	}
}
