assembly 在PIC16F84A上使用PIC组件时出现堆栈下溢问题

sh7euo9m  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(132)

我有一个课程的小项目,要求我们使用PIC汇编语言生成PWM信号。为了简化操作,我将高时间设置为5ms,低时间设置为15ms,这样我就可以多次调用相同的延迟子例程。多次调用此延迟可能会导致堆栈下溢问题。
我真的不知道我可以尝试解决这个问题,因为我是非常新鲜的编程。我已经尝试在这个网站上搜索,以及一般,但还没有能够找到一个解决方案。我用MPLab 9.82以及。
代码如下所示:

list        p=16F84A      
#include    <p16F84A.inc>

    __CONFIG _CP_OFF & _XT_OSC & _PWRTE_ON & _WDT_OFF ;turn off watchdog timer

org 0x00 ; program starts at 0x00

counter equ 4Fh ; create a counter at position 4Fh in RAM

    BSF STATUS, RP0 ; select bank 1
    BCF TRISB, D'1' ; set port B pin 1 to output
    BCF STATUS, RP0 ; select bank 0

    goto main

main

    BSF PORTB,1 ; turn port B pin 1 on
    call delay_5ms ; calls sub routine for 5ms delay
    BCF PORTB,1 ; turn port B pin 1 off
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay

delay_5ms 

    movlw D'200' ; put decimal number 200 into working register
    movwf counter ; move 200 from working register into counter

lp  nop ; no operation. just take 1 instruction
    nop  ; 1 instruction
    decfsz counter ; 1 instruction and decreases counter by 1
    goto lp ; 2 instructions (goto takes 2 instructions)
    return

end

mplab 9.82 Simulator code

0lvr5msh

0lvr5msh1#

每个嵌入式系统都需要一个无限循环。无限循环是必要的,因为嵌入式软件的工作永远不会完成。它的目的是运行,直到世界末日或板被重置,无论哪个先发生。此外,大多数嵌入式系统只有一个软件运行在他们身上。在非嵌入式系统中,当main()完成时,它返回到操作系统,程序从内存中删除。在嵌入式系统中,没有操作系统可以返回,程序不能从内存中删除。
在汇编程序中,该结构可能如下所示:

reset:
 ; do init part

main:
  ; do the job in infinite loop
goto main

或C语言

void main ()
{
    init();
    while(1)
    {
        do_job();
    }
}
ig9co6j1

ig9co6j12#

正如Hans Passant所指出的,main需要一些方法来防止失败,为了更详细地解释这里发生的事情,让我们看一个C函数:

void doNothing()
{
    asm("nop");
}

虽然不是最好的例子,但是我需要一个没有return语句的函数,至少在C语言中没有return语句,但是在汇编语言中,这个函数(假设它没有内联)看起来像这样:

doNothing:
nop
return

用C编写的函数总是编译为带有 *return指令 * 的汇编函数(除非编译器内联该函数),即使您的函数没有C return语句。
为什么需要这样做?因为ASM标签不存在。
程序集源文件中的一行带标签的代码只是对特定内存地址的引用。当我有下面的代码时:

main:
   nop
   nop
   nop
   goto main

goto main只是一个硬件抽象,意思是“后藤main碰巧在的任何内存地址。分支是相对的还是绝对的,这无关紧要--汇编程序为您做数学运算,并用所需的偏移量替换goto main中的main,使分支带您到您想要的地方。然而,当创建可执行文件时,main:(注意后面的冒号,我说的是标签本身)没有了,这导致了汇编语言的一些怪癖,而这些怪癖在其他语言中不会发生:

  • 首先,我可以有多个标签指向同一条指令,这样做不会增加可执行文件的大小。
foo:
bar:
baz:
nop

第二,也是最重要的,没有什么可以阻止执行从标签中掉出来。

main

    BSF PORTB,1 ; turn port B pin 1 on
    call delay_5ms ; calls sub routine for 5ms delay
    BCF PORTB,1 ; turn port B pin 1 off
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay

delay_5ms
    movlw D'200' ; put decimal number 200 into working register

完全一样

main

    BSF PORTB,1 ; turn port B pin 1 on
    call delay_5ms ; calls sub routine for 5ms delay
    BCF PORTB,1 ; turn port B pin 1 off
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay
    call delay_5ms ; calls sub routine for 5ms delay
    movlw D'200' ; put decimal number 200 into working register

也就是说,如果你想执行某个函数固定的次数,而没有循环的开销,那么你可以使用fallthrough。

foo:
;execute "bar" four times

call bar
call bar
call bar

bar:
   nop
   return

相关问题