Перейти к содержанию

Неправильно Работает Программа


Рекомендуемые сообщения

Пробую обрабатывать на контроллере прирывания по таймеру и по порту B (interrupt on change). Суть проблемы в том, что почему-то нажатие на одной из кнопки обрабатывается не корректно. При генерации прерывания на порту RB5 должен меняться уровень порта RA1, но вместе с этим два раза меняется уровень порта RA0, хотя не должен. Код программы ниже. Скриншот схемы в приложении. Сам проект в MPLAB X и ISIS в архиве в приложении, в нем же видео демонстрирующее проблему.

Суть программы в том, что таймер настроен на 1мс (1024мкс) и прерывание обработки таймера дикриментирует переменную COUNTER и если она равна 0, меняет уровень светодиода на порту RA3, таким образом он моргает примерно раз в четверть секунды. Уровни светодиодов RA0 и RA1 меняются только по нажатию на кнопки.

list p=16f84a
#include "P16F84A.INC"
__config _CP_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC

_work equ h'4E'
_status equ h'4F'
COUNTER equ h'0C' ; Счетчик

; Вектор сброса контроллера ----------------------------------------------------
org 000 ; При старте контроллера (адрес программы 000)
goto MAIN ; перейти к метке MAIN

; Вектор прерывания ------------------------------------------------------------
org 004 ; При возникновении прерывания (переход к адресу 004)
goto IRQ_PROCESS ; перейти к метке IRQ_PROCESS

; Фоновая программа начинается с инициализации ---------------------------------
MAIN
bsf INTCON, GIE ; Разрешаем прерывания
bsf INTCON, RBIE ; Разрешаем прерывания на портах RB7:RB4

bsf STATUS, RP0 ; Выбираем первый банк памяти

bcf OPTION_REG, T0CS ; Включаем timer0 в режим таймера, а не счетчика
bcf OPTION_REG, PSA ; Связываем предделитель с таймером
bcf OPTION_REG, PS2 ; Конфигурируем предделитель в соответствии
bcf OPTION_REG, PS1 ; с даташитом в 1:4
bsf OPTION_REG, PS0 ; (Биты PS2:PS0 установлены в 001)
movlw b'00000000' ; Конфигурируем все пины порта А
movwf TRISA ; как выходы
movlw b'00110000' ; Порты RB5:RB4 как входы
movwf TRISB

bcf STATUS, RP0 ; Возвращаемся к нулевому банку памяти

bsf INTCON, T0IE ; Включаем прерывание по таймеру

movlw b'00000' ; Выставляем низкий уровень на всех
movwf PORTA ; пинах порта А

; Бесконечный пустой цикл
M_LOOP
nop ; Ничего не делаем
goto M_LOOP

IRQ_PROCESS
; Сохраняем контекст
movwf _work ; Сохраняем рабочий регистр в памяти данных
swapf STATUS, w ; Считываем регистр STATUS в рабочий регистр не меняя флагов
movwf _status ; И сохраняем его из рабочего регистра в память данных

btfsc INTCON, T0IF ; Если прерывание по таймеру
call IRQ_TMR0 ; вызываем обработчик таймера

btfsc INTCON, RBIF ; Если прерывание по порту B
call IRQ_RB ; вызываем обработчик порта B

; Чтобы сбросить бит RBIF обязательно надо вначале прочитать порт B
; Сбрасывать прерывание на порту B надо всегда, оно постоянно почему-то срабатывает
movf PORTB, w ; Сбрасываем флаг внешнего прерывания, чтобы
bcf INTCON, RBIF ; не получился бесконечный цикл

; Восстанавливаем контекст
swapf _status, w ; Сначала восстанавливаем
movwf STATUS ; регистр STATUS
swapf _work, f ; Затем рабочий регистр
swapf _work, w ; не воздействуя на флаги регистра STATUS

retfie ; И возврат из прерывания в программу

IRQ_TMR0
decf COUNTER

btfsc STATUS, Z
call COUNT_OVER

bcf INTCON, T0IF

return

COUNT_OVER
movf PORTA, w ; Считываем порт А в рабочий регистр
xorlw b'01000' ; и по маске изменяем нужный пин
movwf PORTA ; Записываем изменения в порт А

movlw h'FF' ; Инициализируем счетчик
movwf COUNTER

return

IRQ_RB
; В зависимости от порта, на котором возникло прерывания, вызываем
; соответствующую подпрограмму (проверяем по низкому уровню, т.е. нажатие кнопки)
btfss PORTB, RB4
call IRQ_RB4
btfss PORTB, RB5
call IRQ_RB5

IRQ_RB4
movf PORTA, w ; Считываем порт А в рабочий регистр
xorlw b'00001' ; и по маске изменяем нужный пин
movwf PORTA ; Записываем изменения в порт А

return

IRQ_RB5
movf PORTA, w
xorlw b'00010'
movwf PORTA

return

end

pic.rar

post-156072-0-72448900-1352574564_thumb.png

Изменено пользователем metallic
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Вот блин :vava:

Столько времени убить из-за невнимательности :))

П.С. на соседнем форуме мне тут говорят, что не стоит использовать подпрограммы в прерываниях (именно в пиках), а лучше использовать метки и goto, это правда? И с чем это связано?

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Правда. Связанно с ограниченным уровнем стека.

Ну это понятно. У 8-ми битных 8-ми уровневый стек, если не ошибаюсь. Но если учитывать этот момент, больше никаких подводных камней?

Ссылка на комментарий
Поделиться на другие сайты

Ну вот Вы учитывали, да не учли - запнулись о камень :)

Внутри обработчика нет смысла в подобных вызовах, всё можно сделать через goto. Тем более, в Вашем случае :)

Ссылка на комментарий
Поделиться на другие сайты

Вот блин :vava:

Столько времени убить из-за невнимательности :))

это системная ошибка

примите за правило писать сразу начало и конец(возврат) процедуры и только потом тело процедуры

name_proc_1
................
...............
name_proc_1_end    return

это касается и меток к goto

ну и маленькие замечания: дабы компилятор не выдавал кучу 302-х предупреждений

после объявления инклюда добавляем отключение:

list	  p=16f628A		 
#include <p16F628A.inc>   
errorlevel  -302			  ; suppress message 302 from list file

а вот 305 это уже можно считать ошибкой - забыли указать куда записывать результат декремента....

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...