/******* DevPVz.c *************** * * Q&L Development Board Performance Verification program. * * VDD = 5V for use with standard off-the-shelf 24x2 character LCD. * Use Fosc = 4 MHz for Fcpu = Fosc/4 = 1 MHz. * Sleep for 10 ms, using watchdog timer for wakeup * Toggle RD0 output every loop time for measuring with scope. * Blink LED on RE2 for 16 ms every two seconds. * Display "Qwik&Low Development Bd." on top line of LCD. * Display a single incrementing letter on second line of LCD. * * Current draw = 40 uA (regulator + 4321) * Current draw with LCD = 1.118 mA * ******* Program hierarchy ***** * * main * Initial * InitLCD * DisplayC * BlinkAlive * LoopTime * * LoPriISR * ******************************* */ #include // Define PIC18LF4321 registers and bits /******************************* * 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 ******************************* */ unsigned int DELAY; // Counter for obtaining a delay unsigned char ALIVECNT; // Counter for blinking "Alive" LED char COUNT; // Counter available as local to subroutines unsigned char PORTACOPY; // Used by InitLCD and DisplayC const rom char *romPtr; // Pointer into ROM strings char *ramPtr; // Pointer into RAM strings /******************************* * Constant strings ******************************* */ const rom char LCDstr[] = { 0x33, 0x32, 0x28, 0x01, 0x0c, 0x06, 0x00, 0x00 }; // LCD controller initialization string const rom char StrtStr[] = { "\x80Qwik&Low Development Bd.\x00" }; // Startup screen /******************************* * Variable strings ******************************* */ char VarStr[] = { 0xCC, 0x41, 0x00 }; // One-character variable /******************************* * Function prototypes ******************************* */ void Initial(void); void BlinkAlive(void); void LoopTime(void); void InitLCD(void); void DisplayC(void); void DisplayV(void); /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } /////// Main program ///////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { Initial(); // Initialize everything T1CONbits.TMR1ON = 1; // Start Timer1 counting while (1) { PORTDbits.RD0 ^= 1; // Toggle RD0 for measuring loop time BlinkAlive(); // Blink LED every two seconds LoopTime(); // Sleep for ten ms } } /******************************* * Initial * * This function performs all initializations of variables and registers. ******************************* */ void Initial() { OSCCON = 0b01100010; // Use Fosc = 4 MHz (Fcpu = 1 MHz) ADCON1 = 0b00001111; // RA0,1,2,... digital TRISA = 0b00000000; // Set I/O for PORTA TRISB = 0b01110100; // Set I/O for PORTB TRISC = 0b10000000; // Set I/O for PORTC TRISD = 0b00000000; // Set I/O for PORTD TRISE = 0b00000000; // Set I/O for PORTE PORTA = 0; // Set initial state for all outputs PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; Delay(50000); // Pause for half a second RCONbits.SBOREN = 0; // Now disable brown-out reset ALIVECNT = 122; // Blink immediately InitLCD(); // Initialize LCD romPtr = StrtStr; // Point to StrtStr DisplayC(); // Display startup message WDTCONbits.SWDTEN = 1; // Enable watchdog timer } /******************************* * InitLCD() * * Initialize the LCD for a four-bit interface, a two-line display. Then clear * display, turn off cursor, turn on display and increment cursor automatically. ******************************* */ void InitLCD() { PORTEbits.RE0 = 0; // RS=0 for command Delay(5000); // Wait 50 ms for LCD controller to power up romPtr = LCDstr; // Load pointer to beginning of string while (*romPtr) // Send char if the byte is not zero { PORTACOPY = *romPtr; // Get byte PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble Delay(500); // Wait for 5 ms PORTACOPY = *romPtr; // Get byte again PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will process byte Delay(500); // Wait 5 ms romPtr++; // Increment pointer to next character } } /******************************* * DisplayC() * * This subroutine is called with romPtr loaded with the name of a * constant display string stored in program memory. The format of the * constant string is: * Cursor-position code (CPC) * Displayable characters * A null character (0x00) to terminate the string * The cursor-position code identifies the location to be used by the * first displayable character. * For the top row of the 24x2 LCD, the CPC's are 0x80, 0x81,..., 0x97 * For the second row of the 24x2 LCD, the CPC's are 0xC0, 0xC1,..., 0D7 ******************************* */ void DisplayC() { PORTEbits.RE0 = 0; // RS=0 for command (CPC) while (*romPtr) // Send char if the byte is not zero { PORTACOPY = *romPtr; PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble PORTACOPY = *romPtr; PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will process byte Delay(4); // Wait 40 usec PORTEbits.RE0 = 1; // Drive RS pin high for displayable chars romPtr++; // Increment pointer to next character } } /******************************* * DisplayV() * * This subroutine is called with ramPtr loaded with the name of a * variable display string stored in RAM. The format of the * variable string is: * Cursor-position code (CPC) * Displayable characters * A null character (0x00) to terminate the string * The cursor-position code identifies the location to be used by the * first displayable character. * For the top row of the 24x2 LCD, the CPC's are 0x80, 0x81,..., 0x97 * For the second row of the 24x2 LCD, the CPC's are 0xC0, 0xC1,..., 0D7 ******************************* */ void DisplayV() { PORTEbits.RE0 = 0; // RS=0 for command (CPC) while (*ramPtr) // Send char if the byte is not zero { PORTACOPY = *ramPtr; PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble PORTACOPY = *ramPtr; PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY & 0b00111100; // Force other four bits to zero PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will process byte Delay(4); // Wait 40 usec PORTEbits.RE0 = 1; // Drive RS pin high for displayable chars ramPtr++; // Increment pointer to next character } } /******************************* * BlinkAlive() * * This function briefly blinks the LED every two seconds. * With a looptime of 16 ms, count 125 looptimes ******************************* */ void BlinkAlive() { PORTEbits.RE2 = 0; // Turn off LED if (++ALIVECNT == 125) // Increment counter and return if not 200 { ALIVECNT = 0; // Reset ALIVECNT PORTEbits.RE2 = 1; // Turn on LED for 10 ms every 2 secs ramPtr = VarStr; // Set pointer <<<<---- DisplayV(); VarStr[1] += 1; // Increment character } } /******************************* * LoopTime * * This function puts the chip to sleep upon entry. * It uses the watchdog timer to awaken again. ******************************* */ void LoopTime() { Sleep(); Nop(); }