创建简单的TCNT0程序ATMEGA 328 P-PU

时间:2017-09-17 11:37:30

标签: atmega

我的初学者程序出现问题,我的初学者程序为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

1 个答案:

答案 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