Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

P18F4520 LCD Alarm Clock

Status
Not open for further replies.

symphony888

Newbie level 5
Joined
Nov 28, 2011
Messages
9
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,467
Hello. I need some help here for my programming. I managed to lit the LCD up using the default code. But I'm thinking of how to do an alarm clock or countdown timer by modifying it. I'm not sure how to modify but I need some help here. Here is the code I'm using.

/******* P3_MCC18.c ************************************************************
*
* Use 10 MHz crystal frequency.
* Use Timer0 for ten millisecond looptime.
* Blink "Alive" LED every two and a half seconds.
* Use pushbutton to exercise Screens utility.
*
******* Program hierarchy *****************************************************
*
* Mainline
* Initial
* InitLCD
* LoopTime
* DisplayC
* T40
* BlinkAlive
* Pbutton
* Screens
* DisplayC
* T40
* Frequency
* Period
* PWmax
* RateRPG
* ByteDisplay
* DisplayC
* T40
* DisplayV
* T40
* LoopTime
*
*******************************************************************************
*/

#include <p18cxxx.h>

/*******************************
* Assembler directives
*******************************
*/

/*******************************
* Definitions and equates
*******************************
*/

#define PBthres 30 // Pushbutton threshold for a long press

/*******************************
* Global variables
*******************************
*/

char TMR0LCOPY; // Copy of sixteen-bit Timer0 used by LoopTime
char TMR0HCOPY;
char INTCONCOPY; // Copy of INTCON for LoopTime subroutine
char COUNT; // Counter available as local to subroutines
char TEMP; // Temporary local variable
char ALIVECNT; // Counter for blinking "Alive" LED
char BYTE; // Eight-bit byte to be displayed
char OLDPORTD; // Holds previous value of inputs
char DELRPG; // Generated by RPG
char RPGCNT; // Used to display RPG changes
char PBCOUNT; // Counter for measuring duration of press
char SCREEN; // State of LCD subroutine
char LOOP10; // Scale of ten loop counter
char THR; // Threshold value used by Pbutton

struct { // Control/status bits for pushbutton
unsigned ISC:1; // Initiate screen change for slow press
unsigned ISA:1; // Initiate secondary action for fast press
unsigned PDONE:1; // Pushbutton action has been taken
unsigned OLDPB:1; // Old state of pushbutton
unsigned NEWPB:1; // New state of pushbutton
} PBSTATEbits;

/*******************************
* Constant strings
*******************************
*/

// For stability reasons, create an EVEN number of elements in any given array
const char LCDstr[] = {0x33,0x32,0x28,0x01,0x0c,0x06,0x00,0x00};// LCD Initialization string
const char StrtStr[] = {0x80,'P','u','s','h',' ','P','B',' ',0};// Startup screen
const char BYTE_1[] = {0x80,'B','Y','T','E','=',' ',' ',' ',0};// Write "BYTE=" 1st line of LCD
const char Clear1[] = {0x80,' ',' ',' ',' ',' ',' ',' ',' ',0};// Clear line 1
const char Clear2[] = {0xC0,' ',' ',' ',' ',' ',' ',' ',' ',0};// Clear line 2
const char FreqStr[] = {0x80,'F','r','e','q',' ','k','H','z',0};// Frequency instrument
const char PerStr[] = {0x80,'P','e','r',' ',' ',' ','u','s',0};// Period instrument
const char PWmaxStr[] = {0x80,'P','W','m','a','x',' ','u','s',0};// Max pulse width instrument

/*******************************
* Variable strings
*******************************
*/

char BYTESTR[] = {0,0,0,0,0,0,0,0,0,0}; // Display string for binary version of BYTE

/*******************************
* Function prototypes
*******************************
*/

void Initial(void);
void InitLCD(void);
void Looptime(void);
void T40(void);
void DisplayC(const char *);
void DisplayV(char *);
void BlinkAlive(void);
void LoopTime(void);
void ByteDisplay(void);
void RateRPG(void);
void Pbutton(void);
void Screens(void);
void Frequency(void);
void Period(void);
void PWmax(void);

/////// Mainline program ////////////////////////////////////////

/*******************************
* main()
*******************************
*/

void main()
{
Initial(); // Initialize everything

while(1)
{
PORTBbits.RB0 = !PORTBbits.RB0; // Toggle pin, to support measuring loop time
BlinkAlive(); // Blink "Alive" LED
Pbutton(); // Check pushbutton
Screens(); // Deal with SCREEN state
LoopTime(); // Make looptime be ten milliseconds
}
}

/*******************************
* Initial()
*
* This subroutine performs all initializations of variables and registers.
*******************************
*/

void Initial()
{
ADCON1 = 0b10001110; // Enable PORTA & PORTE digital I/O pins
TRISA = 0b11100001; // Set I/O for PORTA
TRISB = 0b11011100; // Set I/O for PORTB
TRISC = 0b11010000; // Set I/0 for PORTC
TRISD = 0b00001111; // Set I/O for PORTD
TRISE = 0b00000000; // Set I/O for PORTE
T0CON = 0b10001000; // Set up Timer0 for a looptime of 10 ms
PORTA = 0b00010000; // Turn off all four LEDs driven from PORTA
OLDPORTD = PORTD; // Initialize "old" value
RPGCNT = 0; // Clear counter to be displayed
PBCOUNT = 0; // and pushbutton count
SCREEN = 0; // Initialize LCD's SCREEN variable
THR = 0; // Initialize Pbutton's THR variable
PBSTATEbits.ISC = 0; // Initialize pushbutton state
PBSTATEbits.ISA = 0;
PBSTATEbits.PDONE = 0;
PBSTATEbits.OLDPB = 1;
PBSTATEbits.NEWPB = 0;
InitLCD(); // Initialize LCD
DisplayC(StrtStr); // Display startup message
}

/*******************************
* InitLCD()
*
* Initialize the Optrex 8x2 character LCD.
* First wait for 0.1 second, to get past display's power-on reset time.
*******************************
*/

void InitLCD()
{
char currentChar;
char *tempPtr;

COUNT = 10; // Wait 0.1 second
while (COUNT)
{
LoopTime(); // Call LoopTime() 10 times
COUNT--;
}

PORTEbits.RE0 = 0; // RS=0 for command
tempPtr = LCDstr;

while (*tempPtr) // if the byte is not zero
{
currentChar = *tempPtr;
PORTEbits.RE1 = 1; // Drive E pin high
PORTD = currentChar; // Send upper nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will accept nibble
LoopTime();
currentChar <<= 4; // Shift lower nibble to upper nibble
PORTEbits.RE1 = 1; // Drive E pin high again
PORTD = currentChar; // Write lower nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will process byte
LoopTime(); // Wait 40 usec
tempPtr++; // Increment pointerto next character
}
}

/*******************************
* T40()
*
* Pause for 40 microseconds or 40/0.4 = 100 clock cycles.
* Assumes 10/4 = 2.5 MHz internal clock rate.
*******************************
*/

void T40()
{
// Measured with oscilloscope to be about 42.80 us
// including the time to call this routine. Decrementing each
// "cCOUNT" takes approximately 4 us.

unsigned char cCOUNT = 7;
while (cCOUNT)
cCOUNT--;
}

/*******************************
* DisplayC(const char *)
*
* This subroutine is called with the passing in of an array of a constant
* display string. It sends the bytes of the string to the LCD. The first
* byte sets the cursor position. The remaining bytes are displayed, beginning
* at that position.
* This subroutine expects a normal one-byte cursor-positioning code, 0xhh, or
* an occasionally used two-byte cursor-positioning code of the form 0x00hh.
*******************************
*/

void DisplayC(const char * tempPtr)
{
char currentChar;

PORTEbits.RE0 = 0; // Drive RS pin low for cursor-positioning code
while (*tempPtr) // if the byte is not zero
{
currentChar = *tempPtr;
PORTEbits.RE1 = 1; // Drive E pin high
PORTD = currentChar; // Send upper nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will accept nibble
currentChar <<= 4; // Shift lower nibble to upper nibble
PORTEbits.RE1 = 1; // Drive E pin high again
PORTD = currentChar; // Write lower nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will process byte
T40(); // Wait 40 usec
PORTEbits.RE0 = 1; // Drive RS pin high for displayable characters
tempPtr++; // Increment pointerto next character
}
}

/*******************************
* DisplayV(char *)
*
* This subroutine is called with the passing in of an array of a variable
* display string. It sends the bytes of the string to the LCD. The first
* byte sets the cursor position. The remaining bytes are displayed, beginning
* at that position.
*******************************
*/

void DisplayV(char * tempPtr)
{
char currentChar;

PORTEbits.RE0 = 0; // Drive RS pin low for cursor-positioning code
while (*tempPtr) // if the byte is not zero
{
currentChar = *tempPtr;
PORTEbits.RE1 = 1; // Drive E pin high
PORTD = currentChar; // Send upper nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will accept nibble
currentChar <<= 4; // Shift lower nibble to upper nibble
PORTEbits.RE1 = 1; // Drive E pin high again
PORTD = currentChar; // Write lower nibble
PORTEbits.RE1 = 0; // Drive E pin low so LCD will process byte
T40(); // Wait 40 usec
PORTEbits.RE0 = 1; // Drive RS pin high for displayable characters
tempPtr++; // Increment pointerto next character
}
}

/*******************************
* BlinkAlive()
*
* This subroutine briefly blinks the LED next to the PIC every two-and-a-half
* seconds.
*******************************
*/

void BlinkAlive()
{
PORTAbits.RA4 = 1; // Turn off LED
if (!(--ALIVECNT)) // Decrement loop counter and return if not zero
{
ALIVECNT = 250; // Reinitialize BLNKCNT
PORTAbits.RA4 = 0; // Turn on LED for ten milliseconds every 2.5 sec
}
}

/*******************************
* LoopTime()
*
* This subroutine waits for Timer0 to complete its ten millisecond count
* sequence. It does so by waiting for sixteen-bit Timer0 to roll over. To obtain
* a period of precisely 10000/0.4 = 25000 clock periods, it needs to remove
* 65536-25000 or 40536 counts from the sixteen-bit count sequence. The
* algorithm below first copies Timer0 to RAM, adds "Bignum" to the copy ,and
* then writes the result back to Timer0. It actually needs to add somewhat more
* counts to Timer0 than 40536. The extra number of 12+2 counts added into
* "Bignum" makes the precise correction.
*******************************
*/

void LoopTime()
{
#define Bignum 65536-25000+12+2

while (!INTCONbits.T0IF); // Wait until ten milliseconds are up
INTCONCOPY = INTCON; // Save INTCON bits
INTCONbits.GIEH = 0; // Disable all interrupts from CPU
INTCONbits.GIEL = 0;
TMR0LCOPY = TMR0L; // Read 16-bit counter at this moment
TMR0HCOPY = TMR0H;
TMR0LCOPY += Bignum & 0x00FF; // add LSB
if (STATUSbits.C) // If Carry, increment high byte
TMR0HCOPY++;
TMR0HCOPY += (Bignum>>8) & 0x00FF; // add MSB
TMR0H = TMR0HCOPY;
TMR0L = TMR0LCOPY; // Write 16-bit counter at this moment
WREG = INTCONCOPY & 0b11000000; // Reenable interrupts to CPU if enabled prior
INTCON = INTCON | WREG; // to LoopTime
INTCONbits.T0IF = 0; // Clear Timer0 flag
}

/*******************************
* ByteDisplay()
*
* Display whatever is in BYTE as a binary number.
*******************************
*/

void ByteDisplay()
{
DisplayC(BYTE_1); // Display "BYTE="

COUNT = 8; // 8 bits in BYTE
while (COUNT)
{
TEMP = (BYTE & 0b00000001); // Move bit 0 of BYTE into TEMP
TEMP |= 0x30; // Convert to ASCII
BYTESTR[COUNT] = TEMP; // and move to string
BYTE = BYTE>>1; // Right shift bits in BYTE by 1
COUNT--; // Decrement COUNT;
}
BYTESTR[0] = 0xC0; // Add cursor-positioning code
BYTESTR[9] = 0; // and end-of-string terminator
DisplayV(BYTESTR); // Display the string
}


/*******************************
* RateRPG()
*
* This subroutine decyphers RPG changes into values of DELRPG.
* DELRPG = +2 for fast CW change, +1 for slow CW change, 0 for no change,
* -1 for slow CCW change and -2 for fast CCW change.
*******************************
*/

void RateRPG()
{
#define Threshold 3 // Value to distinguish between slow and fast
char W_temp;

PORTAbits.RA2 = 0; // Turn LED off
DELRPG = 0; // Clear for "no change" return value
W_temp = PORTD; // Copy PORTD into W_temp
TEMP = W_temp; // and TEMP
W_temp = W_temp ^ OLDPORTD; // Any change?
W_temp = W_temp & 0b00000011; // If not, W_temp = 0
if (W_temp != 0) // If the two bits have changed then...
{
W_temp = OLDPORTD>>1; // Form what a CCW change would produce
if (OLDPORTD & 0x01) // Make new bit 1 = complement of old bit 0
W_temp &= 0b11111101;
else
W_temp |= 0b00000010;
W_temp = (W_temp ^ TEMP); // Did the RPG actually change to this output?
W_temp &= 0b00000011; // Mask off upper 6 bits
if (W_temp == 0) // If so, then change DELRPG to -1 for CCW
{
DELRPG--;
if (THR != 0)
{
DELRPG--; // If fast turning, decrement again
PORTAbits.RA2 = 1; // Turn LED on
}
}
else
{
DELRPG++; // Otherwise, change DELRPG to +1 for CW
if (THR != 0)
{
DELRPG++; // If fast turning, increment again
PORTAbits.RA2 = 1; // Turn LED on
}
}
THR = Threshold; // Reinitialize THR
}
if (THR != 0) // Does THR equal zero
THR--; // If not, then decrement it
OLDPORTD = TEMP; // Save PORTD as OLDPORTD for ten ms from now
}

/*******************************
* Pbutton()
*
* This subroutine sorts out long and short pushbutton presses into two outputs:
* ISC=1: Initiate screen change for slow press
* ISA=1: Initiate secondary action for fast press
* PDONE=1 One of the above actions has occurred for this press
*******************************
*/

void Pbutton()
{
PBSTATEbits.ISC = 0; // Clear Initiate Screen Change bit (if set)
PBSTATEbits.ISA = 0; // Clear Initiate Secondary Action bit (if set)

if (PORTDbits.RD3 == 1) // Copy pushbutton state to NEWPB
PBSTATEbits.NEWPB = 1;
else
PBSTATEbits.NEWPB = 0;

if (PBSTATEbits.OLDPB) // Look for leading edge (OLDPB=1, NEWPB=0)
{
if (!PBSTATEbits.NEWPB)
PBCOUNT = PBthres; // Start counter
}

if (!PBSTATEbits.NEWPB) // Pushbutton is still pressed
{
if (!PBCOUNT) // and counter has passed threshold
if (!PBSTATEbits.PDONE) // and no action has yet been taken
{
PBSTATEbits.ISC = 1; // Initiate screen change
PBSTATEbits.PDONE = 1; // Done with pulse
}
}
else // Pushbutton has been released
PBSTATEbits.PDONE = 0; // so clear PDONE

if (!PBSTATEbits.OLDPB) // Look for trailing edge (OLDPB=0, NEWPB=1)
if (PBSTATEbits.NEWPB)
{
if (PBCOUNT) // Fast pulse
PBSTATEbits.ISA = 1; // Initiate secondary action
PBSTATEbits.PDONE = 0; // Done with pulse
PBCOUNT = 0; // Finish counting
}

if (PBCOUNT) // Has counter reached zero?
PBCOUNT--; // If not, then decrement it

if (PBSTATEbits.NEWPB) // Copy NEWPB to OLDPB
PBSTATEbits.OLDPB = 1;
else
PBSTATEbits.OLDPB = 0;
}

/*******************************
* Screens()
*
* This subroutine uses the ISC bit from the Pbutton subroutine to cycle the
* state of SCREEN and to take action based upon its value.
* Initially SCREEN=0, so that whatever screen is displayed by the Initial
* subroutine is not changed until a PB switch press. Then the screen
* corresponding to SCREEN=1 is displayed. Subsequent PB switch
* presses cycle through SCREEN=2, 3, etc., recycling back to SCREEN=1.
*******************************
*/

void Screens()
{
#define NumberOfScreens 4 // Change this value if new screens are added

if (PBSTATEbits.ISC)
{
SCREEN++;
if (SCREEN == (NumberOfScreens+1)) // Check if past last screen
SCREEN = 1; // Cycle back to SCREEN = 1

DisplayC(Clear1); // Clear the display when switching screens
DisplayC(Clear2);
}

if (SCREEN == 1)
{
if (PBSTATEbits.ISC)
DisplayC(FreqStr);
Frequency();
}

if (SCREEN == 2)
{
if (PBSTATEbits.ISC)
DisplayC(PerStr);
Period();
}

if (SCREEN == 3)
{
if (PBSTATEbits.ISC)
DisplayC(PWmaxStr);
PWmax();
if (PBSTATEbits.ISA) // Fast pulse, toggle PORTAbits.RA1
PORTAbits.RA1 = !PORTAbits.RA1;
}

if (SCREEN == 4)
{
RateRPG(); // Decypher RPG inputs into DELRPG
RPGCNT += DELRPG; // Increment or decrement RPGCNT from RPG
BYTE = RPGCNT; // Point BYTE to RPGCNT
ByteDisplay();
if (PBSTATEbits.ISA) // Fast pulse, reset RPGCNT
RPGCNT = 0;
}
}

/////// Stubs for measurement subroutines /////////////////////////////////////


void Frequency() { }
void Period() { }
void PWmax() { }
 

OK if your trying to modify your program... you must need to back up you source and then try to experiment the code. But you must need to analyse it first.
In alarm . try the comparing procedure, example you set the alarm time value. compare the value that you set to the real time then try to add some led to the board to test. If the set time and real time will match the led will turn on and if its not its off...
 

I have the LCD all with me. I just need to burn in it. Is there any way I could make like blinking texts or so ?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top