我的初学者程序出现问题,我的初学者程序为Arduino + ATMEGA 328 P-PU,CTC模式下为tcnt0,我使用OCR0A的溢出来产生一些可见的延迟。看起来,计数器正在以某种方式工作,因为OC0A点亮,但是由TOV0或OCF0A引起的延迟不起作用,因为“适当的二极管点亮”。你能帮我在程序中找到错误吗?谢谢大家的帮助!
顺便问一下:你知道Linux下有一些好的和经过验证的debuger吗?有错误的程序:
; TCCR0 registers addresses
.equ tccr0a, 0x44
.equ tccr0b, 0x45
.equ tcnt0, 0x46
.equ ocr0a, 0x47
.equ ocr0b, 0x48
.equ tifr0, 0x35
.equ timsk0, 0x6E
.equ io_tccr0a, 0x24
.equ io_tccr0b, 0x25
.equ io_tcnt0, 0x26
.equ io_ocr0a, 0x27
.equ io_ocr0b, 0x28
.equ io_tifr0, 0x15
; PORT registers addresses
.equ pinb, 0x23
.equ io_pinb, 0x3
.equ ddrb, 0x24
.equ io_ddrb, 0x4
.equ portb, 0x25
.equ io_portb, 0x5
.equ pinc, 0x26
.equ io_pinc, 0x6
.equ ddrc, 0x27
.equ io_ddrc, 0x7
.equ portc, 0x28
.equ io_portc, 0x8
.equ pind, 0x29
.equ io_pind, 0x9
.equ ddrd, 0x2A
.equ io_ddrd, 0xA
.equ portd, 0x2B
.equ io_portd, 0xB
; SREG and STACK registers addresses
.equ sreg, 0x5F
.equ io_sreg, 0x3F
.equ sph, 0x5E
.equ io_sph, 0x3E
.equ spl, 0x5D
.equ io_spl, 0x3D
; Constants
.equ RAMEND, 0x8FF ; End of SRAM for ATMEGA328P
.equ MILIS_VALUE, 0x7C ; EDIT: FUCK THE TIME, TCNT0 HAS NO 128 PRESCALER, PRESCALER WILL BE 1024 JUST BECAUSE I WANT PREVIOUS COMMENT HAS NO MEANING NOW ---> ; Time in milisecond counted for 16MHz with 128 prescaler
.org 0 ; RESTART interupt vector
rjmp INITIALIZATION ; Go to the start of the program
.org 0x1C ; TOV0 interupt vector
rjmp DELAY ; Create visible delay from counter interval
.org 0x34 ; Start the program right behind interupt vector table
INITIALIZATION:
ldi r16, hi8(RAMEND) ; High 8 bit value for SPH
out io_sph, r16 ; Store SPH value to SRAM
ldi r16, lo8(RAMEND) ; Low 8 bit value for SPL
out io_spl, r16 ; Store SPL value to SRAM
clr r16 ; R16 = 0
out io_sreg, r16 ; SREG = 0
ldi r16, 0xF0 ; Only high nibble is set
out io_ddrc, r16 ; High nibble in PORTB is set as output because of possibility to check possible error with ease
ldi r16, 0xF0 ; Byte for Output
out io_ddrd, r16 ; Pin OC0A and other pins (PORTD.7-4 included) is set as output
rcall TOOGLE_LED ; Inicialization LED and delay register(s) to the start condition
TCNT_INIT: ; TCNT0 Initialization - not used label
clr r16 ; Prepare value for counter stop, no FOC, third mode bit WGM2 is 0
out io_tccr0b, r16 ; Stop counter
out io_tcnt0, r16 ; Counting register = 0
ldi r16, 0x42 ; Set OC0A to toogle and CTC mode for TCNT0
out io_tccr0a, r16 ; Set control register a for timer 0
ldi r16, 0x1 ; Interupt on TOV0
sts timsk0, r16 ; Enable overflow interupt
ldi r16, MILIS_VALUE ; Count number for 125 count cycles
out io_ocr0a, r16 ; Set top value for counter 0
sei ; Enable ingerupts globaly
out io_tccr0b, 0x05 ; Set divisor to 1024, counter is running now!
MAIN_LOOP:
rjmp MAIN_LOOP ; Infinite loop because of getting interupt from TCNT0
DELAY: ; TOV0 interupt subroutine
in r20, io_sreg
clr r21
out io_sreg, R21
inc r18
cpi r18, 100
brlt END_DELAY
out io_sreg, R21
clr r18
inc r17
cpi r17, 100
brlt END_DELAY
out io_sreg, R21
clr r17
inc r19
cpi r19, 1
brlt END_DELAY
rcall TOOGLE_LED
out io_sreg, r20
END_DELAY:
reti
TOOGLE_LED:
ldi r17, 0x8 ; The highest bit of the lowest nibble is set for xor mask
in r16, io_portc ; Get actual value of port B
eor r16, r17 ; Toogle the highest pin of port B
out io_portc, r16 ; write changed value to the port B
clr r17 ; R17 = 0 <--- register is used for delay so it must be reseted
clr r18 ; R18 = 0 <--- register is used for delay so it must be reseted
clr r19 ; R19 = 0 <--- register is used for delay so it must be reseted
ret
答案 0 :(得分:0)
我会成为高级程序员,然后有人会在这里给予帮助。 ; - )
代码中有几个错误。
1)我不应该使用TOV0中断,但是我必须在TCNT_INIT部分设置OCIE0A,因此使用适当的中断向量(我在错误的代码中做了部分,因为我已经测试了两者,正如你从旧评论中看到的那样)。
2)在TCNT_INIT序列结束时,我尝试在CTC模式下运行计数器。这绝对是错误的,因为我把值放到了位置,寄存器的地址应该是。因为0x5是寄存器的值,所以它是sucesfuly编译的。
3)最卑鄙的错误 - 中断向量。我直接从数据表中复制它们,所以我想,它们绝对是正确的。然而,在一些寻找代码示例之后,我看到了非常不同的数字作为中断向量。麻烦的是,在数据表中显示的是中断向量的信息,但是闪点的两个地址到两个字节,数据表中的矢量地址必须由两个用于组合器的数据加倍。
应该工作的代码包含在下面。错误应该是固定的。此外,几行可以删除,因为它们用于测试。
度过愉快的一天。
; TCCR0 registers addresses
.equ tccr0a, 0x44
.equ tccr0b, 0x45
.equ tcnt0, 0x46
.equ ocr0a, 0x47
.equ ocr0b, 0x48
.equ tifr0, 0x35
.equ timsk0, 0x6E
.equ io_tccr0a, 0x24
.equ io_tccr0b, 0x25
.equ io_tcnt0, 0x26
.equ io_ocr0a, 0x27
.equ io_ocr0b, 0x28
.equ io_tifr0, 0x15
; PORT registers addresses
.equ pinb, 0x23
.equ io_pinb, 0x3
.equ ddrb, 0x24
.equ io_ddrb, 0x4
.equ portb, 0x25
.equ io_portb, 0x5
.equ pinc, 0x26
.equ io_pinc, 0x6
.equ ddrc, 0x27
.equ io_ddrc, 0x7
.equ portc, 0x28
.equ io_portc, 0x8
.equ pind, 0x29
.equ io_pind, 0x9
.equ ddrd, 0x2A
.equ io_ddrd, 0xA
.equ portd, 0x2B
.equ io_portd, 0xB
; SREG and STACK registers addresses
.equ sreg, 0x5F
.equ io_sreg, 0x3F
.equ sph, 0x5E
.equ io_sph, 0x3E
.equ spl, 0x5D
.equ io_spl, 0x3D
.equ mcucr, 0x55
.equ io_mcucr, 0x35
; Constants
.equ RAMEND, 0x8FF ; End of SRAM for ATMEGA328P
.equ MILIS_VALUE, 0x7C ; EDIT: FUCK THE TIME, TCNT0 HAS NO 128 PRESCALER, PRESCALER WILL BE 1024 JUST BECAUSE I WANT PREVIOUS COMMENT HAS NO MEANING NOW ---> ; Time in milisecond counted for 16MHz with 128 prescaler
.org 0 ; RESTART interupt vector
jmp INITIALIZATION ; Go to the start of the program
.org 0x38 ; OCF0A interupt vector <--- IT LOOKS, THAT ADDRESSES FROM DATASHEET MUST BE DOUBLED BECAUSE OF CALL INSTRUCTION! SEE /usr/lib/avr/include/avr/iom328p.h ,io.h AND OTHER INCLUDE FILES! THIS INFORMATION MUST BE VERIFIED!
jmp DELAY ; Create visible delay from counter interval
.org 0x68 ; Start the program right behind interupt vector table
INITIALIZATION:
ldi r16, hi8(RAMEND) ; High 8 bit value for SPH
out io_sph, r16 ; Store SPH value to SRAM
ldi r16, lo8(RAMEND) ; Low 8 bit value for SPL
out io_spl, r16 ; Store SPL value to SRAM
clr r16 ; R16 = 0
out io_sreg, r16 ; SREG = 0
out io_mcucr, r16 ; MCUCR = 0
ldi r16, 0xFF ; Only high nibble is set
out io_ddrc, r16 ; High nibble in PORTB is set as output because of possibility to check possible error with ease
ldi r16, 0xF0 ; Byte for Output
out io_ddrd, r16 ; Pin OC0A and other pins (PORTD.7-4 included) is set as output
rcall DELAY_INIT ; Inicialization of DELAY subroutine
TCNT_INIT: ; TCNT0 Initialization - not used label
clr r16 ; Prepare value for counter stop, no FOC, third mode bit WGM2 is 0
out io_tccr0b, r16 ; Stop counter
out io_tcnt0, r16 ; Counting register = 0
ldi r16, 0x42 ; Set OC0A to toogle and CTC mode for TCNT0
out io_tccr0a, r16 ; Set control register a for timer 0
ldi r16, 0x2 ; Interupt on OCIE0A
sts timsk0, r16 ; Enable overflow created by OCR0A interupt
ldi r16, MILIS_VALUE ; Count number for 125 count cycles
out io_ocr0a, r16 ; Set top value for counter 0
sei ; Enable global interupts
ldi r16, 0x05
out io_tccr0b, r16 ; Set divisor to 1024, counter is running now! <<<-------THERE WAS ANOTHER MISTAKE!!!!
; in r16, io_sreg ; TEST ONLY !!!! SREG test, control of enabling interupts
; out io_portd, r16 ; TEST ONLY !!!! SREG test, control of enabling interupts
; sbi io_portc, 0 ; TEST ONLY !!!! Test of signal that DELAY subroutine was activated.
MAIN_LOOP:
rjmp MAIN_LOOP ; Infinite loop because of getting interupt from TCNT0
DELAY: ; TOV0 interupt subroutine
in r20, io_sreg
sbi io_portc, 0 ; Tell me, that this interupt was working one times at minimum!
clr r21
out io_sreg, R21
inc r18
cpi r18, 100
brlt END_DELAY
out io_sreg, R21
clr r18
inc r17
cpi r17, 1
brlt END_DELAY
out io_sreg, R21
clr r17
inc r19
cpi r19, 1
brlt END_DELAY
rcall TOOGLE_LED
out io_sreg, r20
END_DELAY:
reti
TOOGLE_LED:
ldi r17, 0x8 ; The highest bit of the lowest nibble is set for xor mask
in r16, io_portc ; Get actual value of port B
eor r16, r17 ; Toogle the highest pin of port B
out io_portc, r16 ; write changed value to the port B
DELAY_INIT:
clr r17 ; R17 = 0 <--- register is used for delay so it must be reseted
clr r18 ; R18 = 0 <--- register is used for delay so it must be reseted
clr r19 ; R19 = 0 <--- register is used for delay so it must be reseted
ret