Using assembly instructions and internal oscillator LFINTOSC...
This is actually a sequel to the previous example, but deals with a bit more complicated problem... The idea is to make LED diodes on the port B blink slowly. It can be done by setting large value for delay parameter in the Delay function. But there is also another, more efficient manner to make this happen. You remember that this microcontroller has built-in oscillator LFINTOSC which operates at the frequency of 31kHz? Now, it’s time to ‘give it a chance’. The program starts with the do-while loop and remains there for 20 cycles. After each iteration, 100mS delay is provided, which is reflected as relatively fast LED blinking of the port B. When the program exits this loop, the microcontroller starts using the LFINTOSC oscillator as a clock signal source. The LED blinking is considerably slower now even though the program executes the same do-while loop with 10 times shorter delay. For the purpose of making some potentionally dangerous situation more obvious here, control bits are activated by assembly instructions. Simply put, when entering or exiting the assembly instruction in the program, the compiler doesn’t save data on currently active RAM bank, which means that in this program section, bank selection depends on the SFR registers in use. When switching back to the program section written in C, the control bits RP0 and RP1 must return the state they had before ‘assembly language adventure’. In this program, the problem is solved by using the saveBank auxiliary variable which saves the state of these two bits./* Header *********************************************/ int k = 0; char saveBank; void main() { ANSEL = 0; // All I/O pins are configured as digital ANSELH = 0; PORTB = 0; // All port B pins are set to 0 TRISB = 0; // Port B pins are configured as outputs do { PORTB = ~PORTB; // Invert port B logic state Delay_ms(100); // 100mS delay k++; // Increment k by 1 } while(k<20); // Remain in loop while k<20 k=0; // Reset variable k saveBank = STATUS & 0b01100000; // Save the state of bits RP0 and RP1 // (bits 5 and 6 of the STATUS register) asm { // Start of assembly sequence bsf STATUS,RP0 // Select memory bank containing the OSCCON bcf STATUS,RP1 // register bcf OSCCON,6 // Select internal oscillator LFINTOSC bcf OSCCON,5 // of 31KHz frequency bcf OSCCON,4 bsf OSCCON,0 // Microcontroller uses internal oscillator } // End of assembly sequence STATUS &= 0b10011111; // Bits RP0 and RP1 return their original state STATUS |= saveBank; do { PORTB = ~PORTB; // Invert port B logic state Delay_ms(10); // 10 mS delay k++; // Increment k by 1 } while(k<20); // Remain in loop while k<20 }You have noticed that the clock signal source is changed ‘on the fly’. If you want to make sure of it, remove quartz crystal prior to switching the microcontroller on. The microcontroller will not start to operate because the Config Word loaded with the program requires the use of crystal on switching on. If you remove the crystal later during operation, nothing will happen, it will not affect the microcontroller at all.