//******************************************************************************
//Software License Agreement
//
//The software supplied herewith by Microchip Technology
//Incorporated (the "Company") is intended and supplied to you, the
//Company?s customer, for use solely and exclusively on Microchip
//products. The software is owned by the Company and/or its supplier,
//and is protected under applicable copyright laws. All rights are
//reserved. Any use in violation of the foregoing restrictions may
//subject the user to criminal sanctions under applicable laws, as
//well as to civil liability for the breach of the terms and
//conditions of this license.
//
//THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
//WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
//TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
//PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
//IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
//CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
// *******************************************************************
// PIC18F45K20 PICkit 3 Debug Express Lesson 9 - Internal_Oscillator
//
// This lesson demonstrates changing the speed of the microcontroller
// clock using the internal clock block from 250kHz to 64MHz.
//
// *******************************************************************
// * See included documentation for Lesson instructions *
// *******************************************************************
/** C O N F I G U R A T I O N B I T S ******************************/
#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF // CONFIG1H
#pragma config PWRT = OFF, BOREN = OFF, BORV = 30 // CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768 // CONFIG2H
#pragma config MCLRE = ON, LPT1OSC = OFF, PBADEN = OFF, CCP2MX = PORTC//CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF // CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF // CONFIG5L
#pragma config CPB = OFF, CPD = OFF // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF // CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF // CONFIG7L
#pragma config EBTRB = OFF // CONFIG7H
/** I N C L U D E S **************************************************/
#include "p18f45k20.h"
#include "delays.h"
#include "09_IntOSC.h" // header file
/** V A R I A B L E S *************************************************/
//#pragma idata // declare statically allocated initialized variables
unsigned char LED_Count = 0; // 8-bit variable
unsigned char SwitchDelay = 1; // delay time to "debounce" switch
//IntOSCFreq ClockSpeed = C_250kHz;
IntOSCFreq ClockSpeed = C_500kHz;
/** I N T E R R U P T S ***********************************************/
//----------------------------------------------------------------------------
// interrupt vector
//#pragma code InterruptVector = 0x08
void InterruptVector (void)
{
//#asm
// goto InterruptService //jump to interrupt routine
//#endasm
asm("call _InterruptService");
;
}
/** D E C L A R A T I O N S *******************************************/
//#pragma code // declare executable instructions
void Delay1KTCYx(unsigned char);
void main (void)
{
// Init I/O
TRISD = 0b00000000; // PORTD bits 7:0 are all outputs (0)
//TRISEbits.TRISE0 = 1; // TRISE0 input
TRISE0 = 1;
//INTCON2bits.RBPU = 0; // enable PORTB internal pullups
RBPU = 0;
//WPUBbits.WPUB0 = 1; // enable pull up on RB0
WPUB0 = 1;
// Set initial clock speed (250kHz)
SetIntOSC(&ClockSpeed);
// Init switch and turn on interrupts
SetupINT0Switch();
EnableInterrupts();
while (1)
{ // delay and count on LEDs here. Interrupt handles switch and freq changes
LATD = LED_Count++; // output count to PORTD LEDs
Delay1KTCYx(32); // delay 64,000 cycles or about 1 sec at 250kHz
}
}
void SetupINT0Switch(void)
{ // Set up switch interrupt on INT0
//INTCON2bits.INTEDG0 = 0;//interrupt on falling edge of INT0 (switch pressed)
INTEDG0 = 0;
//INTCONbits.INT0IF = 0; // ensure flag is cleared
INT0IF = 0;
//INTCONbits.INT0IE = 1; // enable INT0 interrupt
INT0IE = 1;
}
void EnableInterrupts(void)
{ // Set up global interrupts
//RCONbits.IPEN = 0; // Disable priority levels on interrupts
IPEN = 0;
//INTCONbits.PEIE = 1; // Peripheral interrupts allowed (but none are used)
PEIE = 1;
//INTCONbits.GIE = 1; // Interrupting enabled.
GIE = 1;
}
void SetIntOSC(IntOSCFreq *ClockSet)
{ // This function sets the internal oscillator to the frequency of
// the ClockSet argument variable, and then increments ClockSet
// to the next supported frequency.
switch (*ClockSet)
{
case C_250kHz:
OSCCON = 0x10; // IRCFx = 001
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_500kHz;
SwitchDelay = 1;
break;
case C_500kHz:
OSCCON = 0x20; // IRCFx = 010
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_1MHz;
SwitchDelay = 2;
break;
case C_1MHz:
OSCCON = 0x30; // IRCFx = 011
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_2MHz;
SwitchDelay = 4;
break;
case C_2MHz:
OSCCON = 0x40; // IRCFx = 100
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_4MHz;
SwitchDelay = 8;
break;
case C_4MHz:
OSCCON = 0x50; // IRCFx = 101
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_8MHz;
SwitchDelay = 16;
break;
case C_8MHz:
OSCCON = 0x60; // IRCFx = 110
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_16MHz;
SwitchDelay = 32;
break;
case C_16MHz:
OSCCON = 0x70; // IRCFx = 111
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_32MHz;
SwitchDelay = 64;
break;
case C_32MHz:
OSCCON = 0x60; // IRCFx = 110 (8 MHz)
//OSCTUNEbits.PLLEN = 1; // x4 PLL enabled = 32MHz
PLLEN = 1;
*ClockSet = C_64MHz;
SwitchDelay = 128;
break;
case C_64MHz:
OSCCON = 0x70; // IRCFx = 111 (16 MHz)
//OSCTUNEbits.PLLEN = 1; // x4 PLL enabled = 64MHz
PLLEN = 1 ;
*ClockSet = C_250kHz;
SwitchDelay = 255;
break;
default:
// should never get here, but just in case
OSCCON = 0x10; // IRCFx = 001
//OSCTUNEbits.PLLEN = 0; // x4 PLL disabled
PLLEN = 0;
*ClockSet = C_500kHz;
break;
}
}
// -------------------- Iterrupt Service Routines --------------------------
//#pragma interrupt InterruptService //"interrupt" pragma also for high priority
void InterruptService(void)
{
int i;
// Check to see what caused the interrupt
// (Necessary when more than 1 interrupt at a priority level)
// Check for INT0 interrupt
//if (INTCONbits.INT0IF)
if (INT0IF)
{
// Delay about 50ms regardless of frequency to debounce switch.
// NOTE: a delay function from delay.h isn't used as they are
// inline assembly and inline assembly in an interrupt routine
// causes a very long context save/restore since the compiler
// doesn't know what resources are being used and so saves everything.
i = 125 * SwitchDelay;
while(i)
{
i--;
}
// clear (reset) flag
//INTCONbits.INT0IF = 0;
INT0IF = 0;
//if (PORTBbits.RB0 == 0)
if(PORTBbits.RB0 == 0)
{ // if it's still pressed after 100ms delay.
// Change oscilator frequency
SetIntOSC(&ClockSpeed);
}
}
// Check for another interrupt, examples:
// if (PIR1bits.TMR1IF) // Timer 1
// if (PIR1bits.ADIF) // ADC
} // return from high-priority interrupt