每次发生定时器溢出中断时,我都试图在汇编中创建一个向左或向右旋转一位的程序。这是我的代码,但由于某种原因它不起作用。我是这个编程大会世界的新人,我希望有人可以帮助我,因为我被卡住了。这是我的代码:
/*
* 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
答案 0 :(得分:0)
您正在尝试使用中断例程,并轮询中断标志。你应该只做其中一个。我建议中断例程。
(另外,你试图轮询错误的标志。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
编辑:使用子程序
如果您想要旋转的子程序,只要它们以call
结尾,您就可以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
注意分支是在同一个函数中的位置。要退出该功能,您可以调用另一个函数或从函数返回。你不想要的是“意大利面条代码”,它通过该程序分散了很长的距离。