我正在尝试编译此代码以生成 PWM 信号 15us 高电平和 9us 低电平。
#include <xc.h>
void g()
{
for(char val=0; val<20; val++)
{
GPIO = 0xFF;
NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP(); NOP();
NOP(); NOP(); NOP(); NOP();
// Write all GPIO pins LOW
GPIO = 0;
NOP(); NOP(); NOP();
}
}
void main(void) {
// Set all pins at output
TRIS = 0x00;
GPIO = 0;
while(1) {
g();
}
}
问题在于FOR循环的返回需要太多指令。我原以为要少拿一点。在这种情况下,仅使用 3 个
NOP();
函数,仍然有 15 个刻度。
CLRF GPIO // GPIO = 0;
NOP
NOP
NOP
MOVLW 0x1
MOVWF wtemp1
MOVF wtemp1, W
ADDWF __pcstackBANK0, F
MOVLW 0x14
SUBWF __pcstackBANK0, W
BTFSC STATUS, 0x0
RETLW 0x0
GOTO 0x4 // Return to beginning of loop
编译器XC8:
我应该怎么做才能压缩操作码?和mplab有关系吗?
p.s 我无法使用
-O3
标志,因为它不包含在我的许可证中。
我没有你的工具链,所以我无法进行周期计数,但这段代码应该为你提供一个微调版本的基础,该版本可以可靠地生成 15us 高、9us 低。我还提供了示例变量延迟,如果您打算在某个阶段执行 PWM,我认为这些延迟应该是 PIC 友好的机器代码。
@KonstantinMurugov 建议的第一个也是最基本的技巧是将内部
for
循环转为倒计时(PIC 以 DECFSZ 形式提供硬件支持)。我已经把它变成了 while 循环。
然后下一个技巧是将短延迟移到循环的中间,您可以在其中精确控制它,并调整较长高延迟的填充,直到获得两者所需的时间。我最初的猜测是基于有关代码生成和开销的一些假设,因此您可能需要对其进行一些调整才能使时间常数准确。同样出于测试目的,将
val
设置为 1,以便系统误差出现在前几个周期中。然后用 2 和 3 重新测试,以确保它在每个嵌套循环中生成正确的波形。为了使其完全正确,您可能必须减少最内层循环中的 NOP()
计数并将它们添加到其他地方。
#include <xc.h>
void g()
{
char val = 20;
// for fine tuning set this to 1 so that the loop exits each time (then recheck with val = 2,3)
do
{
NOP(); NOP(); NOP(); NOP();
GPIO = 0;
NOP(); NOP(); NOP(); NOP();
GPIO = 0xff;
NOP(); NOP(); NOP(); NOP();
} while (val--);
// this form of countdown loop is friendly to PIC DECFSZ instruction
}
// since `PWM` was mentioned in the original question here are two primitives.
// call overheads are disastrous so allow maximum inlining for speed
// in some ways cycle counting is easier in assembler where you can have
// precise control of the instructions inside the various loops.
void delay(char x)
{ // delay by individual NOPs (a variant on Duff's device)
// it should be PIC friendly but I don't have the toolchain to check.
switch (x)
{
case 7: NOP();
case 6: NOP();
case 5: NOP();
case 4: NOP();
case 3: NOP();
case 2: NOP();
case 1: NOP();
case 0:;
default:;
}
}
void delay2(char x)
{ // delay by countdown loop 2 cycles at a time
while (x--)
;
}
void main(void) {
// Set all pins at output
TRIS = 0x00;
GPIO = 0xff;
NOP(); NOP(); NOP(); NOP(); // so that first cycle is correct length
while (1) {
g();
}
// NB you may have to tweak it again if while(1) becomes a conditional test
}
您必须在模拟器中运行它,然后调整 NOP 的确切数量以获得您想要的波形。不过应该不会太远。