Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何在程序集中为ATmega328p设置计时器溢出?_Assembly_Avr_Atmel - Fatal编程技术网

Assembly 如何在程序集中为ATmega328p设置计时器溢出?

Assembly 如何在程序集中为ATmega328p设置计时器溢出?,assembly,avr,atmel,Assembly,Avr,Atmel,我一直在尝试在汇编中创建一个程序,每当定时器溢出中断发生时,该程序会向左或向右旋转一个位。这是我的代码,但由于某些原因它不起作用。我是编程汇编的新手,我希望有人能在这里帮助我,因为我被卡住了。这是我的密码: /* * lab3b.asm * * Created: 10/18/2014 8:03:22 PM * Author: Isaac Vilchez */ .include "m328pdef.inc" .org 0x0000 jmp main .org 0x0020 jm

我一直在尝试在汇编中创建一个程序,每当定时器溢出中断发生时,该程序会向左或向右旋转一个位。这是我的代码,但由于某些原因它不起作用。我是编程汇编的新手,我希望有人能在这里帮助我,因为我被卡住了。这是我的密码:

/*
 * lab3b.asm
 *
 *  Created: 10/18/2014 8:03:22 PM
 *   Author: Isaac Vilchez
 */ 

.include "m328pdef.inc"
.org 0x0000 jmp main
.org 0x0020 jmp TIM0_OVF_ISR

main:
    .org 0x0033

//Config de Stack Pointer y Timer0
    ldi R16, high(RAMEND)
    out SPH, R16
    ldi R16, low(RAMEND)
    out SPL, R16
    sei

//Inicializando los puertos D y B como salida
ldi r16, 0x00
out DDRC, r16
ldi r16, 0xFF
out DDRD, r16
out DDRB, r16

//Configurando timer0 al intervalo maximo de duracion al timer0
    ldi R19, 0x00
    out TCNT0, R19 //Para que el conteo empiece en 0
    ldi R20, 0x05
    out TCCR0B, R20
    ldi R23, 0x01
    sts TIMSK0, R23 //habitlita el timer0

//Registros proposito general
ldi r16, 0x01   ;registro puerto D
ldi r22, 0x10   ;mascara para ejecutar rot_izqPB
ldi r23, 0x80   ;mascara PD
ldi r20, 0x01   ;registro puerto B
ldi r21, 0x00   ;mascara de 0

out PORTB, r21  ;Posicion inicial puerto B
out PORTD, r21  ;Posicion inicial puerto D

//Cargando a R16 con 0x01 para comenzar la rotacion hacia la izquierda
TIM0_OVF_ISR:
    in r24, PINC    ;Se guarda el valor del puerto C en R24
    andi r24, 0x01  ;Se enmascara el puerto C
    cpi r24, 0x01   ;Se compara con 0x01 para ver su estado
    breq rot_derPB  ;Si esta encendido, rota a la derecha
    rjmp rot_izqPD  ;Si esta apagado rota a la izquierda


//Rotacion hacia la izquierda
rot_izqPD:
    ldi r16, 0x01
    rjmp rot_izqPD1

rot_izqPD1:
    out PORTD, r16
    cpi r16, 0x00
    breq rot_izqPB
    ROL r16
    rjmp wait

//Rotacion hacia la izquierda
rot_izqPB:
    ldi r20, 0x01
    rjmp rot_izqPB1

rot_izqPB1:
    out PORTB, r20
    LSL r20
    cp r20, r22
    breq rot_izqPB1
    rjmp wait

//Rotacion hacia la derecha
rot_derPB:
    ldi r16, 0x08
    rjmp rot_derPB1

rot_derPB1:
    out PORTB, r16
    LSR r16
    cpi r16, 0x00
    breq rot_derPD
    rjmp wait

//Rotacion hacia la derecha
rot_derPD:
    ldi r16, 0x80

rot_derPD1:
    out PORTB, r21
    out PORTD, r16
    LSR r16
    cp r16, r21
    ;breq wait
    rjmp wait

wait:
    brvs TIM0_OVF_ISR
    rjmp wait
编辑: 这是我的新代码。这一个正在工作:

/*
 * lab3b.asm
 *
 *  Created: 10/18/2014 8:03:22 PM
 *   Author: Isaac Vilchez
 */ 

.include "m328pdef.inc"
.org 0x0000 jmp begin
.org 0x0020 jmp TIM0_OVF_ISR

begin:
    .org 0x0033

//Config de Stack Pointer y Timer0
ldi R16, high(RAMEND)
out SPH, R16
ldi R16, low(RAMEND)
out SPL, R16

//Inicializando los puertos D y B como salida
ldi r16,    0x00
out DDRC,   r16
ldi r16,    0xFF
out DDRD,   r16
out DDRB,   r16

//Configurando timer0 al intervalo maximo de duracion al timer0
ldi R19,    0x00
out TCNT0,  R19 //Para que el conteo empiece en 0
ldi R20,    0x05
out TCCR0B, R20
ldi R23,    0x01
sts TIMSK0, R23 //habitlita el timer0

//Habilitando las interrupciones globales
SEI

//Configuracion de Registros
main:
    ldi r16, 0x01
    ldi r17, 0x00
    ldi r19, 0x80
    mov r20, r16
    ldi r21, 0
    mov r23, r19
    ldi r25, 0x01

//Loop de espera en lo que se realiza la interrupcion
wait:
    rjmp wait

//Enciende el led de PB4 y espera a la interrupcion
onPB:
    ldi r22, 0x80
    out PORTB, r22
    rjmp wait

//Enciende el led de PB4 y espera a la interrupcion
ledpb4:
    ldi r22, 0x80
    out PORTB, r22
    reti

reset:
    ldi r16,    0x01
    ldi r18,    0x08
    ldi r19,    0x80
    mov r20,    r16
    ldi r21,    0
    mov r23,    r19
    reti

//Rotacion hacia la izquierda
rot_izqPD:
    out PORTB,  r21
    out PORTD,  r16
    ldi r17, 0x00
    LSL r16
    cp  r16,    r17
    breq    rot_izqPB
    reti

//Rotacion hacia la izquierda
rot_izqPB:
    out PORTB,  r20
    LSL r20
    ldi r17, 0x10
    cp r20, r17
    breq    reset
    reti

//Rotacion hacia la derecha
rot_derPB:
    out PORTB,  r18
    ldi r17, 0x00
    cp r18, r17
    breq rot_derPD
    LSR r18
    reti

//Rotacion hacia la derecha
rot_derPD:
    out PORTB,  r21
    out PORTD,  r19
    cp  r19,    r21
    breq reset
    LSR r19
    reti

TIM0_OVF_ISR:
    in  r24,    PINC    ;Se guarda el valor del puerto C en R24
    andi r24,   0x01    ;Se enmascara el puerto C
    cp  r24,    r25     ;Se compara con 0x01 para ver su estado
    breq    rot_derPB   ;Si esta encendido, rota a la derecha
    rcall   rot_izqPD   ;Si esta apagado rota a la izquierda
    reti

您正在尝试使用中断例程,并轮询中断标志。你应该只做其中一个。我建议使用中断程序

(此外,您试图轮询错误的标志。
brvs
测试算术运算中的溢出标志。计时器溢出标志是其他标志。)

您可以跳转到中断表
.org 0x0020 jmp TIM0_OVF_ISR
中正确位置的例程。您可以在main中启用中断。乍一看,我觉得这没问题

当中断发生时,下一条指令(PC)的地址被推送到堆栈上,中断标志被清除,中断被禁用,控制流跳转到表中的地址

但是你永远不会从中断中回来。在例程结束时,您应该调用
reti
。这将导致流返回到中断时的位置,方法是弹出堆栈中的地址,然后再次启用中断。您不应该在中断例程中进入一个繁忙的循环,就像在这个程序的底部一样

程序的结构应该更像

.include "m328pdef.inc"
.org 0x0000 jmp main
.org 0x0020 jmp TIM0_OVF_ISR

main: 
    Configure all the ports and timer and interrupts.
    sei
wait:
    rjmp wait

TIM0_OVF_ISR: 
    Do the routine
    reti
还请注意,代码中目前不需要某些rjmp指令

rot_izqPD:
    ldi r16, 0x01
    rjmp rot_izqPD1   ;;; not needed. This is the next instruction anyway.

rot_izqPD1:
    out PORTD, r16
编辑:使用子例程

如果要为旋转调用子程序,可以
调用它们,只要它们以
ret
结尾即可。在任何地方使用
rjmp
都非常糟糕,这会给你带来麻烦

.include "m328pdef.inc"
.org 0x0000 jmp main
.org 0x0020 jmp TIM0_OVF_ISR

main: 
    Configure and initialize all the ports and timer and interrupts.
    call rot_derPB   ;; called the subroutine from main. flow returns here.
    sei
wait:
    rjmp wait

rot_derPB:
    do the rotation
    ret

TIM0_OVF_ISR: 
    Do the routine. e.g.,
    call rot_derPB   ;; called the subroutine in the handler. flow returns here.
    reti
编辑2:if/else分支

if/else分支的一个常见技巧是向前跳过“if”子句,然后首先运行“else”子句。例如,代替

/Cargando a R16 con 0x01 para comenzar la rotacion hacia la izquierda
TIM0_OVF_ISR:
    in r24, PINC    ;Se guarda el valor del puerto C en R24
    andi r24, 0x01  ;Se enmascara el puerto C
    cpi r24, 0x01   ;Se compara con 0x01 para ver su estado
    breq rot_derPB  ;Si esta encendido, rota a la derecha
    rjmp rot_izqPD  ;Si esta apagado rota a la izquierda
颠倒顺序,将它们写为
call
s。确保以
ret
结束函数

/Cargando a R16 con 0x01 para comenzar la rotacion hacia la izquierda
TIM0_OVF_ISR:
    in r24, PINC    ;Se guarda el valor del puerto C en R24
    andi r24, 0x01  ;Se enmascara el puerto C
    cpi r24, 0x01   ;Se compara con 0x01 para ver su estado
    breq go_derPB
    call rot_izqPD  ;Si esta apagado rota a la izquierda
    bra TIMO_end
go_derPB:   
    call rot_derPB  ;Si esta encendido, rota a la derecha
TIM0_end:
    reti

请注意,这些分支位于同一函数中的位置。要离开该函数,您可以调用另一个函数或从该函数返回。你不想看到的是“意大利面代码”在程序中长距离分支。

嘿,叔叔!请看我刚刚发布的新答案。我按照你的要求修改了一点代码,但仍然没有成功。请检查I Isaac,您应该编辑您的问题,而不是发布答案。但新代码看起来仍然不正确。也许您应该考虑使用<代码>调用< /COD>和 Re> <代码>指令,而不是<代码> RJMP < /代码>。看起来您仍然在进入一个禁用中断的繁忙循环。我认为它只是停留在“等待”循环,每当我要求它从中断返回时,它就会返回到循环。我编辑了答案以添加子例程。看起来你想在main中旋转一次,然后在中断处理程序中旋转一次。我删除了“wait”循环。我可以清楚地看到,中断实际上正在工作。我如何使旋转刚好在计时器溢出时发生?