/******* T2.c ****************** * * Use Fosc = 4 MHz for Fcpu = Fosc/4 = 1 MHz. * Sleep for 16 ms (nominal), using watchdog timeout for wakeup. * Toggle RC2 output every 16 milliseconds for measuring looptime with scope. * Blink LED on RD4 for 16 ms every four seconds. * Post PRESS PB message on LCD until first pushbutton push. * Increment LCD's CHAR0:CHAR1 every second. * Increment LCD's CHAR3:CHAR4 for each pushbutton press. * * Current draw = 7 uA (with LED and LCD switched off) * ******* Program hierarchy ***** * * main * Initial * Display * BlinkAlive * Time * Pushbutton * UpdateLCD * Display * ******************************* */ #include // Define PIC18LF4321 registers and bits #include // Used by the LoadLCDSTRING macro /******************************* * Configuration selections ******************************* */ #pragma config OSC = INTIO1 // Use internal osc, RA6=Fosc/4, RA7=I/O #pragma config PWRT = ON // Enable power-up delay #pragma config LVP = OFF // Disable low-voltage programming #pragma config WDT = OFF // Disable watchdog timer initially #pragma config WDTPS = 4 // 16 millisecond WDT timeout period, nominal #pragma config MCLRE = ON // Enable master clear pin #pragma config PBADEN = DIG // PORTB<4:0> = digital #pragma config CCP2MX = RB3 // Connect CCP2 internally to RB3 pin #pragma config BOR = SOFT // Brown-out reset controlled by software #pragma config BORV = 3 // Brown-out voltage set for 2.1V, nominal #pragma config LPT1OSC = OFF // Deselect low-power Timer1 oscillator /******************************* * Global variables ******************************* */ char PBFLAG; // Flag, set after first press of pushbutton char LCDFLAG; // Flag, set to send string to display char NEWPB; // Flag, set if pushbutton is now pressed char OLDPB; // Flag, set if pushbutton was pressed last loop unsigned char ALIVECNT; // Scale-of-248 counter for blinking "Alive" LED unsigned char TIMECNT; // Scale-of-62 counter of loop times = 1 second unsigned char ONES; // For display of seconds unsigned char TENS; unsigned char PBONES; // For display of pushbutton count unsigned char PBTENS; unsigned char i; // Index into strings unsigned int DELAY; // Sixteen-bit counter for obtaining a delay char LCDSTRING[] = "PRESS PB "; // LCD display string /******************************* * Function prototypes ******************************* */ void Initial(void); void BlinkAlive(void); void Pushbutton(void); void Time(void); void UpdateLCD(void); void Display(void); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } #define LoadLCDSTRING(lit) strcpypgm2ram(LCDSTRING,(const far rom char*)lit) /////// Main program ////////////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { Initial(); // Initialize everything while (1) { PORTCbits.RC2 ^= 1; // Toggle pin, for measuring loop time BlinkAlive(); // Blink "Alive" LED Time(); // Display seconds Pushbutton(); // Display pushbutton count UpdateLCD(); // Update LCD Sleep(); // Sleep, letting watchdog timer wake up chip Nop(); } } /******************************* * Initial * * This function performs all initializations of variables and registers. ******************************* */ void Initial() { OSCCON = 0b01100010; // Use Fosc = 4 MHz (Fcpu = 1 MHz) SSPSTAT = 0b00000000; // Set up SPI for output to LCD SSPCON1 = 0b00110000; ADCON1 = 0b00001011; // RA0,RA1,RA2,RA3 pins analog; others digital TRISA = 0b00001111; // Set I/O for PORTA TRISB = 0b01000100; // Set I/O for PORTB TRISC = 0b10000000; // Set I/O for PORTC TRISD = 0b10000000; // Set I/O for PORTD TRISE = 0b00000010; // Set I/O for PORTE PORTA = 0; // Set initial state for all outputs low PORTB = 0; PORTC = 0; PORTD = 0b00100000; // except RD5 that drives LCD interrupt PORTE = 0; SSPBUF = ' '; // Send a blank to initialize state of UART Delay(50000); // Pause for half a second RCONbits.SBOREN = 0; // Now disable brown-out reset PBFLAG = 0; // Clear flag until pushbutton is first pressed LCDFLAG = 0; // Flag to signal LCD update is initially off TIMECNT = 0; // Reset TIMECNT TENS = '5'; // Initialize to 59 so first display = 00 ONES = '9'; PBTENS = '0'; // Initialize count of pushbutton presses PBONES = '1'; OLDPB = 0; // Initialize to unpressed pushbutton state ALIVECNT = 247; // Blink immediately WDTCONbits.SWDTEN = 1; // Enable watchdog timer Display(); // Display initial "PRESS PB" message LoadLCDSTRING("00 01 "); // Reinitialize LCDSTRING } /******************************* * BlinkAlive * * This function briefly blinks the LED every four seconds. * With a looptime of about 16 ms, count 4x62 = 248 looptimes ******************************* */ void BlinkAlive() { PORTDbits.RD4 = 0; // Turn off LED if (++ALIVECNT == 248) // Increment counter and return if not 248 { ALIVECNT = 0; // Reset ALIVECNT PORTDbits.RD4 = 1; // Turn on LED for 16 ms every 4 secs } } /******************************* * Time * * After pushbutton is first pushed, display seconds. ******************************* */ void Time() { if (PBFLAG) // After pushbutton is first pushed, { if (++TIMECNT == 62) // count TIMECNT to 1 second { TIMECNT = 0; // Reset TIMECNT for next second if (++ONES > '9') // and increment time { ONES = '0'; if (++TENS > '5') { TENS = '0'; } } LCDSTRING[0] = TENS; // Update display string LCDSTRING[1] = ONES; LCDFLAG = 1; // Set flag to display } } } /******************************* * Pushbutton * * After pushbutton is first pressed, display pushbutton count. ******************************* */ void Pushbutton() { PORTEbits.RE0 = 1; // Power up the pushbutton Nop(); // Delay one microsecond before checking it NEWPB = !PORTDbits.RD7; // Set flag if pushbutton is pressed PORTEbits.RE0 = 0; // Power down the pushbutton if (!OLDPB && NEWPB) // Look for last time = 0, now = 1 { if (!PBFLAG) // Take action for very first PB press { PBFLAG = 1; ALIVECNT = 0; // Synchronize LED blinking to counting TIMECNT = 61; // Update display immediately } else // Take action for subsequent PB presses { if (++PBONES > '9') // and increment count of PB presses { PBONES = '0'; if (++PBTENS > '9') { PBTENS = '0'; } } } LCDSTRING[3] = PBTENS; // Update display string for simulated LCD LCDSTRING[4] = PBONES; LCDFLAG = 1; // Set flag to display } OLDPB = NEWPB; // Save present pushbutton state } /******************************* * UpdateLCD * * This function updates the 8-character LCD once the pushbutton has * first been pressed, if Time or Pushbutton has set LCDFLAG. ******************************* */ void UpdateLCD() { if(PBFLAG && LCDFLAG) { Display(); LCDFLAG = 0; } } /******************************* * Display() * * This function sends LCDSTRING to the LCD. ******************************* */ void Display() { PORTDbits.RD5 = 0; // Wake up LCD display for (i = 0; i <= 8; i++) { PIR1bits.SSPIF = 0; // Clear SPI flag SSPBUF = LCDSTRING[i]; // Send byte while (!PIR1bits.SSPIF); // Wait for transmission to complete } PORTDbits.RD5 = 1; // Return RB5 high, ready for next string }