stm32時鐘設定
阿新 • • 發佈:2020-12-20
在做專案時,碰到一個問題被困擾很久,採集交流電均值時會出現結果為零的情況,但是我設計的是採集一個週期數據的均值,因此是不可能為零的。
隨著不斷深入尋找錯誤,發現是因為我採用的模板晶振為8MHZ,而我使用的板子外部晶振為25MHZ。 問題解決了,但是也證明自己對時鐘這邊瞭解不夠深入。
遂趁週末好好學習了一下,做個記錄。
// 暫存器巨集定義 // 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); } }