单片机时钟初始化配置函数

在前面推文的介绍中,我们知道STM32系统复位后首先进入SystemInit函数进行时钟的设置,然后进入主函数main。那么我们就来看下SystemInit()函数到底做了哪些操作,首先打开我们前面使用库函数编写的LED程序,在system_stm32f10x.c文件中可以找到SystemInit()函数,SystemInit()代码如下:

void SystemInit (void)

{

/* Reset the RCC clock configuration to the default reset state(for debug purpose) /

/ Set HSION bit /

RCC->CR |= (uint32_t)0x00000001;

/ Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits /

#IFndef STM32F10X_CL

RCC->CFGR &= (uint32_t)0xF8FF0000;

#else

RCC->CFGR &= (uint32_t)0xF0FF0000;

#endif / STM32F10X_CL /

/ Reset HSEON, CSSON and PLLON bits /

RCC->CR &= (uint32_t)0xFEF6FFFF;

/ Reset HSEBYP bit /

RCC->CR &= (uint32_t)0xFFFBFFFF;

/ Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits /

RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL

/ Reset PLL2ON and PLL3ON bits */

RCC->CR &= (uint32_t)0xEBFFFFFF;

/* Disable all interrupts and clear pending bits /

RCC->CIR = 0x00FF0000;

/ Reset CFGR2 register /

RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined

STM32F10X_HD_VL)

/ Disable all interrupts and clear pending bits /

RCC->CIR = 0x009F0000;

/ Reset CFGR2 register /

RCC->CFGR2 = 0x00000000;

#else

/ Disable all interrupts and clear pending bits /

RCC->CIR = 0x009F0000;

#endif / STM32F10X_CL /

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined

STM32F10X_HD_VL)

#ifdef DATA_IN_ExtSRAM

SystemInit_ExtMemCtl();

#endif / DATA_IN_ExtSRAM /

#endif

/ Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers /

/ Configure the Flash Latency cycles and enable prefetch buffer /

SetSysClock();

#ifdef VECT_TAB_SRAM

SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; / Vector Table Relocation in Internal SRAM. /

#else

SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; / Vector Table Relocation in

Internal FLASH. */

#endif

}

SystemInit函数开始通过条件编译, 先复位RCC寄存器,同时通过设置CR寄存器的HSI时钟使能位来打开HSI时钟。默认情况下如果CR寄存器复位,是选择HSI作为系统时钟,这点大家可以查看RCC->CR寄存器相关位描述可以得知,当低两位配置为00的时候(复位之后),会选择HSI振荡器为系统时钟。也就是说,调用SystemInit函数之后,首先是选择HSI作为系统时钟。在设置完相关寄存器后才换成HSE作为系统时钟,接下来SystemInit函数内部会调用SetSysClock()函数。这个函数内部是根据宏定义设置系统时钟频率。函数如下:

static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

SetSysClockTo56();

#elif defined SYSCLK_FREQ_72MHz

SetSysClockTo72();

#endif

}

在system_stm32f10x.c文件的开头就有对此宏定义,系统默认的宏定义是72MHz,如下:

#define SYSCLK_FREQ_72MHz 72000000

如果你要设置为36MHz,只需要注释掉上面代码,然后加入下面代码即可:

#define SYSCLK_FREQ_36MHz 36000000

根据该函数内部实现过程可知,直接调用SetSysClockTo72()函数,此函数功能是将系统时钟SYSCLK设置为72M,AHB总线时钟设置为72M,APB2总线时钟设置为72M,APB1总线时钟设置为36M,PLL时钟设置为72M。函数具体实现大家可以打开库函数查看,这里我们就不截取出来。如果SystemInit内实现过程看不懂没有关系,大家只要知道SystemInit函数执行完,时钟大小设置如下:

SYSCLK(系统时钟) =72MHz

AHB 总线时钟(HCLK=SYSCLK) =72MHz

APB1 总线时钟(PCLK1=SYSCLK/2) =36MHz

APB2 总线时钟(PCLK2=SYSCLK/1) =72MHz

PLL 主时钟 =72MHz

在STM32中,这些时钟值是要熟悉的。

最后还是给大家提供一些stm32方面的资料以供后续的学习参考

从0到1,设计自己的开发板

http://www.makeru.com.cn/live/4034_2016.html?s=45051

1小时彻底掌握STM32中断

http://www.makeru.com.cn/live/3523_1666.html?s=45051

(定时器)

http://www.makeru.com.cn/live/1392_1199.html?s=45051

STM32定时器深藏不露的绝技

http://www.makeru.com.cn/live/3523_1495.html?s=45051

stm32 如何用DMA搬运数据

http://www.makeru.com.cn/live/detail/1484.html?s=45051

#include<reg52.h> unsigned char code Segment[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //数码管段码表0~9,带小数点的段码&0x7f unsigned char DispBuf_Clk[4] = {0,0,0,0}; //数码管显示缓冲区_时钟 unsigned char DispBuf_Sec[4] = {0,0,0,0}; //数码管显示缓冲区_秒表 unsigned char DispBuf_Tim[4] = {0,0,0,0}; //数码管显示缓冲区_倒计时 sbit Key1 = P2^4; sbit Key2 = P2^5; sbit Key3 = P2^6; sbit Key4 = P2^7; unsigned char KeyNum; unsigned char Fn = 0; //功能切换键键值(Key1) unsigned char Cursor = 1,Cursor1 = 0x00,Cursor2 = 0x00,Cursor3 = 0x00,Cursor4 = 0x00; //闪烁光标位置 unsigned char blink_cnt = 0; unsigned char clk_cnt = 0; unsigned char Clk_data; unsigned int sec; unsigned int tim = 100; unsigned int temp = 0; sbit S1 = P2^0; //数码管1位选信号,低电平有效 sbit S2 = P2^1; //数码管2位选信号,低电平有效 sbit S3 = P2^2; //数码管3位选信号,低电平有效 sbit S4 = P2^3; //数码管4位选信号,低电平有效 sbit LEDH = P3^5; //AH报警,低电平时亮 sbit LEDL = P3^4; //AL报警,低电平时亮 bit sec_en; bit tim_en; void delayus(unsigned int _t) { while(-- _t); } void delay(unsigned char t) //延时函数 t毫秒 { unsigned int i,j; for(i = 0; i < t; i++) for(j = 0; j < 500; j++); } void Init() //初始化函数 { EA = 1; //开总中断 TMOD = 0x11; //T0、T1均工作在方式1 RCAP2H=(65536-1000)/256; RCAP2L=(65536-1000)%256; //T2用于扫描数码管和键盘,扫描频率=1s/(10000*2us)=50Hz ET2 = 1; //允许定时器2中断 TR2 = 1; //启动定时器2 TH0 = 0x3C; //T0定时时间100ms TL0 = 0xB0; ET0 = 1; // TR0 = 1; TH1 = 0x3C; //T1定时时间100ms TL1 = 0xB0; ET1 = 1; TR1 = 1; } void WriteBuf(unsigned int Val) //写缓冲区函数 { unsigned char val1,val2,val3,val4; //缓冲区内的四个数 val1 = Val/1000; //取出千位 val2 = (Val%1000)/100; //取出百位 val3 = ((Val%1000)%100)/10; //取出十位 val4 = Val%10; //取出个位 switch(Fn) { case 0: { DispBuf_Clk[0] = val1; DispBuf_Clk[1] = val2; DispBuf_Clk[2] = val3; DispBuf_Clk[3] = val4; break; } case 1: { DispBuf_Sec[0] = val1; DispBuf_Sec[1] = val2; DispBuf_Sec[2] = val3; DispBuf_Sec[3] = val4; break; } case 2: { DispBuf_Tim[0] = val1; DispBuf_Tim[1] = val2; DispBuf_Tim[2] = val3; DispBuf_Tim[3] = val4; break; } default:break; } } void DispBuf_C() //显示缓冲区函数 { P0 = 0xff; S1 = 0; P0 = (Segment[DispBuf_Clk[0]] " C
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值