PID 控制:从基本原理到嵌入式实现
假设手边有一块加热台,想让它停在 60 ℃。最直接的办法是低于 60 ℃就开,到了就关。程序确实好写,但断电以后,加热片和底板里的热量还会继续传到测温点,温度往往还要往上走一截。等温度掉下来再开,又开始下一轮。
换成 PWM 呢?给一个固定占空比,确实可能在某个温度附近停住。可一开风扇,或者放上一个冷工件,刚才合适的占空比就不够了。
PID 就是在处理这件事:温度还差多少、这个差距持续了多久、现在升温有多快,合起来决定下一次给多少功率。下面一直用这个加热台作例子,公式和代码也按同一套单位来写。响应曲线里会标明哪些来自厂商资料,哪些是数值仿真;这里没有把仿真当成实测。
1. 应用范围与控制目标
1.1 什么时候适合用 PID
PID 适合这样的闭环任务:有可测的结果、有可以连续或分档调节的执行量,目标会变化,外界也会来捣乱。温控只是其中一种,电机转速、液位、气压和电流环也都符合这个模式。它不是“让设备立刻到目标”的魔法公式;对有明显延迟和热惯性的加热台,首要目标通常是不过冲、稳得住,并能在负载变化后回到设定温度。
1.2 本文的例子和约定
本文以低压直流加热台为例:温度用 ℃ 表示,控制输出归一化到 0~1,对应 PWM 占空比。先看闭环里每个量的角色,再解释 P、I、D 的取舍,最后落到定时任务、代码、整定和保护上。
2. 闭环控制基础与性能指标
2.1 先理解闭环:PID 到底控制什么
以低压直流加热台为例:
| 符号 | 含义 | 加热台中的实例 |
|---|---|---|
| 设定值,setpoint | 60 ℃ | |
| 测量值,process variable | 传感器测得的温度 | |
| 误差 | 目标温度减去测量温度 | |
| 控制量 | 经过限幅的 PWM 占空比 | |
| 被控对象的动态模型 | 加热功率到温度的关系 |
定义误差为:

图 1:本文绘制的负反馈框图。控制器期望输出与执行器实际输出应区分,后者可能受到占空比、电流或电压限制。
顺着图走一圈:目标是 60 ℃,传感器读到 50 ℃,相减得到 10 ℃的误差;PID 算出占空比,功率级开始加热,下一次再读温度。开风扇以后,温度下降会重新变成误差,控制器就有了加大输出的依据。
本文约定占空比越大,温度越高。如果接的是制冷器,方向就反过来了。上电调参前可以先给一点输出,看读数往哪边走;方向接反时,误差会越调越大。
3. P、I、D 原理及响应对比
3.1 比例 P:对当前误差直接作出反应
先只留 P。若 ,差 10 ℃就给 20% 占空比,差 5 ℃就给 10%。快接近目标时,供热也跟着减小。
麻烦在于,加热台即使到了 60 ℃也一直在散热,维持温度还得供电。可纯 P 在误差为零时,输出也变成了零。没有额外的偏置或前馈,温度就可能停在目标下面一点,用这点误差换取保温所需的功率。

图 2:裁自 Microchip / Atmel AVR221,2016 年版第 5 页,Figure 1-3。红色虚线是目标,蓝线最后仍低一点。原图未标横轴单位,这里只比较曲线形状。
可以用一个简单模型说明。对单位负反馈、稳定且无积分的对象,若直流增益为 ,设定值为幅度 的阶跃,且闭环稳定、没有饱和,则:
这个模型里,增大 能把残差压小。但加热和测温都有滞后,增益太大又容易来回振荡。所以看到“还差几度”时,不能一直加 P。上式也有适用条件;带积分的对象等其他系统,结论可能不同。
3.2 积分 I:把持续存在的误差积累起来
假如温度一直停在 58 ℃,P 的输出已经不再变了,I 还会把这 2 ℃的误差一拍一拍累加进去,慢慢把占空比抬高。到了 60 ℃,新增的积分变成零,之前攒下来的输出还在,可以继续保温。
例如误差持续为 2 ℃,,那么积分输出每秒增加 0.01,即一个百分点的占空比。

图 3:AVR221 第 5 页,Figure 1-4。绿色 PI 曲线靠近目标,蓝色纯 I 曲线慢得多。这张原图省略了坐标刻度,只用来说明趋势。
前提是目标确实够得着,而且闭环能稳定下来。若加热器已经全功率,温度还是上不去,积分继续加也变不出更多功率,反而会留下一个很大的内部数值。后面单独处理它。
3.3 微分 D:对变化速度作出反应
理想的误差微分形式为:
比如温度只有 55 ℃,但升温速度很快,继续给大功率就可能冲过头。这时 D 可以先减一点输出。它用的是眼下的变化速度,传感器迟到的那部分信息仍然补不回来。
D 对噪声也很敏感。温度读数只跳了 0.1 ℃,若两次采样只隔 1 ms,差分算出来就是 100 ℃/s。控制器看见的“快速变化”可能全是噪声,所以实际使用时通常要给微分加滤波。
还有一个容易碰到的尖峰:目标从 40 ℃改成 60 ℃,实物温度还没动,误差已经跳了 20 ℃。直接对误差微分,就会产生 derivative kick。常见做法是把 D 改接到测量值上:
目标不变时,误差的变化就是测量值变化的相反数,两种写法相同。目标跳变时,测量微分不会直接响应这个跳变;P 项仍然会变。Control Guru把这两条信号的区别画得很清楚。

图 4:AVR221 第 6 页,Figure 1-5。PD 改变了过渡过程,最终仍和 P 留着相近的残差。D 并不负责提供恒定的保温功率。
3.4 为什么很多工程系统只用 PI
先把 PI 调到能用,是个省事的起点。若超调和恢复速度已经能接受,就可以先不加 D。尤其当读数本身一直跳动时,加 D 很可能先得到一条抖得更厉害的 PWM 曲线。
只有确实还缺一点阻尼、测量信号也够干净时,再试带滤波的 D,并同时记录温度和输出。
3.5 连续 PID:先统一参数形式
3.5.1 并联形式
本文使用以下增益定义:
是偏置或前馈基值。忽略偏置,并在零初始条件下取拉普拉斯变换,理想控制器为:

图 5:裁自 TI《Real-Time Control Reference Guide》,2021 年 10 月版第 24 页,Figure 8。P、I、D 各走一条支路,最后相加。原始 PDF。
图上的理想微分器在高频处会一直放大信号。实际常用的写法会多一个滤波时间常数:
决定微分支路的滤波强度,MathWorks 的 pid 文档使用的就是这套并联参数。注意上式仍对误差微分,后面的 C 代码则按前面讨论的方式改成测量微分。
3.5.2 标准形式与并联形式不能直接抄参数
另一种常见表达是:
在相同理想结构下:
抄参数时尤其容易在这里弄反。“积分增益 2”和“积分时间 2 s”差别很大:增大 ,积分更快;增大 ,积分反而更慢。先看清调参界面或代码到底收哪一种。
如果输入误差单位为 ℃、输出为 0~1 的占空比,三项增益的量纲分别为:
| 参数 | 单位 |
|---|---|
若把输出单位从 0~1 改为 0~100,保持同样控制作用时增益的数值也要相应换算。
3.6 从曲线看控制器的作用

图 6:AVR221 第 6 页,Figure 1-6。原资料这组示例中,PI 消除了残差,PID 的超调更小。图中没有给出完整模型和增益,不能据此提取一组实物参数。
这种对比图很直观,但读完往往还有个问题:换个参数会怎样?为方便自己跑一遍,下面另选一个写得清楚的二阶对象:
目标从 0 跳变为 1,全部初始状态为零。控制周期 ,微分作用于测量值,滤波时间常数 。对象通过步长 0.001 s 的前向欧拉法积分,控制输出在两次更新之间保持不变。本组仿真不加输出限幅、噪声和额外纯延迟。

图 7:本文数值仿真,参数在图例中,和上一张厂商图不是同一组实验。
这次 P 的稳态值是 ,可以直接用前面的稳态误差公式核对。PI 把残差补上了,不过也带来了超调;再加合适的测量微分,过渡过程又变了。换一组增益,曲线的好坏顺序也可能改变。
看曲线时,除了多久升上去,还要看最高冲到哪里、多久才停稳、最后差多少。“2 秒稳定”要说清楚容差,比如进入目标 ±2% 后不再跑出去;否则两个人口中的“稳定”可能差很多。
加热台还得试一次放上冷工件,看看温度跌下去以后多久恢复。目标变化与负载变化走过的信号通道不同,MathWorks 的跟踪与抗扰示例专门比较了这件事。启动曲线好看,不一定代表受扰以后也恢复得好。
4. 离散化、采样与 C 实现
4.1 位置式计算
设采样周期为固定的 ,使用当前误差的后向矩形积分和一阶后向差分:
每次算出来的都是完整输出,所以叫位置式。得到 1.2 也只能输出 100% 占空比,这一步限幅放在写 PWM 之前。
网上的代码有时只有 sum += ki * error,看起来少乘了一个周期,其实可能在初始化时就算进 ki 了。例如 Arduino PID Library 的 SetTunings()会把连续 乘上周期、 除以周期。对照代码时要连初始化一起看。本文代码保留连续增益,在计算时显式带入 。
4.2 增量式从哪里来
将同一位置式在相邻时刻相减,偏置恒定时得到:
这个等价关系用的是同一套固定周期、理想误差微分、无饱和的公式。换成测量微分或加上滤波以后,先写出新状态方程,再相减,才能知道到底等价到哪一步。
增量式也要处理饱和。u[k-1] 存的是限幅前的计算值,还是上次实际给出去的值,会直接影响下一拍。Arm CMSIS-DSP 的 PID 文档给出了这种递推结构;其中 Ki、Kd 已按离散公式使用,移植时同样要先换算周期。
4.3 对测量微分并增加一阶滤波
采用:
用后向欧拉替代 ,整理得到:
后面的 C 代码就用这一行更新 D。增大 ,曲线会平滑些,反应也会慢些。如果为了压住噪声不断加大滤波,最后可能把原本想要的微分作用也拖迟了。传感器和模拟前端已有的滤波延迟也算在环路里。
4.4 一份可移植的 C 实现

图 8:AVR221 第 9 页,Figure 2-1。定时触发计算,参数和历史状态放进一个结构体。右侧文字在原 PDF 中已有重叠,裁图保留原样;这里主要看调用关系。
真正写程序时,PID 函数不需要知道 ADC 寄存器和 PWM 通道。外层按时送进目标与测量值,函数保留上一拍状态,返回一个输出即可。下面按这个分工写位置式 PID,D 用测量差分加一阶滤波,I 用条件积分。
integral 和 derivative 存的是已经乘过各自增益的输出分量。因此日志里把 P、I、D 加上偏置,就能和未限幅输出核对。
调用前检查输入是有限值,参数满足 、、,输出上下限顺序正确。这里仍按“输出越大,温度越高”来写;制冷等反向对象要统一处理控制方向。
#include <stdbool.h>
typedef struct { float kp, ki, kd; float ts, tf; float out_min, out_max; float bias; float integral; float derivative; float prev_y; bool initialized;} PID;
static float clampf(float x, float lo, float hi){ if (x < lo) return lo; if (x > hi) return hi; return x;}
/* initial_output is the desired output at the transfer instant. * A sufficiently large I term is allowed to cancel P during transfer. */static void pid_reset(PID *p, float setpoint, float measured, float initial_output){ const float u0 = clampf(initial_output, p->out_min, p->out_max); p->integral = u0 - p->bias - p->kp * (setpoint - measured); p->derivative = 0.0f; p->prev_y = measured; p->initialized = true;}
static float pid_step(PID *p, float setpoint, float measured){ if (!p->initialized) { pid_reset(p, setpoint, measured, p->bias); }
const float error = setpoint - measured; const float proportional = p->kp * error; const float alpha = p->tf / (p->tf + p->ts); p->derivative = alpha * p->derivative - p->kd / (p->tf + p->ts) * (measured - p->prev_y); p->prev_y = measured;
const float delta_i = p->ki * p->ts * error; const float trial_i = p->integral + delta_i; const float trial_u = p->bias + proportional + trial_i + p->derivative;
const bool pushes_high = trial_u > p->out_max && delta_i > 0.0f; const bool pushes_low = trial_u < p->out_min && delta_i < 0.0f; if (!pushes_high && !pushes_low) { p->integral = trial_i; }
const float raw_u = p->bias + proportional + p->integral + p->derivative; return clampf(raw_u, p->out_min, p->out_max);}调用方式如下。这里的数值只是为了把 ℃、秒和 0~1 占空比接起来,实物要重新调参:
static PID heater = { .kp = 0.02f, .ki = 0.005f, .kd = 0.01f, .ts = 0.1f, .tf = 0.3f, .out_min = 0.0f, .out_max = 1.0f, .bias = 0.0f,};
/* Call once after configuration and after the first valid measurement. */static void heater_start(float target_c, float measured_c){ pid_reset(&heater, target_c, measured_c, 0.0f);}
/* Call every 100 ms with a fresh, validated measurement. * The returned duty is mapped to the hardware PWM compare register. */static float heater_update(float target_c, float measured_c){ return pid_step(&heater, target_c, measured_c);}4.4.1 初始化与手自动切换
假设手动模式下正在输出 30%,切自动时却一下跳到 80%,温度就会多冲一段。pid_reset() 用当前误差反算积分,让 P、I 和偏置之和先接上这 30%。下次调用仍会正常积一拍分,所以匹配的是切换瞬间。
这个选择更适合手动切自动。冷启动时,如果拿 0% 去匹配,它可能用负积分抵消初始 P,让升温慢下来。希望开机就体现 P 的作用,可以改成积分清零、D 清零,再把 prev_y 设成当前测量值。MathWorks 的无扰切换示例还展示了手动期间持续跟踪输出的做法。
还有个小细节:把 ki 设成零,只是停止新增积分,旧的 integral 仍会参与输出。想测试纯 P,记得同时处理这个旧状态。换参数、换方向时也一样。
4.4.2 不要把控制核心当成完整设备程序
传感器断线返回什么?ADC 数据超范围以后关不关输出?控制任务多久没运行算故障?这些判断放在外层。尤其别把 NaN 直接传进来,它可能一路污染内部状态,普通的大小比较也拦不住它。
参数和状态尽量由同一个任务管理。串口调参时一次换完整组参数,避免刚换完 kp 就被控制中断打断,算了一拍新旧混用的结果。长时间关闭输出时,也别让积分在后台照常积着。
4.5 采样周期:不只是把代码放进定时器

图 9:裁自 TI 参考手册第 16 页,Figure 5。右边的对象连续变化,左边的控制器只在离散时刻计算;Hold 表示两次更新之间保持控制输出。
一次控制更新,实际经历的是传感器响应、采样、计算、PWM 生效。PID 函数算得快,不代表这整条链就快。比如传感器每 200 ms 才刷新一次,主循环每 1 ms 算一次,大部分时候用的还是旧温度。
初步估算时,可以先让采样频率 比期望闭环带宽 高一个数量级,再把采样保持、滤波与计算延迟放进模型检查。这个比例只给起点,不能据此断言稳定。温控和电机电流环的时间尺度也差得很远。
| 环节 | 要确认的问题 |
|---|---|
| 传感器 | 数据是否真的在每次控制更新前刷新? |
| ADC 与前端 | 是否同步采样,是否存在混叠或较大的滤波延迟? |
| 控制任务 | 周期是否稳定,最坏计算时间是否满足截止时间? |
| PWM | 控制更新和 PWM 载波是什么关系,比较值何时生效? |
| 数据记录 | 日志和通信是否阻塞了控制任务? |
PWM 每秒开关多少次,和 PID 每秒更新多少次,是两件事。加热器可以使用较高频率的 PWM,而控制任务慢一些;具体周期仍要看对象和测量链路。
本例 ts=0.1,就每 100 ms 调用一次。如果实际每 10 ms 调用,程序还以为过了 100 ms,单位时间内的积分就加了十倍。若使用实测间隔,积分、微分和滤波系数要一起跟着变;任务严重超时则另作故障处理。

图 10:裁自 Microchip AN937,2004 年版第 6 页,Figure 4。它把累积误差和差分历史放进定时中断,适合对照早期整数实现的任务分工。
这张老图也值得带着问题看:它有 error = 0? 的提前返回分支。零误差时仍可能需要积分提供保温功率,测量值也可能仍在变化,所以不能把这个分支直接搬成“误差为零就输出零”,也不能因此漏掉通用实现里的状态更新。本文代码每次都更新历史值并计算输出。
5. 加热台硬件和整定
5.1 真实硬件还需要哪些环节

图 11:低压直流加热系统的功能连接示意。箭头表示信号或作用关系,不是完整导线连接,不能直接用于投板。
MCU 给的是逻辑信号,真正承受负载电流的是功率级。MOSFET 选型、驱动电压和散热要按负载来算。采样线如果贴着大电流回路走,读数可能跟着开关动作跳;传感器如果离加热片很远,读到的又是迟到的温度。两种情况都会让调参变得费劲。
图里的独立过温切断也要保留。传感器断线、程序卡住时,仍应有办法关掉加热输出。
5.2 先记录一次对象响应
先给一个小幅、可控的开环输出变化,同时记下时间、占空比和温度。看温度多久开始动、大约多久接近新平衡、最终升了多少。对某些温控工况,可以先试着拟合成:
这里 是局部静态增益, 是时间常数, 是延迟。比如占空比加了 0.1,稳定温度升了 8 ℃,这个工况附近的 约为 80 ℃/单位占空比。若曲线一直爬升、明显振荡,或不同工况差别很大,就要换更合适的模型。
5.3 一套有顺序的手动整定方法
先关闭 I、D,清掉旧状态,从小 P 做一点目标变化。观察温度的同时也看占空比;若占空比一直打满,只看温度曲线很难分清是参数问题,还是设备本来就只能这么快。
P 增大到响应明显快起来以后,若开始超调或振荡,就退回一些。然后一点点加 I,把持续残差补掉。热过程有时很慢,改完要等足够久再判断,否则上一组参数的热量还没散完,下一组已经换上去了。
PI 能满足要求就先用 PI。还想压超调,再试带滤波的 D,比较加入前后的温度与输出抖动。最后试试冷工件、风扇、不同温度目标,以及长时间全功率后把目标调低。最后这一项,正好能检查抗饱和有没有实际起作用。
每次只改一类参数,把周期和曲线一起保存。否则调了半天,很容易只记得“刚才那组好像更好”。
5.4 如何看待 Ziegler–Nichols
Ziegler–Nichols 能给出一组经验初值,NI 文档介绍了相关整定方法。用之前先看清是哪一种实验、哪一种 PID 参数形式,别拿到三个数字就填进去。
闭环临界比例法会把系统推到持续振荡附近,测临界增益和周期。加热台若不允许过温,就不适合硬做这种实验。得到初值后也要重新检查超调、噪声、饱和恢复和不同工作点。
6. 抗积分饱和、噪声与安全
6.1 为什么限幅之后,还需要抗积分饱和
把目标设得很高,加热器全功率跑了很久,温度还是差一截。积分每一拍都在增加,PWM 却早已卡在 100%。这时把目标调低,明明该减功率了,程序还可能继续全功率加热:之前攒下来的积分太多,一时减不掉。
这就是积分饱和,也称 integral windup。只写 u = clamp(u, 0, 1),并没有约束内部积分状态。

图 12:本文仿真。对象为 ,PI 参数 、,周期 0.01 s,输出范围 0~1。前 8 s 的目标是不可达的 1.5,之后降为 0.4。只限幅的那条曲线在目标降低后仍持续饱和,条件积分则更快退出。
6.2 条件积分和反算
可以先试算一次。若输出已经超上限,本次积分还想往上加,就舍弃这次积分;超下限时反过来处理。若这次变化能把输出拉回范围内,就允许它减下去。代码里把候选值叫作 trial_i 和 trial_u,正好能对上这几步。
这种写法不难检查,不过限幅边界附近的行为还受每次积分步长影响。另外,软件以为自己输出了 80%,功率级可能已经因限流只能给出 40%;只看软件里的限幅就发现不了这件事。
另一类方法把饱和前后的差值反馈到积分器:
例如算出 1.4,限幅后只有 1.0,差值就是 −0.4;这条反馈会把积分往回拉。实现上先用旧积分求 ,再限幅,最后更新积分,就不会互相等着对方的新值。 的单位是 ,越大拉回得越快,仍需按离散周期检查稳定性。
如果执行器另有电流环或限流器,最好把实际执行量反馈回来;有前馈时,还要分清哪一部分输出属于 PID。MathWorks 的抗饱和示例分别展示了条件积分、反算和外部跟踪,可以对着框图查。
6.3 噪声与独立保护
微分支路和采样链路的滤波会带来相位滞后,不能只靠把 调大来压住输出抖动。先核对传感器刷新率、布线和测量噪声,再决定是否真的需要 D。无论控制器参数怎样,独立过温切断、传感器断线处理和输出故障默认态都应在 PID 外层生效。
7. 检查表、总结与资料
7.1 常见故障与排查方向
| 现象 | 优先检查 |
|---|---|
| 一启动输出就迅速打满 | 反馈方向、单位换算、初始状态、目标是否可达 |
| 纯 P 稳定但总差一点 | 保持输出所需的偏置是否存在,是否需要 I 或前馈 |
| 升温越过目标后还继续大功率 | 积分饱和、传感器滞后、热惯性、实际执行器是否跟随命令 |
| 输出出现高频抖动 | 测量噪声、D 增益、微分滤波、ADC 与 PWM 的采样关系 |
| 改了定时周期后效果完全不同 | 是否遗漏 ,或重复折算了离散增益 |
| 目标改变时控制量突然尖峰 | 是否对误差直接微分,P 项阶跃是否也需要设定值斜坡 |
| 仿真稳定,实物却振荡 | 模型漏掉的延迟、执行器动态、死区、采样滤波与负载变化 |
| 只在某些工作点稳定 | 对象增益随工况变化、执行器非线性,是否需要分区整定 |
遇到振荡,先导出一段日志:目标、测量值、限幅前后输出、P/I/D 分量和时间戳。I 一直往上爬、D 跟着噪声跳、更新周期忽长忽短,会在这些数据里表现得很不一样。
7.2 本文小结
对加热台而言,先确认方向、采样周期和硬件保护,再从 P 或 PI 起步,通常比直接套一组“PID 参数”更可靠。P 负责眼前误差,I 补偿持续残差,D 用来处理变化趋势但会放大噪声;当输出会饱和时,积分状态必须被单独管理。曲线、日志和实际保护逻辑都要一起验收。
7.3 想继续看,可以从这些资料入手
本文原创图的生成脚本为仓库中的 scripts/generate-pid-figures.py,需要 Python、NumPy、Matplotlib 和中文字体。运行:
python scripts/generate-pid-figures.py可以重建图 1、图 7、图 11、图 12。厂商图的 PDF 页码、裁切坐标和重建命令在配图来源说明见随文的 ./pid-control-guide/images/SOURCES.txt里;裁切脚本是 scripts/crop-pid-references.py。这些图片随文章保存在本地,阅读时不用等第三方图床。
参考资料
- **先看整体:**TI,Real-Time Control Reference Guide,2021 年 10 月版。第 16 页把采样与保持画在一起,第 24~25 页对照并联、串联 PID。本文图 5、图 9 来自这份手册。
- **从公式走到小 MCU:**Microchip / Atmel,AVR221: Discrete PID Controller on tinyAVR and megaAVR devices,2558C,2016 年 9 月。第 5~6 页看响应,第 7~8 页看离散化,第 9~11 页看定点缩放、状态保存和积分限制。本文图 2~4、图 6、图 8 从这里裁取。
- **读一份完整的老式实现:**Chris Valenti / Microchip,AN937: Implementing a PID Controller Using a PIC18 MCU,2004 年。第 5~6 页的主程序与中断流程、第 7~10 页的时间基准和三项计算,适合对照阅读。它的整数实现和条件分支有特定背景,本文没有直接移植。图 10 来自第 6 页。
- **查参数的定义:**MathWorks,pid — PID controller in parallel form。拿到一组 时,可以先查这里,核对形式和离散方法。
- **查为什么要对测量微分:**Control Guru,PID Control and Derivative on Measurement。重点看目标跳变时,误差与测量值的差别。
- **查积分饱和:**MathWorks,Anti-Windup Control Using PID Controller Block。有反算、条件积分、级联执行器和前馈的例子,适合查实际输出该从哪里反馈。
- **查切换时为什么跳一下:**MathWorks,Bumpless Control Transfer Between Manual and PID Control。比较有无输出跟踪时,手动切自动的响应。
- **比较两种调参目标:**MathWorks,PID Tuning for Setpoint Tracking vs. Disturbance Rejection。能解释为什么目标跟得好,负载扰动后却恢复得慢。
- **对照一份常见库的源码:**Brett Beauregard,Arduino PID Library / PID_v1.cpp。重点看
Compute()、SetTunings()、SetSampleTime()和Initialize(),对应测量微分、周期换算、限幅和初始化。 - **准备使用 Cortex-M 库:**Arm,CMSIS-DSP PID Motor Control。给出了递推系数和 Q15、Q31、浮点接口;定点版本要继续查各自的溢出与缩放说明。
- **了解经典整定:**NI,Ziegler-Nichols Autotuning Method。看经验整定怎样给初值,再拿设备的实际约束筛选。
资料检索日期:2026-10-16。原创文字、代码和原创图采用 CC BY 4.0。TI、Microchip / Atmel 的原图只做局部裁切,权利归各自所有,不包含在本文的原创许可里。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!