PIC单片机RC振荡器的使用及校准方法

在pic的单片机中有多种型号有内部rc振荡器的功能,从而省去了晶振,不但节省了成本,并且我们还多了两个io端口可以使用。
但是,由于rc振荡器中电阻、电容的离散性很大,因此,在有内部rc振荡器的单片机中,它的内部ram中都会有一个名为osccal的校准寄存器,通过置入不同的数值来微调rc振荡器的振荡频率。并且,单片机的程序存储器中,也会有一个特殊的字来储存工厂生产时测得的校准值。下面我以常用的12c508a和12f629为例加以说明。
12c508a的复位矢量是程序的最高字0x1ff,这个字节生产商已经固定的烧写为movlw 0xxx,指令执行后,w寄存器中即为校准值xx,当我们需要校准时,那么,在紧接着的地址0x0应该是一条这样的指令:movwf osccal。接下去rc振荡器就会以标准的振荡频率运行了。
12f629的校准值也存放在最高字--0x3ff中,内容是retlw 0xxx,但它的复位矢量却是0x0。这样,在我们需要校准rc振荡器时,在初始化过程中要加上下面两句:
call 0x3ff
movwf osccal
当然,你还要注意寄存器的块选择位。
以前,我在做项目时,没太注意这个问题,这是因为在使用12c508a时,hi-tech在进行编译时已经偷偷地替我们做了这项工作。它会在程序的0x0处自动加一条movwf osccal。用12f629做接收解码代替2272时也没发生什么问题,但是在用被它作滚动码解码器时却发现接收距离的离散性很大。经多次试验终于找出是没对振荡器的振荡频率进行校正所至。
因此,需要另外编写用于校正的语句,我用了两种方法来实现这个目的:
1、用内嵌汇编的形式
#asm //此段汇编程序用于将位于程序段3ffh的
call 3ffh //内部rc振荡器的校准值放入校准寄存器,
bsf _status,5 //在进行c语言调试时应屏蔽这段程序
movwf _osccal
#endasm
2、用c语言标准形式
const unsigned char cs @ 0x3ff; //在函数体外
。..
osccal=cs; //仿真时屏蔽此句
用这两种方法都有一个小缺陷--仿真时,程序无法运行,这是由于c编译器并没有为我们在0x3ff放置一条retlw 0xxx的语句。因此,程序运行到这里之后,并没有把一个常数(校准值)放入w寄存器然后返回,而是继续执行这条语句的下一句--0x0及其之后的程序,也就是说程序到此就乱了。因此如程序后面注释所示,在仿真时,应先屏蔽这几句程序。在程序调试完成后,需要烧写时,把注释符去掉,再编译一次就可以了。
我还有一种想法,不用屏蔽语句,那就是用函数来实现,就是在0x3ff起建立一个函数,函数体内只有一条语句,如下:
char jz()
{
return 0;
}
当然,还要考虑c函数返回时,一定会选择寄存器0,实际上这个函数的起始地址应小于0x3ff。但是我找了我所能找到的参考资料,并上网找了多次,也没找到为函数绝对定位的方法,希望有知道的朋友指点一下。
还有,12c508a是一次性编程的,并且0x1ff处的内容,我们是无法改变的,也就是说你在此处编写任何指令,编程器都不会为你烧写,或者说即使烧写了也不会改变其中的内容。
可12f629是flash器件,可多次编程,如果你没有故意选择,正品的编程器(如microchip的picstart plus)是不会对存有校准值的程序空间进行编程的。即使你无意中对这个程序空间进行了编程,你也可以用一条retlw 0xxx放在0x3ff处再编程一次就可以了,但这个xx值可能是不正确的,需经实验确定(请参考后面说明)。
为了检验osccal的值对振荡器频率的影响,特编写了下面一个小程序进行验证:
#include
//*********************************************************
__config(intio & wdtdis & pwrten & mclrdis & boren & protect & cpd);
//内部rc振荡器普通io口;无效看门狗;上电延时;内部复位;掉电复位;代码保护;数据保护
//*********************************************************
#define out gpio0 //定义输出端
#define jc gpio3 //定义检测端
//*********************************************************
void interrupt zd(); //声明中断函数
//主函数***************************************************
void main()
{
cmcon=7;
option=0b00000011; //分频比为1:16,
trisio=0b11111110;
gpio=0b00000000;
wpu=0;
t0if=0;
gie=1;
t0ie=1;
while(1){
if(jc)osccal=0xff;
else osccal=0;
}
}
//中断函数*************************************************
void interrupt zd()
{
t0if=0;
out=!out;
}
程序其实很简单,就是在中断中让out脚的电平翻转,翻转的时间为4096个指令周期,电平周期为8192个指令周期。而指令的周期又决定于rc时钟频率。在主程序中,不断的检测jc端口的电平,然后根据此端口电平的值修改osccal寄存器的值。当然,最后从out脚的波形周期上反映出了osccal寄存器的值改变。
经用示波器测量(抱歉,手边没有频率计),jc端接地时,out端的电平周期为9.5毫秒左右;而jc端接正电源时,out端的电平周期为6毫秒左右。也就是说osccal的值越大,单片机的时钟频率越高。并且,这个变化范围是很大的,因此,如果使用pic单片机的内部rc振荡器时,对其振荡频率进行校正是十分必要的。这也是我在做滚动码接收解码器时,产品离散性很大的原因。望大家以后使用内部rc振荡器时能够注意到此点。
但还有一点要注意,即使你对rc振荡器进行了校正,你也别指望这个4mhz的rc振荡器肯定会很标准,实际上它还是一个rc振荡器,它的振荡频率是电压、温度的函数,也就是说这个振荡频率会随着电压和温度的变化而变化,只是经校正后的值更接近4mhz罢了,这在产品开发的一开始就要注意的。

西部数据发布全新内存固态盘:近DRAM的性能,4TB容量
目前市面上的手机谁家通信性能最好?
iphone8什么时候上市?iphone8上市在即:9月12日发布,史上最贵iPhone8售价破万你买吗?
揭秘!1200W LED灯“瘦身”秘诀
您的WiFi模块选型小贴士已到 请注意查收
PIC单片机RC振荡器的使用及校准方法
风电波动对电网影响规律剖析讲解
如何为嵌入式应用程序选择操作系统
加快自动驾驶商用和智能交通普及,实现碳达峰的目标
关于电池修复断格明细的详细解析
我们在选购气动三通球阀时,这些要点需要注意
BAL-0009SMG微波巴伦
小米6最新消息:小米6亮银版8.3上市,要价3999限量100台,能够想象到抢购的激烈了
油气田能源监控系统的组成架构和应用特点
MUN123C01-SGB输入输出过滤Cyntec
工控机在电力调度自动化系统解决方案
汽车超声波清洗机的优点你知道吗?
江西省吉水县为农业领域引进了智能工厂化育秧设备
示波器带宽对测量结果的影响
如何通过张量的降维来降低卷积计算量(CP分解)