/**************************************************************
        Schemat podłączeń programowanego układu
                       +----v----+
                 MCLR [| 1     28|] VDD
            W1 -> RA0 [| 2     27|] VSS
            W2 -> RA1 [| 3     26|] RP15 -> DB4        
            W3 -> RB0 [| 4     25|] RP14 -> DB5
            W4 -> RB1 [| 5     24|] RP13 -> DB6
            K1 <- RB2 [| 6     23|] 
            K2 <- RB3 [| 7     22|] RP11 -> DB7
                  VSS [| 8     21|] RP10 -> RS
       (8 MHz) / OSCI [| 9     20|] VCAP/VDDCORE
               \ OSCO [|10     19|] DISVREG
                      [|11     18|] RB9 -> EN
                      [|12     17|] 
                  VDD [|13     16|] RB7 -> K4 
            K3 <- RB5 [|14     15|] 
                       +---------+
                     PIC24FJ64GB002
***************************************************************/
#include <p24Fxxxx.h>
//definiujemy szybkość oscylatora dla funkcji __delay_
#define FCY 16000000UL 
//biblioteka z funkcjami __delay_us i __delay_ms
#include <libpic30.h>
//dyrektywa zapewniająca zgodność z wcześniejszą konwencją zapisu danych makr
#define USE_AND_OR	
//biblioteka funckji i makr obsługi modułu RTCC
#include <rtcc.h>

//ustawienia bitów konfiguracyjnych
//1. 
//FWDTEN_OFF - Watchdog wyłączony
//JTAGEN_OFF - JTAG wyłączony
_CONFIG1(FWDTEN_OFF & JTAGEN_OFF)
//2.
//FNOSC_PRIPLL - układ taktowany zewnętrznym oscylatorem z pętlą PLL
//POSCMOD_XT - częstotliwość taktowania oscylatora 8 MHz
//PLLDIV_DIV2 - konieczność podzielenia przez 2 dla modułu USB PLL
_CONFIG2(FNOSC_PRIPLL & POSCMOD_XT & PLLDIV_DIV2)
//4.
//RTCOSC_LPRC - moduł RTCC taktowany zegarem wewnętrznym
_CONFIG4(RTCOSC_LPRC)
//////////////////////////////////////
#define TRIS_RS_LCD   TRISBbits.TRISB10
#define TRIS_EN_LCD   TRISBbits.TRISB9
#define TRIS_DB4_LCD  TRISBbits.TRISB15
#define TRIS_DB5_LCD  TRISBbits.TRISB14
#define TRIS_DB6_LCD  TRISBbits.TRISB13
#define TRIS_DB7_LCD  TRISBbits.TRISB11

#define RS_LCD   LATBbits.LATB10
#define EN_LCD   LATBbits.LATB9
#define DB4_LCD  LATBbits.LATB15
#define DB5_LCD  LATBbits.LATB14
#define DB6_LCD  LATBbits.LATB13
#define DB7_LCD  LATBbits.LATB11

#include "lcd.h"
//////////////////////////////////////
#define TRIS_W1  TRISAbits.TRISA0
#define TRIS_W2  TRISAbits.TRISA1
#define TRIS_W3  TRISBbits.TRISB0
#define TRIS_W4  TRISBbits.TRISB1
#define TRIS_K1  TRISBbits.TRISB2
#define TRIS_K2  TRISBbits.TRISB3
#define TRIS_K3  TRISBbits.TRISB5
#define TRIS_K4  TRISBbits.TRISB7

#define PORT_W1  PORTAbits.RA0
#define PORT_W2  PORTAbits.RA1
#define PORT_W3  PORTBbits.RB0
#define PORT_W4  PORTBbits.RB1
#define PORT_K1  LATBbits.LATB2
#define PORT_K2  LATBbits.LATB3
#define PORT_K3  LATBbits.LATB5
#define PORT_K4  LATBbits.LATB7

#include "klawiatura.h"
//////////////////////////////////////
//struktury obsługi modułu RTCC
rtccTimeDate RtccTimeDate;
unsigned char sekunda_poprzednia;
unsigned char dzien_poprzedni;

//tablice znakowe dla funkcji LCD
char napis0[8] = "        ";
char napis1[] = "Data:";		//5 znaków
char napis2[] = "Czas:";		//5 znaków
//zmienna pomocnicza dla obsługi klawiatury
char znak;

void No_dawaj_ten_czas_na_LCD()
{
	//resetuj poprzednio wyświetlany czas
	UstawKursorLCD(2, 7);		//wiersz 2 kolumna 7
	WyswietlLCD(napis0, 8);		//wyświetl 8 spacji
	UstawKursorLCD(2, 7);		//wiersz 2 kolumna 7

	//wyświetl dziesiątki godziny 
	Wyslij_do_LCD(((RtccTimeDate.f.hour&0x70)>>4)+0x30);
	//wyświetl jedności godziny 
	Wyslij_do_LCD((RtccTimeDate.f.hour&0x0F)+0x30);
	//wyświetl :
	Wyslij_do_LCD(':');
	//wyświetl dziesiątki minut 
	Wyslij_do_LCD(((RtccTimeDate.f.min&0x70)>>4)+0x30);
	//wyświetl jedności minut 
	Wyslij_do_LCD((RtccTimeDate.f.min&0x0F)+0x30);
	//wyświetl :
	Wyslij_do_LCD(':');	
	//wyświetl dziesiątki sekund 
	Wyslij_do_LCD(((RtccTimeDate.f.sec&0x70)>>4)+0x30);
	//wyświetl jedności sekund 
	Wyslij_do_LCD((RtccTimeDate.f.sec&0x0F)+0x30);
}

void No_dawaj_ten_datownik_na_LCD()
{
	//resetuj poprzednio wyświetlaną datę
	UstawKursorLCD(1, 7);		//wiersz 1 kolumna 7
	WyswietlLCD(napis0, 8);		//wyświetl 8 spacji
	UstawKursorLCD(1, 7);		//wiersz 1 kolumna 7

	//wyświetl dziesiątki dni 
	Wyslij_do_LCD(((RtccTimeDate.f.mday&0x30)>>4)+0x30);
	//wyświetl jedności dni 
	Wyslij_do_LCD((RtccTimeDate.f.mday&0x0F)+0x30);
	//wyświetl -
	Wyslij_do_LCD('-');
	//wyświetl dziesiątki miesięcy 
	Wyslij_do_LCD(((RtccTimeDate.f.mon&0x10)>>4)+0x30);
	//wyświetl jedności miesięcy 
	Wyslij_do_LCD((RtccTimeDate.f.mon&0x0F)+0x30);
	//wyświetl -20
	Wyslij_do_LCD('-');	
	Wyslij_do_LCD('2');
	Wyslij_do_LCD('0');
	//wyświetl dziesiątki lat 
	Wyslij_do_LCD(((RtccTimeDate.f.year&0xF0)>>4)+0x30);
	//wyświetl jedności lat 
	Wyslij_do_LCD((RtccTimeDate.f.year&0x0F)+0x30);
}

unsigned char BCD_plus(unsigned char x)
{
	static unsigned char x4, x0;
	x4 = (x>>4);
	x0 = (x&0x0F);
	x0++;
	if(x0>9)
	{
		x0 = 0;
		x4++;
	}
	if(x4>9) x4 = 0;
	return (x4<<4)|x0;
}

unsigned char BCD_minus(unsigned char x)
{
	static unsigned char x4, x0;
	x4 = (x>>4);
	x0 = (x&0x0F);
	x0--;
	if(x0>9)
	{
		x0 = 9;
		x4--;
	}
	if(x4>9) x4 = 9;
	return (x4<<4)|x0;
}

int main()
{
	/////////////////////////////////////////////////////
	AD1PCFGL = 0xFFFF;			//wszystkie linie cyfrowe

	/////////////////////////////////////////////////////
	//uruchomienie wyświetlacz LCD///////////////////////
	WlaczLCD();					//inicjalizacja wyświetlacza LCD
	WyswietlLCD(napis1, 5);		//wyświetl napis "Data:"
	UstawKursorLCD(2, 1);		//wiersz 2 kolumna 1
	WyswietlLCD(napis2, 5);		//wyświetl napis "Czas:"

	/////////////////////////////////////////////////////
	Wlacz_klawiature();			//inicjalizacja portów klawiatury

	/////////////////////////////////////////////////////
	//konfiguracja modułu RTCC///////////////////////////
	RtccInitClock();			//inicjalizacja modułu RTCC
	mRtccSetInt(0);				//wyłącz obsługę przerwania RTCC
	RtccWrOn();            		//ustaw bit RTCWREN - zezwól na modyfikację rejestrów   
	//ustawienia początkowe czasu i daty (01.07.2011, godzina 01.01.00)
	RtccTimeDate.f.hour = 1;
	RtccTimeDate.f.min =  1;
	RtccTimeDate.f.sec =  0;
	RtccTimeDate.f.mday = 1;
	RtccTimeDate.f.mon =  7;
	RtccTimeDate.f.year = 0x11;
	sekunda_poprzednia = 100;	//ta wartość wymusi wyświetlenie godziny
	dzien_poprzedni = 100;		//ta wartość wymusi wyświetlenie daty
	//załaduj dane do rejestrów modułu
	RtccWriteTimeDate(&RtccTimeDate,0);
	mRtccOn();					//włącz moduł RTCC
	/////////////////////////////////////////////////////

	for(;;)						//nieskończona pętla
	{
		//odczytaj czas i datę z modułu RTCC
		RtccReadTimeDate(&RtccTimeDate);	
	
		if(sekunda_poprzednia != RtccTimeDate.f.sec)	
		//jeśli czas się zmienił
		{	
			//wyświetl czas
			No_dawaj_ten_czas_na_LCD();
			//załaduj nową wartość sekundy
			sekunda_poprzednia = RtccTimeDate.f.sec;
		}
		if(dzien_poprzedni != RtccTimeDate.f.mday)	
		//jeśli data się zmieniła
		{	
			//wyświetl datę
			No_dawaj_ten_datownik_na_LCD();
			//załaduj nową wartość dnia
			dzien_poprzedni = RtccTimeDate.f.mday;
		}

		//sprawdź klawiaturę
		znak = Czekaj_na_klawisz();
		//jeśli został wciśnięty przycisk, wykonaj akcję
		if(znak)
		{
			switch(znak)
			{
				case 1:			//inkrementuj dzień
					RtccTimeDate.f.mday = BCD_plus(RtccTimeDate.f.mday);
					break;
				case 5:			//dekrementuj dzień
					RtccTimeDate.f.mday = BCD_minus(RtccTimeDate.f.mday);
					break;
				case 2:			//inkrementuj miesiąc
					RtccTimeDate.f.mon = BCD_plus(RtccTimeDate.f.mon);
					break;
				case 6:			//dekrementuj miesiąc
					RtccTimeDate.f.mon = BCD_minus(RtccTimeDate.f.mon);
					break;
				case 3:			//inkrementuj rok
					RtccTimeDate.f.year = BCD_plus(RtccTimeDate.f.year);
					break;
				case 7:			//dekrementuj rok
					RtccTimeDate.f.year = BCD_minus(RtccTimeDate.f.year);
					break;
				case 9:			//inkrementuj godzinę
					RtccTimeDate.f.hour = BCD_plus(RtccTimeDate.f.hour);
					break;
				case 13:		//dekrementuj godzinę
					RtccTimeDate.f.hour = BCD_minus(RtccTimeDate.f.hour);
					break;
				case 10:		//inkrementuj minutę
					RtccTimeDate.f.min = BCD_plus(RtccTimeDate.f.min);
					break;
				case 14:		//dekrementuj minutę
					RtccTimeDate.f.min = BCD_minus(RtccTimeDate.f.min);
					break;
			}
			
			//załaduj dane do rejestrów modułu
			RtccWriteTimeDate(&RtccTimeDate,0);
			sekunda_poprzednia = 100;	//wymuś wyświetlenie zmiany czasu
			dzien_poprzedni = 100;		//wymuś wyświetlenie zmiany daty
			__delay_ms(250);			//czas stabilizacji
		}
	}
}
