搜索
bottom↓
回复: 12

PICC 用C写程序,PIC12fXX内部RC校正该如何处理?(picc如何实现函数绝对定位?)

[复制链接]

出0入0汤圆

发表于 2009-11-29 10:40:05 | 显示全部楼层 |阅读模式
RT!

下文有这么一段:
12F629是FLASH器件,可多次编程,如果你没有故意选择,正品的编程器(如Microchip的PICSTART  PLUS)是不会对存有校准值的程序空间进行编程的。即使你无意中对这个程序空间进行了编程,你也可以用一条RETLW 0xXX放在0x3FF处再编程一次就可以了,但这个XX值可能是不正确的,需经实验确定。。。

正如上所述,
1。将一片未曾烧写过的629进行读取,可以读出正确的校正值,我试过几片,分别读出0x3ff里放的是0x40 0x43..(精度没有进行测试,手头没工具)

2。我所使用的"非正品"的编程器在编译后,把12f629的0x3ff改成了0x3ff,再读取进行校正的话就是错误的;

如何解决这问题:

函数绝对定位如何做?




===============================================================================================================================
转一篇关于PIC12XX内部RC校正的文章:

出处:http://www.bjlxjw.com/gkwx/gkdpjkf/4538781839.html

在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罢了,这在产品开发的一开始就要注意的

出0入0汤圆

 楼主| 发表于 2009-11-29 16:05:48 | 显示全部楼层
看都没人看~~一个下午了才点击19次,。。。星期天大家都去找乐子了?

出0入0汤圆

发表于 2009-11-29 16:47:20 | 显示全部楼层

出0入0汤圆

发表于 2009-11-29 19:33:08 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2009-11-30 09:20:53 | 显示全部楼层
typedef unsigned char(* _tFuncPtr)(void);
.
.
.
_tFuncPtr fp1 = (_tFuncPtr)0x3FF;
OSCCAL = (*fp1)();

出0入0汤圆

发表于 2009-11-30 09:28:43 | 显示全部楼层
我用PIC的内部RC做时钟频率,经常定时不是很准,误差比较大,即使用软件来补偿都很难达到,有时候仿真波形很精确,但是输出实际波形差异很大,不像STC内部时钟稍微会精确一些,感觉PIC的RC变化范围确实很大!

出0入0汤圆

发表于 2009-11-30 09:37:31 | 显示全部楼层
buy a pickit2: it can calibrate osccal automatically.

出0入0汤圆

 楼主| 发表于 2009-11-30 09:55:40 | 显示全部楼层
感谢三楼精辟的C写法,我试了一下,还OK,

65:                void Fre_Cli(void)
66:                {
71:                        _tFuncPtr fp1 = (_tFuncPtr)0x3FF;
72:                        OSCCAL = (*fp1)();
                   }

   1D7    30FF     MOVLW 0xff       
   1D8    1283     BCF 0x3, 0x5
   1D9    00C4     MOVWF 0x44
   1DA    3003     MOVLW 0x3
   1DB    00C5     MOVWF 0x45

   1DC    1283     BCF 0x3, 0x5
   1DD    23FF     CALL 0x3ff
   1DE    1683     BSF 0x3, 0x5
   1DF    0090     MOVWF 0x10



另外,直接这样写似乎更简便些:
        asm("call         03FFh");
        asm("BSF        _STATUS,5");
        asm("MOVWF        _OSCCAL");
        asm("BCF        _STATUS,5");

出0入0汤圆

 楼主| 发表于 2009-11-30 10:01:00 | 显示全部楼层
但是另一个问题的根本还没有解决,0X3FFF还是会被“非正品”的烧写器所覆盖,还有就是PICC编译器编译后会在0x3ff处存放机器码。。。。。

难道只能:buy a pickit2: it can calibrate osccal automatically.

出0入0汤圆

发表于 2009-11-30 14:08:04 | 显示全部楼层
感谢楼主分享资料。最近做个东西也是要用到内部振荡。到时要好好测试一下。

出0入0汤圆

发表于 2009-12-1 01:13:00 | 显示全部楼层
7楼,貌似你谢错人了:-)

当时没有考虑到PIC的哈佛结构的问题,应该有更简单的写法:

typedef unsigned char(* _tFuncPtr)(void);
.
.
.
OSCCAL = (*(_tFuncPtr)0x3FF)();

你再看看生成的汇编代码。

出0入0汤圆

发表于 2009-12-1 01:18:00 | 显示全部楼层
但是另一个问题的根本还没有解决,0X3FFF还是会被“非正品”的烧写器所覆盖,还有就是PICC编译器编译后会在0x3ff处存放机器码。。。。。

难道只能:buy a pickit2: it can calibrate osccal automatically.

“非成品”的烧写器会覆盖内部振荡器校准字的问题,是否可以通过向烧写器指定编程范围的方式来解决?
PICC编译器会占用程序校准字空间的问题,是否可以通过向编译器指定ROM空间大小(比实际空间小1)或者使用变量绝对地址定位技术(人为占用该空间)来解决?

出0入0汤圆

发表于 2010-5-4 12:56:52 | 显示全部楼层
你太帅了,谢谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-9 21:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表