当前位置:首页>Linux>嵌入式C++教程实战之Linux下的单片机编程(9):HAL时钟使能 —— 不开时钟,外设就是一坨睡死的硅

嵌入式C++教程实战之Linux下的单片机编程(9):HAL时钟使能 —— 不开时钟,外设就是一坨睡死的硅

  • 2026-04-16 15:56:57
嵌入式C++教程实战之Linux下的单片机编程(9):HAL时钟使能 —— 不开时钟,外设就是一坨睡死的硅

嵌入式C++教程实战之Linux下的单片机编程(9):HAL时钟使能 —— 不开时钟,外设就是一坨睡死的硅

仓库已经开源!仍然在持续建设中,喜欢的话点个⭐!

相关的链接如下: 

https://github.com/Awesome-Embedded-Learning-Studio/Tutorial_AwesomeModernCPP 

静态网页直接阅览:

https://awesome-embedded-learning-studio.github.io/Tutorial_AwesomeModernCPP/

前言:从硬件原理到软件API

在上一篇里,我们把LED点亮这件事从硬件层面拆了个底朝天——GPIO端口是什么、引脚怎么被寄存器控制、推挽输出和开漏输出的区别、上拉下拉电阻又在扮演什么角色。我们现在对"引脚上发生了什么"已经有了非常清晰的认识,但这只是故事的一半。硬件原理是地基,但光有地基你盖不了楼——你还需要砖头和水泥。在我们这个场景里,HAL库的API就是那些砖头和水泥。

从这一篇开始,我们正式进入HAL库API的学习阶段。我们将逐个拆解那些在代码中出现的关键函数调用,搞清楚每一个参数、每一个宏、每一行配置背后到底在做什么。而这一切要从哪里开始呢?不是GPIO初始化,不是引脚状态设置,而是——时钟使能。

你可能会觉得奇怪:我就是要点个LED,跟时钟有什么关系?关系大了。这是嵌入式开发初学者踩的第一个、也是最大的一个坑——外设不工作,百分之九十的原因是你忘了开时钟。笔者自己在学习STM32的那段时间里,不知道有多少个夜晚对着一块不亮的LED板子抓耳挠腮,反复检查代码逻辑,反复确认引脚编号,反复核对电路连接,最后发现问题出在一个根本没注意过的地方:时钟没开。

时钟之于外设,就像心跳之于人。心脏停止跳动,人也就没了——不管这个人有多强壮、多聪明、多有用,心跳一停,一切都是零。时钟也是一样的道理。STM32上的每一个外设——GPIO、USART、SPI、I2C、定时器——都需要时钟信号才能工作。时钟信号不供给它,它就是一坨睡死的硅,你对它写什么寄存器、调什么函数,它统统不理你,甚至连一个错误码都不会给你。这种无声的拒绝才是最可怕的,因为你的代码在逻辑上完全正确,编译没有警告,运行没有报错,但硬件就是不动。

所以我们这篇教程的第一步,就是要彻底搞懂时钟使能这件事——它为什么存在、它怎么工作、忘记它会发生什么、以及我们的C++模板系统是如何帮你自动解决这个问题的。

时钟是外设的生命线

要理解时钟使能,首先要理解STM32的设计哲学——省电。这颗芯片的设计目标之一就是能在各种低功耗场景下工作,从电池供电的传感器节点到手持设备,功耗控制都是核心考量。STM32F103C8T6是一颗Cortex-M3内核的微控制器,它的设计者面对一个现实问题:芯片上集成了几十个外设——GPIO有五个端口(A到E),通用定时器有好几个(TIM2、TIM3、TIM4),高级定时器有TIM1,串口有USART1、USART2、USART3,SPI有SPI1、SPI2、SPI3,I2C有I2C1、I2C2,ADC有两个,还有DMA控制器、USB、CAN等等。如果这些外设全部同时接收时钟信号、全部处于活跃状态,哪怕你只用了其中一个GPIO端口去点一个LED,芯片的待机电流也会非常高——那些你没用到但依然在运转的外设,每一个都在消耗电能。

想象一下你家有二十个房间,但你只在其中一个房间里看书。如果你把所有房间的灯都打开、空调都开着、电视都开着,电费账单会让你哭出来。合理的做法是什么?你进哪个房间,就开哪个房间的灯和空调;离开的时候关掉。STM32就是这么做的——这就是**时钟门控(Clock Gating)**机制。

时钟门控的核心思想很简单:每个外设都有独立的时钟开关。你需要用哪个外设,就手动打开它的时钟;不用的外设,时钟默认关闭,它就处于"断电"状态,几乎不消耗电能。这个开关不是物理上的电源开关,而是时钟信号的门控——时钟信号到达外设之前要经过一个"闸门",这个闸门由软件控制,打开就放行时钟信号,关闭就阻断。外设没有时钟信号输入,内部的时序逻辑电路就无法工作,寄存器的写入操作会被硬件直接忽略。

那么谁来管理这些闸门呢?答案是**RCC(Reset and Clock Control)**模块。RCC是STM32内部一个非常重要的模块,它负责三件事:第一,管理时钟源的选择和配置(用内部振荡器还是外部晶振?要不要倍频?);第二,管理时钟的分频和分配(CPU跑多少MHz?各个总线跑多少MHz?);第三,管理每个外设的时钟使能(哪个外设开、哪个外设关)。RCC本身就是一颗芯片内部的"电力调度中心",我们在代码中对时钟做的一切操作,最终都是通过配置RCC模块内部的寄存器来实现的。

在我们的项目代码中,clock.cpp文件里的ClockConfig::setup_system_clock()方法就是用来配置RCC模块的,它设定了系统时钟源和各级分频参数。而GPIO外设的时钟使能,则是在gpio.hpp中的GPIOClock::enable_target_clock()方法里完成的。两者分工明确:前者配置整棵时钟树,后者打开特定外设的时钟闸门。下面我们先来看时钟树,搞清楚GPIO的时钟到底从哪里来。

STM32F103C8T6的时钟树简图

要理解时钟使能,光知道"开个开关"是不够的,我们还需要知道时钟信号本身的来龙去脉。STM32的时钟系统是一棵树状结构——从一个源头开始,经过各种分频器、倍频器、选择器,最终到达每一个外设。理解这棵树,你才能理解为什么GPIO的时钟使能宏叫__HAL_RCC_GPIOx_CLK_ENABLE而不是别的名字。

下面是我们项目配置下的简化时钟树。注意,这是我们实际使用的配置,而不是STM32参考手册里那张让人看一眼就头疼的完整时钟树。我们先只看与我们相关的部分:

                            ┌──────────────┐                            │  HSI 8MHz    │                            │ (内部RC振荡器) │                            └──────┬───────┘                                   │                                /2 分频                                   │                              4MHz ──→ PLL ×16 ──→ 64MHz                                              │                                         SYSCLK                                         64MHz                                              │                    ┌─────────────────────────┤                    │                         │                AHB /1                    AHB /1               HCLK = 64MHz             HCLK = 64MHz                    │                         │         ┌──────────┤                  ┌──────┤         │          │                  │      │     APB1 /2    APB2 /1            DMA   Flash     32MHz      64MHz             控制器  接口         │          │    ┌────┤     ┌────┴────┐    │    │     │         │  TIM2-4  USART1     GPIOA-E  USART2-3 SPI1      ADC1-2  I2C1-2   TIM1  SPI2-3   ...

我们逐层来看这棵树。

第一层:时钟源——HSI(High Speed Internal)

HSI是芯片内部的8MHz RC振荡器。"内部"意味着你不需要在电路板上焊接任何外部晶振,芯片自己就能产生8MHz的时钟信号。这对于最小系统来说非常方便——一个芯片就能跑起来。但RC振荡器的精度不如外部晶振,如果你对时钟精度有要求(比如USB通信需要精确的48MHz时钟),就需要用外部晶振(HSE)。不过在点亮LED这种场景下,HSI完全够用。

在我们的clock.cpp中,时钟源的配置是这样的:

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/system/clock.cpposc.OscillatorType = RCC_OSCILLATORTYPE_HSI;osc.HSIState = RCC_HSI_ON;osc.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;

这三行代码的意思是:使用HSI作为振荡器源,打开HSI,使用默认校准值。

第二层:PLL倍频——从8MHz到64MHz

HSI的8MHz对于一颗Cortex-M3来说太慢了。STM32F103C8T6的最高主频是72MHz(在数据手册中有明确标注),但我们这里的配置选择了64MHz——这是一个安全且稳定的频率。要把8MHz提升到64MHz,中间要经过一个叫**PLL(Phase Locked Loop,锁相环)**的模块。PLL本质上是一个倍频器:你给它一个输入频率,它输出一个更高的频率。

倍频的过程分两步:先分频,再倍频。HSI的8MHz先经过2分频变成4MHz,然后4MHz经过16倍频变成64MHz。数学上就是:8 / 2 × 16 = 64MHz。这个配置在我们的代码中一目了然:

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/system/clock.cpposc.PLL.PLLState = RCC_PLL_ON;osc.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;  // 8MHz / 2 = 4MHzosc.PLL.PLLMUL = RCC_PLL_MUL16;              // 4MHz × 16 = 64MHz

RCC_PLLSOURCE_HSI_DIV2表示PLL的输入源是HSI经过2分频后的信号,RCC_PLL_MUL16表示PLL将输入信号乘以16。PLL输出的64MHz信号被选择为SYSCLK——也就是整个系统的主时钟。

第三层:AHB和APB总线分频

SYSCLK的64MHz并不是直接给所有模块用的。它先经过**AHB(Advanced High-performance Bus)**分频器得到HCLK,这是CPU本身运行的时钟频率,也是整个总线矩阵的核心时钟。在我们的配置中,AHB分频系数是1,所以HCLK = SYSCLK = 64MHz:

clk.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;   // SYSCLK = PLL输出clk.AHBCLKDivider = RCC_SYSCLK_DIV1;          // HCLK = SYSCLK / 1 = 64MHz

HCLK再分别经过两个APB(Advanced Peripheral Bus)分频器,得到两条外设总线的时钟:

APB1总线:分频系数为2,所以APB1的时钟频率(PCLK1)= HCLK / 2 = 32MHz。为什么要除以2?因为APB1总线上挂载的外设(如USART2-3、TIM2-4、I2C、SPI2-3)最高只能承受36MHz的时钟频率。如果你给它64MHz,它可能会工作不稳定甚至损坏。32MHz在安全范围内,留有足够的余量。

APB2总线:分频系数为1,所以APB2的时钟频率(PCLK2)= HCLK / 1 = 64MHz。APB2是高速外设总线,挂载的外设(如GPIOA-E、USART1、SPI1、TIM1、ADC)可以承受更高的时钟频率。注意,GPIO就挂在这条总线上——这意味着GPIO可以以64MHz的速度响应操作,这对高速IO操作来说是非常重要的。

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/system/clock.cppclk.APB1CLKDivider = RCC_HCLK_DIV2;   // APB1 = 64MHz / 2 = 32MHzclk.APB2CLKDivider = RCC_HCLK_DIV1;   // APB2 = 64MHz / 1 = 64MHz

很好,现在我们知道了GPIO挂载在APB2总线上,APB2的时钟是64MHz。那"打开GPIO时钟"到底是在打开什么?答案在下一节。

__HAL_RCC_GPIOx_CLK_ENABLE宏详解

在前面的时钟树分析中,我们得出了一个关键结论:GPIO挂载在APB2总线上。这意味着,GPIO端口的时钟使能开关,必然位于APB2相关的RCC寄存器中。HAL库为我们封装了一系列宏来操作这些开关,它们的命名规则非常统一:

__HAL_RCC_GPIOA_CLK_ENABLE();    // 使能GPIOA的时钟__HAL_RCC_GPIOB_CLK_ENABLE();    // 使能GPIOB的时钟__HAL_RCC_GPIOC_CLK_ENABLE();    // 使能GPIOC的时钟__HAL_RCC_GPIOD_CLK_ENABLE();    // 使能GPIOD的时钟__HAL_RCC_GPIOE_CLK_ENABLE();    // 使能GPIOE的时钟

这些看起来像函数调用的东西,实际上是宏(Macro)。C语言宏在预处理阶段会被展开成真正的代码。以GPIOC为例,这个宏展开后本质上是这样的:

#define __HAL_RCC_GPIOC_CLK_ENABLE()  \    do { \        __IO uint32_t tmpreg; \        RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; \        tmpreg = RCC->APB2ENR; \        (void)tmpreg; \    } while(0)

让我们逐行拆解这个展开结果。

RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;是核心操作。RCC是一个指向RCC寄存器结构体的指针,APB2ENR是APB2外设时钟使能寄存器(APB2 Peripheral Clock Enable Register),它的物理地址是0x40021018|=是"读-改-写"操作——先读出寄存器当前的值,与RCC_APB2ENR_IOPCEN做按位或运算(也就是把特定位置1),然后写回寄存器。RCC_APB2ENR_IOPCEN是一个位掩码,代表第4位(bit4),置1就表示使能GPIOC的时钟。

tmpreg = RCC->APB2ENR; (void)tmpreg;这两行看起来很奇怪——读出来赋给一个临时变量然后又不用。这不是Bug,而是刻意为之的延迟操作。ARM Cortex-M3的总线写操作是缓冲的,写入指令执行完毕时,数据可能还没有真正到达寄存器。紧接着读一次同一个寄存器,可以强制等待前一次写操作完成,确保时钟使能真正生效后再继续执行后续代码。这是一个非常重要的细节——如果你在使能时钟之后立刻去操作外设的寄存器,而时钟还没有真正稳定,可能会导致不可预测的行为。

每个GPIO端口对应APB2ENR寄存器的不同位:

  • GPIOA
     = bit2(IOPAEN),位掩码 0x00000004
  • GPIOB
     = bit3(IOPBEN),位掩码 0x00000008
  • GPIOC
     = bit4(IOPCEN),位掩码 0x00000010
  • GPIOD
     = bit5(IOPDEN),位掩码 0x00000020
  • GPIOE
     = bit6(IOPEEN),位掩码 0x00000040

你会发现,每个端口的时钟使能操作是不同的寄存器位。这意味着你不能用一个通用的宏来使能所有端口的时钟——你必须针对不同的端口调用不同的宏。这个看似不起眼的细节,在我们设计C++模板系统的时候会产生非常重要的影响,我们稍后会看到。

还有一个需要注意的点:这些宏只能使能时钟,没有对应的__HAL_RCC_GPIOx_CLK_DISABLE的常用场景(虽然HAL库确实提供了disable宏)。在实际开发中,一旦时钟使能,通常就不会再去关闭它——你不太会在运行时决定"我不再需要GPIOC了,把它的时钟关了吧"。时钟使能本质上是一个一次性的初始化操作。

先别急,在进入下一节之前,我们再回过头来看一个容易混淆的概念。你可能注意到了,除了IOPxEN(比如IOPCEN),APB2ENR寄存器里还有一个类似的位叫AFIOEN(Alternate Function IO clock enable)。这个位控制的是"复用功能IO"模块的时钟,和GPIO端口时钟不是一回事。AFIO模块用于引脚复用功能的重映射(比如把USART1的TX引脚从PA9重映射到其他引脚),在简单的GPIO输出场景下不需要使能AFIO时钟。我们的点亮LED项目只用了GPIO的普通输出功能,所以代码中没有出现__HAL_RCC_AFIO_CLK_ENABLE()

忘开时钟的症状和排查

⚠️ 踩坑预警:这是STM32初学者第一大坑。

这一节值得用警告框来开头,因为笔者自己在这个坑里摔过太多次了,也见过太多初学者在论坛上发帖求助:"我的代码看起来完全正确,LED就是不亮,救命!"而回复中最常见的答案就是:"你开时钟了吗?"

忘开时钟之所以是个大坑,不是因为它难解决——解决方法只需一行代码,而是因为它的症状太有欺骗性了。让我们来详细描述一下你会遇到什么。

典型症状:

首先,你的代码编译通过,没有任何警告。然后你把程序烧录到芯片上,运行——什么都没发生。LED不亮。你以为可能是延时的问题,于是加了更长的延时——还是不亮。你以为可能是引脚编号写错了,仔细核对了一遍——没问题。你甚至把代码和官方例程逐行对比,发现逻辑完全一样。

最让你崩溃的是:你在代码中调用的每一个HAL函数都没有返回错误。HAL_GPIO_Init()返回了HAL_OK(虽然它实际上不怎么检查时钟),HAL_GPIO_WritePin()也没有任何异常。一切都"成功"了,但引脚上用示波器量,完全没有任何电压变化——它就静静地待在那里,像一根死线。

为什么HAL不报错?

这是最让人困惑的部分。当外设的时钟没有使能时,你对这个外设寄存器的写入操作会被硬件默默忽略。注意,不是"报错",不是"返回错误码",而是像什么都没发生过一样。原因是这样的:CPU通过总线(AHB/APB)向某个外设的寄存器地址发起写操作。在时钟使能的情况下,这个写操作会正常到达外设的寄存器并被锁存。但在时钟未使能的情况下,外设内部的时序逻辑电路因为没有时钟驱动而无法工作,写操作到达了地址,但没有人"接收"它。从CPU和总线的角度来看,这个写操作已经完成了——总线协议层面没有发生任何错误(没有超时、没有总线fault)。但从外设的角度来看,这个写操作根本没有发生过。

这就像你给一个睡着了的人说话——你的话确实说出来了,声波确实传播了,但他没听见。你说得再大声、重复再多遍,他也不会有反应。你唯一能做的就是先把他叫醒——在我们这个场景里,"叫醒"就是使能时钟。

排查方法:

当你遇到"代码没问题但硬件不动"的情况时,按以下步骤排查:

第一步,检查是否调用了对应端口的时钟使能宏。如果你用的是GPIOC,代码里必须有__HAL_RCC_GPIOC_CLK_ENABLE()。如果你用的是GPIOA,就必须是__HAL_RCC_GPIOA_CLK_ENABLE()。不能搞混。

第二步,检查传入的端口是否正确。这是一个更隐蔽的错误——你在某处定义了使用GPIOC的引脚,但时钟使能那里写成了GPIOA。编译器不会报错(因为两者都是合法的宏调用),但GPIOC没有时钟自然不工作,GPIOA虽然有了时钟但你根本没用到它。

第三步,如果你有调试器(ST-Link或J-Link),直接查看RCC_APB2ENR寄存器的值。这个寄存器的地址是0x40021018,你可以在调试器的寄存器窗口中找到它,或者在代码中打印它的值。如果你使能了GPIOC的时钟,那么这个寄存器的bit4应该为1。如果它是0,说明时钟使能的代码没有被执行到,或者被后续代码覆盖了。

你会发现,这三个排查步骤本质上都在验证同一件事:时钟使能操作是否真正生效。这就是为什么这个坑这么隐蔽——因为它发生在你最容易忽略的地方。

我们的C++模板如何自动处理时钟

在理解了时钟使能的原理和忘记它的后果之后,我们来看看项目中的C++模板系统是如何优雅地解决这个问题的。

在我们项目的device/gpio/gpio.hpp文件中,时钟使能被封装在GPIO模板类的setup()方法中。每当用户调用setup()来初始化一个GPIO引脚时,时钟使能会作为第一步自动执行:

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/device/gpio/gpio.hppvoidsetup(Mode gpio_mode, PullPush pull_push = PullPush::NoPull, Speed speed = Speed::High){    GPIOClock::enable_target_clock();  // 第一步:自动使能对应端口的时钟    GPIO_InitTypeDef init_types{};    init_types.Pin = PIN;    init_types.Mode = static_cast<uint32_t>(gpio_mode);    init_types.Pull = static_cast<uint32_t>(pull_push);    init_types.Speed = static_cast<uint32_t>(speed);HAL_GPIO_Init(native_port(), &init_types);}

注意看setup()方法的第一行——GPIOClock::enable_target_clock()。这个调用隐藏在GPIO类的private区域中,用户完全不需要关心。不管你是初始化GPIOA的Pin5还是GPIOC的Pin13,只要调用了setup(),对应的端口时钟就会被自动使能。

而这个自动选择是怎么实现的呢?答案在GPIOClock这个嵌套类中,它使用了C++17的if constexpr来实现编译期的条件分支:

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/device/gpio/gpio.hppclassGPIOClock {public:staticinlinevoidenable_target_clock(){ifconstexpr(PORT == GpioPort::A){            __HAL_RCC_GPIOA_CLK_ENABLE();        } elseifconstexpr (PORT == GpioPort::B) {            __HAL_RCC_GPIOB_CLK_ENABLE();        } elseifconstexpr (PORT == GpioPort::C) {            __HAL_RCC_GPIOC_CLK_ENABLE();        } elseifconstexpr (PORT == GpioPort::D) {            __HAL_RCC_GPIOD_CLK_ENABLE();        } elseifconstexpr (PORT == GpioPort::E) {            __HAL_RCC_GPIOE_CLK_ENABLE();        }    }};

if constexpr是C++17引入的编译期条件判断。和普通的if语句不同,if constexpr的条件在编译时就被求值,只有条件为true的那个分支会被编译进最终的代码,其他分支会被直接丢弃。因为PORT是模板的非类型参数(GpioPort枚举值),它在编译时就确定了,所以编译器可以完全确定应该调用哪个时钟使能宏。

这意味着,当你写下GPIO<GpioPort::C, GPIO_PIN_13>这个模板实例化时,编译器自动生成了只包含__HAL_RCC_GPIOC_CLK_ENABLE()enable_target_clock()函数——没有运行时的if-else判断开销,没有函数指针,没有任何多余的东西。最终生成的机器码和你手写一行__HAL_RCC_GPIOC_CLK_ENABLE()完全等价。

这就是C++模板元编程的魅力——零成本抽象。你在源代码层面获得了"不可能忘记开时钟"的安全性(因为setup()自动帮你做了),在编译后的二进制层面又没有任何额外开销。

回到我们的main.cpp

// 来源: codes_and_assets/stm32f1_tutorials/1_led_control/main.cppintmain(){HAL_Init();    clock::ClockConfig::instance().setup_system_clock();    device::LED<device::gpio::GpioPort::C, GPIO_PIN_13> led;while (1) {HAL_Delay(500);        led.on();HAL_Delay(500);        led.off();    }}

当你实例化device::LED<device::gpio::GpioPort::C, GPIO_PIN_13>这个对象时,它的构造函数会调用GPIO<GpioPort::C, GPIO_PIN_13>::setup(),而setup()会自动调用GPIOClock::enable_target_clock(),后者在编译期被确定为__HAL_RCC_GPIOC_CLK_ENABLE()。整个链条严丝合缝,用户在main.cpp中不需要写一行与时钟有关的代码。

关键点是:使用这个模板系统后,你不可能忘记开时钟——只要你的初始化路径经过setup()方法,时钟使能就一定会被执行。这是一个非常好的工程设计:把容易出错的手动步骤封装成自动化的基础设施,让开发者无法犯错,而不是依赖开发者的记忆力和纪律性。

收尾

时钟使能是STM32开发中最基础也最重要的一步。在这篇文章中,我们从STM32的省电设计哲学出发,理解了时钟门控机制的必要性;通过时钟树简图,理清了从HSI到PLL到SYSCLK再到APB2总线的完整时钟链路;深入拆解了__HAL_RCC_GPIOx_CLK_ENABLE宏的底层实现,搞清楚了它本质上是在操作RCC_APB2ENR寄存器的特定位;然后花了大量篇幅讨论了"忘开时钟"这个初学者第一大坑的症状和排查方法;最后看到了我们的C++模板系统如何用if constexpr在编译期自动选择正确的时钟使能宏,实现了零成本的安全性。

时钟使能讲完了,GPIO的时钟供应已经打通。下一步是什么?时钟开好了,但引脚还不知道自己应该是什么模式——是输出还是输入?推挽还是开漏?要不要上下拉?速度设多少?这些都是通过HAL_GPIO_Init()函数和GPIO_InitTypeDef结构体来配置的。下一篇,我们就来拆解这个初始化过程,看看那些电气属性到底是怎么通过代码被配置到硬件寄存器中的。


相关阅读

  1. 嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(6):从点亮第一盏LED开始 —— 我们为什么要用现代C++写STM32 - 相似度 80%
  2. 模板与继承:CRTP与静态多态 - 相似度 60%
  3. 现代Qt教程——0.2——第一个 CMake Qt6 工程从零跑通 - 相似度 60%

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-04-16 19:22:28 HTTP/2.0 GET : https://f.mffb.com.cn/a/485638.html
  2. 运行时间 : 0.097372s [ 吞吐率:10.27req/s ] 内存消耗:4,857.34kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=f06f3a863dce90268f0f15f7a077f026
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000397s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000525s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000286s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000221s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000514s ]
  6. SELECT * FROM `set` [ RunTime:0.000199s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000611s ]
  8. SELECT * FROM `article` WHERE `id` = 485638 LIMIT 1 [ RunTime:0.000434s ]
  9. UPDATE `article` SET `lasttime` = 1776338548 WHERE `id` = 485638 [ RunTime:0.000751s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000257s ]
  11. SELECT * FROM `article` WHERE `id` < 485638 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000483s ]
  12. SELECT * FROM `article` WHERE `id` > 485638 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000558s ]
  13. SELECT * FROM `article` WHERE `id` < 485638 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002756s ]
  14. SELECT * FROM `article` WHERE `id` < 485638 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.007703s ]
  15. SELECT * FROM `article` WHERE `id` < 485638 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.014513s ]
0.099057s