HR8P506,时钟配置,一切从内部时钟HRC开始. —— i7gly 32-bit M0 MCU

admin 2021-6-30 843

-— 转自http://m.blog.csdn.net/article/details?id=54586128

首先,在进行这项工作之前,建议大伙先熟读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)
返回