//******************************************************************************
// Projeto teste_DS1307 com PIC16F876A
// Demonstra como utilizar o RTC DS1307 com PIC16F876A 
//
// Desenvolvido por: Eng. Márcio José Soares
// 
// V1.0 - 11/04/2024
//
// Compilador: XC8 v2.45
// IDE       : MPLABX 6.0 Linux
// Plataforma: PIC16F876A no protoboard
// Gravador  : PICKIT3
//
// Pinos utilizados p/ I2C:
// RC4 : SDA
// RC3 : SCL
//
// Pinos utilizados p/ USART
// RC7 - RXD
// RC6 - TXD
//
// Led Live:
// RA0 - Led Live
//
//******************************************************************************
// Últimas alterações:
//
//  em 11/04/2024:
//      - inicio do projeto
//      - criadas funções para tratamento do DS1307
//      - testes com DS1307 não ok!!! Provavelmente os cristais que tenho
//        são fake ou podreira total!
//
//  em 12/04/2024:
//      - retomado os testes usando gerador de funções com onda quadrada de
//        aproximadamente 32.768kHz e funcionou!!! Preciso de cristais 32.768kHz
//        de qualidade!!!
//
// em 18/04/2024:
//      - retomados os testes com cristais novos e funcionou! Porém tive que 
//        inserir um resistor de 2M2 entre o VBAT e o X2 para ajudar na
//        oscilação do cristal mantendo o mesmo em operação!!!
//******************************************************************************

//******************************************************************************
// O Copyright deste programa está reservado para Márcio José Soares e seu
// conteúdo está protegido pela Lei de Direitos Autorais LEI Nº 9.610, de
// 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou
// parcial dos conteúdos aqui apresentados sem prévia autorização, por escrito,
// do autor.
//******************************************************************************

//******************************************************************************
// Bits de configuração
#pragma config FOSC = XT        // oscilador
#pragma config WDTE = OFF       // Watchdog Timer desabilitado
#pragma config PWRTE = ON       // Power-up Timer habilitado
#pragma config BOREN = OFF      // Brown-out Reset desabilitado
#pragma config LVP = OFF        // Low-Voltage desabilitado (RB3 é pino de I/O)
#pragma config CPD = OFF        // Data EEPROM Memory Code off
#pragma config WRT = OFF        // Flash Program Memory Write off
#pragma config CP = OFF         // Flash Program Memory Code off

//******************************************************************************
// Inclui arquivos
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "my_defines.h"
#include "pic_comm.h"
#include "pic_timer0.h"
#include "pic16F_i2c.h"
#include "pic_ds1307.h"

//******************************************************************************
// Variáveis do módulo
volatile uint8_t count_timer0;
volatile uint8_t LedState;

uint8_t segundos = 0;
uint8_t minutos = 0;
uint8_t horas = 0;
uint8_t segundos_old = 0;
uint8_t minutos_old = 0;
uint8_t horas_old = 0;

uint8_t dia = 0;
uint8_t mes = 0;
uint8_t ano = 0;

uint8_t tipohora = 0;
uint8_t prima = 0;

volatile uint8_t reply = 0;
volatile uint8_t rel_acert = 0;
volatile uint8_t show_relogio = 0;
volatile uint8_t count_rel = 0;

uint8_t h,m,s;
uint8_t day, month, year;
    
char msgU[80];
char p[10];
char q[10];

volatile byte autoriza = 0;

//******************************************************************************
// Funções externas do módulo
extern void bin_hex(byte binchar, byte *high_char, byte *low_char);
extern void print_hex(char *string, byte hex_ascii, byte w_wo_H);
extern byte bin_bcd(byte rec);

//******************************************************************************
// Funções do módulo

//******************************************************************************
// Função config pic - configura pinos de I/O e outros
//
// Entradas - nenhuma
// Saídas   - nenhuma
//******************************************************************************
void config_pic(void){
    
    INTCON = 0x00;              // Todas as ints desligadas
    ADCON0 = 0x00;
	ADCON1 = 0x06;				//todos os pinos são I/Os digitais
    
    PORTA = 0x00;               // zera ports
    PORTB = 0x00;
    PORTC = 0x00;
    
   
    TRISA = 0x00;               // todos como saída, exceto RA5 - SS SPI
    TRISB = 0x00;             
    TRISC = 0x18;               // RC3,RC4 entrada              
    
}

//******************************************************************************
// Função get_hour - pega hora no RTC e trabalha valores nas variáveis
//
// Entradas - nenhuma
// Saídas   - nenhuma
//******************************************************************************
void get_hour(void){
    
    h = 0;
    m = 0;
    s = 0;
    RTC_GetTime(&h,&m,&s); 
    if(tipohora)    //padrão 12 horas
        horas = ((((h >> 0x04) & 0x1) * 10) + (h & 0x0F));
    else            //padrão 24 horas 
        horas = ((((h >> 0x04) & 0x03) * 10) + (h & 0x0F));
    
    minutos = ((((m >> 0x04) & 0x07) * 10) + (m & 0x0F));
    segundos = ((((s >> 0x04) & 0x07) * 10) + (s & 0x0F));
}

//******************************************************************************
// Função get_date - pega data no RTC e trabalha valores nas variáveis
//
// Entradas - nenhuma
// Saídas   - nenhuma
//******************************************************************************
void get_date(void){
    
    day = 0;
    month = 0;
    year = 0;
    RTC_GetDate(&day, &month, &year);
    dia = ((((day >> 0x04) & 0x03) * 10) + (day & 0x0F));
    mes = ((((month >> 0x04) & 0x01) * 10) + (month & 0x0F));
    ano = ((((year >> 0x04) & 0x0F) * 10) + (year & 0x0F));
}

//******************************************************************************
// Função principal
//
// Entradas - nenhuma
// Saídas   - nenhuma
//******************************************************************************
void main(void) {
        
    uint8_t i;
    
    //**************************************************************************
    // Configura pic
    config_pic();                           // inicia pinos de I/O, etc
#ifdef __DS1307__
    i2c_init(I2C_SPEED_STANDARD_100KHZ);    // I2C vel 100kHz
#endif
    init_usart();                           // inicia USART
    init_timer0();
    
    RTC_Init();
    
    LEDoff;
    
    __delay_ms(1000);
    
    //**************************************************************************
    // Flags de controle das interrupções
    INTCONbits.PEIE = 1;                // PEIE=1 - habilita int dos periféricos (timers, comparadores, usart, etc)
    INTCONbits.GIE = 1;                 // GIE=1 - habilita interrupções globais.
    
    //**************************************************************************
    // Envia mensagem via USART
    strcpy(msgU,"\n\r\n\r---------------------------------------");
    putch_str(&msgU[0]);
    strcpy(msgU,"\n\rBem-vindo ao laboratorio do Arne!!!"); // insere mensagens
    strcat(msgU,"\n\rTeste do RTC DS1307");
    putch_str(&msgU[0]);
    strcpy(msgU,"\n\r---------------------------------------");
    putch_str(&msgU[0]);
    
#ifdef __DS1307__
    //**************************************************************************
    // Pega a hora no RTC
    //**************************************************************************
    get_hour();
    
    //**************************************************************************
    // Pega a data no RTC
    //**************************************************************************
    // se não atualizou ainda, use a função abaixo... apenas uma vez ok!
    //RTC_SetDate(bin_bcd(18), bin_bcd(4), bin_bcd(24), QUINTA);
    get_date();
        
    //**************************************************************************
    // Envia para tela
    //**************************************************************************  
    strcpy(msgU,"\n\rRelogio lido como : ");
    putch_str(&msgU[0]);
    
    sprintf(p,"%02d:",horas);
    strcpy(msgU,p);
    sprintf(p,"%02d:",minutos);
    strcat(msgU,p);
    sprintf(p,"%02d | ",segundos);
    strcat(msgU,p);
    putch_str(&msgU[0]);
    
    sprintf(p,"%02d/",dia);
    strcpy(msgU,p);
    sprintf(p,"%02d/",mes);
    strcat(msgU,p);
    sprintf(p,"20%02d",ano);
    strcat(msgU,p);
    putch_str(&msgU[0]);
    
#ifdef __DEBUG__
    strcpy(msgU,"\n\rHoras    :");
    print_hex(&msgU[0],horas,0);
    
    strcpy(msgU,"       Dia :");
    print_hex(&msgU[0],dia,0);
    
    strcpy(msgU,"\n\rMinutos  :");
    print_hex(&msgU[0],minutos,0);
    
    strcpy(msgU,"       Mes :");
    print_hex(&msgU[0],mes,0);
    
    strcpy(msgU,"\n\rSegundos :");
    print_hex(&msgU[0],segundos,0); 
    
    strcpy(msgU,"       Ano :");
    print_hex(&msgU[0],ano,0);
#endif 
#endif
       
    //**************************************************************************
    // Laço principal
    while(TRUE){                        // faz eternamente!
        if(!prima){
            strcpy(msgU,"\n\r\n\rDeseja acertar o relogio?! (S/N) :");
            putch_str(&msgU[0]);
            reply = 1;
            prima = 1;                       // não mostra mais!
        }
        
        if(rel_acert == 1){                  // pediu para acertar o relógio
            strcpy(msgU,"\n\r\n\rEnvie o novo horario (string) hh:mm:ss -> ");
            putch_str(&msgU[0]);
            reply = 2;
            rel_acert = 0;
        }
        else if(rel_acert == 2){
            
            strcpy(msgU,"\n\rNovo horario -> ");
            strcat(msgU,p);
            putch_str(&msgU[0]); 
            
            horas = p[1] - 0x30;
            horas += ((p[0] - 0x30) * 10);
            
            minutos = p[4] - 0x30;
            minutos += ((p[3] - 0x30) * 10);
                    
            segundos = p[7] - 0x30;
            segundos += ((p[6] - 0x30) * 10);
            
            RTC_SetTime(bin_bcd(horas), bin_bcd(minutos), bin_bcd(segundos), tipohora);
            rel_acert = 0;
            show_relogio = 1;
        }
        
        if(show_relogio == 1){
            strcpy(msgU,"\n\r\n\r");
            putch_str(&msgU[0]); 
            show_relogio = 2;    
        }
        
        if(show_relogio == 2){               // apenas mostra o relógio
                     
            if(autoriza){
                autoriza = 0;
                get_hour();
                if((horas != horas_old) || 
                   (minutos != minutos_old) || 
                   (segundos != segundos_old))
                {
                    for(i=0;i<8;i++)
                        mputch(BS);
                    
                    sprintf(p,"%02d:",horas);
                    strcpy(msgU,p);
                    sprintf(p,"%02d:",minutos);
                    strcat(msgU,p);
                    sprintf(p,"%02d",segundos);
                    strcat(msgU,p);
                    putch_str(&msgU[0]);
                
                    horas_old = horas;
                    minutos_old = minutos;
                    segundos_old = segundos;
                }
            }
            
        }
        
    }
    
    return;
}
