news 2026/10/23 10:46:05

STM32入门不买板:CubeMX生成工程+Keil纯软件仿真实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32入门不买板:CubeMX生成工程+Keil纯软件仿真实践

把 STM32 入门做成“纯软件”版本这件事,我做了差不多两个月,现在回头看,最大的感受是:这条路真的能走通,而且对纯新手比买一块板子更友好。STM32 入门卡住大多数人的,不是芯片本身有多难,而是板子、下载器、接线、烧录这些硬件准备工作太劝退。所以我把整套入门流程拆开,用 CubeMX 生成工程 + Keil 的 Simulator 仿真模式,把 GPIO、UART、定时器、中断这些外设一个个在软件里点亮、跑通、调通。这篇就是把我踩过的坑和验证过的流程完整说一遍,给不想先花钱买板子的朋友一条可复制的路。

1. 为什么要把 STM32 入门改造成纯软件路线

1.1 硬件门槛到底卡在哪

STM32 入门的第一道坎,很多人以为是 C 语言,其实是硬件准备工作。买一块最小系统板少说几十块,一个下载调试器又是几十块,如果还想加传感器、显示屏模块,起步成本轻松上百。更麻烦的是硬件环境本身自带的各种不确定性:杜邦线接触不良、芯片供电不足、下载器驱动装不上、板子上的 LED 焊错了引脚。这些问题对老手来说几分钟就排除了,但对一个刚开始接触单片机的人来说,每一个都是劝退点。

我见过不少初学者,代码逻辑明明是对的,结果卡在“下载不了程序”或者“板子没反应”上,最后放弃。硬件问题干扰了软件学习的主线,这是传统入门方式最大的痛点。

软件仿真模式恰好把这些问题全部隔离开。Keil 的 Simulator 不依赖任何真实电路,代码在 PC 上直接执行,寄存器状态、内存数据、外设行为全部通过软件模拟。你不用管电源、不用管晶振电路、不用管 Boot 引脚,只需要把精力集中在“这段代码到底做了什么”上。

1.2 三条路怎么选:纯软件仿真、Proteus、直接买板

在确定纯软件方案之前,我其实纠结过两条备选路线。第一条是用 Proteus 搭一个 STM32 最小系统,在里面画电路、放元件、加载 hex 文件仿真。第二条是直接买一块几十块的板子走传统路线。

Proteus 的优势是你能看到硬件连接的直观效果,比如 LED 亮了、数码管跳数字了,视觉反馈很好。但它的问题在于:上手成本不低,元件库需要熟悉,仿真模型和真实芯片行为有偏差,尤其是 STM32 这种复杂芯片,Proteus 的外设仿真模型覆盖并不完整。而且 Proteus 本身是收费软件,虽然有试用版,市面上的版本情况也比较复杂。

直接买板子当然是最接近真实的,如果你预算充足、时间充裕,这依然是首选。但如果你目前只是想先把 GPIO、中断、定时器这些核心概念吃透,又不确定自己会不会长期学下去,直接花钱买硬件就有点像还没确定要健身就先办了年卡。

最终我选了 Keil Simulator。原因很简单:Keil 本身就是 STM32 开发最常用的 IDE 之一,CubeMX 生成的代码也是面向 Keil 生态的,仿真模式内置在调试环境里,不需要额外装软件,也不需要学习新的电路绘制工具。从这个环境切换到真实板子,代码和工程结构完全一致,中间没有多余的学习成本。

1.3 我的最终选择:Keil Simulator 的真实理由

仿真调试窗口对新手真正的价值,不是“看到灯亮”这个结果,而是能看清楚程序执行的每个细节。Keil 的 Simulator 模式下,你可以单步执行、查看变量实时值、观察外设寄存器的每一位变化,甚至可以把 GPIO 输出电平拉成波形图看。这种“显微镜式”的观察方式,是拿到真实板子后很难做到的。

打个比方,真机上跑 GPIO 点灯,LED 亮了就是亮了,你只能通过亮灭判断对错。但仿真环境下,你可以一步步走代码,看引脚电平从低翻到高,看数据寄存器从 0 变成 1,再对应到芯片手册上的寄存器位定义。这种双重对应关系,是建立底层认知最有效的方式。

所以我的结论是:纯软件仿真不只是“没钱买板子”的妥协方案,它在某些维度上甚至比真机更适合教学和入门。

2. 环境准备与仿真前必须要做的三件事

2.1 CubeMX 生成工程的几个关键配置

纯软件仿真不需要重新设计工具链,就是最常见的 STM32CubeMX + Keil MDK 组合。CubeMX 负责图形化配置引脚和外设,生成初始化代码;Keil 负责编译、调试和仿真执行。

CubeMX 里需要重点关注的配置项有三个。第一个是芯片型号,我用的 STM32F103C8T6,这个型号资料多、外设典型,作为学习和仿真对象最合适。第二个是调试接口,默认的 Debug 选项里选 Serial Wire,和仿真正式运行时使用 SWD 作为调试口保持一致。如果你要用仿真调试,这个选项必须选,否则仿真模式下调试器初始化会有问题。

第三个是时钟树配置。对于仿真来说,外部高速晶振 HSE 是不存在的,仿真环境里没有真实晶振模型,所以 RCC 配置里最好把时钟源直接选 HSI 内部高速时钟,也就是芯片内部自带的 RC 振荡器。在 Clock Configuration 页面里把系统时钟设到 64MHz 或者 72MHz 都可以,仿真器对频率只是一种数值模拟,实际速度取决于编译后的指令周期模拟,不必太纠结精确值。

我在实际配置时选择 HSI 作为系统时钟源,这样从工程层面就避免了“仿真时外部时钟无法起振”的潜在问题。这一点在 CubeMX 的 RCC 设置里只需要改一个下拉选项,但能省掉后续很多奇怪的故障。

生成代码时记得选择 MDK-ARM V5 工具链,这也是 Keil 对应项目的标准格式。生成完成后用 Keil 打开工程,第一件事不是编译,而是检查工程选项里的仿真配置。

2.2 在 Keil 里把调试模式切到 Simulator

Keil 默认连接的是真实调试设备,需要手动切换到软件仿真模式。操作路径是:Options for Target -> Debug 选项卡,左侧选中 Use Simulator,同时下面勾选 Run to main()。这里有一个容易被忽略的细节:右上角的 Dialog DLL 参数要保持默认,这是 Keil 用来模拟外设寄存器的接口,不能删。

切换完成之后,点击编译,然后进入调试界面。你会看到代码停在 main() 函数入口,而不是像真机调试那样先跑一段启动代码。这一点特别适合新手,因为从 main 开始看逻辑最简单,不会被 startup 汇编文件和 SystemInit 初始化吓到。

进入调试界面后,有几个窗口必须打开:View -> Watch Window 用来观察变量,View -> System Viewer 可以展开查看所有外设寄存器,View -> Analysis Windows -> Logic Analyzer 用来抓波形。这三个窗口是纯软件调试的核心工具。

我第一次切换仿真模式时犯了个低级错误:没有勾选 Run to main(),结果每次调试都停在启动文件里,我还以为是工程配置出了问题。后来才发现,这只是一个选项的事情。

2.3 仿真前的时钟与 SysTick 预处理

纯软件仿真最大的坑,其实藏在 SysTick 里。CubeMX 生成的 HAL 库代码,默认用 SysTick 作为时基,HAL_Delay() 函数也依赖 SysTick 计数器。这在真机上没有问题,因为 SysTick 由真实的系统时钟驱动。

但仿真模式下,如果你直接把代码跑起来,有时会发现程序卡在 HAL_Delay() 里出不来。原因在于仿真器的 SysTick 模拟和实际时钟存在偏差,或者时钟配置不正确导致 SysTick 中断无法按预期触发。

解决办法有两种。第一种是在仿真模式下减少对 HAL_Delay() 的依赖,比如点灯延时改用循环计数;第二种是确保时钟树配置正确,让 SysTick 的时钟源和系统时钟一致。我建议初学阶段直接采用第一种思路——在纯软件阶段,延时用 for 循环就够用了,没必要非用 HAL_Delay()。等到换到真机上,再把 HAL_Delay() 加回来也不迟。

另外一个预处理技巧是:在调试模式下,可以在 Options for Target -> Debug 里把 Initialization File 配置成上电后自动初始化时钟。但对于入门阶段,直接使用 HSI 时钟源,不配置外部晶振,就能绕开大部分启动问题。

我把这三件事做完之后,测试了第一个 GPIO 工程,整个过程没有再碰到“程序跑飞”或者“卡死在启动”的问题。这就是纯软件仿真最核心的准备动作。

3. 外设一个个跑通的全过程

3.1 GPIO 点灯:软件仿真里怎么看“灯真的亮了”

纯软件仿真里没有真实的 LED,怎么判断 GPIO 输出是否正确?答案是看波形和寄存器。

我做的第一个实验是让一个引脚周期性翻转,模拟 LED 闪烁。CubeMX 里把 PC13 配为 GPIO_Output,这是最常见的最小系统板 LED 位置。生成代码后,在 while(1) 循环里写:

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); Delay_Loop(); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); Delay_Loop();

进入仿真调试后,先把光标停在循环开头,单步执行几轮,同时在 System Viewer 里展开 GPIOC 的 ODR(输出数据寄存器)。你会看到当 WritePin 传参为 SET 时,ODR 的第 13 位变成 1;传参为 RESET 时,这一位变回 0。这就是软件仿真里最直观的“灯亮了”——寄存器位的变化。

如果你想看得更直观点,用 Logic Analyzer 窗口就行。在调试界面打开 Logic Analyzer,添加 GPIO_IDR_PIN_13 这个信号,然后全速运行,你会看到一条方波曲线,周期正好取决于你的延时循环次数。这个波形和真实示波器抓到的基本一致,只是来源是模拟数据。

这个实验虽小,但它建立了很重要的概念:GPIO 输出生效,本质就是控制寄存器里的每一位。理解了这一步,后面操作任何外设都围绕同一个思路展开——操作寄存器,观察变化,验证逻辑。

3.2 外部中断:模拟一个按键触发

GPIO 输出是单项操作,外部中断就能进一步练习“事件触发”的思维方式。CubeMX 里把一个引脚,比如 PA0,配置为 GPIO_EXTI0,同时使能 EXTI0 中断。中断回调函数里做一个标志位翻转:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == GPIO_PIN_0) { flag = !flag; } }

真机上,中断触发需要你物理按下按键,改变引脚电平。仿真环境里没有按键,怎么模拟这次触发?

你可以在调试过程中,手动把 PA0 的输入数据寄存器 IDR 从 0 改成 1,再改回 0。具体操作是:在 System Viewer 里找到 GPIOA 模块,展开 IDR 寄存器,双击第 0 位把它从 0 改为 1,然后再改回 0。这个电平跳变会让 EXTI 控制器检测到上升沿,触发对应的中断。

实际操作时,第一次修改寄存器值需要等代码运行到等待状态,把断点在主循环里设置好,然后修改 IDR 值,再全速运行。如果你在修改 IDR 后没看到中断触发,检查一下 EXTI 的上升沿触发器是否使能,以及 NVIC 里 EXTI0 中断有没有被打勾。

通过这种方式,我理解到了中断的完整链路:引脚电平变化 -> 外设控制器检测到边沿 -> 置位挂起寄存器 -> NVIC 响应 -> CPU 跳转到中断服务函数。以前这些都是抽象概念,现在每一步都能在寄存器里亲眼看到。

3.3 UART 输出:让仿真数据“看得见”

串口是最常用的调试手段,在仿真环境里依然可以“假装”有串口数据。CubeMX 里把 USART2 配置为异步模式,波特率 115200,生成代码后用 HAL_UART_Transmit() 发送字符串。真机上你需要 USB 转串口模块接上 TX 和 RX 才能看到数据,仿真里怎么处理?

Keil 的 Simulator 提供了一个串口模拟窗口。在仿真调试界面中,点击 View -> Serial Windows -> UART #1,这个窗口就是模拟的串口终端。前提是你需要把程序里的串口句柄映射到这个窗口,通常是在仿真调试的 Command 窗口里输入:

MODE UART1

然后输入:

SER1 115200

这里要注意,UART1 指的是调试器逻辑上的第一个串口窗口,和芯片外设的 USART1/2 不是同一套编号。如果你的代码用的是 USART2,仿真窗口照样捕获到,只要 MODE 命令指定的是 UART1 作为第一个虚拟串口即可。

配置完成后,全速运行程序,虚拟串口窗口就会出现你要发送的字符。

我第一次在这个窗口看到“Hello STM32”的时候,很有成就感。更重要的是,通过这个过程我能把串口的波特率、数据位、停止位这些参数和实际协议格式对应起来。后来我甚至封装了一个自己的 printf 重定向函数,这样在代码里写 printf 就可以直接往虚拟串口窗口输出调试信息,和真机的调试体验一模一样。

3.4 定时器与 PWM:验证时序逻辑

定时器是嵌入式开发里非常重要的一类外设,纯软件仿真在这一块的还原度也不错。我用的例子是 TIM2 定时中断,在 CubeMX 里配置预定分频器和自动重装值,产生一个 1 秒周期的中断。

TIM2 的配置思路:系统时钟 64MHz,预分频设为 64-1,计数器时钟变成 1MHz,自动重装值设为 1000-1,这样定时器每 1000 个时钟周期溢出一次,也就是每 1 毫秒溢出一次。在中断回调里累加计数,累加到 1000 就翻转一次引脚电平,这样就实现了软件秒表。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static uint16_t count = 0; if (htim->inst == TIM2) { count++; if (count >= 1000) { count = 0; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); } } }

仿真运行后,打开 System Viewer 里的 TIM2 模块,你能看到计数寄存器 CNT 在实时变化,时不时自动清零重新计数。通过单步调试,还能观察到溢出产生的更新事件置位 UIF 标志,这个标志又触发中断。

PWM 模式同理,把 TIM2 的 Channel 1 配置为 PWM 模式,占空比设成 50%。全速运行后打开逻辑分析仪,添加定时器通道输出信号,你会看到一组周期性的方波,改变 CCR 寄存器的值,波形的占空比立刻变化。这种“改参数立刻看到波形变化”的体验,在真机上反而需要接示波器才行。

3.5 ADC 采样:模拟量如何仿真

ADC 可能是纯软件仿真里最“抽象”的一个外设,因为模拟输入电压这个概念在数字世界里并不存在。但 Keil 的 Simulator 同样提供了一种处理方式:直接写模拟输入寄存器的值。

CubeMX 里把 ADC1 配为单通道扫描模式,通道对应 PA0。生成代码后,用 HAL_ADC_Start() 启动转换,然后读取转换结果:

HAL_ADC_Start(&hadc1); uint32_t value = HAL_ADC_GetValue(&hadc1);

在仿真调试时,你需要手动在 ADC 的外设寄存器区域找到对应的数据寄存器,直接修改它的值来模拟模拟输入。然后重新调用一次转换,转换结果寄存器 DR 就会变成你写入的值。

这里的关键是理解 ADC 的转换流程:启动转换 -> 采样保持 -> 逐次逼近 -> 结果写入 DR 寄存器。通过手动修改寄存器模拟电压输入,你虽然看不到真实的电压值,但可以验证 ADC 逻辑里的读取函数、数据处理函数是否正常工作。

比如我写了一个简单的电压采集程序,将原始 ADC 值除以 4096 再乘以 3.3 转成电压值。在仿真里手动把 DR 设为 2048,程序算出 1.65V;设为 4095,算出约 3.3V。这个结果足以验证换算逻辑的准确性。

4. 仿真和真机之间那几道坎

4.1 电气特性永远无法模拟

纯软件仿真的本质是芯片逻辑层面的模拟,它关注的是“程序执行是否正确”,而不是“电路上电平是否合法”。所以和电气特性相关的部分,仿真统统无能为力。

比如开漏输出模式,仿真结果只是寄存器里的一位变化,不会表现出真实开漏模式下需要外部上拉电阻才能抬高电平的特性;再比如推挽输出驱动大负载的电流限制,仿真完全没有概念;GPIO 的输入模式,仿真默认你填什么就是什么,不会有真实电路中的浮空输入噪声、按键抖动、长线耦合干扰。这些物理世界的特性,只有真实板子才能呈现。

我在把第一个 GPIO 程序从仿真迁移到真机时,最明显的差异就是引脚悬空状态。仿真环境下读引脚电平是确定值,但真机上浮空引脚的输入是不确定的。这提醒我,在学完仿真之后,需要专门补一下硬件设计的基础知识,尤其是上下拉电阻的用法。

4.2 时序精度只能信个大概

Keil Simulator 对指令执行有一个粗略的周期模型,但它的计时精度不能和芯片手册上的精确时序相提并论。比如你用 HAL_Delay(100) 在仿真里可能计时得比较准,但换成不同编译器优化等级或者不同型号芯片,结果会有偏差。模拟器的主要用途是验证函数逻辑和事件顺序,不是测量精确时间。

尤其是涉及定时器触发 ADC、ADC 触发 DMA 这种跨外设协作场景,仿真环境下只能验证“事件发生顺序是否正确”,精确的时间间隔必须在真机上用示波器确认。所以如果你在做 PWM 频率精度相关的设计,比如舵机控制周期或者音频频率产生,仿真只能证明频率调整的逻辑链路是对的,具体频率值是否精准,最终还是要上真机。

4.3 仿真替代不了的部分与变通办法

有些外设纯软件仿真完全没有对应模型,比如传感器(温度、湿度、加速度)、显示屏(OLED、LCD)、无线通信模块。这些器件依赖真实的物理输入和输出,仿真环境不可能凭空模拟它们的行为。

但这不意味着这些外设完全不能在软件阶段学。我的变通思路是:把传感器数据抽象成寄存器值或者数组,然后用代码模拟传感器产生数据的过程。比如学 I2C 总线读取传感器时,我会在仿真里直接构造一组模拟数据,放到对应的缓冲区,然后走完整的 I2C 读取流程逻辑。这样虽然“数据是假的”,但代码逻辑、错误处理、容错分支这些核心能力全部得到了练习。

等你把这些模拟数据的处理逻辑写稳定了,换到真机时只需要把“模拟数据源”替换成“真实传感器驱动”,主体代码基本不用改动。这也是为什么我认为软件仿真适合入门和逻辑调试,而不适合作为最终验证手段。

5. 实操中踩过的那些坑与排查清单

5.1 仿真卡死在启动阶段

这是我最开始遇到的第一个问题。代码编译没问题,下载进仿真器后,程序卡在启动文件里无法进入 main()。后来排查发现是 Debug 设置里没有勾选 Run to main(),程序自然停在启动代码的 Reset_Handler。

另一个卡死原因跟时钟有关。如果你在 CubeMX 里选择了外部晶振 HSE,仿真器没有对应模型,初始化代码会在等待时钟就绪标志时陷入死循环。解决办法就是在仿真阶段用 HSI 内部时钟,或者修改 CubeMX 配置重新生成代码。

5.2 printf 没有输出

我刚开始做 UART 实验时,虚拟串口窗口没有任何输出。排查后发现,我没有执行 MODE UART1 命令,虚拟串口没有开启监听。Keil 的仿真串口窗口不是自动打开的,你需要先运行那两条命令让它进入监听状态。

另外要注意的是,HAL 库的 UART 发送函数经常要求传入缓冲区长度,如果你传的长度不对,比如少了一个字节,就会导致发送不完整。这类问题在仿真里也能通过观察 USART 的数据寄存器看到蛛丝马迹。

5.3 中断进不去

外部中断实验里,我修改了 IDR 电平,但中断服务函数始终没有触发。问题出在两个地方。第一个,CubeMX 里使能了 EXTI 中断线,但 NVIC 里对应的中断优先级没有勾选,导致中断信号被屏蔽。第二个,我手动修改 IDR 的时机不对,代码停在断点时修改的寄存器,需要在全速运行后才被 EXTI 检测到。

排查技巧是:在中断服务函数入口设断点,然后在 System Viewer 里观察 EXTI 的挂起寄存器 PR,如果电平变化后 PR 被置位,说明外设检测到了事件,问题出在 NVIC 响应环节;如果 PR 根本没置位,说明是边沿触发配置有问题,回到 CubeMX 检查触发方式。

5.4 外设寄存器显示异常

有时候 System Viewer 里看到的外设寄存器值“不对”,比如 GPIO 输出寄存器明明写 1 了,但输入寄存器还是 0。这不一定说明代码有 bug,可能是外设时钟没有使能。STM32 的外设默认大多关闭时钟,CubeMX 生成代码时使能了 RCC 的外设时钟,但如果你手动写了不完整的初始化代码,可能会漏掉这一步。

这时我会重新检查 CubeMX 生成的初始化序列,确认对应的 RCC 时钟使能函数被调用了。这个步骤在仿真里很容易被忽略,因为仿真器不会因为你没开时钟就报错,但寄存器行为会异常。

实操总结与个人体会

走完这一整套纯软件仿真流程,我最想告诉后来人的是:STM32 入门的关键不是板子,而是把“程序如何控制硬件”这件事想明白。纯软件仿真给你提供了一个零成本的实验场,让你可以安全地拆开每个外设,看清楚它的寄存器怎么变化、事件怎么流动、中断怎么触发。这种理解深度,甚至比直接插一块真板子跑 demo 更扎实。

我个人的体会是,先通过仿真把 GPIO、UART、定时器、中断这几个核心外设的软件模型建立起来,后面上真机时再补充硬件调试的经验,整个学习曲线会平滑很多。如果你是学生、转行开发者,或者只是想知道自己适不适合学嵌入式,这条路值得先走一遍。

最后分享一个我后来常用的技巧:在仿真调试时,每次跑通一个外设,把寄存器的关键变化截图保存下来,整理成自己的笔记。积累多了之后会发现,所有外设的套路都惊人的一致,你真正学会的其实是一套“阅读芯片手册、验证物理行为”的方法论。这个方法,放到任何一款 MCU 上都适用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 4:02:24

SAP批处理入门:BDC录屏与LSMW数据迁移的实操要点

简介:《SAP两种批处理工具使用方法详解(BDC&LSMW)》是一份面向SAP顾问、实施及运维人员的实用文档,重点解决批量数据录入、数据迁移及重复事务码操作中的效率问题。资源包内为单个docx文档,大小约2.49MB&#xff0…

作者头像 李华
网站建设 2026/10/23 6:43:40

华为eNSP中ISIS协议实战:从原理到故障排查

1. 项目概述:为什么ISIS在现代网络中依然不可替代你打开eNSP,拖出几台路由器,刚配完IP地址,就卡在了“下一步该选OSPF还是ISIS”这个路口。这不是个别现象——某高校网络实验室的模拟项目X里,超过65%的高年级学生在完成…

作者头像 李华
网站建设 2026/10/19 5:29:24

SQL Server 2008 R2 CPU与内存调优实战:从MAXDOP到max server memory

简介:数据库性能优化中,CPU与内存资源分配常被忽视却直接影响系统稳定性。SQL Server 2008 R2 的并行查询机制依赖 MAXDOP 与 cost threshold 两个核心参数,默认配置会让低开销查询过度并行,导致 CPU 冲高;而无上限的 …

作者头像 李华
网站建设 2026/10/21 13:46:59

Kubernetes上部署Rasa训练任务:StatefulSet与持久化存储实战

1. 项目背景与整体设计思路1.1 为什么要在Kubernetes上跑Rasa训练任务做过对话系统的人都知道,Rasa的模型训练不是一锤子买卖。业务话术在变、用户问法在变、意图边界在调整,模型就得跟着重新训练。早期我们图省事,直接在服务器上跑rasa trai…

作者头像 李华
网站建设 2026/10/19 15:03:20

多重背包优化:从二进制拆分到单调队列

1. 从一道题看多重背包的本质多重背包问题,是动态规划里一个非常经典的模型。它的核心场景很朴素:有若干种物品,每种物品有有限的件数,每件物品有自己的重量和价值,现在给你一个固定容量的背包,问在不超过背…

作者头像 李华
网站建设 2026/10/22 16:03:27

PL/SQL流程控制实战:条件分支、循环与性能优化

1. 程序流程控制:为什么这是PL/SQL的“命根子”我最早写PL/SQL的时候,觉得流程控制嘛,不就是IF套循环、循环套IF,谁不会?直到后来接手一个某公司订单折扣计算的存储过程,原开发者用三十多层IF嵌套实现了三个…

作者头像 李华