时钟输出实例

如何判断时钟是否配置正确,最有效的方式就是让配置好的时钟从某个引脚输出,然后在外部通过频率计或示波器来进行检测,现在就来讨论一下这个实例。要使用前面写好的时钟配置函数,还得结合MDK5开发环境来实现。这里先给出一段完整的时钟配置程序,内容如下:
void SystemInit(void)
{
 SysCLK_config();  //调用时钟配置函数
}
int main(void)
{
 SystemInit ();  //调用系统初始化函数
 while(1)
 {
  ; //空循环
 }
}
从上述程序中可以看出,主函数的写法和普通单片机开发的没有什么两样,都有一个死循环。由于这里只做时钟配置的仿真,所以在调用时钟配置函数后只进行一个空循环。
在上述代码中需要特别注意三点:1、main函数必须是整型(int型)的;2、在程序结束的最后一行要有一个空行(即要回一下车),否则在编译时会出现警告;3、在项目自动加载的启动文件中规定,程序中必须要有一个系统初始化函数(SystemInit函数),否则程序不能编译链接。所以上述程序虽然只调用了一个时钟配置函数,但仍然要把它放入到系统初始化函数中去供主函数调用。
把上述函数及前面的时钟配置函数写到新建好的main.c主程序文件中,点击编译按钮(或按Ctrl+F7快捷键),会发现编译不能通过,显示有4条错误,提示“uint8_t”、“LPC_SYSCON”、“LPC_IOCON”和“LPC_SWM”没有定义。这是因为程序没有包含一些特定头文件的缘故,在这些头文件内包含了相关变量的申明。所以要让程序顺利编译通过,必须要把这些头文件包含进来。但由于开发LPC824所需要的头文件很多,且有些头文件还有彼此的依赖关系,对于不同的开发环境,定义的名称也不完全一致,因此,为了先快速把第一个程序运行起来,减小学习上的挫折感,这里暂时使用不包含头文件的形式,而是把程序用到的所有代码都罗列出来,这样只要把下面的代码全部复制到开发环境中,就可以顺利通过编译了。

时钟输出的完整程序代码如下:

#define   __I     volatile const
#define   __O     volatile
#define   __IO    volatile
typedef unsigned           char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef struct {                 
  __IO uint32_t  SYSMEMREMAP;    
  __IO uint32_t  PRESETCTRL;     
  __IO uint32_t  SYSPLLCTRL;     
  __I  uint32_t  SYSPLLSTAT;     
  __I  uint32_t  RESERVED0[4];
  __IO uint32_t  SYSOSCCTRL;     
  __IO uint32_t  WDTOSCCTRL;     
  __IO uint32_t  IRCCTRL;        
  __I  uint32_t  RESERVED1;
  __IO uint32_t  SYSRSTSTAT;     
  __I  uint32_t  RESERVED2[3];
  __IO uint32_t  SYSPLLCLKSEL;   
  __IO uint32_t  SYSPLLCLKUEN;   
  __I  uint32_t  RESERVED3[10];
  __IO uint32_t  MAINCLKSEL;     
  __IO uint32_t  MAINCLKUEN;     
  __IO uint32_t  SYSAHBCLKDIV;   
  __I  uint32_t  RESERVED4;
  __IO uint32_t  SYSAHBCLKCTRL;  
  __I  uint32_t  RESERVED5[4];
  __IO uint32_t  UARTCLKDIV;     
  __I  uint32_t  RESERVED6[18];
  __IO uint32_t  CLKOUTSEL;      
  __IO uint32_t  CLKOUTUEN;      
  __IO uint32_t  CLKOUTDIV;      
  __I  uint32_t  RESERVED7;
  __IO uint32_t  UARTFRGDIV;                                      
  __IO uint32_t  UARTFRGMULT;                                      
  __I  uint32_t  RESERVED8;
  __IO uint32_t  EXTTRACECMD;    
  __I  uint32_t  PIOPORCAP0;     
  __I  uint32_t  RESERVED9[12];
  __IO uint32_t  IOCONCLKDIV6;                                    
  __I  uint32_t  RESERVED10[6];
  __IO uint32_t  BODCTRL;        
  __IO uint32_t  SYSTCKCAL;      
  __I  uint32_t  RESERVED11[6];
  __IO uint32_t  IRQLATENCY;                                      
  __IO uint32_t  NMISRC;         
  __IO uint32_t  PINTSEL0;       
  __IO uint32_t  PINTSEL1;       
  __IO uint32_t  PINTSEL2;       
  __IO uint32_t  PINTSEL3;       
  __IO uint32_t  PINTSEL4;       
  __IO uint32_t  PINTSEL5;       
  __IO uint32_t  PINTSEL6;       
  __IO uint32_t  PINTSEL7;       
  __I  uint32_t  RESERVED12[27];
  __IO uint32_t  STARTERP0;      
  __I  uint32_t  RESERVED13[3];
  __IO uint32_t  STARTERP1;      
  __I  uint32_t  RESERVED14[6];
  __IO uint32_t  PDSLEEPCFG;     
  __IO uint32_t  PDAWAKECFG;     
  __IO uint32_t  PDRUNCFG;       
  __I  uint32_t  RESERVED15[111];
  __I  uint32_t  DEVICE_ID;      
} LPC_SYSCON_Type;
typedef struct {                 
  __IO uint32_t  PIO0_17;        
  __IO uint32_t  PIO0_13;        
  __IO uint32_t  PIO0_12;        
  __IO uint32_t  PIO0_5;         
  __IO uint32_t  PIO0_4;         
  __IO uint32_t  PIO0_3;         
  __IO uint32_t  PIO0_2;         
  __IO uint32_t  PIO0_11;                                          
  __IO uint32_t  PIO0_10;                                          
  __IO uint32_t  PIO0_16;        
  __IO uint32_t  PIO0_15;        
  __IO uint32_t  PIO0_1;         
  __I  uint32_t  RESERVED0;
  __IO uint32_t  PIO0_9;         
  __IO uint32_t  PIO0_8;         
  __IO uint32_t  PIO0_7;         
  __IO uint32_t  PIO0_6;         
  __IO uint32_t  PIO0_0;         
  __IO uint32_t  PIO0_14;        
  __I  uint32_t  RESERVED1;
  __IO uint32_t  PIO0_28;        
  __IO uint32_t  PIO0_27;        
  __IO uint32_t  PIO0_26;        
  __IO uint32_t  PIO0_25;        
  __IO uint32_t  PIO0_24;        
  __IO uint32_t  PIO0_23;        
  __IO uint32_t  PIO0_22;        
  __IO uint32_t  PIO0_21;        
  __IO uint32_t  PIO0_20;        
  __IO uint32_t  PIO0_19;        
  __IO uint32_t  PIO0_18;        
} LPC_IOCON_Type;
typedef struct {                 
  __IO uint32_t  PINASSIGN0;                                       
  __IO uint32_t  PINASSIGN1;                                      
  __IO uint32_t  PINASSIGN2;                                     
  __IO uint32_t  PINASSIGN3;                                     
  __IO uint32_t  PINASSIGN4;                                     
  __IO uint32_t  PINASSIGN5;                                      
  __IO uint32_t  PINASSIGN6;                                      
  __IO uint32_t  PINASSIGN7;                                       
  __IO uint32_t  PINASSIGN8;                                       
  __IO uint32_t  PINASSIGN9;                                       
  __IO uint32_t  PINASSIGN10;                                      
  __IO uint32_t  PINASSIGN11;                                      
  __I  uint32_t  RESERVED0[100];
  __IO uint32_t  PINENABLE0;                                       
} LPC_SWM_Type;
#define LPC_SYSCON_BASE                 0x40048000UL
#define LPC_IOCON_BASE                  0x40044000UL
#define LPC_SWM_BASE                    0x4000C000UL
#define LPC_SYSCON                      ((LPC_SYSCON_Type         *) LPC_SYSCON_BASE)
#define LPC_IOCON                       ((LPC_IOCON_Type          *) LPC_IOCON_BASE)
#define LPC_SWM                         ((LPC_SWM_Type            *) LPC_SWM_BASE)
void SysCLK_config(void)
{
 uint8_t i;
 LPC_SYSCON->PDRUNCFG &= ~(1 << 5);  //给系统振荡器上电
 LPC_SYSCON->SYSOSCCTRL = 0x00000000;  //系统振荡器未旁路,1~12MHz输入
 for(i = 0; i < 200; i++) __nop();      //延时等待振荡器稳定
 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18);  //使能IOCON时钟
 LPC_IOCON->PIO0_8 &= ~(3 << 3);          //把P0_8引脚配置为无上下拉电阻方式
 LPC_IOCON->PIO0_9 &= ~(3 << 3);          //把P0_9引脚配置为无上下拉电阻方式
 LPC_SWM->PINENABLE0 &= ~(3 << 6);     //把P0_8、P_9引脚配置为XTALIN、XTALOUT引脚
 LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 18);  //禁止IOCON时钟
 LPC_SYSCON->SYSPLLCLKSEL = 0x00000001;  //PLL输入选择外部晶体振荡
 LPC_SYSCON->SYSPLLCLKUEN = 0x00;
 LPC_SYSCON->SYSPLLCLKUEN = 0x01;  //先写0后写1更新时钟源
 while(!(LPC_SYSCON->SYSPLLCLKUEN & 0x01)); //等待更新完成
 LPC_SYSCON->SYSPLLCTRL = 0x00000041;  //M=2、P=4,倍频后的时钟为24MHz
 LPC_SYSCON->PDRUNCFG &= ~(1 << 7);   //给PLL上电
 while(!(LPC_SYSCON->SYSPLLSTAT & 0x01)); //等待PLL锁定
 LPC_SYSCON->MAINCLKSEL = 0x00000003;   //主时钟选择PLL倍频后的时钟
 LPC_SYSCON->MAINCLKUEN = 0x00;
 LPC_SYSCON->MAINCLKUEN = 0x01;   //先写0后写1更新时钟源
 while(!(LPC_SYSCON->MAINCLKUEN & 0x01));  //等待更新完成
 LPC_SYSCON->SYSAHBCLKDIV = 0x00000001;  //AHB为1分频,AHB时钟为24MHz
}
void SystemInit(void)
{
 SysCLK_config();  //调用时钟配置函数
}
void CLKOUT_EN(uint8_t CLKOUT_DIV)
{
 LPC_SWM->PINASSIGN11 = 0xFF18FFFF;   //CLKOUT输出引脚为P0_24
 LPC_SYSCON->CLKOUTDIV = CLKOUT_DIV;   //输出分频为48/ CLKOUT_DIV
 LPC_SYSCON->CLKOUTSEL= 0x00000003;   //CLKOUT时钟选择主时钟
 LPC_SYSCON->CLKOUTUEN =0x00;
 LPC_SYSCON->CLKOUTUEN =0x01;    //先写0后写1更新时钟源
 while(!(LPC_SYSCON->CLKOUTUEN & 0x01));  //等待更新完成
}
int main(void)
{
 SystemInit();
  CLKOUT_EN(24); 
  while(1)
  {
    ;
  }
}

先提示一点,在MDK环境中,程序的最后一行都应该多一个空行,否则编译会出现警告。

从上面的程序中可以看到,变量的申明都是以结构体的形式出现的,较为复杂,现在暂时不去讨论它。先来看一个多出的新函数CLKOUT_EN,它的作用是配置要输出哪个时钟、在哪个引脚上输出、以多少分频输出。如果系统使用的是24MHz的主时钟,分频系数CLKOUT_DIV取24,则该函数执行完后,LPC824的PIO0_24脚就会有1MHz的脉冲输出。
接下来讨论一下CLKOUT_EN函数中用到的寄存器,下表给出的是CLKOUT时钟分频寄存器CLKOUTDIV的全部位结构,其字节地址为0x400480E8。
(1)第0到7位(DIV)为CLKOUT时钟选择位,值为0时禁止时钟输出,其他值为CLKOUT时钟的分频值。
(2)第8到31位为保留位
下表给出的是CLKOUT时钟源选择寄存器CLKOUTSEL的全部位结构,其字节地址为0x400480E0。
(1)第0、1两位(SEL)为CLKOUT时钟源选择位,值从0x0到0x3,分别对应选择内部RC时钟、系统振荡时钟、看门狗时钟、主时钟。
(2)第2到31位为保留位。
下表给出的是CLKOUT时钟源更新寄存器CLKOUTUEN的全部位结构,其字节地址为0x400480E4。
(1)第0位(ENA)为允许CLKOUT时钟源更新控制位,置0时无变化,置1时更新,默认为无变化。
(2)第1到31位为保留位。
实验时可根据需要更改上述寄存器的值来改变CLKOUT的输出,从而观察不同的时钟频率。另外还有一个PINASSIGN11寄存器,它用于把可移动功能分配到具体的引脚上,这将在以后再作具体讨论。
把上面的代码直接替换掉刚才main.c当中的代码并保存。再次点击编译按钮,会发现编译顺利通过了。接着点击工具条上的Build按钮(或按F7键)进行链接生成下载文件,然后把文件下载到LPC824中,就可以通过示波器观察到PIO0_24引脚上输出的脉冲了。至于如何下载程序,我们将在下次讨论。
posted @ 2020-04-26 09:28  fxzq  阅读(810)  评论(0编辑  收藏  举报