Created
August 28, 2017 19:38
-
-
Save CaitlynMainer/6cc74717c10d8ecc4f2d3921358ad238 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <xc.h> //PIC hardware mapping | |
#define _XTAL_FREQ 8000000 //Used by the XC8 delay_ms(x) macro | |
//so Fosc is 8MHz | |
#define KEY_SHORT_TIME 200 | |
//#define KEY_LONG_TIME 50 | |
#define POWERSAVE_TIMEOUT 3000 | |
//CONFIGURATION word | |
//FOSC<2:0>: 100 = INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN | |
__PROG_CONFIG(1, 0x00E4); //0b0000 0000 1110 0100 page201 | |
void flash_digital(void);//7-segment LED digital display update | |
void detect_key(void);//detect user key | |
void clock_increase(void);//clock update | |
//display variables: | |
const char seg_tab[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//for common anode segment | |
volatile char digital[4];//data to be display on every segments | |
volatile char show_dots = 1;//the flag represent if show the dots, 0: hide, 1: show | |
volatile char flash_dots = 0;//if flash the dots, 0: do not flash, 1: flash dots | |
//key variables: | |
volatile char key_value = 0;//0: no key, 1:single key, 2:continuous key | |
volatile char key_delay_time = KEY_SHORT_TIME; | |
volatile unsigned int no_key_time = 0;//the time represent that how much time since release the key | |
//system variables: | |
enum SysState{NormalMode, Setting}; | |
enum SysState sysstate = NormalMode;//System State Mechine, | |
volatile char isPowerSaveMode = 0;//0: normal working, 1: power save mode | |
volatile unsigned int power_save_timeout = 0; | |
volatile char hours = 1, minutes = 0, seconds = 0;//hours, minutes and seconds to be display | |
void main(void) | |
{ | |
//System Clock Configuration | |
//IRCF<2:0>: 111 = 8MHz | |
//SCS: 0 = Clock source defined by FOSC<2:0> of the CONFIG register | |
OSCCON = 0b01110000;//page50 | |
while((OSCCON & (1<<2) == 0));//wait for HFINTOSC stable | |
//timer0 clock is Fosc / 4 = 8MHz / 4 = 2MHz | |
//after config OPTION_REG, TMR rate is 2MHz / 16 = 125kHz due to PS<2:0> = 011 | |
OPTION_REG=0b00000011; // Pull-ups on PORTA/PORTB are enabled | |
// Interrupt on falling edge of INT pin | |
// Internal instruction cycle clock (FOSC/4) | |
// Increment on high-to-low transition on T0CKI pin | |
// Prescaler is assigned to the Timer0 module | |
// PS<2:0>: Prescaler Rate Select bits: 011 1:16 | |
//set flow rate: 125kHz / 125 = 1kHz | |
TMR0 = 256 - 125; //reset timer counter | |
INTCONbits.GIE=1; // Enable Global interrupt | |
INTCONbits.T0IE=1; // Enable Timer0 interrupts | |
INTCONbits.T0IF=0; // Clear the interrupt flag bit of timer 0 | |
ANSEL = 0; // Initialize A/D ports off | |
CM1CON0 = 0; // Initialize Comparator 1 off | |
CM2CON0 = 0; // Initialize Comparator 2 off | |
//GPIO configuration | |
TRISA |= ((1<<2) | (1<<3)); //configure RA2/3 as input | |
TRISA &=~ ((1<<0) | (1<<1) | (1<<4) | (1<<5)); //configure RA0/1/4/5 as output | |
TRISC = 0x00; //configure RC as output | |
PORTA &= ~((1<<0) | (1<<1) | (1<<4) | (1<<5)); //no segment on | |
PORTC = 0xFF; | |
TRISB |= (1<<7); //configure RB7 as input | |
WPUB |= (1<<7); //enable RB7 internal pull up | |
//loop | |
while(1) | |
{ | |
if(sysstate == NormalMode)//Idle State | |
{ | |
if(key_value == 1) | |
{ | |
key_value = 0; | |
//no action | |
} | |
if(key_value == 2)//continuous key | |
{ | |
sysstate = Setting;//switch to setting mode | |
flash_dots = 1;//begin to flash dots | |
while((PORTA & (1<<2)) == 0); | |
key_value = 0; | |
} | |
} | |
else//Setting State` | |
{ | |
if((key_value == 1) || (key_value == 2)) | |
{ | |
key_value = 0; | |
//clock_increase(); | |
//the key will increase minutes | |
minutes++; | |
if(minutes == 60) | |
{ | |
minutes = 0; | |
hours++; | |
if(hours == 13) | |
{ | |
hours = 1; | |
} | |
} | |
} | |
if(no_key_time > 500) | |
{ | |
sysstate = NormalMode;//return to Idle mode after release the key for a while | |
flash_dots = 0; | |
} | |
} | |
if((isPowerSaveMode == 1) && ((PORTB & (1<<7)) == 0))//return to normal mode when RB7 goes to 0 | |
{ | |
isPowerSaveMode = 0;//enter normal mode | |
power_save_timeout = 0; | |
} | |
} | |
} | |
//7-segment LED digital display update 5ms | |
void flash_digital(void) | |
{ | |
static char curseg = 0;//which segment to flash | |
static char show_dots = 1;//the flag represent if show the dots, 0: hide, 1: show | |
static int counter = 0; | |
digital[3] = hours / 10; | |
digital[2] = hours % 10; | |
digital[1] = minutes / 10; | |
digital[0] = minutes % 10; | |
if(flash_dots != 0)//flash dots | |
{ | |
counter++; | |
if(counter == 100) | |
{ | |
show_dots = 0; | |
} | |
if(counter == 200) | |
{ | |
counter = 0; | |
show_dots = 1; | |
} | |
} | |
else//do not flash dots | |
{ | |
counter = 0; | |
show_dots = 1; | |
} | |
PORTA &= ~((1<<0) | (1<<1) | (1<<4) | (1<<5));//shut all segments first | |
if(isPowerSaveMode == 0)//normal display | |
{ | |
switch (curseg)//light up the specified one | |
{ | |
case 0: | |
if(show_dots != 0) PORTC = seg_tab[digital[0]] & ~(1<<7);//data to be displayed | |
else PORTC = seg_tab[digital[0]];//data to be displayed | |
PORTA |= (1<<0);//light up one segment | |
break; | |
case 1: | |
if(show_dots != 0) PORTC = seg_tab[digital[1]] & ~(1<<7);//data to be displayed | |
else PORTC = seg_tab[digital[1]];//data to be displayed | |
PORTA |= (1<<1);//light up one segment | |
break; | |
case 2: | |
PORTC = seg_tab[digital[2]];//data to be displayed | |
PORTA |= (1<<4);//light up one segment | |
break; | |
case 3: | |
PORTC = seg_tab[digital[3]];//data to be displayed | |
PORTA |= (1<<5);//light up one segment | |
break; | |
default: | |
break; | |
} | |
} | |
if(++curseg == 4) | |
curseg = 0; | |
} | |
//clock update | |
void clock_increase(void) | |
{ | |
seconds++; | |
if(seconds == 60) | |
{ | |
seconds = 0; | |
minutes++; | |
if(minutes == 60) | |
{ | |
minutes = 0; | |
hours++; | |
if(hours == 13) | |
{ | |
hours = 1; | |
} | |
} | |
} | |
} | |
//detect user key 10ms | |
void detect_key(void) | |
{ | |
static char keystate = 0; | |
static char counter = 0; | |
char key; | |
if (key_value != 0) | |
{ | |
return; | |
} | |
key = PORTA & (1<<2); | |
if(key != 0)//no key pressed | |
{ | |
if(no_key_time < 520) no_key_time++; | |
} | |
else | |
{ | |
no_key_time = 0;//clear the counter | |
} | |
switch (keystate) | |
{ | |
case 0: | |
if (key == 0)//first press | |
{ | |
keystate = 1; | |
} | |
break; | |
case 1: | |
if (key == 0)//press confirmed | |
{ | |
keystate = 2; | |
key_value = 1;//generate a single key flag | |
isPowerSaveMode = 0;//enter normal mode | |
power_save_timeout = 0; | |
} | |
else//press jitter | |
{ | |
keystate = 0;//back to idle | |
} | |
break; | |
case 2: | |
if (key == 0)//keep pressing | |
{ | |
if(counter < key_delay_time)//wait for a moment | |
{ | |
counter++; | |
} | |
else | |
{ | |
key_value = 2;//generate a continuous key | |
isPowerSaveMode = 0;//enter normal mode | |
power_save_timeout = 0; | |
} | |
} | |
else//first released | |
{ | |
keystate = 3; | |
} | |
break; | |
case 3: | |
if (key != 0)//release confirmed | |
{ | |
keystate = 0; | |
counter = 0; | |
} | |
else//released jitter | |
{ | |
keystate = 2;//back to last state | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
//timer0 overflow interrupt | |
void interrupt ISR(void) | |
{ | |
static char cnt1 = 0, cnt2 = 0; | |
static int timming_cnt = 0; | |
static char x = 0; | |
if (INTCONbits.T0IF)//confirm it is the timer0 overflow interrupt | |
{ | |
INTCONbits.T0IF = 0;//MUST clear interrupt flag by software | |
TMR0 = 256 - 125; //reset timer counter | |
if(x == 0) | |
{ | |
PORTB |= (1<<7); | |
x = 1; | |
} | |
else | |
{ | |
PORTB &= ~(1<<7); | |
x = 0; | |
} | |
cnt1++; | |
if (cnt1 >= 5) | |
{ | |
cnt1 = 0; | |
flash_digital(); | |
} | |
cnt2++; | |
if (cnt2 >= 10) | |
{ | |
cnt2 = 0; | |
detect_key();//key check periodically | |
} | |
// clock counter | |
timming_cnt++; | |
if(timming_cnt >= 1000) | |
{ | |
timming_cnt = 0; | |
clock_increase(); | |
} | |
if(power_save_timeout < POWERSAVE_TIMEOUT) | |
{ | |
power_save_timeout++; | |
} | |
else if((sysstate == NormalMode) && ((PORTB & (1<<7)) != 0)) | |
{ | |
isPowerSaveMode = 1;//enter power save mode | |
power_save_timeout = 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment