STM32從零開始(三) 點亮led燈並且配置時鐘爲72mhz

在這裏插入圖片描述**

這部分感覺有點亂可以先看後邊的總結部分,代碼的上邊那裏

**
stm32的時鐘就是這個圖。時鐘她是一級一級整上去的。通過pll鎖相環,把外部晶振的頻率給他頂上去。再需要多少就分頻多少,得到需要的頻率

我們要通過外部晶振HSE來得到apb2處的點亮gpiob處的流水燈。需要的是72mhz的頻率

所以看圖
在這裏插入圖片描述
是這麼個路線
但是這個是要配置的。所以在這裏插入圖片描述
這個是內部時鐘,上電以後內部時鐘先運行,讓cpu能夠切換到外部時鐘那裏去。

所以我們看圖,
在這裏插入圖片描述
先是這個,決定輸入的時鐘是否二分頻。
在這裏插入圖片描述
然後是src,選擇內部還是外部時鐘源
mul來倍頻

在這裏插入圖片描述
下一步這裏,sw選擇用哪個做系統時鐘源
下一步ahb分頻。在這裏插入圖片描述
下一步apb2分頻,也就是pclk2

這樣就可以得到想要的時鐘頻率

然後我們來查手冊
在這裏插入圖片描述第一個PLLXTPRE,

這個寄存器
在這裏插入圖片描述

第十七位,就是我們的第一道門檻,因爲復位值是0x00000000
在這裏插入圖片描述
所以這個不用管,自動不分頻。

然後PLLSRC
用來選擇哪個時鐘源來pll倍頻
我們選hse,置一。

在這裏插入圖片描述
然後還是這個寄存器,PLLMUL,第18-21位。我們的晶振是8mhz,所以要9倍頻,就是0111。
在這裏插入圖片描述
然後sw,0-1位,我們選10,倍頻過後的時鐘給他。
在這裏插入圖片描述
往下走,是ahb預分頻器,我們不讓他分頻,0000
在這裏插入圖片描述
繼續往下,apb2分頻器,不分頻,000
在這裏插入圖片描述
輸出就是72mhz

這裏注意了,pll還有個專門配置的寄存器,就是RCC_CR
在這裏插入圖片描述
偏移量0,復位值0x00000083
在這裏插入圖片描述
24位置一,然後等PLL準備好後,25位由硬件置一,代表可用了。

在這裏插入圖片描述16位,我們要啓用外部時鐘源,得置一。在這裏插入圖片描述
準備好後,這個17位就會被硬件置一,代表準備完畢

在這裏插入圖片描述
0位是1,因爲一開始cpu肯定要有一個時鐘來提供時鐘源,就是這個高速內部時鐘源。他先運行起來,然後才能切換到外部
1位也是1,能用肯定是就緒的。下一個是內部高速時鐘調整,這個是人家系統默認的。10000
所以0x83是這麼來的。1000 0011

————————————————————————————_________________------------------------------------------------------

總結一下。

  1. RCC_CR 地址:0x40021000 + 0 = 0x40021000 復位值:0x00000083
    16位HSEON置一,然後判斷17位HSERDY,外部時鐘就緒後進性下一步
  2. RCC_CFGR 地址:0x40021000 + 0x04 = 0x40021004 復位值:0x00000000
    就是我們上邊說的哪個順序,16位PLLSRC置1,17位PLLXTPRE置0 ,然後18-21位的PLLMUL 置0111,4-7位AHB預分頻置0000不分頻,8-10位APB1預分頻置100,2分頻(因爲ahb是72mhz,apb1最高可以36mhz,所以必須分頻)。11-13位APB2預分頻置000,不分頻。
  3. RCC_CR
    24位PLLON置一,判斷25位PLLRDY,爲1說明就緒,繼續下一步。
  4. RCC_CFGR
    0-1位SW置10,PLL輸出作爲系統時鐘,然後判斷2-3位,是否爲10(PLL輸出作爲系統時鐘)

配置完畢
思路很簡單,先配置外部時鐘穩定,然後設置裏邊的時鐘路線,配置完畢就啓動PLL開始倍頻。倍頻完畢後把倍頻出來的結果送給系統。切換完成
所以是三層的嵌套。第一層判斷HSE是否準備完畢,第二層判斷PLL是否倍頻完畢,第三層判斷系統時鐘是否已經切換爲PLL的輸出

下面是代碼部分
設置時鐘函數。我都給他分頻了賊低。

#include "setClock.h"

void SetClock72MHZ(void )
{
	uint GPIO_LED_HSERDY = 0;
	uint GPIO_LED_PLLRDY = 0;
	uint GPIO_LED_SWS = 0;
	uint WAIT_TIME = 0;
	
	rRCC_CR = 0x00000083;
	rRCC_CR &= ~(1 << 16); 
	rRCC_CR |= (1 << 16); 
	
	do
	{
		GPIO_LED_HSERDY = rRCC_CR & (1 << 17);
		WAIT_TIME ++;
	}
	while((WAIT_TIME < 0x0fffffff) && (GPIO_LED_HSERDY == 0));//confirm it's 1 or no respond
	
	if((rRCC_CR & (1 << 17)) != 0) //confirm it's 1 again
	{
		//rFLASH_ACR |= 0x10;
		//rFLASH_ACR &= (~0x03);
		//rFLASH_ACR |= (0x02);
		
		//now, HSE is ok, you can set references
		rRCC_CFGR &= ~((0x0f << 4) | (0x07 << 8) | (0x07 << 11));
		rRCC_CFGR |= ((0x09 << 4) | (0x04 << 8) | (0x07 << 11));
		
		rRCC_CFGR &= ~((1 << 16) | (1 << 17));
		rRCC_CFGR |= ((1 << 16) | (0 << 17));
		
		rRCC_CFGR &= ~(0x0f << 18);
		rRCC_CFGR |= (0x07 << 18);
		
		rRCC_CR &= ~(1 << 24);
		rRCC_CR |= (1 << 24);
		
		WAIT_TIME = 0;
		
		do
		{
			//ledFlash();
			delay(50);
			GPIO_LED_PLLRDY = rRCC_CR & (1 << 25);
			WAIT_TIME ++;
			
		}
		while(GPIO_LED_PLLRDY == 0);
		
		if((rRCC_CR & (1 << 25)) != 0)
		{
			
			//PLL is ready
			rRCC_CFGR &= ~(0x03 << 0);
			rRCC_CFGR |= (0x02 << 0);
			
			WAIT_TIME = 0;
			ledFlash();
		do
		{
			GPIO_LED_SWS = rRCC_CR & (0x03 << 2);
			WAIT_TIME ++;
		}
		while((WAIT_TIME < 0x0fffffff) && (GPIO_LED_SWS != (0x02 << 2)));
		
		if((rRCC_CR & (0x03 << 2)) == (0x02 << 2))
		{
			//all ready
			
		}
		
		else 
		{
			while(1); //pll set is wrong
		}
		}
		else 
		{
			while (1);// PLL is wrong
		}
	}
	else 
	{
		while (1);//HSE is wrong
	}
	
}

咱們是用位操作乾的,不是用庫函數。用位操作就很容易理解這玩意的原理。
爲什麼要先與取反呢
是因爲先要給他清零,再給值

//2020.5.5, the last day of haoliday. The first day for study every day...
#include "GPIO_LED72MHZ.h"
#include "setClock.h"

void  main(void)
{
	ledInit();
	ledFlash();
	ledInit();
	SetClock72MHZ();
	ledFlash();
	while(1);
	//return 0;
}

void ledInit(void)
{
	rRCC_APB2ENR = 0x00000008;
	rGPIOB_CRH = 0x33333333;
	rGPIOB_ODR = 0x0000ff00;
}

void ledFlash(void)
{
	unsigned char i,j;
	for(i = 0; i < 4; i ++)
	{
		rGPIOB_ODR = 0x0000ff00;
		for(j = 0; j < 100; j++)
			delay(50000);
		rGPIOB_ODR = 0x0000f000;
		for(j = 0; j < 100; j++)
			delay(50000);
	}
	
}

void delay(unsigned int i)
{
	while(i --);
}

這個是主函數,明顯看到改變以後閃的慢了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章