Calibration of the internal RC oscillator of the PIC microcontroller

Publisher:polkmmLatest update time:2016-11-07 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
There are many models of PIC microcontrollers with internal RC oscillator function, which eliminates the need for a crystal oscillator. This not only saves costs, but also gives us two more IO ports to use.

However, due to the large discreteness of the resistors and capacitors in the RC oscillator, there is a calibration register called OSCCAL in the internal RAM of the microcontroller with an internal RC oscillator, which can be used to fine-tune the oscillation frequency of the RC oscillator by entering different values. In addition, there is a special word in the program memory of the microcontroller to store the calibration value measured during factory production. Below I will use the commonly used 12C508A and 12F629 as examples to illustrate.

The reset vector of 12C508A is the highest word of the program 0x1FF. This byte has been fixed by the manufacturer as MOVLW 0xXX. After the instruction is executed, the calibration value XX is in the W register. When we need to calibrate, then the next address 0x0 should be an instruction like this: MOVWF OSCCAL. Then the RC oscillator will run at the standard oscillation frequency.

The calibration value of 12F629 is also stored in the highest word - 0x3FF, the content is RETLW 0xXX, but its reset vector is 0x0. So, when we need to calibrate the RC oscillator, we need to add the following two sentences during the initialization process:

    CALL 0x3ff
    MOVWF OSCCAL

Of course, you also have to pay attention to the block select bits of the register.

In the past, when I was working on a project, I didn't pay much attention to this problem. This is because when using 12C508A, HI-TECH has secretly done this work for us during compilation. It will automatically add a MOVWF OSCCAL at 0x0 of the program. There was no problem when using 12F629 to replace 2272 for receiving decoding, but when using it as a rolling code decoder, it was found that the receiving distance was very discrete. After many tests, I finally found that the oscillation frequency of the oscillator was not calibrated.

Therefore, it is necessary to write additional statements for correction. I used two methods to achieve this goal:

1. Use inline assembly

#asm //This assembly program is used to
  put the calibration value of the internal RC oscillator //at call 3ffh in the program segment 3FFH into the calibration register,
  bsf _STATUS,5 //This program should be shielded when debugging in C language
  movwf _OSCCAL
#endasm

2. Use the standard form of C language

const unsigned char cs @ 0x3ff; //Outside the function
...
OSCCAL=cs; //Shield this sentence during simulation

Both methods have a small flaw - the program cannot run during simulation, because the C compiler does not place a RETLW 0xXX statement at 0x3FF for us. Therefore, after the program runs to this point, it does not put a constant (calibration value) into the W register and then return, but continues to execute the next statement of this statement - 0x0 and the program after it, which means that the program is messed up here. Therefore, as shown in the comments behind the program, these sentences should be blocked during simulation. After the program is debugged, when it needs to be burned, remove the comment symbol and compile it again.

I have another idea, which is to use functions instead of shielding statements. That is, to create a function starting at 0x3FF, with only one statement in the function body, as follows:

char jz()
{
 return 0;
}

Of course, we also need to consider that when a C function returns, register 0 will be selected. In fact, the starting address of this function should be less than 0x3FF. However, I have searched all the reference materials I can find and searched the Internet many times, but I still can't find a way to absolutely locate the function. I hope friends who know can give me some advice.

Also, 12C508A is a one-time programmable device, and the content at 0x1FF cannot be changed. That is to say, if you write any instructions here, the programmer will not burn it for you, or even if it is burned, it will not change the content.

However, 12F629 is a FLASH device and can be programmed multiple times. If you do not intentionally select it, the genuine programmer (such as Microchip's PICSTART PLUS) will not program the program space where the calibration value is stored. Even if you accidentally program this program space, you can use a RETLW 0xXX to put it at 0x3FF and program it again, but this XX value may be incorrect and needs to be determined by experiment (please refer to the following instructions).

In order to test the effect of OSCCAL value on oscillator frequency, a small program is written to verify:

#include
//************************************************************
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS & BOREN & PROTECT & CPD);
//Internal RC oscillator common IO port; invalid watchdog; power-on delay; internal reset; power-off reset; code protection; data protection
//****************************************************************
#define out GPIO0 //Define output terminal
#define jc GPIO3 //Define detection terminal
//****************************************************************
void interrupt zd(); //Declare interrupt function
//Main function*******************************************************
void main()
{
 CMCON=7;
 OPTION=0B00000011; //Division ratio is 1:16,
 TRISIO=0B11111110;
 GPIO=0B00000000;
 WPU=0;
 T0IF=0;
 GIE=1;
 T0IE=1;
 while(1){
   if(jc)OSCCAL=0xFF;
   else OSCCAL=0;
 }
}
//Interrupt function******************************************************
void interrupt zd()
{
 T0IF=0;
 out=!out;
}

The program is actually very simple. It is to flip the level of the OUT pin in the interrupt. The flipping time is 4096 instruction cycles, and the level cycle is 8192 instruction cycles. The instruction cycle is determined by the RC clock frequency. In the main program, the level of the JC port is constantly detected, and then the value of the OSCCAL register is modified according to the value of the port level. Of course, the change of the value of the OSCCAL register is reflected in the waveform cycle of the OUT pin.

After measuring with an oscilloscope (sorry, I don't have a frequency meter at hand), when the JC terminal is grounded, the level cycle of the OUT terminal is about 9.5 milliseconds; and when the JC terminal is connected to the positive power supply, the level cycle of the OUT terminal is about 6 milliseconds. That is to say, the larger the value of OSCCAL, the higher the clock frequency of the microcontroller. In addition, this range of variation is very large. Therefore, if the internal RC oscillator of the PIC microcontroller is used, it is very necessary to correct its oscillation frequency. This is also the reason why the product discreteness is very large when I make a rolling code receiving decoder. I hope everyone can pay attention to this point when using the internal RC oscillator in the future.

But there is one more thing to note. Even if you calibrate the RC oscillator, don't expect that this 4MHz RC oscillator will be very standard. In fact, it is still an RC oscillator, and its oscillation frequency is a function of voltage and temperature. That is to say, the oscillation frequency will change with changes in voltage and temperature. It's just that the calibrated value is closer to 4MHz. This should be paid attention to at the beginning of product development.
Reference address:Calibration of the internal RC oscillator of the PIC microcontroller

Previous article:PIC18F97J60 TCP/IP reconnection problem after changing IP
Next article:Issues that must be noted when using PIC microcontroller port level change interrupts

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号