3

我正在为使用 16 位 PIC 以 40 MIPS 运行并用 C 编程的嵌入式设备开发一些固件。系统将控制两个步进电机的位置并始终保持每个电机的步进位置。每个电机的最大位置大约是 125000 步,所以我不能使用 16 位整数来跟踪位置。我必须使用 32 位无符号整数 (DWORD)。电机以每秒 1000 步的速度移动,我设计了固件,以便在 Timer ISR 中处理步数。定时器 ISR 执行以下操作:

1)比较一个电机的当前位置和目标位置,如果它们相同,将isMoving标志设置为false并返回。如果它们不同,则将 isMoving 标志设置为 true。

2) 如果目标位置大于当前位置,向前移动一步,然后增加当前位置。

3) 如果目标位置小于当前位置,则向后移动一步,然后递减当前位置。

这是代码:

void _ISR _NOPSV _T4Interrupt(void)
{
    static char StepperIndex1 = 'A';    

    if(Device1.statusStr.CurrentPosition == Device1.statusStr.TargetPosition)
    {
        Device1.statusStr.IsMoving = 0;
        // Do Nothing
    }   
    else if (Device1.statusStr.CurrentPosition > Device1.statusStr.TargetPosition)
    {
        switch (StepperIndex1)      // MOVE OUT
        {
            case 'A':
                SetMotor1PosB();
                StepperIndex1 = 'B';
                break;
            case 'B':
                SetMotor1PosC();
                StepperIndex1 = 'C';
                break;
            case 'C':
                SetMotor1PosD();
                StepperIndex1 = 'D';
                break;
            case 'D':
                default:
                SetMotor1PosA();
                StepperIndex1 = 'A';
                break;      
        }
        Device1.statusStr.CurrentPosition--;    
        Device1.statusStr.IsMoving = 1;
    }   
    else
    {
        switch (StepperIndex1)      // MOVE IN 
        {
            case 'A':
                SetMotor1PosD();
                StepperIndex1 = 'D';
                break;
            case 'B':
                SetMotor1PosA();
                StepperIndex1 = 'A';
                break;
            case 'C':
                SetMotor1PosB();
                StepperIndex1 = 'B';
                break;
            case 'D':
                default:
                SetMotor1PosC();
                StepperIndex1 = 'C';
                break;      
        }
        Device1.statusStr.CurrentPosition++;
        Device1.statusStr.IsMoving = 1;
    }   
    _T4IF = 0;          // Clear the Timer 4 Interrupt Flag.
}

当接收到移动请求时,在主程序循环中设置目标位置。SetMotorPos 行只是用于打开/关闭特定端口引脚的宏。

我的问题是:有什么办法可以提高这段代码的效率吗?如果位置是 16 位整数,则代码功能正常,但作为 32 位整数,处理过多。该设备必须毫不犹豫地与 PC 通信,并且正如所写的那样,性能会受到明显影响。我真的只需要 18 位数学,但我不知道这样做的简单方法!任何建设性的意见/建议将不胜感激。

4

5 回答 5

6

警告:所有数字都是虚构的......

假设上述 ISR 有大约 200 条(可能更少)编译代码指令,其中包括在 ISR 之前和之后保存/恢复 CPU 寄存器的指令,每个需要 5 个时钟周期(可能是 1 到 3 个),然后您调用其中 2 个每个每秒 1000 次,我们最终得到 2*1000*200*5 = 2 百万个时钟周期每秒或 2 MIPS。

你真的会在其他地方消耗剩下的 38 MIPS 吗?

唯一可能在这里很重要但我看不到的是SetMotor*Pos*()函数内部所做的事情。他们会做任何复杂的计算吗?它们是否与电机进行了一些缓慢的通信,例如等待它们响应发送给它们的命令?

无论如何,这样简单的代码在处理 32 位整数时会明显比处理 16 位更慢是值得怀疑的。

如果您的代码很慢,请找出时间花在了哪里以及花费了多少时间,然后对其进行分析。在 ISR 中生成一个方脉冲信号(当 ISR 启动时变为 1,当 ISR 即将返回时变为 0)并用示波器测量其持续时间。或者做任何更容易找到它的事情。衡量在程序的所有部分花费的时间,然后在真正需要的地方进行优化,而不是在你之前认为的地方进行优化。

于 2011-11-04T22:12:15.847 回答
1

我认为 16 位和 32 位算术之间的差异不应该那么大,因为您只使用增量和比较。但问题可能在于每个 32 位算术运算都意味着一个函数调用(如果编译器不能/愿意进行更简单操作的内联)。

一个建议是自己进行算术运算,将 Device1.statusStr.CurrentPosition 分成两部分,例如 Device1.statusStr.CurrentPositionH 和 Device1.statusStr.CurrentPositionL。然后使用一些宏来执行操作,例如:

#define INC(xH,xL) {xL++;if (xL == 0) xH++;}

于 2011-11-04T22:48:25.820 回答
0

我会摆脱StepperIndex1变量,而是使用 的两个低位CurrentPosition来跟踪当前的步长索引。或者,跟踪完整旋转(而不是每一步)的当前位置,以便它可以放入 16 位变量中。移动时,您仅在移动到“A”阶段时增加/减少位置。当然,这意味着您只能针对每个完整的旋转,而不是每一步。

于 2011-11-04T23:09:13.470 回答
0

抱歉,您使用了糟糕的程序设计。

让我们检查一下 16 位和 32 位 PIC24 或 PIC33 asm 代码之间的区别......

16 位增量

inc    PosInt16               ;one cycle

所以 16 位增量需要一个周期

32位增量

clr    Wd                     ;one cycle
inc    low PosInt32           ;one cycle
addc   high PosInt32, Wd      ;one cycle

和 32 增量需要三个周期。总差异为 2 个周期或 50ns(纳秒)。

简单的计算会告诉你一切。您每秒有 1000 步和 40Mips DSP ,因此您在每秒 1000 步时每步有 40000 条指令。绰绰有余!

于 2011-11-05T10:34:51.353 回答
0

当您将其从 16 位更改为 32 位时,您是否更改了任何编译标志以告诉它编译为 32 位应用程序。

您是否尝试过使用 32 位扩展进行编译,但只使用 16 位整数。你还有这样的性能下降吗?

很可能只是通过从 16 位更改为 32 位,一些操作的编译方式不同,也许在两组编译的 ASM 代码之间做一个 Diff,看看实际上有什么不同,是很多还是只有几行。

解决方案可能不是使用 32 位整数,而是使用两个 16 位整数,当 valueA 为 int16.Max 然后将其设置为 0,然后将 valueB 增加 1 否则只需将 ValueA 增加 1,当 value B >= 3 你然后检查 valueA >= 26696(或类似的值,具体取决于您使用无符号或有符号 int16),然后在 12500 处检查电机。

于 2011-11-07T12:46:16.787 回答