一、基本设定(为了理解)
ARR = 10(你设定的测试值)
CNT范围:0, 1, 2, 3, 4, 5, 6, 7, 8, 9(共10个值)
溢出:从9→0(正向)或从0→9(反向)
二、为什么 n * 10 是溢出部分的总脉冲?
先看一个直观的例子:
假设: 电机一直在正向旋转,我们观察CNT变化:
时间:t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11
CNT: 0 → 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 0 → 1 → 2
标志: ↑ ↑ ↑
正常计数 溢出! 正常计数
计数过程分解:
-
第一次完整循环:0→9(10个脉冲)
-
当CNT从9变成0时,发生溢出
-
n++(n从0变成1) -
这10个脉冲就是
n * 10中的第一个10
-
-
第二次计数:0→2
-
这是当前未完成的循环
-
计数值x=2
-
这部分还没溢出,所以不计入n
-
数学表达:
总脉冲数 = 已完成的完整循环数 × 每循环脉冲数 + 当前部分脉冲数
= n × 10 + x
其中:
-
n:完整循环的次数(每次溢出记一次) -
10:每个完整循环的脉冲数(0-9共10个值) -
x:当前循环已走的脉冲数(0到当前值)
三、分解说明 n × 10 的含义
情景1:n = 1(溢出1次)
n × 10 = 1 × 10 = 10个脉冲
含义:已经完整地走完了1个0→9的循环
情景2:n = 3(溢出3次)
n × 10 = 3 × 10 = 30个脉冲
含义:已经完整地走完了3个0→9的循环
用更生活化的比喻:
比喻1:汽车的里程表(老式,会归零)
里程表范围:00000-99999(相当于ARR=100000)
1. 你开了50000公里:里程表显示50000
2. 你再开50000公里:里程表回到00000(溢出)
3. 你又开了30000公里:里程表显示30000
实际总里程 = 溢出的100000 + 当前的30000 = 130000公里
这里的100000就是 n×ARR(n=1, ARR=100000)
比喻2:时钟(12小时制)
时钟范围:1-12点(ARR=12)
1. 从3点开始
2. 经过24小时(溢出2圈)
3. 停在5点
实际经过时间 = 2圈×12小时 + 从3点到5点的2小时
= 2×12 + 2 = 26小时
四、具体数值示例(ARR=10)
示例1:正向旋转,中等速度
初始状态:TIM2开始时,CNT=0, n=0
旋转过程:
脉冲# | CNT | n | 说明
-------|-----|-----|----------
第1个 | 1 | 0 | 正常计数
第2个 | 2 | 0 | 正常计数
... | ... | ... | ...
第9个 | 9 | 0 | 正常计数
第10个 | 0 | 1 | 溢出!n++
第11个 | 1 | 1 | 新循环开始
第12个 | 2 | 1 | 新循环继续
TIM2结束时:
x = CNT = 2
n = 1
计算:
total = x + n×10
= 2 + 1×10
= 2 + 10
= 12个脉冲
验证:确实经过了12个脉冲(第1-12个)
示例2:正向旋转,更快速度
初始:CNT=0, n=0
过程:旋转了32个脉冲
详细过程:
第1-10个脉冲:CNT:0→9,然后溢出,n=1
第11-20个脉冲:CNT:0→9,再次溢出,n=2
第21-30个脉冲:CNT:0→9,再次溢出,n=3
第31-32个脉冲:CNT:0→1,n=3
结束时:
x = 1
n = 3
计算:
total = 1 + 3×10
= 1 + 30
= 31个脉冲?等等,应该是32!
问题:这里有个差1的错误!
五、重要纠正:差1错误!
这里有一个常见的边界错误:
正确理解:
-
当CNT从9变成0时,n增加1
-
但这表示已经完成了10个脉冲(0,1,2,...,9)
-
所以
n × 10确实对应了已完成的脉冲数
但是,我们的计数方式有微妙差异:
实际脉冲数计算应该是:
总脉冲数 = n × 10 + x
但这里的x是当前值 ,不是当前循环已走脉冲数!
正确公式(考虑从0开始计数):
总脉冲数 = n × 10 + (x - 开始时的CNT值)
如果开始时CNT=0,结束时CNT=x,那么:
总脉冲数 = n × 10 + x
这是正确的!
验证示例2(32个脉冲):
开始:CNT=0
过程:
第1-10个脉冲:CNT从0→9,溢出时n=1
第11-20个脉冲:CNT从0→9,溢出时n=2
第21-30个脉冲:CNT从0→9,溢出时n=3
第31-32个脉冲:CNT从0→1
结束:
x = 1
n = 3
计算:
total = 1 + 3×10 = 1 + 30 = 31 ❌
问题在哪?
实际上,当第30个脉冲时,CNT=9
第31个脉冲:CNT=0,n=4(不是3!)
第32个脉冲:CNT=1
所以应该是:
x = 1
n = 4
total = 1 + 4×10 = 41 ❌(更错了)
六、正确的思考方式
关键在于:溢出发生在CNT回到0的那一刻,而不是在9的时候。
重新思考:
每个完整循环:CNT变化 0→1→2→...→9→0
↑
这里发生溢出
脉冲计数:
当CNT=0时,表示:
1. 要么还没开始(0脉冲)
2. 要么刚完成一个循环(10个脉冲)
所以,当CNT=x时:
- 如果x>0,表示当前循环已走了x个脉冲
- n表示之前已完成的全循环数
正确示例(32个脉冲):
开始:CNT=0(表示尚未开始,或刚复位)
过程:
脉冲# 变化 CNT n
1 0→1 1 0
2 1→2 2 0
...
10 9→0 0 1 ← 溢出!完成10个脉冲
11 0→1 1 1
12 1→2 2 1
...
20 9→0 0 2 ← 溢出!又完成10个脉冲(共20)
21 0→1 1 2
22 1→2 2 2
...
30 9→0 0 3 ← 溢出!又完成10个脉冲(共30)
31 0→1 1 3
32 1→2 2 3 ← 停止
结束:
x = 2
n = 3
计算:
total = x + n×10
= 2 + 3×10
= 2 + 30
= 32 ✓
七、总结公式
对于ARR=M(你的情况M=10)的编码器:
正向旋转(n≥0):
总脉冲数 = 当前CNT值 + n × M
解释:
-
n × M:已完成的全循环脉冲数 -
当前CNT值:当前循环已走的脉冲数(从0开始)
反向旋转(n<0):
总脉冲数 = 当前CNT值 + n × M
注意: n是负数,所以结果是负数,表示反向脉冲数
例如: n=-2, x=3, M=10
total = 3 + (-2)×10 = 3 - 20 = -17
表示反向17个脉冲
八、为什么你的代码反向公式不同?
代码:
total = (10-x) - (n+1)*10; // 对于反向
这其实是在尝试计算绝对值,但会丢失方向信息。
建议统一公式:
// 无论正反向,统一使用:
total = x + n * M; // n可正可负
这样:
-
结果>0:正向旋转
-
结果=0:静止
-
结果<0:反向旋转
数值的正负直接表示了方向!
这就是n × M作为溢出部分总脉冲的完整解释。关键是理解:每次溢出代表完成了一个完整的M个脉冲循环。