OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 21496|回复: 25

[F1开发板通用] STM32F103使用库函数如何修改外部晶振频率?如何修改主频? 教学贴。。。

  [复制链接]

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
发表于 2017-3-3 18:10:38 | 显示全部楼层 |阅读模式
很多初学者,用库函数开发STM32的时候不知道如何修改系统主频?不知道如何修改外部晶振频率?
这里,我们针对这两个问题,给大家做一个简单的教程。希望大家能够掌握,以后可以轻松修改主频。

A客户:自己做了板子,使用了12M的外部晶振,主频还是想要72M,应该如何修改库函数代码呢?
B客户:自己做了板子,使用了12M的外部晶振,主频我想改为120M,应该如何修改呢?

首先,针对A客户的问题,修改办法如下:
STM32F1的固件库,外部晶振频率的定义在stm32f10x.h里面,如下:
[mw_shl_code=c,true]#if !defined HSE_VALUE
#ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */[/mw_shl_code]
其中,HSE_VALUE就是外部晶振的频率,对通用型STM32,默认是8M,对互联型,默认是25M。
如果我们使用12M外部晶振,那么修改HSE_VALUE 的值为:12000000,即可,代码如下:
[mw_shl_code=c,true]#if !defined HSE_VALUE
#ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#else
#define HSE_VALUE ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */[/mw_shl_code]
然后,由于客户A还是使用72M的主频,在system_stm32f10x.c里面,有如下宏定义:
[mw_shl_code=c,true]#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif
[/mw_shl_code]
默认定义了:SYSCLK_FREQ_72MHz 72000000,也就是72M,所以这里不用改,但是,事实上,修改主频为72M的是通过
SetSysClockTo72函数实现的,该函数核心代码如下:
[mw_shl_code=c,true]    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
                            RCC_CFGR_PLLMULL9);
#else   
    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;[/mw_shl_code]其中,修改主频的核心代码为:
[mw_shl_code=c,true]RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);[/mw_shl_code]
通过RCC_CFGR_PLLMULL9将倍频系数设置为9,如果默认外部晶振是8M,那么刚好得到72M的频率。
不过,我们修改外部晶振为12M了,所以这里得改为6,修改后代码如下:
[mw_shl_code=c,true] RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);[/mw_shl_code]
这样,我们就完成了客户A的要求,使用外部晶振12M,且设置系统主频为72Mhz。我们通过战舰V3的串口通信实验,测试,效果如下:
72M.png

再来看客户B的问题,首先,还是要修改HSE_VALUE的值为12000000,详见客户A问题的改动。
然后,在system_stm32f10x.c里面,需要进行一系列修改:
首先,在106行附件,新增宏定义:SYSCLK_FREQ_120MHz,同时注释掉SYSCLK_FREQ_72MHz ,修改后代码如下:
[mw_shl_code=c,true]#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
#define SYSCLK_FREQ_24MHz  24000000
#else
/* #define SYSCLK_FREQ_HSE    HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz  24000000 */
/* #define SYSCLK_FREQ_36MHz  36000000 */
/* #define SYSCLK_FREQ_48MHz  48000000 */
/* #define SYSCLK_FREQ_56MHz  56000000 */
/* #define SYSCLK_FREQ_72MHz  72000000 */
#define SYSCLK_FREQ_120MHz  120000000
#endif[/mw_shl_code]

然后,在 第152行附近,新增120M时,对SystemCoreClock 的赋值,修改后代码如下:
[mw_shl_code=c,true]/*******************************************************************************
*  Clock Definitions
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSE
  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_24MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_36MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_48MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_56MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_72MHz;        /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz
  uint32_t SystemCoreClock         = SYSCLK_FREQ_120MHz;       /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
  uint32_t SystemCoreClock         = HSI_VALUE;        /*!< System Clock Frequency (Core Clock) */
#endif[/mw_shl_code]

然后,在第181行附近,新增SetSysClockTo120的函数定义,修改后代码如下:
[mw_shl_code=c,true]#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#elif defined SYSCLK_FREQ_120MHz
  static void SetSysClockTo120(void);
#endif[/mw_shl_code]

然后,在第424行附近,修改:SetSysClock函数,新增对120M主频的设置,修改后代码如下:
[mw_shl_code=c,true]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();
#elif defined SYSCLK_FREQ_120MHz
  SetSysClockTo120();
#endif

/* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */
}[/mw_shl_code]

最后,实现SetSysClockTo120函数,其中绝大部分代码,可以照搬SetSysClockTo72函数的。在第1089行附近,新增SetSysClockTo120函数代码如下:
[mw_shl_code=c,true]#elif defined SYSCLK_FREQ_120MHz
/**
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2
* and PCLK1 prescalers.
* @note This function should be used only after reset.
* @param None
* @retval None
*/
static void SetSysClockTo120(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);

/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}

if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;


/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
{
}


/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL10);
#endif /* STM32F10X_CL */

/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;

/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}

/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}[/mw_shl_code]该函数重点是:RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL10);
这句代码,修改时钟频率为10倍频,12M*10=120M,就实现了设置系统主频为120M的目的。


这样,我们就完成了客户B的要求,使用外部晶振12M,且设置系统主频为120Mhz。


同样通过战舰V3的串口通信实验,测试,效果如下:
120M主频.png

最后,两个例程的代码见附件,方便大家参考。
实验4 串口实验_改为12M晶振_72M主频.rar (281.34 KB, 下载次数: 1274)
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
 楼主| 发表于 2017-3-4 01:20:44 | 显示全部楼层
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165352
金钱
165352
注册时间
2010-12-1
在线时间
2108 小时
 楼主| 发表于 2017-3-6 18:14:10 | 显示全部楼层
顶一下
回复 支持 反对

使用道具 举报

8

主题

145

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
462
金钱
462
注册时间
2016-12-14
在线时间
75 小时
发表于 2017-3-7 09:44:13 | 显示全部楼层
原子哥辛苦了,学习了
书山有路勤为径,学海无涯苦作舟!
回复 支持 反对

使用道具 举报

8

主题

206

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1010
金钱
1010
注册时间
2016-4-6
在线时间
234 小时
发表于 2017-4-5 20:12:02 | 显示全部楼层
感谢原子哥,学习了!
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2017-3-21
在线时间
10 小时
发表于 2017-4-6 10:26:01 | 显示全部楼层
谢谢原子哥 ,学习了  ,要怎么收藏呢
回复 支持 反对

使用道具 举报

8

主题

145

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
462
金钱
462
注册时间
2016-12-14
在线时间
75 小时
发表于 2017-4-21 16:19:56 | 显示全部楼层
谢谢分享,学习了。。。。。
书山有路勤为径,学海无涯苦作舟!
回复 支持 反对

使用道具 举报

17

主题

465

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2142
金钱
2142
注册时间
2013-1-11
在线时间
504 小时
发表于 2017-5-17 22:58:11 | 显示全部楼层
回复 支持 反对

使用道具 举报

2

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
177
金钱
177
注册时间
2017-5-3
在线时间
37 小时
发表于 2017-6-2 12:22:58 | 显示全部楼层
我顶!!!
回复 支持 反对

使用道具 举报

14

主题

50

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1011
金钱
1011
注册时间
2016-10-28
在线时间
82 小时
发表于 2017-6-21 16:47:23 | 显示全部楼层
谢谢分享,学习了。。。。。
回复 支持 反对

使用道具 举报

18

主题

99

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
465
金钱
465
注册时间
2016-1-20
在线时间
89 小时
发表于 2017-7-2 12:06:40 | 显示全部楼层

顶····································
回复 支持 反对

使用道具 举报

14

主题

50

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1011
金钱
1011
注册时间
2016-10-28
在线时间
82 小时
发表于 2017-7-12 18:13:16 | 显示全部楼层
原子哥 我用的8M外部晶振,按照上面的设置时钟,打开仿真却看到时钟还是8M,这是怎么回事呢? 单片机是stm32f103vet6
L1_FU18FA4K7YWX3J)RC2$T.png
回复 支持 反对

使用道具 举报

14

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2015-5-25
在线时间
39 小时
发表于 2017-12-14 09:23:49 | 显示全部楼层
山山水水 发表于 2017-7-12 18:13
原子哥 我用的8M外部晶振,按照上面的设置时钟,打开仿真却看到时钟还是8M,这是怎么回事呢? 单片机是stm3 ...

知道怎么打开这个界面吗
,我不知道点哪个按钮打开这个界面看时钟频率
回复 支持 反对

使用道具 举报

14

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2015-5-25
在线时间
39 小时
发表于 2017-12-14 09:30:12 | 显示全部楼层
有帮助,刚刚好解决了我的问题
回复 支持 反对

使用道具 举报

14

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2015-5-25
在线时间
39 小时
发表于 2017-12-14 09:30:37 | 显示全部楼层
哪个界面怎么打开的还是不知道
回复 支持 反对

使用道具 举报

14

主题

81

帖子

0

精华

初级会员

Rank: 2

积分
183
金钱
183
注册时间
2015-5-25
在线时间
39 小时
发表于 2017-12-21 17:46:54 | 显示全部楼层

原子大哥,仿真时候点哪里打开查看时钟的界面
回复 支持 反对

使用道具 举报

17

主题

237

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1312
金钱
1312
注册时间
2017-3-1
在线时间
259 小时
发表于 2018-7-5 22:06:56 | 显示全部楼层
本帖最后由 NewGuard 于 2018-7-5 22:08 编辑

原子哥:
在这里有个疑点想问下,这里的【#define HSE_VALUE    ((uint32_t)8000000)】中(HSE_VALUE )在【RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);】怎么联系上的,单步调试好像并没有直接关系呀,如果没关系的话有何必设置呢?谢谢!
[#define  RCC_CFGR_PLLSRC_HSE    ((uint32_t)0x00010000)],HSE_VALUE    是怎么跟这个地址挂钩的,不太明白?
回复 支持 反对

使用道具 举报

2

主题

3

帖子

0

精华

初级会员

Rank: 2

积分
62
金钱
62
注册时间
2018-3-20
在线时间
6 小时
发表于 2018-9-5 13:55:06 | 显示全部楼层
顶了再看
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
4
金钱
4
注册时间
2018-10-12
在线时间
1 小时
发表于 2018-10-12 20:05:23 | 显示全部楼层
HSE_VALUE   更改晶振
回复 支持 反对

使用道具 举报

0

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
172
金钱
172
注册时间
2013-5-18
在线时间
52 小时
发表于 2018-11-14 13:51:24 | 显示全部楼层
mark! STM32F103使用库函数如何修改外部晶振频率?如何修改主频? 教学贴
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-9-20
在线时间
12 小时
发表于 2018-12-20 13:33:59 | 显示全部楼层
马一下马一下
回复 支持 反对

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2019-12-7
在线时间
60 小时
发表于 2019-12-14 10:29:54 | 显示全部楼层
想问下如果外部晶振是11.0592M,主频还想要72M,按照上面的说明进行更改OK么?
除过之后倍数约等于6.489。不看到stm32f10x.h里有个RCC_CFGR_PLLMULL6_5 ,这个是6.5倍,貌似可以???
回复 支持 反对

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2019-12-7
在线时间
60 小时
发表于 2019-12-19 22:45:50 | 显示全部楼层
山山水水 发表于 2017-7-12 18:13
原子哥 我用的8M外部晶振,按照上面的设置时钟,打开仿真却看到时钟还是8M,这是怎么回事呢? 单片机是stm3 ...

图片里第一行的HSERDY没有对勾,故外部晶振没有准备好,感觉应该检查外部晶振问题。
回复 支持 反对

使用道具 举报

2

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
143
金钱
143
注册时间
2019-12-7
在线时间
60 小时
发表于 2019-12-20 11:11:42 | 显示全部楼层
原子哥,想问下:更改72MHz后,在PRCC界面里的RCC_CR寄存器的值还是0x03030083,意味着还是使用内部晶振,而不是外部晶振?(位16=0,位0=1)
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

初级会员

Rank: 2

积分
116
金钱
116
注册时间
2019-7-6
在线时间
32 小时
发表于 2019-12-25 17:41:42 | 显示全部楼层
寄存器版本怎么做?
回复 支持 反对

使用道具 举报

0

主题

35

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
359
金钱
359
注册时间
2020-10-15
在线时间
54 小时
发表于 2022-9-8 09:33:16 | 显示全部楼层
感谢原子哥
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 22:49

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表