时钟系统与复位管理
时钟系统概述
时钟系统是单片机(MCU)正常运行的基础,它决定了系统的运行速度和功耗。ABOV M0S11系列单片机提供了多种时钟源和时钟配置方式,以满足不同应用场景的需求。本节将详细介绍ABOV M0S11系列单片机的时钟系统,包括时钟源、时钟配置和时钟分频等内容。
时钟源
ABOV M0S11系列单片机支持多种时钟源,包括内部时钟源和外部时钟源。以下是一些主要的时钟源:
- 内部高速RC振荡器(HIRC):提供一个高精度的内部时钟源,频率为16MHz。
- 内部低速RC振荡器(LIRC):提供一个低功耗的内部时钟源,频率为32.768kHz。
- 外部高速晶振(HXT):通过外部晶振提供一个高精度的时钟源,频率范围为4MHz至24MHz。
- 外部低速晶振(LXT):通过外部晶振提供一个低功耗的时钟源,频率为32.768kHz。
时钟树
时钟树是单片机时钟系统的重要组成部分,它将不同的时钟源通过时钟分频器和选择器组合起来,为不同的外设和系统提供所需的时钟频率。ABOV M0S11系列单片机的时钟树如下图所示:
+----------------+
| HIRC (16MHz) |
+----------------+
|
v
+----------------+
| HXT (4-24MHz) |
+----------------+
|
v
+----------------+
| PLL (可选) |
+----------------+
|
v
+----------------+
| 系统时钟源 |
+----------------+
/ | \
/ | \
v v v
+--------+ +--------+ +--------+
| CPU | | APB | | AHB |
+--------+ +--------+ +--------+
时钟配置
时钟配置是通过配置寄存器来选择和设置时钟源和分频比。以下是一些主要的时钟配置寄存器:
- CLKSEL寄存器:用于选择系统时钟源。
- CLKDIV寄存器:用于设置时钟分频比。
- PLLCON寄存器:用于配置PLL(锁相环)。
示例代码:配置系统时钟源
以下是一个示例代码,展示如何配置ABOV M0S11系列单片机的系统时钟源为外部高速晶振(HXT)。
#include "abov_m0s11.h"
// 配置系统时钟源为HXT
void configure_system_clock(void) {
// 使能HXT
CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk; // 使能12MHz外部高速晶振
// 等待HXT稳定
while (!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));
// 选择HXT作为系统时钟源
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | CLK_CLKSEL0_HCLKSEL_HXT;
}
int main(void) {
// 配置系统时钟
configure_system_clock();
// 主程序
while (1) {
// 应用代码
}
}
时钟分频
时钟分频是通过时钟分频器将时钟源的频率分成不同的频率,以满足不同外设的需求。ABOV M0S11系列单片机提供了多个时钟分频器,包括AHB分频器、APB分频器等。
AHB分频器
AHB分频器用于配置CPU和其他高速外设的时钟频率。分频比可以通过CLKDIV
寄存器的HCLKDIV
位域进行设置。
APB分频器
APB分频器用于配置低速外设的时钟频率。分频比可以通过CLKDIV
寄存器的PCLKDIV
位域进行设置。
示例代码:配置时钟分频
以下是一个示例代码,展示如何配置AHB分频器和APB分频器。
#include "abov_m0s11.h"
// 配置AHB和APB分频器
void configure_clock_dividers(void) {
// 配置AHB分频器,分频比为1
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_HCLKDIV_Msk) | CLK_CLKDIV_HCLKDIV(1);
// 配置APB分频器,分频比为2
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_PCLKDIV_Msk) | CLK_CLKDIV_PCLKDIV(2);
}
int main(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 主程序
while (1) {
// 应用代码
}
}
复位管理
复位管理是单片机系统中的重要功能,它确保系统在启动时或异常情况下能够正确地初始化。ABOV M0S11系列单片机提供了多种复位源和复位配置方式,以确保系统的稳定性和可靠性。
复位源
ABOV M0S11系列单片机支持以下复位源:
- 上电复位(POR):当单片机上电时自动复位。
- 掉电复位(PDR):当单片机掉电时自动复位。
- 外部复位(EXR):通过外部复位引脚(RST)触发复位。
- 软件复位(SWR):通过软件指令触发复位。
- 看门狗复位(WDR):当看门狗定时器超时后触发复位。
- 低电压检测复位(LVR):当电源电压低于设定阈值时触发复位。
复位配置
复位配置是通过配置寄存器来选择和设置复位源。以下是一些主要的复位配置寄存器:
- RSTCON寄存器:用于配置复位源和复位行为。
- LVDCON寄存器:用于配置低电压检测复位的阈值。
示例代码:配置低电压检测复位
以下是一个示例代码,展示如何配置低电压检测复位(LVR)。
#include "abov_m0s11.h"
// 配置低电压检测复位
void configure_low_voltage_reset(void) {
// 选择LVR阈值为2.7V
SYS->LVDCON = (SYS->LVDCON & ~SYS_LVDCON_LVD_VLSEL_Msk) | SYS_LVDCON_LVD_VLSEL_2_7V;
// 使能LVR
SYS->LVDCON |= SYS_LVDCON_LVR_EN_Msk;
}
int main(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 配置低电压检测复位
configure_low_voltage_reset();
// 主程序
while (1) {
// 应用代码
}
}
示例代码:软件复位
以下是一个示例代码,展示如何通过软件触发系统复位。
#include "abov_m0s11.h"
// 触发软件复位
void trigger_software_reset(void) {
// 设置软件复位标志
SYS->RSTCON |= SYS_RSTCON_RSTKEY_Msk | SYS_RSTCON_PORST_Msk;
}
int main(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 配置低电压检测复位
configure_low_voltage_reset();
// 触发软件复位
trigger_software_reset();
// 主程序
while (1) {
// 应用代码
}
}
复位状态寄存器
复位状态寄存器用于记录复位的来源和状态,以便在系统启动后进行诊断和处理。以下是一些主要的复位状态寄存器位域:
- RSTSRC寄存器:记录复位来源。
PORST_IF
:上电复位标志PDRST_IF
:掉电复位标志EXTRST_IF
:外部复位标志SWRST_IF
:软件复位标志WDRST_IF
:看门狗复位标志LVRST_IF
:低电压检测复位标志
示例代码:读取复位状态
以下是一个示例代码,展示如何读取复位状态寄存器并判断复位来源。
#include "abov_m0s11.h"
// 读取复位状态寄存器
void read_reset_status(void) {
// 读取复位状态寄存器
uint32_t reset_status = SYS->RSTSRC;
// 判断复位来源
if (reset_status & SYS_RSTSRC_PORST_IF_Msk) {
printf("上电复位\n");
}
if (reset_status & SYS_RSTSRC_PDRST_IF_Msk) {
printf("掉电复位\n");
}
if (reset_status & SYS_RSTSRC_EXTRST_IF_Msk) {
printf("外部复位\n");
}
if (reset_status & SYS_RSTSRC_SWRST_IF_Msk) {
printf("软件复位\n");
}
if (reset_status & SYS_RSTSRC_WDRST_IF_Msk) {
printf("看门狗复位\n");
}
if (reset_status & SYS_RSTSRC_LVRST_IF_Msk) {
printf("低电压检测复位\n");
}
// 清除复位标志
SYS->RSTSRC = reset_status;
}
int main(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 配置低电压检测复位
configure_low_voltage_reset();
// 读取复位状态
read_reset_status();
// 主程序
while (1) {
// 应用代码
}
}
复位处理
在复位后,单片机需要进行一系列的初始化操作,以确保系统能够正常运行。这些初始化操作通常包括:
- 系统时钟配置:设置系统的时钟源和分频比。
- 外设初始化:初始化GPIO、定时器、ADC等外设。
- 中断配置:配置中断控制器和中断向量表。
- 主程序入口:跳转到主程序的入口点。
示例代码:复位处理函数
以下是一个示例代码,展示如何在复位后进行系统初始化。
#include "abov_m0s11.h"
// 配置系统时钟
void configure_system_clock(void) {
// 使能HXT
CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk; // 使能12MHz外部高速晶振
// 等待HXT稳定
while (!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));
// 选择HXT作为系统时钟源
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | CLK_CLKSEL0_HCLKSEL_HXT;
}
// 配置时钟分频
void configure_clock_dividers(void) {
// 配置AHB分频器,分频比为1
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_HCLKDIV_Msk) | CLK_CLKDIV_HCLKDIV(1);
// 配置APB分频器,分频比为2
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_PCLKDIV_Msk) | CLK_CLKDIV_PCLKDIV(2);
}
// 配置低电压检测复位
void configure_low_voltage_reset(void) {
// 选择LVR阈值为2.7V
SYS->LVDCON = (SYS->LVDCON & ~SYS_LVDCON_LVD_VLSEL_Msk) | SYS_LVDCON_LVD_VLSEL_2_7V;
// 使能LVR
SYS->LVDCON |= SYS_LVDCON_LVR_EN_Msk;
}
// 读取复位状态寄存器
void read_reset_status(void) {
// 读取复位状态寄存器
uint32_t reset_status = SYS->RSTSRC;
// 判断复位来源
if (reset_status & SYS_RSTSRC_PORST_IF_Msk) {
printf("上电复位\n");
}
if (reset_status & SYS_RSTSRC_PDRST_IF_Msk) {
printf("掉电复位\n");
}
if (reset_status & SYS_RSTSRC_EXTRST_IF_Msk) {
printf("外部复位\n");
}
if (reset_status & SYS_RSTSRC_SWRST_IF_Msk) {
printf("软件复位\n");
}
if (reset_status & SYS_RSTSRC_WDRST_IF_Msk) {
printf("看门狗复位\n");
}
if (reset_status & SYS_RSTSRC_LVRST_IF_Msk) {
printf("低电压检测复位\n");
}
// 清除复位标志
SYS->RSTSRC = reset_status;
}
// 复位处理函数
void reset_handler(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 配置低电压检测复位
configure_low_voltage_reset();
// 初始化GPIO
GPIO->MODE = (GPIO->MODE & ~GPIO_MODE_MODE0_Msk) | GPIO_MODE_MODE0_INPUT;
// 初始化定时器
TIMER->TCSR0 = (TIMER->TCSR0 & ~TIMER_TCSR0_PSC_Msk) | TIMER_TCSR0_PSC(127); // 设置预分频器
TIMER->TCSR0 |= TIMER_TCSR0_EN_Msk; // 使能定时器
// 初始化中断控制器
NVIC_EnableIRQ(TIMER0_IRQn); // 使能定时器0中断
// 读取复位状态
read_reset_status();
}
// 定时器0中断处理函数
void TIMER0_IRQHandler(void) {
// 清除定时器0中断标志
TIMER->TCSR0 |= TIMER_TCSR0_IF_Msk;
// 处理定时器0中断
printf("定时器0中断\n");
}
// 复位向量表
__attribute__((section(".isr_vector"))) const uint32_t isr_vector[] = {
(uint32_t)&__stack_end__, // 堆栈指针
(uint32_t)&reset_handler, // 复位处理函数
(uint32_t)&NMI_Handler, // NMI中断处理函数
(uint32_t)&HardFault_Handler, // 硬故障中断处理函数
(uint32_t)&MemManage_Handler, // 内存管理中断处理函数
(uint32_t)&BusFault_Handler, // 总线故障中断处理函数
(uint32_t)&UsageFault_Handler, // 使用故障中断处理函数
0, 0, 0, 0, // 保留
0, 0, 0, 0, // 保留
(uint32_t)&SVCall_Handler, // 系统调用中断处理函数
(uint32_t)&DebugMon_Handler, // 调试监控中断处理函数
0, // 保留
(uint32_t)&PendSV_Handler, // 挂起服务中断处理函数
(uint32_t)&SysTick_Handler, // 系统节拍定时器中断处理函数
(uint32_t)&TIMER0_IRQHandler, // 定时器0中断处理函数
// 其他中断处理函数
};
// 缺省中断处理函数
void NMI_Handler(void) __attribute__((weak, alias("default_handler")));
void HardFault_Handler(void) __attribute__((weak, alias("default_handler")));
void MemManage_Handler(void) __attribute__((weak, alias("default_handler")));
void BusFault_Handler(void) __attribute__((weak, alias("default_handler")));
void UsageFault_Handler(void) __attribute__((weak, alias("default_handler")));
void SVCall_Handler(void) __attribute__((weak, alias("default_handler")));
void DebugMon_Handler(void) __attribute__((weak, alias("default_handler")));
void PendSV_Handler(void) __attribute__((weak, alias("default_handler")));
void SysTick_Handler(void) __attribute__((weak, alias("default_handler")));
// 缺省中断处理函数
void default_handler(void) {
while (1) {
// 处理缺省中断
}
}
int main(void) {
// 跳转到复位处理函数
reset_handler();
// 主程序
while (1) {
// 应用代码
}
}
复位后的系统初始化
在复位后,单片机需要进行一系列的初始化操作,以确保系统能够正常运行。这些初始化操作通常包括:
- 系统时钟配置:设置系统的时钟源和分频比。
- 外设初始化:初始化GPIO、定时器、ADC等外设。
- 中断配置:配置中断控制器和中断向量表。
- 主程序入口:跳转到主程序的入口点。
示例代码:复位后的系统初始化
以下是一个示例代码,展示如何在复位后进行系统初始化。
#include "abov_m0s11.h"
// 配置系统时钟
void configure_system_clock(void) {
// 使能HXT
CLK->PWRCON |= CLK_PWRCON_XTL12M_EN_Msk; // 使能12MHz外部高速晶振
// 等待HXT稳定
while (!(CLK->CLKSTATUS & CLK_CLKSTATUS_XTL12M_STB_Msk));
// 选择HXT作为系统时钟源
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | CLK_CLKSEL0_HCLKSEL_HXT;
}
// 配置时钟分频
void configure_clock_dividers(void) {
// 配置AHB分频器,分频比为1
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_HCLKDIV_Msk) | CLK_CLKDIV_HCLKDIV(1);
// 配置APB分频器,分频比为2
CLK->CLKDIV = (CLK->CLKDIV & ~CLK_CLKDIV_PCLKDIV_Msk) | CLK_CLKDIV_PCLKDIV(2);
}
// 配置低电压检测复位
void configure_low_voltage_reset(void) {
// 选择LVR阈值为2.7V
SYS->LVDCON = (SYS->LVDCON & ~SYS_LVDCON_LVD_VLSEL_Msk) | SYS_LVDCON_LVD_VLSEL_2_7V;
// 使能LVR
SYS->LVDCON |= SYS_LVDCON_LVR_EN_Msk;
}
// 读取复位状态寄存器
void read_reset_status(void) {
// 读取复位状态寄存器
uint32_t reset_status = SYS->RSTSRC;
// 判断复位来源
if (reset_status & SYS_RSTSRC_PORST_IF_Msk) {
printf("上电复位\n");
}
if (reset_status & SYS_RSTSRC_PDRST_IF_Msk) {
printf("掉电复位\n");
}
if (reset_status & SYS_RSTSRC_EXTRST_IF_Msk) {
printf("外部复位\n");
}
if (reset_status & SYS_RSTSRC_SWRST_IF_Msk) {
printf("软件复位\n");
}
if (reset_status & SYS_RSTSRC_WDRST_IF_Msk) {
printf("看门狗复位\n");
}
if (reset_status & SYS_RSTSRC_LVRST_IF_Msk) {
printf("低电压检测复位\n");
}
// 清除复位标志
SYS->RSTSRC = reset_status;
}
// 复位处理函数
void reset_handler(void) {
// 配置系统时钟
configure_system_clock();
// 配置时钟分频
configure_clock_dividers();
// 配置低电压检测复位
configure_low_voltage_reset();
// 初始化GPIO
GPIO->MODE = (GPIO->MODE & ~GPIO_MODE_MODE0_Msk) | GPIO_MODE_MODE0_INPUT;
// 初始化定时器
TIMER->TCSR0 = (TIMER->TCSR0 & ~TIMER_TCSR0_PSC_Msk) | TIMER_TCSR0_PSC(127); // 设置预分频器
TIMER->TCSR0 |= TIMER_TCSR0_EN_Msk; // 使能定时器
// 初始化中断控制器
NVIC_EnableIRQ(TIMER0_IRQn); // 使能定时器0中断
// 读取复位状态
read_reset_status();
}
// 定时器0中断处理函数
void TIMER0_IRQHandler(void) {
// 清除定时器0中断标志
TIMER->TCSR0 |= TIMER_TCSR0_IF_Msk;
// 处理定时器0中断
printf("定时器0中断\n");
}
// 复位向量表
__attribute__((section(".isr_vector"))) const uint32_t isr_vector[] = {
(uint32_t)&__stack_end__, // 堆栈指针
(uint32_t)&reset_handler, // 复位处理函数
(uint32_t)&NMI_Handler, // NMI中断处理函数
(uint32_t)&HardFault_Handler, // 硬故障中断处理函数
(uint32_t)&MemManage_Handler, // 内存管理中断处理函数
(uint32_t)&BusFault_Handler, // 总线故障中断处理函数
(uint32_t)&UsageFault_Handler, // 使用故障中断处理函数
0, 0, 0, 0, // 保留
0, 0, 0, 0, // 保留
(uint32_t)&SVCall_Handler, // 系统调用中断处理函数
(uint32_t)&DebugMon_Handler, // 调试监控中断处理函数
0, // 保留
(uint32_t)&PendSV_Handler, // 挂起服务中断处理函数
(uint32_t)&SysTick_Handler, // 系统节拍定时器中断处理函数
(uint32_t)&TIMER0_IRQHandler, // 定时器0中断处理函数
// 其他中断处理函数
};
// 缺省中断处理函数
void NMI_Handler(void) __attribute__((weak, alias("default_handler")));
void HardFault_Handler(void) __attribute__((weak, alias("default_handler")));
void MemManage_Handler(void) __attribute__((weak, alias("default_handler")));
void BusFault_Handler(void) __attribute__((weak, alias("default_handler")));
void UsageFault_Handler(void) __attribute__((weak, alias("default_handler")));
void SVCall_Handler(void) __attribute__((weak, alias("default_handler")));
void DebugMon_Handler(void) __attribute__((weak, alias("default_handler")));
void PendSV_Handler(void) __attribute__((weak, alias("default_handler")));
void SysTick_Handler(void) __attribute__((weak, alias("default_handler")));
// 缺省中断处理函数
void default_handler(void) {
while (1) {
// 处理缺省中断
}
}
int main(void) {
// 跳转到复位处理函数
reset_handler();
// 主程序
while (1) {
// 应用代码
}
}
总结
本章详细介绍了ABOV M0S11系列单片机的时钟系统和复位管理。时钟系统包括内部和外部时钟源、时钟树、时钟配置和时钟分频。复位管理包括多种复位源、复位配置、复位状态寄存器、复位处理函数和复位向量表。通过示例代码,我们展示了如何配置和初始化这些系统功能,以便在实际应用中确保单片机的稳定性和可靠性。希望这些内容能够帮助您更好地理解和使用ABOV M0S11系列单片机。