以下程式碼基於 air105_project 的庫函數
暫存器手冊 Air105晶片資料手冊_1.1.pdf
暫存器的基礎地址, 定義在 air105.h
#define AIR105_FLASH_BASE (0x01000000UL) /*!< (FLASH ) Base Address */
#define AIR105_SRAM_BASE (0x20000000UL) /*!< (SRAM ) Base Address */
#define AIR105_PERIPH_BASE (0x40000000UL) /*!< (Peripheral) Base Address */
#define AIR105_AHB_BASE (AIR105_PERIPH_BASE)
#define AIR105_APB0_BASE (AIR105_PERIPH_BASE + 0x10000)
#define SYSCTRL_BASE (AIR105_APB0_BASE + 0xF000)
SYSCTRL_BASE
振盪源選擇
SYSCTRL_SYSCLKSourceSelect(SELECT_EXT12M);
12MHz 時鐘來源選擇: 0:片外 XTAL, 1:片內 OSC
void SYSCTRL_SYSCLKSourceSelect(SYSCLK_SOURCE_TypeDef source)
{
assert_param(IS_SYSCLK_SOURCE(source));
switch (source)
{
case SELECT_EXT12M:
// FREQ_SEL 是一個32bit的暫存器, 先與二補數(清零第12位元), 然後寫入值(0)
SYSCTRL->FREQ_SEL = ((SYSCTRL->FREQ_SEL & (~SYSCTRL_FREQ_SEL_CLOCK_SOURCE_Mask)) | SYSCTRL_FREQ_SEL_CLOCK_SOURCE_EXT);
break;
case SELECT_INC12M:
// 先與二補數(清零第12位元), 然後寫入值(1)
SYSCTRL->FREQ_SEL = ((SYSCTRL->FREQ_SEL & (~SYSCTRL_FREQ_SEL_CLOCK_SOURCE_Mask)) | SYSCTRL_FREQ_SEL_CLOCK_SOURCE_INC);
break;
}
}
設定使用預設的內部時鐘HSI(Internal clock)
void SystemClock_Config_HSI(void)
{
// 設定CPU頻率, 直接選擇, 不需要計算
SYSCTRL_PLLConfig(SYSCTRL_PLL_204MHz);
// 分頻後產生 FCLK -> 這是主程式的時鐘
SYSCTRL_PLLDivConfig(SYSCTRL_PLL_Div_None);
// 分頻產生 HCLK, 如果 FCLK > 102MHz 則無論如何設定, 都會被二分頻
SYSCTRL_HCLKConfig(SYSCTRL_HCLK_Div2);
// 分頻產生 PCLK -> 這是大部分外設的時鐘
SYSCTRL_PCLKConfig(SYSCTRL_PCLK_Div2);
QSPI_SetLatency((uint32_t)0);
}
PLL分頻的選項
#define SYSCTRL_PLL_Div_None ((uint32_t)0x00)
#define SYSCTRL_PLL_Div2 ((uint32_t)0x01)
#define SYSCTRL_PLL_Div4 ((uint32_t)0x10)
void Delay_Init(void)
{
SYSCTRL_ClocksTypeDef clocks;
SYSCTRL_GetClocksFreq(&clocks);
SysTick_Config(clocks.CPU_Frequency / 1000000); ///< 1us
}
呼叫 SysTick_Config 將單個 SysTick 設定為 1 us.
也可以直接使用SYSCTRL->HCLK_1MS_VAL * 2 / 1000
這個變數代表了當前時鐘設定下, 1ms需要的HCLK時鐘週期, 根據當前FCLK是否大於108MHz 確定是否要乘以2.
之後就會每隔1us呼叫 SysTick_Handler(void), 在這裡設定 32bit g_current_tick 遞增, 可以用於延時控制. 因為32bit數的限制, 1.2個小時後會溢位, 所以這裡有一個延遲的極限.
void SysTick_Handler(void)
{
g_current_tick++;
}
為避免溢位造成的延遲錯誤, 需要做一個判斷
uint32_t get_diff_tick(uint32_t cur_tick, uint32_t prior_tick)
{
if (cur_tick < prior_tick)
{
// 如果當前值比前值還小, 說明發生了溢位, 用當前值加上原值取反(即原值離溢位的距離)
return (cur_tick + (~prior_tick));
}
else
{
return (cur_tick - prior_tick);
}
}
延遲的函數
void Delay_us(uint32_t usec)
{
uint32_t old_tick;
old_tick = g_current_tick;
while (get_diff_tick(g_current_tick, old_tick) < usec);
}
void Delay_ms(uint32_t msec)
{
uint32_t old_tick;
old_tick = g_current_tick;
while (get_diff_tick(g_current_tick, old_tick) < (msec * 1000));
}
程式碼地址: https://gitee.com/iosetting/air105_project
可以使用Keil5 MDK 直接開啟 Demos 目錄下的範例專案, 與Air105開發板接線參考前一篇合宙AIR105(一): Keil MDK開發環境, DAP-Link 燒錄和偵錯