Проблема с прерываниями на ATMega328P-PU

Тема в разделе "Микроконтроллеры AVR", создана пользователем Ramirag, 19 фев 2014.

  1. Ramirag

    Ramirag Нерд

    Код пишется в Atmel studio. Плата Arduino UNO c ATMega328P-PU. Заливаю hex файл через XLoader v1.00. Есть две проблемы.
    Первая: Прерывание по PCIE0:2
    Код (Text):
    .cseg
            .org    0

            rjmp    init    ; Reset Handler
            reti            ; IRQ0 Handler
            reti            ; IRQ1 Handler
            rjmp    pci0    ; PCINT0 Handler
            rjmp    pci1    ; PCINT1 Handler
            rjmp    pci2    ; PCINT2 Handler
            reti            ; Watchdog Timer Handler
            reti            ; Timer2 Compare A Handler
            reti            ; Timer2 Compare B Handler
            reti            ; Timer2 Overflow Handler
            reti            ; Timer1 Capture Handler
            reti            ; Timer1 Compare A Handler
            reti            ; Timer1 Compare B Handler
            reti            ; Timer1 Overflow Handler
            reti            ; Timer0 Compare A Handler
            reti            ; Timer0 Compare B Handler
            reti            ; Timer0 Overflow Handler
            reti            ; SPI Transfer Complete Handler
            reti            ; USART, RX Complete Handler
            reti            ; USART, UDR Empty Handler
            reti            ; USART, TX Complete Handler
            reti            ; ADC Conversion Complete Handler
            reti            ; EEPROM Ready Handler
            reti            ; Analog Comparator Handler
            reti            ; 2-wire Serial Interface Handler
            reti            ; Store Program Memory Ready Handler

    ;-------------------------- Инициализация стека

    init:    ldi        r31, 0x8
            ldi        r30, 0xFF

            out        SPL, r30
            out        SPH, r31

    ;-------------------------- Активация прерываний

            ldi        r16, 1 << PCIE2 | 1 << PCIE1 | 1 << PCIE0
            sts        PCICR, r16

            ldi        r16, 1 << PCINT0
            sts        PCMSK0, r16

            ldi        r16, 1 << PCINT8
            sts        PCMSK1, r16

            ldi        r16, 1 << PCINT16
            sts        PCMSK2, r16

    ;-------------------------- Инициализация портов ВВ

            ldi        r16, 0b11111110
            out        DDRB, r16
            out        DDRC, r16
            out        DDRD, r16

            ldi        r16, 0b11111111
            out        PORTB, r16
            out        PORTC, r16
            out        PORTD, r16

            ldi        r16, 0b00000001

            sei
    main:
            rjmp    main

    pci0:    out        PORTB, r16
            reti

    pci1:    out        PORTC, r16
            reti

    pci2:    out        PORTD, r16
            reti
    Регистры DDRB0, DDRC0, DDRD0 настроены на ввод, а так-же на генерацию прерывания при изменении сигнала. Все остальные на вывод.
    Прерывание должно менять выходное значение на порту и зажигать диоды, но оно не происходит.

    Вторая: Прерывание по INT0:1
    Код (Text):
           
    .cseg  
            .org    0  

            rjmp    init    ; Reset Handler
            rjmp    irq0    ; IRQ0 Handler
            rjmp    irq1    ; IRQ1 Handler
            reti            ; PCINT0 Handler
            reti            ; PCINT1 Handler
            reti            ; PCINT2 Handler
            reti            ; Watchdog Timer Handler
            reti            ; Timer2 Compare A Handler
            reti            ; Timer2 Compare B Handler
            reti            ; Timer2 Overflow Handler
            reti            ; Timer1 Capture Handler
            reti            ; Timer1 Compare A Handler
            reti            ; Timer1 Compare B Handler
            reti            ; Timer1 Overflow Handler
            reti            ; Timer0 Compare A Handler
            reti            ; Timer0 Compare B Handler
            reti            ; Timer0 Overflow Handler
            reti            ; SPI Transfer Complete Handler
            reti            ; USART, RX Complete Handler
            reti            ; USART, UDR Empty Handler
            reti            ; USART, TX Complete Handler
            reti            ; ADC Conversion Complete Handler
            reti            ; EEPROM Ready Handler
            reti            ; Analog Comparator Handler
            reti            ; 2-wire Serial Interface Handler
            reti            ; Store Program Memory Ready Handler

    ;-------------------------- Инициализация стека

    init:    ldi        r31, 0x8
            ldi        r30, 0xFF

            out        SPL, r30
            out        SPH, r31

    ;-------------------------- Активация прерываний

            ldi        r16, 1 << INT1 | 1 << INT0
            out        EIMSK, r16

            ldi        r16, 0 << ISC11 | 0 << ISC10 | 0 << ISC01 | 0 << ISC00
            sts        EICRA, r16

    ;-------------------------- Инициализация портов ВВ

            ldi        r16, 0b11110011
            out        DDRB, r16
            out        DDRD, r16

            ldi        r16, 0b11111111
            out        PORTB, r16
            out        PORTD, r16

            sei
    main:
            rjmp    main

    irq0:    ldi        r16, 0b11111110
            out        PORTB, r16
            reti

    irq1:    ldi        r17, 0b11111101
            out        PORTB, r17
            reti
     
    Регистры DDRD2:3 настроены на ввод, а так-же на генерацию прерывания при низком уровне. DDRB0:1 на вывод.
    Прерывание по INT0 у меня вызывает не irq0, а irq1.
    Дальше методом тыка я узнал, что INT1 у меня вызовет irq0, если я напишу так:
    Код (Text):
            rjmp    init    ; Reset Handler
            reti            ; IRQ0 Handler
            rjmp    irq0    ; IRQ1 Handler
            reti            ; PCINT0 Handler
            rjmp    irq1    ; PCINT1 Handler
            reti            ; PCINT2 Handler
    Я совсем ничего не понимаю, тк в даташите по другому расписана таблица прерываний.
     
  2. Ramirag

    Ramirag Нерд

    Проблема решена. Оказалось, что есть опечатка в datasheet. По данному коду, можно видеть, что на каждое прерывание у меня есть по два байта.
    Код (Text):
    0x0000 jmp RESET ; Reset Handler
    0x0002 jmp EXT_INT0 ; IRQ0 Handler
    0x0004 jmp EXT_INT1 ; IRQ1 Handler
    0x0006 jmp PCINT0 ; PCINT0 Handler
    Только вот команда jmp занимает не 2, а 4 байта. В своей программе я использовал rjmp, который занимает 2 байта и как результат у меня вызывались не те прерывания, что должны были. Те выходит, что на самом деле таблица прерываний для моего мк будет выглядеть так.

    Код (Text):
    0x0000 jmp RESET ; Reset Handler
    0x0004 jmp EXT_INT0 ; IRQ0 Handler
    0x0008 jmp EXT_INT1 ; IRQ1 Handler
    0x000В jmp PCINT0 ; PCINT0 Handler
     
    acos и Megakoteyka нравится это.
  3. Ramirag

    Ramirag Нерд

    Узнал еще одну вещь, спасибо AlexPM с easyelectronics.ru Так что это от не знания, а не ошибка в datasheet
    http://forum.easyelectronics.ru/viewtopic.php?f=4&t=17994&p=320176#p320176
     
  4. Airbus

    Airbus Радиохулиган Модератор

    Здорово!А смысл такие программы на Асме писать?Я понял если бы для тини12 или Тини13 а для Меги.....
     
  5. Ramirag

    Ramirag Нерд

    Для того что бы лучше понимать, как оно все работает. Это поможет тебе исправить непонятные баги. Они могут быть вызваны компилятором к примеру, вроде в С коде все написано нормально, а прога почему-то не работает как надо. Или к примеру к трудоемком участке кода, написать все через асм и получить хороший такой буст.
    Вот прочти статью DI HALT о бесполезности знания асма, человек не знающий асм такую проблему не найдет и не решит. http://easyelectronics.ru/avr-uchebnyj-kurs-programmirovanie-na-si-atomarnye-operacii.html
     
  6. Airbus

    Airbus Радиохулиган Модератор

    DI HALT так никогда не считал.Если программа крохотная типа помигать светодиодом или даже работа с USART то асм если большая и сложная то однозначно Си
     
  7. Ramirag

    Ramirag Нерд

    Ты сарказм не уловил:) И прочти еще раз, что я написал.