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.

Delete this entry (admin only).