时钟输出实例
如何判断时钟是否配置正确,最有效的方式就是让配置好的时钟从某个引脚输出,然后在外部通过频率计或示波器来进行检测,现在就来讨论一下这个实例。要使用前面写好的时钟配置函数,还得结合MDK5开发环境来实现。这里先给出一段完整的时钟配置程序,内容如下:
void SystemInit(void)
{
SysCLK_config(); //调用时钟配置函数
}
int main(void)
{
while(1)
{
; //空循环
}
}
从上述程序中可以看出,主函数的写法和普通单片机开发的没有什么两样,都有一个死循环。由于这里只做时钟配置的仿真,所以进行了一个空循环。
在上述代码中需要特别注意三点:1、main函数必须是整型(int型)的;2、在程序结束的最后一行要有一个空行(即要回一下车),否则在编译时会出现警告;3、在项目启动文件startup_LPC82x.s中,会先去调用一个名为Systeminit的系统初始化函数,所以上述程序虽然只调用了一个时钟配置函数SysCLK_config,但仍然要把它放入到系统初始化函数Systeminit中去,在执行完该函数后才会跳转到main函数中去执行,这一过程可通过启动文件startup_LPC82x.s中的以下代码看出来。
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
把上述函数及前面的时钟配置函数写到新建好的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++) __asm__("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; //输出分频为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) { CLKOUT_EN(24); while(1) { ; } }
再提示一下,在MDK环境中,程序的最后一行都应该多一个空行,否则编译会出现警告。

(2)第8到31位为保留位

(2)第2到31位为保留位。

(2)第1到31位为保留位。

浙公网安备 33010602011771号