在做項目時,碰到一個問題被困擾很久,採集交流電均值時會出現結果為零的情況,但是我設計的是採集一個週期數據的均值,因此是不可能為零的。

隨着不斷深入尋找錯誤,發現是因為我採用的模板晶振為8MHZ,而我使用的板子外部晶振為25MHZ。

出現這個問題的主要原因是,之前一直使用的是F103的板子,手冊上明確表示晶振的選型範圍是4-16MHZ

stm32cubemx配置有源晶振_#define


而我現在使用的板子為F107,晶振是可以使用25MHZ的,所以沒有想到會是這個的原因。

stm32cubemx配置有源晶振_#define_02

問題解決了,但是也證明自己對時鐘這邊瞭解不夠深入。遂趁週末好好學習了一下,做個記錄。
下面為F103芯片時鐘的配置過程:

// 寄存器宏定義
// RCC寄存器基地址為0x40021000
#define RCC_BASE	0x40021000			// RCC部分寄存器的基地址
#define RCC_CR		(RCC_BASE + 0x00)	// RCC_CR的地址
#define RCC_CFGR	(RCC_BASE + 0x04)

#define FLASH_ACR	0x40022000

// 用C語言來訪問寄存器的宏定義
#define rRCC_CR		(*((volatile unsigned int *)RCC_CR))
#define rRCC_CFGR	(*((volatile unsigned int *)RCC_CFGR))
#define rFLASH_ACR	(*((volatile unsigned int *)FLASH_ACR))

void Set_SysClockTo72M(void)
{
	unsigned int rccCrHserdy = 0;
	unsigned int rccCrPllrdy = 0;
	unsigned int rccCfrSwsPll = 0;
	unsigned int faultTime = 0;
    
	rRCC_CR = 0x00000083;
	rRCC_CR &= ~(1<<16);	  	// bit16為0,關閉HSEON
	rRCC_CR |= (1<<16);			// 打開HSEON,讓HSE工作,這裏的打開關閉主要是指內部振盪電路

	do                      //開始振盪到穩定需要一段時間,所以需要判斷
	{
		rccCrHserdy = rRCC_CR & (1<<17);	//檢測第17位是否為1,第17位為HSERDY
		faultTime++;//檢測時間
	}
	while ((faultTime<0x0FFFFFFF) && (rccCrHserdy==0));  //不超時或者HSERDY為0,也就是沒準備好,繼續循環

	if ((rRCC_CR & (1<<17)) != 0)   //不為零説明是因為HSERDY為1,也就是HSE準備好了
	{
		rFLASH_ACR |= 0x10;         //與FLASH相關,暫不深究
		rFLASH_ACR &= (~0x03);
		rFLASH_ACR |= (0x02);

		// 到這裏HSE就ready了,下面再去配PLL並且等待他ready
		//HPRE為bit4-7,是AHB預分頻器;PPRE1為8-10,APB1;PPRE2為11-13,APB2;
		rRCC_CFGR &= (~((0x0f<<4) | (0x07<<8) | (0x07<<11))); //全部置0
		//rRCC_CFGR &= (~(0x3ff<<4));
		// AHB和APB2未分頻,APB1被2分頻,所以最終:AHB和APB2都是72M,APB1是36M 
		rRCC_CFGR |= ((0x0<<4) | (0x04<<8) | (0x0<<11));

		// PLLSRC為bit16,輸入時鐘源;PLLXTPRE為bit17,HSE分頻後作為PLL輸入;
		//選擇HSE作為PLL輸入並且HSE不分頻,所以PLL輸入為8M
		rRCC_CFGR &= (~((1<<16) | (1<<17)));   	// 清零bit17和bit16
		rRCC_CFGR |= ((1<<16) | (0<<17));		// 置1 bit16

		// 設置PLL倍頻係數為9
		rRCC_CFGR &= (~(0x0f<<18));   			// PLLMUL倍頻參數bit18-21 清零
		rRCC_CFGR |= (0x07<<18);				// 9倍頻

		// 打開PLL開關
		rRCC_CR |= (1<<24);

		// do while 循環等待PLL時鐘穩定
		faultTime = 0;
		do
		{
			rccCrPllrdy = rRCC_CR & (1<<25);	//檢測第25位是否為1
			faultTime++;//檢測時間
		}
		while ((faultTime<0x0FFFFFFF) && (rccCrPllrdy==0));
		//while (rccCrPllrdy==0);

		if ((rRCC_CR & (1<<25)) == (1<<25))
		{
		  	// 到這裏説明PLL已經穩定了,可以用了,下面就可以切了
			
			// 切換PLL輸出為SYSCLK
			//SW系統時鐘切換bit1:0,10表示PLL作為系統時鐘
			rRCC_CFGR &= (~(0x03<<0));   //低兩位置零
			rRCC_CFGR |= (0x02<<0);	     //bit2置為1

			faultTime = 0;
			do
				{                                        //SWS系統時鐘轉換狀態位bit3:2
				rccCfrSwsPll = rRCC_CFGR & (0x03<<2);	//檢測第2、3位
				faultTime++;//檢測時間
			}
			while ((faultTime<0x0FFFFFFF) && (rccCfrSwsPll!=(0x02<<2)));
			
		   	if ((rRCC_CFGR & (0x03<<2))== (0x02<<2))
			{
				// 到這裏我們的時鐘整個就設置好了,可以結束了

			}
			else
			{
				// 到這裏就説明PLL輸出作為SYSCLK不成功
				while (1);
			}

		}
		else
		{
			// 到這裏就説明PLL啓動時出錯了,PLL不能穩定工作
			while (1);
		}

	}
	else        //HSE沒有開啓,死循環
	{
		// HSE配置超時,説明HSE不可用,一般硬件就有問題要去查
		while (1);   
	}
}

25MHZ的晶振就是通過如下圖的方式來倍頻成72MHZ的

stm32cubemx配置有源晶振_stm32cubemx配置有源晶振_03