原创 PIC24HJ单片机自学笔记-时钟和延时问题

2013-12-20 10:24 3760 26 26 分类: MCU/ 嵌入式 文集: PIC24HJ单片机自学笔记

PIC24HJ头文件中包含了delay函数,定义如下:

/**************************
延时函数头文件
**************************/
#include "Generic.h"
#if defined(__PIC24H__)
#ifndef Fcy
#define Fcy 10000000 //10 000 000 10M
#endif
#endif
 
#define Delay_60nS_Cnt (Fcy * 0.00000006)
#define Delay_150nS_Cnt (Fcy * 0.00000015)
#define Delay_360nS_Cnt (Fcy * 0.00000036)
#define Delay_450nS_Cnt (Fcy * 0.00000045)
#define Delay_600nS_Cnt (Fcy * 0.0000006)
#define Delay200uS_count (Fcy * 0.0002)
#define Delay_1mS_Cnt (Fcy * 0.001)
#define Delay_2mS_Cnt (Fcy * 0.002)
#define Delay_5mS_Cnt (Fcy * 0.005)
#define Delay_15mS_Cnt (Fcy * 0.015)
#define Delay_1S_Cnt (Fcy * 1)
 
 
/* delays specific to each LCD type */
/* delay btw RS/RW signal to E signal */
#define DelayRSSetupTime_Cnt Delay_60nS_Cnt
/* delay btw E rise and Data available */
#define DelayDBOutput_Cnt Delay_360nS_Cnt
/* min E pulse width low */
#define DelayEPulseWidthLow_Cnt Delay_150nS_Cnt
/* min E pulse width high */
#define DelayEPulseWidthHigh_Cnt Delay_450nS_Cnt
/* E pulse cycle time */
#define DelayEPulseWidth_Cnt Delay_600nS_Cnt
/* min Power On Reset time */
#define DelayPORXLCD_Cnt Delay_15mS_Cnt
/* generic delay for LCD */
#define DelayXLCD_Cnt Delay_5mS_Cnt
 
//void delaynus(uint);
就是进行了一些简单的宏定义,没有看到实际的延时函数,然后找了一下PIC24FJ中的函数函数,是用于XLCD的,而里面的函数在src中已经定义了,进行移植怕出现问题。
然后在PIC24HJ的目录下找delay的函数,果然找到了一个,但是放在XLCD目录下,也就是说,这个是编译器一定定义好的,发现这个延时函数也是用于液晶的延时,定义的形式如下:
void DelayDBOutput(void) /* provides delay for Data Output */
{
 int i;
 for(i=0;i
  asm("clrwdt");
}
这里有一个CLRWDT,如何通过这样的形式实现延时?另外还有一个参数TCY_CNT_PER_LOOP这个是怎么用的?
这里的一条汇编语句,clrwdt应该是在函数函数中避免看门狗复位。
这样的话,延时函数还是需要自己来编写的,但是时钟的问题又出现了。
 
下面先引用一段关于XT,LP和
 
HS是使用超过4M的石英晶体振荡器
XT是使用1M到4M的石英晶体振荡器。
LP是使用低于1M的陶瓷振荡器,不是什么感抗震荡
上述都是用外部晶振,只是所用晶振的材质和频率不同。
RC是不使用外部晶振,直接用内部的RC时钟电路。
其中HS和XT因为用石英晶体振荡器,所得时钟比较准确,适用于各种串口、can、TCPIP通信的场合。但缺点是频率大所以功耗也大。
用LP和RC的特点是功耗小,但LP频率低,陶瓷振荡器输出的时钟精度不够高,RC的误差更大。适用于不用通信的普通控制场合。 


一共有四个时钟源,包括外部晶振,内部快速RC和慢速RC,以及一个辅助时钟源。
其中,外部晶振可以选择是否倍频,以及XT,HS,EC三种模式,就有6种时钟。
FRC包括不分频,固定为16和N分频,和PLL,一共有四种。
另外包括一个辅助晶振和一个低频的振荡器,一个有12种。
其中POSCMD选择外部时钟还是高速,低速的时钟模式:
 
其中HS模式为高增益模式,在高频时应用。
 
 
 
按照分频和倍频,可以将外部时钟设置到高达40M的Fcy,如下图:
 
 
 
 
这里,如果选用外部晶振为10M,然后通过PLLPRE分频到0.8M~8M,默认为/2,这样,为5M,然后,经过锁相环倍频,
这里默认为50,这样,得到的频率为250M,然后再经过PLLPOST,默认为/4,这样得到的是62.5M,超过了40M的限制。
应该设置PLLPOST为/8,则时钟为31.25M
 
下面是头文件对CLKDIV的申明,如下:
__extension__ typedef struct tagCLKDIVBITS {
  union {
    struct {
      unsigned PLLPRE:5;
      unsigned :1;
      unsigned PLLPOST:2;
      unsigned FRCDIV:3;
      unsigned DOZEN:1;
      unsigned DOZE:3;
      unsigned ROI:1;
    };
    struct {
      unsigned PLLPRE0:1;
      unsigned PLLPRE1:1;
      unsigned PLLPRE2:1;
      unsigned PLLPRE3:1;
      unsigned PLLPRE4:1;
      unsigned :1;
      unsigned PLLPOST0:1;
      unsigned PLLPOST1:1;
      unsigned FRCDIV0:1;
      unsigned FRCDIV1:1;
      unsigned FRCDIV2:1;
      unsigned :1;
      unsigned DOZE0:1;
      unsigned DOZE1:1;
      unsigned DOZE2:1;
    };
  };
} CLKDIVBITS;
寄存器的结构如下:
 
 
 
OK,根据上面的设置,可以进行如下的编程:
采用10M的时钟,通过如下的时钟的初始化得到:
void osc_init()
{
 //_CLKLOCK=0;
 _PLLPRE=0;
 _PLLDIV=0X1E;
 _PLLPOST=0;
}
得到一个40M的FCY,然后主程序中执行如下程序:
int main(void)
{
 osc_init();
// uchar i;
 mPORTBOutputConfig(IOPORT_BIT_9);
 while(1)
 {
    mPORTBClearBits(IOPORT_BIT_9);
 delayn(255);
 mPORTBSetBits(IOPORT_BIT_9);
 delayn(255);
 
 }
 return 0;
}
查看汇编语言窗口,执行一条设置端口电平的指令的时间为:4个周期,这样,按照上面的设置,B9拉低电平,然后延时25*4+(25*6*255)=38.35us
25: mPORTBOutputConfig(IOPORT_BIT_9);
 004F2 801630 mov.w 0x02c6,0x0000
 004F4 2FDFF1 mov.w #0xfdff,0x0002
 004F6 600001 and.w 0x0000,0x0002,0x0000
 004F8 881630 mov.w 0x0000,0x02c6
 
如果设置PLLPRE为6,则一开始8分频,得到指令周期是10M,则一条设置端口的指令时间为4*100ns=400ns。
通过仿真验证程序OK.
 
而DOZE模式的设置,对端口是没有影响的,以为端口是外设,不会影响外设的时间,而只会影响到CPU.
;i+=tcy_cnt_per_loop)<>

文章评论0条评论)

登录后参与讨论
我要评论
0
26
关闭 站长推荐上一条 /2 下一条