6digit Source

You might also like

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 12

/*

* PROJECT:
< LED 6-digit 24 / 12hr Clock >
* MCU:
PIC16F628a @4MHz
* Compiler:
mikroC PRO C ...
* Revision:
0.1b (conforms to hardware revision 0.1b and above)
* Status:
Working & complete pending further "real world" testing ...
Compiler Messages:
Available RAM: 208 [bytes], Available ROM: 2048 [bytes]
Used RAM (bytes): 25 (12%) Free RAM (bytes): 183 (88%)
Used ROM (program words): 660 (32%) Free ROM (program words): 1388 (68%)
Project Linked Successfully clock.mcppi
Linked in 657 ms
Project 'clock.mcppi' completed: 2032 ms
Finished successfully: 12 Apr 2011, 12:18:55 clock.mcppi
*/
//

:: Global Scope Variables ::

unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned

short
short
short
short
short
short
short
short
short
short

unsigned
unsigned
unsigned
unsigned

int
int
int
int

digitSc
hrsOnes
hrsTens
minOnes
minTens
secOnes
secTens
userSet
dgToSet
tScaler

flDgHrs
flDgMin
flDgSec
dBounce

=
=
=
=
=
=
=
=
=
=

0;
2;
1;
0;
0;
0;
0;
0;
0;
0;

//
//
//
//
//
//
//
//
//
//

Digit num (1 of 6) in current multiplex scope


Hours LSD (least significant digit)
Hours MSD (most significant digit)
Minutes LSD
Minutes MSD
Seconds LSD
Seconds MSD
Flag set true when user is adjusting time
Current set of digits in scope of adjustment
Time scaler to derive seconds from mS

=
=
=
=

0;
0;
0;
0;

//
//
//
//

Flash hours digits when being adjusted


^^ Minutes
^^ Seconds
De-bounce switch (timeout period no polling)

//

:: Defines ::

// Segments on displays ...


#define segA PORTB.F0
#define segB PORTB.F1
#define segC PORTB.F2
#define segD PORTB.F3
#define segE PORTB.F4
#define segF PORTB.F5
#define segG PORTB.F6
// User-defined 12 or 24hr mode operation ...
#define mode PORTB.F7

// Control lines to 4017 decade counter for display multiplexing


#define mclr PORTA.F0
#define clkc PORTA.F1
// Switch lines (set / inc switches for time adjustment) ...
#define cSet PORTA.F2
#define cInc PORTA.F3
//

:: Methods ::

/*
Tables containing segment settings corresponding to numbers for displays
*/
void num0()
{
segA = 1;
segB = 1;
segC = 1;
segD = 1;
segE = 1;
segF = 1;
segG = 0;
}
void num1()
{
segA = 0;
segB = 1;
segC = 1;
segD = 0;
segE = 0;
segF = 0;
segG = 0;
}
void num2()
{
segA = 1;
segB = 1;
segC = 0;
segG = 1;
segD = 1;
segE = 1;
segF = 0;
}
void num3()
{
segA = 1;
segB = 1;
segC = 1;
segD = 1;
segE = 0;
segF = 0;
segG = 1;
}
void num4()

{
segA
segD
segE
segF
segG
segB
segC

=
=
=
=
=
=
=

0;
0;
0;
1;
1;
1;
1;

}
void num5()
{
segA = 1;
segB = 0;
segE = 0;
segF = 1;
segG = 1;
segC = 1;
segD = 1;
}
void num6()
{
segA = 1;
segB = 0;
segC = 1;
segD = 1;
segE = 1;
segF = 1;
segG = 1;
}
void num7()
{
segA = 1;
segB = 1;
segC = 1;
segD = 0;
segE = 0;
segF = 0;
segG = 0;
}
void num8()
{
segA = 1;
segB = 1;
segC = 1;
segD = 1;
segE = 1;
segF = 1;
segG = 1;
}
void num9()
{
segA = 1;
segB = 1;
segC = 1;
segD = 0;

segE = 0;
segF = 1;
segG = 1;
}
void blankDigit()
{
segA = 0;
segB = 0;
segC = 0;
segD = 0;
segE = 0;
segF = 0;
segG = 0;
}
void interrupt()
{
/*
Interrupt handler triggered by MCU's TMRO (pre-scaler enabled)
*/
// Inc scaler
tScaler ++;
// 1000mS / 1 sec of time elapsed?
if (tScaler == 121)
{
// Inc seconds if enabled
if (userSet == 0)
{
secOnes ++;
}
// Fine tune adj
delay_us(2);
// Reset scaler
tScaler = 0;
}
// 50uS before re-triggering interrupt
delay_us(50);
// Fine tune adj
delay_us(3);
// Re-enable and bail
TMR0 = 0;
INTCON = 0x20;
}
void setDigit(unsigned short digit)
{
/*
Apply data to current display digit in scope
Structure implements no "ELSE IF" logic enabling for a relatively
good equalization of execution time regardless of program flow. Program

memory is also preserved.


*/
if (digit ==
{
num0();
}
if (digit ==
{
num1();
}
if (digit ==
{
num2();
}
if (digit ==
{
num3();
}
if (digit ==
{
num4();
}
if (digit ==
{
num5();
}
if (digit ==
{
num6();
}
if (digit ==
{
num7();
}
if (digit ==
{
num8();
}
if (digit ==
{
num9();
}

0)

1)

2)

3)

4)

5)

6)

7)

8)

9)

}
flashDigits(unsigned int digits)
{
/*
Counter for flashing digits on / off when user is adjusting them
*/
digits ++; // Inc
// Counter reached targed? -- reset if so ...
if (digits == 5000)
{
digits = 0;
}
// Return current count to calling procedure

return digits;
}
void incCounter()
{
// Current display off ...
blankDigit();
// Clock decade counter (inc to next display)
clkc = 1;
clkc = 0;
}
void multiplexDisplays()
{
/*
1. Procedure applies data to current display digit in scope ...
2. Successive handling of the displays in an multiplexing fashion
Structure implements no "ELSE IF" logic between digit scanning, enabling
for a relatively good equalization of execution time, regardless of
program flow. Program memory is also preserved, and consistent scanning
frequencies are the end results
*/
//
:: Hours Digit 1 ::
if (digitSc == 0)
{
if (flDgHrs < 2500)
{
// Lead zero blanking for 12hr mode ...
if (mode == 0 && hrsTens == 0)
{
blankDigit();
}
else
{
setDigit(hrsTens);
}
}
else
{
blankDigit();
}
}
//
if (digitSc == 1)
{
if (flDgHrs < 2500)
{
setDigit(hrsOnes);
}
else
{
blankDigit();
}
}

:: Hours Digit 2 ::

//

:: Minutes Digit 1 ::

if (digitSc == 2)
{
if (flDgMin < 2500)
{
setDigit(minTens);
}
else
{
blankDigit();
}
}
//
if (digitSc == 3)
{
if (flDgMin < 2500)
{
setDigit(minOnes);
}
else
{
blankDigit();
}
}

:: Minutes Digit 2 ::

//
if (digitSc == 4)
{
if (flDgSec < 2500)
{
setDigit(secTens);
}
else
{
blankDigit();
}
}

:: Seconds Digit 1 ::

//
if (digitSc == 5)
{
if (flDgSec < 2500)
{
setDigit(secOnes);
}
else
{
blankDigit();
}
}

:: Seconds Digit 2 ::

// Next digit to apply to ...


digitSc++;
// Reset 'n start again if this is the final digit in the chain
if (digitSc == 6)
{
digitSc = 0;
}
}

void doTime()
{
/*
Handles the incrementing and control of all time-related variables
in either 12 or 24hr time
1. Seconds
2. Minutes
3. Hours ...
*/
//

:: Seconds ::

if (secOnes == 10)
{
secTens ++; //
secOnes = 0; //
}
if (secTens == 6)
{
minOnes ++; //
secTens = 0; //
}

Inc tens
Reset ones

Inc / carry min ones


Reset tens

//

:: Mins ... ::

if (minOnes == 10)
{
minTens ++; //
minOnes = 0; //
}
if (minTens == 6)
{
hrsOnes ++; //
minTens = 0; //
}

Inc tens ...


Reset ones

Inc / carry hour ones


Reset min tens

//
:: Hours ... ::
if (hrsOnes == 10)
{
hrsTens ++; // Inc / carry tens
hrsOnes = 0; // Reset ones ...
}
// 12 or 24 mode in scope?
if (mode == 0)
{
//

:: (12hr mode) ::

// 12 hrs elapsed? -- reset ones & tens ...


if (hrsTens == 1)
{
if (hrsOnes == 3)
{
hrsTens = 0;
hrsOnes = 1;
}
}
}

else //
:: (24hr mode) ::
{
// 24 hrs elapsed? -- reset ones & tens ...
if (hrsTens == 2)
{
if (hrsOnes == 4)
{
hrsTens = 0;
hrsOnes = 0;
}
}
}
}
void doUser()
{
/*
Procedure handles the user adjusting the time via the 2
push button tactile switches ...
This proc renders the above proc out of scope until the
user has set all digits
*/
switch (dgToSet)
{
case 1: //

:: Setting Hours ::

// Inc button pressed and enabled after debounce period?


if (dBounce == 0)
{
if (cInc == 0)
{
// Debounce switch contacts (ignore port for a short time)
dBounce = 1250;
// 12 or 24 mode in play?
if (mode == 0)
{
// (12hr mode) -- reset tens & ones if exceeded 12
if (hrsTens == 1)
{
if (hrsOnes == 2)
{
hrsTens = 0;
hrsOnes = 0;
}
}
}
else // (24hr mode) -- reset tens & ones if exceeded 24
{
// Reset tens & ones
if (hrsTens == 2)
{
if (hrsOnes == 4)
{
hrsTens = 0;
hrsOnes = 0;
}
}

}
// Inc ones?
if (Hrsones != 9)
{
hrsOnes ++;
}
else // Inc tens & reset ones
{
hrsTens ++;
hrsOnes =0;
}
}
}
// Call method to flash digits
flDgHrs = flashDigits(flDgHrs);
break;
case 2: //

:: Setting Minutes ::

// Inc button pressed and enabled after debounce period?


if (dBounce == 0)
{
if (cInc == 0)
{
// Debounce switch contacts (ignore port for a short time)
dBounce = 1250;
// Reset tens & ones if exceeded 60
if (minTens == 5)
{
if (minOnes == 9)
{
minTens = 0;
minOnes = 0;
}
}
// Inc ones?
if (minOnes != 9)
{
minOnes ++;
}
else // Inc tens & reset ones
{
minTens ++;
minOnes =0;
}
}
}
// Call method to flash digits
flDgMin = flashDigits(flDgMin);
break;
case 3: //

:: Setting Seconds ::

// Inc button pressed and enabled after debounce period?


if (dBounce == 0)

{
if (cInc == 0)
{
// Debounce switch contacts (ignore port for a short time)
dBounce = 1250;
// Reset tens & ones if exceeded 60
if (secTens == 5)
{
if (secOnes == 9)
{
secTens = 0;
secOnes = 0;
}
}
// Inc ones?
if (secOnes != 9)
{
secOnes ++;
}
else // Inc tens & reset ones
{
secTens ++;
secOnes =0;
}
}
}
// Call method to flash digits
flDgSec = flashDigits(flDgSec);
break;
case 4: // Exit adj time proc ...
userSet = 0;
dgToSet = 0;
break;
}
}
void main()
{
/*
Program entry point ... (as per usual with any C compiler)
*/
// Configuration of ports etc ...
CMCON
TRISA
TRISB
PORTA
PORTB
OPTION_REG
//

=
=
=
=
=
=

7;
0x0C;
0x00;
0x00;
0x00;
0x84;

//
//
//
//
//
//

Disable analog comparators


2 inputs rest outputs
All outputs ...
Init port, all pins low
Init port, all pins low
assign prescaler to TMR0

TMR0
INTCON

OPTION_REG = %10000111
= 96;
= 0xA0;

' TMRO prescale = 256

// initial TMR0 value


// enable TMRO interrupt

// Reset decade counter & merger to main loop below ...


mclr = 1;
mclr = 0;
while(1)
{
// :: Infinite program loop :: //
// Display current digit ...
multiplexDisplays();
// Button allowed to be polled? / debounce period expired
if (dBounce == 0)
{
// Set button pressed?
if (cSet == 0)
{
userSet = 1;
// Flag set denoting user is adjusting time ...
dgToSet ++;
// Sec / min / hr digits in scope of being set
dBounce = 2500; // Set debounce period
// Reset specific variables:
flDgHrs = 0;
flDgMin = 0;
flDgSec = 0;

// Flash hours digits


// ^^ Minutes
// ^^ Seconds

}
}
else
{
dBounce --; // Dec counter to re-enable key polling
}
// Run clock or user is setting new time:
if (userSet == 0)
{
doTime(); // Update clock ...
}
else
{
doUser(); // User is adjusting the time
}
// Next display digit in scope
incCounter();
}
}

You might also like