/******************************************************************** * FileName: reference code.c * Processor: PIC18F4520 * Compiler: MPLAB C18 v.8.36 * * This file is a compilation of code snippets used in ME430 for reference purposes * Note: Copy and Paste only gets you so far. Make sure you understand things! * * Author Date Comment *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ // David Fisher 10-28-08 // David Fisher 10-21-09 Add UART reference info /** Header Files **************************************************/ #include #include #include "LCD Module.h" #include #include #include #include #include #include /** Configuration Bits *********************************************/ #pragma config OSC = INTIO67 #pragma config WDT = OFF #pragma config LVP = OFF #pragma config BOREN = OFF #pragma config XINST = OFF /** Define Constants Here ******************************************/ #define PRESSED 0 #define UNPRESSED 1 #define DELAY_TIME 100 // Buzzer #define VOLUME 100 #define NO_VOLUME 0 // Some mustic note #defines to use with OpenPWM1 on the buzzer. Only works for... // 4 MHz with a 16 prescaler on Timer 2 // 1 MHz with a 4 prescaler on Timer 2 //or 250 kHz with a 1 prescaler on Timer 2 #define A_UP_880_HZ 70 #define G_UP_784_HZ 78 #define F_UP_698_HZ 88 #define E_UP_659_HZ 93 #define D_UP_587_HZ 105 #define C_UP_523_HZ 118 #define B_MID_494_HZ 125 #define A_MID_440_HZ 141 #define G_MID_392_HZ 158 #define F_MID_349_HZ 177 #define E_MID_330_HZ 188 #define D_MID_294_HZ 211 #define C_MID_262_HZ 237 // UART constants #define MAX_RX_MESSAGE_SIZE 32 #define MESSAGE_TERMINATOR 10 /** Local Function Prototypes **************************************/ void low_isr(void); void high_isr(void); // Remember no UART on Exam 2, but still a useful reference. void clearBuffer(char bufferToClear[]); // UART helper function void loadNewMessage(void); // UART helper function /** Declare Interrupt Vector Sections ****************************/ #pragma code high_vector=0x08 void interrupt_at_high_vector(void) { _asm goto high_isr _endasm } #pragma code low_vector=0x18 void interrupt_at_low_vector(void) { _asm goto low_isr _endasm } /** Global Variables ***********************************************/ char recentButtonState = UNPRESSED; // Digital IO int RA0result = 0; // ADC variables char line1[17]; // LCD variables char line2[17]; char tempRxBuffer[MAX_RX_MESSAGE_SIZE]; // UART variables char newRxMessage[MAX_RX_MESSAGE_SIZE]; char newMessageAvailable = 0; /******************************************************************* * Function: void main(void) ********************************************************************/ #pragma code void main(void) { // -------------------------- General Pin I/O ----------------------------- // REQUIRES: #include /* ADCON1 = 0x0F; // All pins digital IO (simple 1 liner instead of the OpenADC command if not using the ADC) TRISC = 0x00; // All of PORTC is an output TRISAbits.TRISA4 = 1; // Makes RA4 an input PORTC = 0b0110; // Turn on RC2 and RC3 others off PORTCbits.RC5 = 1; // Turn on RC5 others no change // Optional PRESSED/UNPRESSED code // To do stuff once on a button press if(PORTAbits.RA4 == PRESSED) { if(recentButtonState == UNPRESSED) { // Do stuff that happens once per press PORTBbits.RB0 = 1; } recentButtonState = PRESSED; } else { recentButtonState = UNPRESSED; PORTB = 0x00; } // Same code as above but using RB0 and refactored to look like the version in Lab 4. if ((PORTBbits.RB0 == PRESSED) && (recentButtonState == UNPRESSED)) { // This is a new press of the button // Stuff for a new button press goes below // // new button press stuff // new button press stuff // recentButtonState = PRESSED; } else if ((PORTBbits.RB0 == PRESSED) && (recentButtonState == PRESSED)) { // This is an old press of the button // We don't need to do anything } else { // The button isn't pressed. // Record that the button isn't pressed and put stuff for an unpressed button below // // unpressed button stuff // unpressed button stuff // recentButtonState = UNPRESSED; } */ // ---------------------- Using Delay Functions --------------------------- // REQUIRES: #include /* OSCCONbits.IRCF2 = 1; // 4 MHz OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 0; PORTB = 0b00000001; Delay1KTCYx(DELAY_TIME); PORTB = 0b00000010; Delay1KTCYx(DELAY_TIME); PORTB = 0b00000100; Delay1KTCYx(DELAY_TIME); PORTB = 0b00001000; Delay1KTCYx(DELAY_TIME); PORTB = 0b00000100; Delay1KTCYx(DELAY_TIME); PORTB = 0b00000010; Delay1KTCYx(DELAY_TIME); // If clock is at 4 MHz each instruction takes 1 uS (0.000001 seconds) // If DELAY_TIME = 100 then Delay1KTCYx(DELAY_TIME) would be 1000 * 100 * 1 uS = 0.1 second */ // ---------------- Displaying information to the LCD -------------------- // REQUIRES: #include "LCD Module.h" // REQUIRES: #include /* XLCDInit(); XLCDClear(); sprintf(line1, "RA0 ADC -> %d", RA0result); XLCDL1home(); XLCDPutRamString(line1); sprintf(line2,"RA1 ADC -> %d",RA1result); XLCDL2home(); XLCDPutRamString(line2); */ // --------------------------- Using Timers ------------------------------- // REQUIRES: #include /* OSCCONbits.IRCF2 = 1; // 4 MHz OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 0; // Note, this section is for Timers WITHOUT interrupts. // See the interrupts section later for Timers with interrupts OpenTimer0( TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT & T0_PS_1_128 ); OpenTimer1( TIMER_INT_OFF & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8 & T1_OSC1EN_OFF); // Note T1_OSC1EN_OFF was added to free up RC0 to use for digital IO (see video 7-3 12:00) OpenTimer2(TIMER_INT_OFF & T2_PS_1_16); // If using PWM you must open Timer 2 // PWM period =[(timer ticks) + 1] x 4 x TOSC x TMR2 prescaler OpenTimer3(TIMER_INT_OFF & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_8); // Sample calculation: // Clock Frequency = 4 MHz // Instruction Cycle Frequency = 1 MHz // Timer 0 Frequency = 1 MHz / 128 = 7812.5 Hz // Timer 0 Period = 128 uSeconds <-- Always equals prescaler when clock is 4 MHz // Overflow every 128 uSecond * 2^16 ticks = 8.4 seconds // Set timer value WriteTimer0(60000); // Example here goes 5536 ticks before overflow // Read Timer value unsigned int readTimer = ReadTimer0(); // Less commonly used, but functional */ // -------------------------- Using the ADC ------------------------------- // REQUIRES: #include /* OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_12_TAD, ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS, 0x0E); SetChanADC(ADC_CH0); // Select the pin ConvertADC(); // Start conversion while( BusyADC() ); // Wait for completion RA0result = ReadADC(); // Read result */ // -------------------------- Using the PWM ------------------------------- // REQUIRES: #include // REQUIRES: #include /* OSCCONbits.IRCF2 = 1; // 4 MHz OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 0; OpenTimer2(TIMER_INT_OFF & T2_PS_1_16); OpenPWM1(162); // 163 Timer ticks per period SetDCPWM1(512); // 50% duty cycle // PWM period =[timer ticks + 1] x 4 x TOSC x TMR2 prescaler // Create an Excel spreadsheet and use that to find frequencies quickly // or use #defines for specific notes (setup OpenPWM1(A_MID_440_HZ); // Use the middle A #define to set the frequency SetDCPWM1(VOLUME); // set the duty cycle (provides volume) SetDCPWM1(NO_VOLUME); // Stop the buzzer */ // -------------------- Using UART Communication -------------------------- // REQUIRES: #include // REQUIRES: #include /* OSCCONbits.IRCF2 = 1; // 4 MHz OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF0 = 0; // configure USART for 19200 buad rate (from 4 MHz) with receive interrupts RCONbits.IPEN = 1; // Priority mode interrupts OpenUSART( USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH, 12 ); clearBuffer(newRxMessage); // Clear the Rx buffers clearBuffer(tempRxBuffer); IPR1bits.RCIP = 1; // Make the UART Rx interrupt a high priority interrupt INTCONbits.GIEH = 1; //Turn on high priority interrupts printf("Hello\n"); while(1) { if( newMessageAvailable ) { // Do stuff with new message newMessageAvailable = 0; } } */ // ------------------------ Using Interrupts ------------------------------ // REQUIRES: #include // REQUIRES: #include /* RCONbits.IPEN = 1; // Put the interrupts into Priority Mode // Pushbuttons // Turn on the RB0 interrupt INT0, falling edge, always high priority OpenRB0INT( PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_OFF); // Note, setting the priority is not necessary since INT0 is always High priority // -- OR -- INTCONbits.INT0IE = 1; // Same thing using the two SFRs directly INTCON2bits.INTEDG0 = 0; // Sets the INT0 to look for falling edges INTCONbits.INT0IF = 0; // Optional. Clearing the flag MIGHT help avoid initially calling isr at startup // Turn on the RB1 interrupt INT1, falling edge OpenRB1INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_OFF); INTCON3bits.INT1IP = 1; // Setting the prior as high here // Turn on the RB2 interrupt INT2, falling edge OpenRB2INT(PORTB_CHANGE_INT_ON & FALLING_EDGE_INT & PORTB_PULLUPS_OFF); INTCON3bits.INT2IP = 1; // Setting the prior as high here // Turn on the Change on RB4:RB7 interrupt OpenPORTB( PORTB_CHANGE_INT_ON & PORTB_PULLUPS_OFF); INTCON2bits.RBIP = 0; // Make it low priority (for example) // Timers // Open Timer 0 with high priority interrupts 128 prescaler OpenTimer0(TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_128); INTCON2bits.TMR0IP = 1; // Confirm high priority (the default) OpenTimer1( TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8 & T1_OSC1EN_OFF); IPR1bits.TMR1IP = 0; // Set to use low priority mode here. // Note, decided not to do interrupts with Timer 2 since it is mainly used with the PWM // Open Timer 3 with low priority interrupts, 16 bit mode, 1:4 Prescaler OpenTimer3(TIMER_INT_ON & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_4); IPR2bits.TMR3IP = 0; // Set to use low priority mode here. INTCONbits.GIE = 1; // Turn on Global interrupts (core interrupts only) (Compatibility mode) INTCONbits.PEIE = 1; // Turn on Global interrupts (peripheral interrupts) (Compatibility mode) // - OR - INTCONbits.GIEH = 1; // Turn on High Priority interrupts (Priority mode) INTCONbits.GIEL = 1; // Turn on Low Priority interrupts (Priority mode) // For more info see the PDF document "Where is that interrupt bit" */ } /***************************************************************** * Additional Helper Functions if using the UART ******************************************************************/ /***************************************************************** * Function: void clearBuffer(char bufferToClear[]) * Input Variables: bufferToClear - The buffer to clear * Output Return: none * Overview: Clears the contents of a buffer ******************************************************************/ void clearBuffer(char bufferToClear[]) { char i; for (i = 0; i < MAX_RX_MESSAGE_SIZE; i++) { bufferToClear[i] = 0; } } /***************************************************************** * Function: void loadNewMessage(void) * Input Variables: none * Output Return: none * Overview: Copies the contents of tempRxBuffer into newRxBuffer ******************************************************************/ void loadNewMessage(void) { char i; for (i = 0; i < MAX_RX_MESSAGE_SIZE; i++) { newRxMessage[i] = tempRxBuffer[i]; } } /***************************************************************** * Function: void high_isr(void) ******************************************************************/ #pragma interrupt high_isr void high_isr(void) { // Add code here for the high priority Interrupt Service Routine (ISR) // All eight possible interrupts used in this class if (INTCONbits.INT0IF) { // Interrupt 0, RB0 INTCONbits.INT0IF = 0; } if (INTCONbits.INT0IF) { // Interrupt 0, RB0 with debounce INTCONbits.INT0IF = 0; Delay1KTCYx(30); // Assumes a 4 MHz clock if (PORTBbits.RB0 == PRESSED) { // do stuff } } if (INTCON3bits.INT1IF) { // Interrupt 1, RB1 INTCON3bits.INT1IF = 0; } if (INTCON3bits.INT1IF) { // Interrupt 1, RB1 with debounce INTCON3bits.INT1IF = 0; Delay1KTCYx(30); // Assumes a 4 MHz clock if (PORTBbits.RB1 == PRESSED) { // do stuff } } if (INTCON3bits.INT2IF) { // Interrupt 2, RB2 INTCON3bits.INT2IF = 0; } if (INTCON3bits.INT2IF) { // Interrupt 2, RB2 with debounce INTCON3bits.INT2IF = 0; Delay1KTCYx(30); // Assumes a 4 MHz clock if (PORTBbits.RB2 == PRESSED) { // do stuff } } if (INTCONbits.RBIF) { // Change on RB4:RB7 interrupt // Rarely used. char currentPORTBvalue; // Weird note: Can only clear this flag AFTER doing a read or write to PORTB currentPORTBvalue = PORTB; INTCONbits.RBIF = 0; } if (INTCONbits.TMR0IF) { // Timer 0 interrupt INTCONbits.TMR0IF = 0; WriteTimer0(65535 - 7812); } if (PIR1bits.TMR1IF) { // Timer 1 interrupt PIR1bits.TMR1IF = 0; } if (PIR1bits.TMR2IF) { // Timer 2 interrupt (uncommon) PIR1bits.TMR2IF = 0; } if (PIR2bits.TMR3IF) { // Timer 3 interrupt PIR2bits.TMR3IF = 0; } // Advanced UART interrupt for String messages if (PIR1bits.RCIF) { static unsigned char txCounter = 0; // Makes the variable remember the prior state char newByte; newByte = RCREG; PIR1bits.RCIF = 0; // Clear the interrupt flag if (newByte == MESSAGE_TERMINATOR) { if (newMessageAvailable == 0) { clearBuffer(newRxMessage); loadNewMessage(); newMessageAvailable = 1; } clearBuffer(tempRxBuffer); txCounter = 0; } else { if (txCounter < MAX_RX_MESSAGE_SIZE && newByte > 31 && newByte < 127) { tempRxBuffer[txCounter] = newByte; txCounter++; } } } } /****************************************************************** * Function: void low_isr(void) * Possible sources of interrupt - none * Overview: ********************************************************************/ #pragma interruptlow low_isr void low_isr(void) { // Add code here for the low priority Interrupt Service Routine (ISR) }