首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

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

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<delaydboutput_cnt;i+=tcy_cnt_per_loop)  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
</delaydboutput_cnt;i+=tcy_cnt_per_loop)
返回列表