HR8P506,时钟配置,一切从内部时钟HRC开始.

首先,在进行这项工作之前,建议大伙先熟读HR8P506手册的系统时钟章节.
前面我们已经进行过点灯工作了,为什么我们什么都没有配置单片机仍然会跑呢?
好吧,一般单片机从上电开始就会默认开启内部IRC时钟,所以不用担心芯片没有时钟不会跑,你只要担心它具体上电频率是多少.
这里留个悬念,到底单片机上电时是多少频率在跑,在芯片手册上应该能找到答案.

这里写图片描述

让我们先看看时钟树,我们如果要将系统时钟配置成内部时钟,要经过多少到关卡…
内部时钟有两个,,,这里我只讨论HRC,就是内部高速时钟,

我们可以很直观的看到,我们要将系统时钟设置成HRC,要经过CLK_SEL[1:0]时钟源选择,PLL_MUX,CLKFLT_BY.SYSCLK_DIV分频,
貌似好复杂,,,头痛….

那我们就一步一步来捋顺它.

我们的目标,将系统时钟设置成HRC并经PLL锁相环倍频频到48M,并以此作为系统时钟…
PLL为什么可以倍频,,,自行搜索.

具体流程
使能HRC
|
将HRC设置成PLL时钟输入
|
将PLL设置成48M输出
|
将系统时钟设置成PLL输入,不分频
|
大功告成

那么,知道流程之后我们就可以开干了,

首先我们要知道这几个要用到的函数,在”lib_scu.c”文件里面

PLLClock_Config();
SCU_SysClkSelect();
DeviceClockAllEnable();
SCU_RegUnLock();
SCU_RegLock();

具体函数怎么运行,是什么函数欢迎大家去看库函数代码,因为代码已经写得很清楚了,如果我这里再赘述一遍就显得我不尊重库代码编辑人员了,
还有”lib.scu.h”这里面也有几行宏

/* 系统时钟后分频选择 */
#define SCU_SysClk_Div1()   (SCU->SCLKEN0.SYSCLKDIV = 0)
#define SCU_SysClk_Div2()   (SCU->SCLKEN0.SYSCLKDIV = 1)
#define SCU_SysClk_Div4()   (SCU->SCLKEN0.SYSCLKDIV = 2)
#define SCU_SysClk_Div8()   (SCU->SCLKEN0.SYSCLKDIV = 3)
#define SCU_SysClk_Div16()  (SCU->SCLKEN0.SYSCLKDIV = 4)
#define SCU_SysClk_Div32()  (SCU->SCLKEN0.SYSCLKDIV = 5)
#define SCU_SysClk_Div64()  (SCU->SCLKEN0.SYSCLKDIV = 6)
#define SCU_SysClk_Div128()     (SCU->SCLKEN0.SYSCLKDIV = 7)

来,举起双手跟我一起写代码:
上面一节,我们已经知道SystemInit函数是什么东西了,这里,我们就将时钟配置放在这个函数里面,

void SystemInit(void)
{
    GPIO_InitSettingType GPIO_InitTmp;      //定义结构体变量
    //打开所有外设时钟
    DeviceClockAllEnable();
    //原始时钟源选择为HRC
    SCU_SysClkSelect(SCU_CLK_HRC);
    //打开PLL锁相环,输入为内部HRC 16M,输出为48M,系统时钟使用PLL
    PLLClock_Config(Enable,SCU_PLL_IN16M,SCU_PLL_48M,Enable);
    //系统时钟后分频为1:1
    SCU_RegUnLock();
    SCU_SysClk_Div1();
    SCU_RegLock();
    GPIO_InitTmp.Func   = GPIO_Reuse_Func0;             //管脚功能定义为功能0
    GPIO_InitTmp.Dir    = GPIO_Direction_Output;            //设置为输出
    GPIO_InitTmp.DS     = GPIO_DS_Output_Normal;            //普通电流
    GPIO_InitTmp.ODE    = GPIO_ODE_Output_Disable;      //开漏禁止
    GPIO_InitTmp.PDE    = GPIO_PDE_Input_Disable;           //弱下拉禁止
    GPIO_InitTmp.PUE    = GPIO_PUE_Input_Disable;           //弱上拉禁止
    GPIO_InitTmp.Signal = GPIO_Pin_Signal_Digital;  //管脚类型为数字模式
    GPIO_Init(GPIO_Pin_B0,&GPIO_InitTmp);                   //初始化管脚
    GPIO_Init(GPIO_Pin_B1,&GPIO_InitTmp);
}

好了,这么写我们就把系统时钟配置好了,是不是很方便,只增加了几行代码.
很多具体操作都被库函数封装好了,所以我们的代码可以这么简单,
想了解具体运行方式的可以打开库函数了解了解,我就不展开说明了.,

编译,下载.
额,,,,有错…..

这里写图片描述

SYSCLKDIV这个字段没有…..
这是怎么回事,,,,这可是官方出的裤子啊,,,
我现在用的库版本是V1.1,后期大家用升级版的时候,可能不会报这个错误了,

好了,废话多了,让我们找找这是什么原因.

#define SCU_SysClk_Div1() (SCU->SCLKEN0.SYSCLKDIV = 0)

这个宏定义,具体的就是将SCU->SCLKEN0这个寄存器的系统后分频位赋值而已,这里报错,是因为寄存器定义的时候根本就没有SYSCLKDIV这个字段.
找啊找,,让我找到了SCLKEN0这个联合体的定义.


typedef union
{
    struct
    {
        uint32_t CLK_SEL: 2;
        uint32_t XTAL_LP: 1;
        uint32_t RESERVED0: 5;
        uint32_t PLL_MUX: 1;
        uint32_t RESERVED1: 3;
        uint32_t SYSCLK_DIV: 3;
        uint32_t RESERVED2: 1;
        uint32_t CLKFLT_BY: 8;
        uint32_t CLKOUT0_SEL: 2;
        uint32_t CLKOUT1_SEL: 2;
        uint32_t RESERVED3: 4;
    };
    uint32_t Word;
} SCU_SCLKEN0_Typedef;

很显然,在这个联合体里面确实没有SYSCLKDIV这个字段,只有SYSCLK_DIV这个字段,少了一个下划键.
将”lib_scu.h”这个文件里面的后分频宏定义的SYSCLKDIV都改成SYSCLK_DIV,

/* 系统时钟后分频选择 */
#define SCU_SysClk_Div1()   (SCU->SCLKEN0.SYSCLK_DIV = 0)
#define SCU_SysClk_Div2()   (SCU->SCLKEN0.SYSCLK_DIV = 1)
#define SCU_SysClk_Div4()   (SCU->SCLKEN0.SYSCLK_DIV = 2)
#define SCU_SysClk_Div8()   (SCU->SCLKEN0.SYSCLK_DIV = 3)
#define SCU_SysClk_Div16()  (SCU->SCLKEN0.SYSCLK_DIV = 4)
#define SCU_SysClk_Div32()  (SCU->SCLKEN0.SYSCLK_DIV = 5)
#define SCU_SysClk_Div64()  (SCU->SCLKEN0.SYSCLK_DIV = 6)
#define SCU_SysClk_Div128()     (SCU->SCLKEN0.SYSCLK_DIV = 7)

再编译,好了.
下载,LED跑得比原来更欢了…

有人会说,,,你怎么这么不严谨,单纯看个LED闪烁就能看出系统时钟吗,

好吧,,,,我试试将系统时钟输出示波器看看,让大伙心服口服才行….

“芯片支持 2 路 IO 端口输出时钟信号。其中 CLKO0 端口支持高频时钟直接输出,CLKO1
端口支持高频时钟 512 分频后输出。使用时需配置相应的端口复用选择寄存器
GPIO_PAFUNC/GPIO_PBFUNC,使能管脚的时钟输出功能。当使用高频时钟直接输出
时,需使能管脚大电流驱动模式,以免输出时钟波形严重失真。”

那么动手吧,

我这个48脚的芯片CLKO0管脚在24脚,PA9上.
配置PA9复用功能,并使能PA9管脚为大电流输出模式

    GPIO_InitTmp.Func   = GPIO_Reuse_Func3;             //复用功能3
    GPIO_InitTmp.Dir    = GPIO_Direction_Output;        //设置为输出
    GPIO_InitTmp.DS     = GPIO_DS_Output_Strong;        //大电流
    GPIO_InitTmp.ODE    = GPIO_ODE_Output_Disable;      //开漏禁止
    GPIO_InitTmp.PDE    = GPIO_PDE_Input_Disable;       //弱下拉禁止
    GPIO_InitTmp.PUE    = GPIO_PUE_Input_Disable;       //弱上拉禁止
    GPIO_InitTmp.Signal = GPIO_Pin_Signal_Digital;      //管脚类型为数字模式
    GPIO_Init(GPIO_Pin_A9,&GPIO_InitTmp);

然后配置CLKOUT0输出的时钟,在SCU_SCLKEN0这个寄存器的CLKOUT0_SEL这几位上配置,

这里写图片描述

由于我这个版本的库函数还没有这个功能,所以这段只能自己写了,.

    //CLKOUT0输出时钟为系统时钟
    SCU_RegUnLock();
    SCU->SCLKEN0.CLKOUT0_SEL = 1;
    SCU_RegLock();

编译,下载,拿示波器看看,
确实是48M无误.

这里写图片描述

很好,今天就写到这.有疑问,可以留言.,
源码:http://pan.baidu.com/s/1i4GpR5j

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值