/*
* File: main_v2.c
* Author: Fabrizio Barragan
*
* https://twitter.com/IObrizio
* http://amedialab.com/
* https://www.youtube.com/user/AutomationMediaLab
*
*
* Created on 17 de Marzo de 2016, 02:41 PM
*
* RTC reloj binario / Horas:Minutos
*
* Cambio de oscilador entre LP@32.768KHz<->Internal@1MHz
* Entrada a Menu por Ext Int0 RB0 / RB1 incrementa valor
* horas:minutos:segundos
* 11:59:59
*
* Solo muestra HH:MM
*/
// 'C' source line config statements
#define _XTAL_FREQ 32768 // 32.768KHz Crystal frecuency
#include <xc.h>
#include <stdint.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1H
#pragma config FOSC = INTIO67 // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 18 // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)
// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = PORTBE // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = ON // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for low-power operation)
#pragma config HFOFST = OFF // HFINTOSC Fast Start-up (The system clock is held off until the HFINTOSC is stable.)
#pragma config MCLRE = ON // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-003FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (004000-007FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (008000-00BFFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (00C000-00FFFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-003FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (004000-007FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (008000-00BFFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (00C000h-00FFFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)
//--------------------------------------------------------
#define menu_option 5 // numero de opciones del menu
#define led_row_0 LATAbits.LATA6 // habilita fila 0
#define led_row_1 LATAbits.LATA7 // habilita fila 1
#define led_stat LATBbits.LATB5 //
#define button_swicth_0 PORTBbits.RB0 // Boton sin presionar = 1
#define button_swicth_1 PORTBbits.RB1 // Boton presionado = 0
void config_OSC(void); //configuracion e reloj
void config_EUSART(void); // Configuracion puerto serial
void config_TMR0(void); // configurarion Timer0
void config_TMR1(void); // configurarion Timer1
void config_PORT(void); // configuracion puertos
void show_data(uint8_t data_to_display_hi,uint8_t data_to_display_lo,uint16_t time_active);
// Actualiza los datos a visualizar
//------------------------------------------------------------
uint8_t segundos = 0; // Contador segundos
uint8_t minutos = 0; // contador minutos
uint8_t horas = 0; // contador horas
uint8_t data_disp_hi; // 4 LEDS datos a dibujar parte alta
uint8_t data_disp_lo; // 6 LEDS datos a dibujar parte baja
uint16_t display_active_time; // Duración de encendido display
// Maximo 65536 // 100 aprox = 500ms
uint8_t display_en = 0; // bandera refresco display
uint8_t led_row_index = 0; // indicador parte alta o baja
uint16_t tmr0_retries = 0; // contador desbordes Tmr0
uint8_t menu_index = 0; // indica tarea a ejecutar
uint8_t button_flag = 0; // bandera boton interrupción Externa
// 0 esperando interrupción
// 1 button_switch_0 presionado
int main(void) {
config_OSC(); // Configuracion Oscilador
config_TMR0(); // Configurarion Timer0
config_TMR1(); // Configuracion Tmr1
config_PORT(); // Configuracion de Pines
INTCONbits.PEIE = 1;
//When IPEN = 0:
//1 = Enables all unmasked peripheral interrupts
//0 = Disables all peripheral interrupts
PIE1bits.TMR1IE = 1;
//TMR1IE: TMR1 Overflow Interrupt Enable bit
//1 = Enables the TMR1 overflow interrupt
//0 = Disables the TMR1 overflow interrupt
INTCON2bits.INTEDG0 = 0;
//INTEDG0: External Interrupt 0 Edge Select bit
//1 = Interrupt on rising edge
//0 = Interrupt on falling edge
INTCONbits.INT0IF = 0; // Limpiar bandera Ext Int0
INTCONbits.INT0IE = 1; // Initerrupción Externa Int0 ON
INTCONbits.GIE = 1; // Interrupción Global ON
//When IPEN = 0:
//1 = Enables all unmasked interrupts
//0 = Disables all interrupts including peripherals
while(1){ // Programa Principal
if(button_flag){ // Se presiono button_switch_0 ?
// Desperto uC
__delay_ms(100); // retardo antirebotes
if(button_swicth_0){ // Interruptor Abierto ?
show_data(horas,minutos,500); // Activar display X tiempo
while(display_en); // Esperar a que termine de
}// if button_0 // dibujar display
else{ // El Interruptor se mantiene Cerrado
while(button_swicth_0 == 0){ // Mientras interruptor
// Cerrado
menu_index++; // Incrementa variable Menu
if(menu_index > menu_option){
menu_index = 0; // Menu solo de 0 a menu_option
}//if menu index
show_data(menu_index,0,100); // Indice Menu mostrado en
while(display_en); // display parte Alta
}// while button_0
while(menu_index == 1 && button_swicth_0 == 1){
// Mientras Indice Menu 1 y no se
// presiones button_0
show_data(0,minutos,30); // parpadea minutos
while(display_en); // editables
if(button_swicth_1 == 0) // Incrementa minutos
minutos++; // si se presiona button_1
show_data(0,0,10);
while(display_en);
}// while menu_index 1
while(menu_index == 2 && button_swicth_0 == 1){
// Mientras Indice Menu 1 y no se
// presiones button_0
show_data(horas,0,30); // parpadea horas
while(display_en); // editables
if(button_swicth_1 == 0) // Incrementa horas
horas++; // si se presiona button_1
show_data(0,0,10);
while(display_en);
}// while menu_index 2
// Agregar Opciones siguiendo la sintaxis previa.
// while(menu_index == #opcion && button_swicth_0 == 1)...
}// else button_0
INTCONbits.INT0IF = 0; // Limpiar bandera Ext Int0
INTCONbits.INT0IE = 1; // Initerrupción Externa Int0 ON
button_flag = 0; // Limpiar bandera button
menu_index = 0; // Reinicia opciones menu_index
}
Sleep(); // Consumo Minimo,A despertar por Ext Int0/TMR1
} //loop Programa Principal
} //main loop
//------------------------------------------
void show_data(uint8_t data_to_display_hi,uint8_t data_to_display_lo,uint16_t time_active){
data_disp_hi = data_to_display_hi;
data_disp_lo = data_to_display_lo;
display_active_time = time_active; // indica tiempo de display encendido
// led_stat = 1; // LED de estado
OSCCONbits.SCS = 0b10; // Cambio de Oscilador LP a
// OScilador Inter 1MHz
TMR0 = 100; // Recarga Tmr0 para desborde
INTCONbits.TMR0IF = 0; // Limpiar bandera Tmr0
INTCONbits.TMR0IE = 1; // Interrupcion Tmr0 ON
T0CONbits.TMR0ON = 1; // Tmr0 ON
display_en = 1; // Habilita refresco display
}// show_data- datos parte alta/datos parte baja/tiempo de encendido
//------------------------------------------
void config_TMR0(void){ // configurarión Timer0
T0CON = 0b01000010;
//bit 7 TMR0ON: Timer0 On/Off Control bit
//1 = Enables Timer0
//0 = Stops Timer0
//bit 6 T08BIT: Timer0 8-bit/16-bit Control bit
//1 = Timer0 is configured as an 8-bit timer/counter
//0 = Timer0 is configured as a 16-bit timer/counter
//bit 5 T0CS: Timer0 Clock Source Select bit
//1 = Transition on T0CKI pin
//0 = Internal instruction cycle clock (CLKOUT)
//bit 4 T0SE: Timer0 Source Edge Select bit
//1 = Increment on high-to-low transition on T0CKI pin
//0 = Increment on low-to-high transition on T0CKI pin
//bit 3 PSA: Timer0 Prescaler Assignment bit
//1 = TImer0 prescaler is NOT assigned. Timer0 clock input bypasses prescaler.
//0 = Timer0 prescaler is assigned. Timer0 clock input comes from prescaler output.
//bit 2-0 T0PS<2:0>: Timer0 Prescaler Select bits
//111 = 1:256 prescale value
//110 = 1:128 prescale value
//101 = 1:64 prescale value
//100 = 1:32 prescale value
//011 = 1:16 prescale value
//010 = 1:8 prescale value
//001 = 1:4 prescale value
//000 = 1:2 prescale value
}
//------------------------------------------
void config_TMR1(void){ // configurarión Timer1
T1CON = 0b00001111;
//bit 7 RD16: 16-bit Read/Write Mode Enable bit
//1 = Enables register read/write of TImer1 in one 16-bit operation
//0 = Enables register read/write of Timer1 in two 8-bit operations
//bit 6 T1RUN: Timer1 System Clock Status bit
//1 = Main system clock is derived from Timer1 oscillator
//0 = Main system clock is derived from another source
//bit 5-4 T1CKPS<1:0>: Timer1 Input Clock Prescale Select bits
//11 = 1:8 Prescale value
//10 = 1:4 Prescale value
//01 = 1:2 Prescale value
//00 = 1:1 Prescale value
//bit 3 T1OSCEN: Timer1 Oscillator Enable bit
//1 = Timer1 oscillator is enabled
//0 = Timer1 oscillator is shut off
//The oscillator inverter and feedback resistor are turned off to eliminate power drain.
//bit 2 T1SYNC: Timer1 External Clock Input Synchronization Select bit
//When TMR1CS = 1:
//1 = Do not synchronize external clock input
//0 = Synchronize external clock input
//When TMR1CS = 0:
//This bit is ignored. Timer1 uses the internal clock when TMR1CS = 0.
//bit 1 TMR1CS: Timer1 Clock Source Select bit
//1 = External clock from pin RC0/T1OSO/T13CKI (on the rising edge)
//0 = Internal clock (FOSC/4)
//bit 0 TMR1ON: Timer1 On bit
//1 = Enables Timer1
}
//------------------------------------------
void config_PORT(VOID){
ANSEL = 0; // NO ANALOG
ANSELH = 0;
LATA = 0;
TRISA = 0;
// General I/O pins LED MAtrix
// RA7 -> Out LED horas mosfet enable
// RA6 -> Out LED minutos mosfet enable
// RA5 -> MSB LED
// RA4 ->
// RA3 ->
// RA2 ->
// RA1 ->
// RA0 -> LSB LED
INTCON2bits.RBPU = 0;
//RBPU: PORTB Pull-up Enable bit
//1 = All PORTB pull-ups are disabled
//0 = PORTB pull-ups are enabled provided that the pin is an input and the corresponding WPUB bit is
//set.
WPUB = 0b00000011;
// RB0-RB1 pull up enables
LATB = 0;
TRISB = 0b00000011;
// RB7
// RB6
// RB5
// RB4
// RB3
// RB2
// RB1 <- Input Button 1
// RB0 <- Input Button 2
LATC = 0;
TRISC = 0;
// RC7 <- Input SERIAL_RX
// RC6 -> Out SERIAL_TX
// RC5 ->
// RC4 ->
// RC3 // not used
// RC2 ->
// RC1 ->
// RC0 <->
}
//------------------------------------------
void config_OSC(void){
OSCCONbits.SCS = 0b01;
// SCS<1:0>: System Clock Select bits
//1x = Internal oscillator block
//01 = Secondary (Timer1) oscillator
//00 = Primary clock (determined by CONFIG1H[FOSC<3:0>]).
OSCCONbits.IRCF = 0b011; // 1MHz
// IRCF<2:0>: Internal Oscillator Frequency Select bits
//111 = 16 MHz (HFINTOSC drives clock directly)
//110 = 8 MHz
//101 = 4 MHz
//100 = 2 MHz
//011 = 1 MHz(3)
//010 = 500 kHz
//001 = 250 kHz
//000 = 31 kHz (from either HFINTOSC/512 or LFINTOSC directly)
//OSCTUNEbits.PLLEN = 1;
}
//------------------------------------------
/*** INTERRUPT SERVICE ROUTINE ***/
void interrupt isr(void){
//----------------- INT0 --------------------------------
if(INTCONbits.INT0IE == 1 && INTCONbits.INT0IF == 1){
// Interruptcion Externa Int0
button_flag = 1; // Establece bandera button
INTCONbits.INT0IE = 0; // Interrupcion Externa OFF
INTCONbits.INT0IF = 0; // limpiar bandera Ext Int0
}
//----------------- TIMER0 --------------------------------
if(INTCONbits.TMR0IE == 1 && INTCONbits.TMR0IF ==1){
//----------------- Rutina encendido LED ----------------
if(display_en){ // ¿habilitar display ?
if(led_row_index){
LATA = data_disp_lo; // Datos LEDs parte baja
led_row_1 = 0;
led_row_0 = 1; // Activa fila baja
led_row_index = 0; //parte baja
}// if led row
else{
LATA = data_disp_hi; // Datos LEDs parte alta
led_row_0 = 0; // fila apagada
led_row_1 = 1; // Activa fila Alta
led_row_index = 1; // parte Alta
}// else if led row
tmr0_retries++; // Incrementar contador de
// desbordes
if(tmr0_retries > display_active_time){
// Tiempo Activo alcanzado?
display_en = 0; // Limpiar bander display
tmr0_retries = 0; // Contador de desborde a 0
LATA = 0; // Puerto Apagado
OSCCONbits.SCS = 0b01; // LP oscillator
//SCS<1:0>: System Clock Select bits
//1x = Internal oscillator block
//01 = Secondary (Timer1) oscillator
INTCONbits.TMR0IF = 0; // Limpiar bandera Tmr0
INTCONbits.TMR0IE = 0; // Interrupcion Tmr0 OFF
T0CONbits.TMR0ON = 0; // Tmr0 OFF
// led_stat = 0; // LED indicador OFF
}// if / tiempo de encendido alcanzado
TMR0=100; // Precarga Tmr0/desborde en 5ms aprox
// refresco @ 100Hz
}// if- display Refresco @ 100Hz
//---------------------------------------------------------
INTCONbits.TMR0IF = 0; // Limpiar bandera Tmr0
}// TRM0 interrupt
//----------------- TIMER1 --------------------------------
if(PIE1bits.TMR1IE == 1 && PIR1bits.TMR1IF == 1){
TMR1H |= 1 << 7; // Precarga TMR1 =32768
// desborde cada 1segundo
PIR1bits.TMR1IF = 0; // limpiar bandera Tmr1
segundos++; // incrementa segundos
if(segundos > 59){ // 60 segundos?
minutos++; // aumenta minutos
segundos = 0; // reinicia regundos
if(minutos > 59){ // 60 minutos?
horas++; // aumenta horas
minutos = 0; // reinicia minutos
if(horas > 11){ // 12 horas ?
horas = 0; // reinicia horas
}// horas
}// minutos
}// segundos
}//TRM1 interrupt
//------------------------------------------------------------
}// ISR