在做項目時,碰到一個問題被困擾很久,採集交流電均值時會出現結果為零的情況,但是我設計的是採集一個週期數據的均值,因此是不可能為零的。
隨着不斷深入尋找錯誤,發現是因為我採用的模板晶振為8MHZ,而我使用的板子外部晶振為25MHZ。
出現這個問題的主要原因是,之前一直使用的是F103的板子,手冊上明確表示晶振的選型範圍是4-16MHZ
而我現在使用的板子為F107,晶振是可以使用25MHZ的,所以沒有想到會是這個的原因。
問題解決了,但是也證明自己對時鐘這邊瞭解不夠深入。遂趁週末好好學習了一下,做個記錄。
下面為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的