Entry 3092
PIC stuff
Submitted by anonymous
on Jan. 26, 2010 at 6:04 a.m.
Language: C. Code size: 15.8 KB.
/******* DevPV.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 Timer1 for wakeup. * Toggle RD0 output every loop time for measuring with scope. * Blink LED on RE2 for 10 ms every two seconds. * Display "Qwik&Low Development Bd." on 24x2 character LCD. * * Current draw = 33 uA (regulator + 4321) * Current draw with LCD = 1.118 mA * ******* Program hierarchy ***** * * main * Initial * InitLCD * DisplayRom * DisplayV * BlinkAlive * LoopTime * * LoPriISR * ******************************* */ //#include <p18f4321.h> // 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 char LPISRFLAG; // Flag, set when LP interrupt has been // handled Timer1 unsigned char RED; unsigned char GREEN; unsigned char BLUE; unsigned int TIME1; unsigned int TIME2; unsigned int period; unsigned int BIGNUM; unsigned char TENTHOUSANDS; unsigned char THOUSANDS; unsigned char HUNDREDS; unsigned char TENS; unsigned char ONES; unsigned char DELRPG; unsigned char NEW_PRESSED; unsigned char OLD_PRESSED; unsigned char mode = 0; unsigned int RPGVAL; int temp_color; char loopcnt; char color; char timer_toggle; /******************************* * Constant strings ******************************* */ const char LCDstr[] = { 0x33, 0x32, 0x28, 0x01, 0x0c, 0x06, 0x00, 0x00 }; // LCD controller initialization string //const char StrtStr[] = { "\x80Qwik&Low Development Bd.\x00" }; // Startup screen /******************************* * Variable strings ******************************* */ const rom char T_RED[] = {"\x80 red \x00"}; const rom char T_BLUE[] = {"\x8B blue \x00"}; const rom char T_GREEN[] = {"\x85 green \x00"}; //const rom char sending[] = {"\x90sending\x00"}; //const rom char not_sending[] = {"\x90 \x00"}; char RED_STR[] = { "\xc0 000 \x00" }; char BLUE_STR[] = { "\xcB 000 \x00" }; char GREEN_STR[] = { "\xc5 000 \x00" }; char NUM[] = { "\xd0 00000\x00" }; /******************************* * Function prototypes ******************************* */ void Initial(void); void BlinkAlive(void); void LoopTime(void); void InitLCD(void); void DisplayRom(const rom char *); void DisplayV(char *); void LoPriISR(void); void HiPriISR(void); void ASCII4(void); void RPG(void); void InitTX(void); const unsigned char MAX_CAP_TIME = 50; /******************************* * Macros ******************************* */ #define Delay(x) DELAY = x; while(--DELAY){ Nop(); Nop(); } #define TXascii(in) TXREG = in; while(!TXSTAbits.TRMT) /******************************* * Interrupt vector ******************************* */ // For low priority interrupts: #pragma code low_vector=0x18 void interrupt_at_low_vector(void) { _asm GOTO LoPriISR _endasm } #pragma code #pragma interruptlow LoPriISR /////// Main program ///////////////////////////////////////////////////// /******************************* * main ******************************* */ void main() { int capture_time = MAX_CAP_TIME; Initial(); // Initialize everything InitTX(); T1CONbits.TMR1ON = 1; // Start Timer1 counting T3CONbits.TMR3ON = 1; color = 0; loopcnt = -10; timer_toggle = 0; PORTDbits.RD1 = 1; //turn on the chip PORTDbits.RD4 = 1; //100% frequency scalling PORTDbits.RD5 = 1; //100% frequency scalling mode = 2; while (1) { //INTCONbits.GIEL = 0; T1CONbits.TMR1ON = 0; PORTDbits.RD0 ^= 1; // Toggle RD0 for measuring loop time RPG(); if (DELRPG) { DELRPG = 0; loopcnt = -10; PORTDbits.RD3 = 1;//disable output PORTDbits.RD4 = 1; //power up PORTDbits.RD5 = 1; Delay(50); color = mode; if (color == 0) {//red PORTDbits.RD6 = 0; PORTDbits.RD7 = 0; timer_toggle = 1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 0; //enable output while (PIR1bits.CCP1IF != 1) { } TIME1 = CCPR1; PIR1bits.CCP1IF = 0; while (PIR1bits.CCP1IF != 1) { } TIME2 = CCPR1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 1; //disable output PORTDbits.RD4 = 0; //powerdown mode PORTDbits.RD5 = 0; period = TIME2 - TIME1; temp_color = (int) (255 - ((long int) (period - 45) * 255) / 1860); if (temp_color > 255) RED = 255; else if (temp_color < 0) RED = 0; else RED = (unsigned char) temp_color; BIGNUM = RED; ASCII4(); RED_STR[2] = HUNDREDS; RED_STR[3] = TENS; RED_STR[4] = ONES; DisplayV(RED_STR); TXascii(RED) ; } else if (color == 2) {//blue PORTDbits.RD6 = 0; PORTDbits.RD7 = 1; timer_toggle = 1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 0; //enable output while (PIR1bits.CCP1IF != 1) { } TIME1 = CCPR1; PIR1bits.CCP1IF = 0; while (PIR1bits.CCP1IF != 1) { } TIME2 = CCPR1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 1; //disable output PORTDbits.RD4 = 0; //powerdown mode PORTDbits.RD5 = 0; period = TIME2 - TIME1; temp_color = (int) (255 - ((long int) (period - 50) * 255) / 5700); //temp_color = (int) (255 - (period - 300)*(((double)255)/5700)); if (temp_color > 255) BLUE = 255; else if (temp_color < 0) BLUE = 0; else BLUE = (unsigned char) temp_color; BIGNUM = BLUE; ASCII4(); BLUE_STR[2] = HUNDREDS; BLUE_STR[3] = TENS; BLUE_STR[4] = ONES; DisplayV(BLUE_STR); TXascii(BLUE) ; } else if (color == 1) {//green PORTDbits.RD6 = 1; PORTDbits.RD7 = 1; timer_toggle = 1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 0; //enable output while (PIR1bits.CCP1IF != 1) { ; } TIME1 = CCPR1; PIR1bits.CCP1IF = 0; while (PIR1bits.CCP1IF != 1) { ; } TIME2 = CCPR1; PIR1bits.CCP1IF = 0; PORTDbits.RD3 = 1; //disable output PORTDbits.RD4 = 0; //powerdown mode PORTDbits.RD5 = 0; period = TIME2 - TIME1; temp_color = (int) (255 - ((long int) (period - 18) * 255) / 3360); if (temp_color > 255) GREEN = 255; else if (temp_color < 0) GREEN = 0; else GREEN = (unsigned int) temp_color; BIGNUM = GREEN; ASCII4(); GREEN_STR[2] = HUNDREDS; GREEN_STR[3] = TENS; GREEN_STR[4] = ONES; DisplayV(GREEN_STR); TXascii(GREEN) ; } BIGNUM = period; ASCII4(); NUM[2] = TENTHOUSANDS; NUM[3] = THOUSANDS; NUM[4] = HUNDREDS; NUM[5] = TENS; NUM[6] = ONES; DisplayV(NUM); } PORTDbits.RD3 = 1; //disable output PORTDbits.RD4 = 0; //powerdown mode PORTDbits.RD5 = 0; BlinkAlive(); // Blink LED every two seconds //INTCONbits.GIEL = 1; T1CONbits.TMR1ON = 1; LoopTime(); // Sleep for ten ms } } /******************************* * LoPriISR * * This low-priority interrupt service routine updates Timer1 to interrupt * every 10 ms. Ten ms = 10000 * 0.032768 = 328 to cut out all * but 328 counts. Reload TMR1 with 65536+1-328 = 65209 = 0xFEB9. ******************************* */ void LoPriISR() { T1CONbits.TMR1ON = 0; // Pause Timer1 counter TMR1L += 0xB9; // Cut out all but 328 counts of Timer1 T1CONbits.TMR1ON = 1; // Resume Timer1 counter TMR1H = 0xFE; // Upper byte of Timer1 will be 0xFE PIR1bits.TMR1IF = 0; // Clear interrupt flag LPISRFLAG = 1; // Set a flag for LoopTime } /******************************* * 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 //OSCCONbits.IDLEN = 1; TRISA = 0b00000000; // Set I/O for PORTA TRISB = 0b01011100; // Set I/O for PORTB // Set I/O for PORTB TRISC = 0b10000100; // 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 = 247; // Blink immediately InitLCD(); // Initialize LCD DisplayRom(T_RED); // Display startup message DisplayRom(T_BLUE); DisplayRom(T_GREEN); TMR1H = 0xFE; // Set Timer1 to be 10 ms away from TMR1L = 0xB9; // next roll over (65536 + 1 - 328 = 0xFEB9) IPR1bits.TMR1IP = 0; // Use Timer1 for low-priority interrupts PIR1bits.TMR1IF = 0; // Clear overflow flag PIE1bits.TMR1IE = 1; // Enable local interrupt source T1CON = 0b01001111; // Start Timer1 counting CPU clock cycles RCONbits.IPEN = 1; // Enable high/low priority interrupt feature INTCONbits.GIEL = 1; // Global low-priority interrupt enable //INTCONbits.GIEH = 1; // Enable both high and low interrupts //setup ccp1 T3CON = 0b01001001; CCP1CON = 0b00000101; //setup rising edge PIR1bits.CCP1IF = 0; //IPR1bits.CCP1IP = 1; //PIE1bits.CCP1IE = 1; INTCONbits.GIEH = 1; // Enable both high and low interrupts } /******************************* * 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() { static char PORTACOPY; static char *tempPtr; PORTEbits.RE0 = 0; // RS=0 for command PORTA = 0b10000000; // Power up LCD Delay(5000); // Wait 50 ms for LCD controller to power up tempPtr = LCDstr; // Load pointer to beginning of string while (*tempPtr) // Send char if the byte is not zero { PORTACOPY = *tempPtr; // Get byte PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY | 0b10000000; // Send while maintaining LCD power PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble Delay(500); // Wait for 5 ms PORTACOPY = *tempPtr; // Get byte again PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY | 0b10000000; // and maintain LCD power PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will process byte Delay(500); // Wait 5 ms tempPtr++; // Increment pointer to next character } } /******************************* * DisplayV(char *) * * This subroutine is called with a parameter consisting of 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 DisplayV(char *tempPtr) { static char PORTACOPY; PORTEbits.RE0 = 0; // RS=0 for command (CPC) while (*tempPtr) // Send char if the byte is not zero { PORTACOPY = *tempPtr; PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY | 0b10000000; // Send while maintaining LCD power PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble PORTACOPY = *tempPtr; PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY | 0b10000000; // Send while maintaining LCD power 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 tempPtr++; // Increment pointer to next character } } /******************************* * DisplayRom(const rom char *) * * This subroutine is called with a parameter consisting of 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 DisplayRom(const rom char *tempPtr) { static char PORTACOPY; PORTEbits.RE0 = 0; // RS=0 for command (CPC) while (*tempPtr) // Send char if the byte is not zero { PORTACOPY = *tempPtr; PORTACOPY >>= 2; // Shift upper nibble into position PORTA = PORTACOPY | 0b10000000; // Send while maintaining LCD power PORTEbits.RE1 = 1; // Drive E pin high PORTEbits.RE1 = 0; // and low so LCD will accept nibble PORTACOPY = *tempPtr; PORTACOPY <<= 2; // Shift lower nibble into position PORTA = PORTACOPY | 0b10000000; // Send while maintaining LCD power 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 tempPtr++; // Increment pointer to next character } } /******************************* * BlinkAlive * * This function briefly blinks the LED every two seconds. * With a looptime of 10 ms, count 200 looptimes ******************************* */ void BlinkAlive() { PORTEbits.RE2 = 0; // Turn off LED if (++ALIVECNT == 200) // Increment counter and return if not 250 { ALIVECNT = 0; // Reset ALIVECNT PORTEbits.RE2 = 1; // Turn on LED for 10 ms every 2 secs } } /******************************* * LoopTime * * This function puts the chip to sleep upon entry. * For a Timer1 interrupt, it executes the LPISR and then exits. * For any other interrupt, it executes the ISR and then returns to sleep. ******************************* */ void LoopTime() { while (!LPISRFLAG) // Sleep upon entry and upon exit from HPISR { // Return only if LPISR has been executed, Sleep(); // which sets LPISRFLAG Nop(); } LPISRFLAG = 0; // Sleep upon next entry to LoopTime } void ASCII4() { TENTHOUSANDS = '0'; THOUSANDS = '0'; HUNDREDS = '0'; TENS = '0'; ONES = '0'; while (BIGNUM >= 10000) { TENTHOUSANDS++; BIGNUM -= 10000; } while (BIGNUM >= 1000) { THOUSANDS++; BIGNUM -= 1000; } while (BIGNUM >= 100) { HUNDREDS++; BIGNUM -= 100; } while (BIGNUM >= 10) { TENS++; BIGNUM -= 10; } ONES += BIGNUM; } void RPG() { RPGVAL = 0x00; DELRPG = 0; PORTBbits.RB5 = 1; Nop(); RPGVAL = PORTB & 0b00011100; PORTBbits.RB5 = 0; NEW_PRESSED = ((RPGVAL >> 2) & 1); if (OLD_PRESSED == 1 && NEW_PRESSED == 0) { mode++; DELRPG = 1; } OLD_PRESSED = NEW_PRESSED; if (mode == 3) mode = 0; } /******************************* * InitTX * * This function initializes the UART for its TX output function. It assumes * Fosc = 4 MHz. For a different oscillator frequency, use Figure 6-3c to * change BRGH and SPBRG appropriately. ******************************* */ void InitTX() { RCSTA = 0b10010000; // Enable UART TXSTA = 0b00100000; // Enable TX SPBRG = 12; // Set baud rate BAUDCON = 0b00111000; // Invert TX output }
This snippet took 0.09 seconds to highlight.
Back to the Entry List or Home.