Пробема с прерываниями

Обсуждаем контроллеры компании Atmel.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Пробема с прерываниями

Сообщение vk_31 »

Добрый вечер!
Прошу помощи в решении проблемы. Имеется контроллер ATmega169pa-au. PORTE настроен на вход и подтянут резисторами внутри контроллера. На PE3 и PE6 подключена кнопка замыкающая на землю. PORTB настроен на выход и на PB6 повешен светодиод. Так же настроены прерывания по PCINT0..7.
Проблема вот в чем: на реальном устройстве не происходит отработка прерывания PCINT0 (кнопка повешена на PE3/PCINT3). При нажатии на кнопку, которая подвешена на PE6 светодиод включается.
Схема устройства упрощена (отсутствует LCD с обвязкой, кварц, ключи на транзисторах и т.д.), но суть проблемы передает.
Изображение
Вот такой код залит в контроллер:

Код: Выделить всё

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


int main (void)
{

   DDRE = 0x00; // Порт E на вход
   PORTE = 0xff; // включаем поддтяжки на порте E
   PCMSK0 = 0xff; //маска прерываний на порт E   

   EIMSK |= (1<<PCIE0); // включение прерываний PCINT7..0   
   
   sei();// Разрешаем прерывания глобально.   
   
   DDRB |= (1<<PB0) | (1<<PB6); // Порт B на выход   
   PORTB = 0x00;
   
   while(1) {
      if (!(PINE & (1<<PE6)))
         PORTB |= (1<<PB6);
   };
}


ISR(PCINT0_vect) {   
   PORTB ^= (1<<PB6);
}
Аватара пользователя
pyzhman
Друг Кота
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск
Контактная информация:

Re: Пробема с прерываниями

Сообщение pyzhman »

Просимулировал в протеусе. Работает согласно программе. А в реальном устройстве обратите внимание на то, что у кнопок есть дребезг контактов, от которого нужно всегда избавляться.
Docendo discimus
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

pyzhman писал(а):Просимулировал в протеусе. Работает согласно программе. А в реальном устройстве обратите внимание на то, что у кнопок есть дребезг контактов, от которого нужно всегда избавляться.

С дребезгом все равно был бы какой-нибудь результат, тем более что опрос кнопки в цикле работает (решение избавления от дребезга уже есть, только все уперлось в прерывания)
Может кто сталкивался с ошибками в разводке платы при которых не срабатывали прерывания? Есть еще подозрение на китайский МК, но если была бы подделка он не прошивался бы...
Аватара пользователя
B@R5uk
Собутыльник Кота
Сообщения: 2896
Зарегистрирован: Сб ноя 13, 2010 12:53:25
Откуда: приходит весна?

Re: Пробема с прерываниями

Сообщение B@R5uk »

Когда ничего не работает, то начинать надо сначала:
1) проверить наличие питания.
2) помигать светодиодом без всяких кнопок (я вместо этого обычно таймер на выход включаю и звук слушаю, за одно можно системную частоту проверить) а то вдруг генератор не завёлся.
3) проверять уже программу, вставляя всевозможные системные выводы в разные места: переключить ножку, отправить введённый с порта байт по USART и так далее.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

B@R5uk писал(а):Когда ничего не работает, то начинать надо сначала:
1) проверить наличие питания.
2) помигать светодиодом без всяких кнопок (я вместо этого обычно таймер на выход включаю и звук слушаю, за одно можно системную частоту проверить) а то вдруг генератор не завёлся.
3) проверять уже программу, вставляя всевозможные системные выводы в разные места: переключить ножку, отправить введённый с порта байт по USART и так далее.

1) питание есть
2) светодиод моргает по таймеру и по нажатию на кнопку если ее опрашивать в цикле программы
3) программу специально упростил для примера
Все работает, таймер тикает, LCD завелся, порты окрашиваются и устанавливаются все кроме этого прерывания.
Уже не знаю где ошибка. Может адрес вектора прерывания МК изменен, а WinAvr со старыми работает? Даташит имеется для ATMega169, а у меня ATMega169pa-au, хотя врят ли это имеет большое значение
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Re: Пробема с прерываниями

Сообщение Vov123 »

Отключи fuse JTAG.
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: Пробема с прерываниями

Сообщение Z_h_e »

Тоже такая мысль в голову пришла. Глянул ДШ, он там на порте F висит. Вроде как не при делах.

vk_31, попробуйте прерывание с других пинов запустить. Может стоит глянуть в дезассемблере вектора прерываний :dont_know: .
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

Z_h_e писал(а):Тоже такая мысль в голову пришла. Глянул ДШ, он там на порте F висит. Вроде как не при делах.

vk_31, попробуйте прерывание с других пинов запустить. Может стоит глянуть в дезассемблере вектора прерываний :dont_know: .


На все портах E одинакова ситуация(
Дизассемблер попробую посмотреть
Аватара пользователя
Mishany
Электрический кот
Сообщения: 1031
Зарегистрирован: Чт июн 20, 2013 00:00:58
Откуда: москва, м.Сходненская

Re: Пробема с прерываниями

Сообщение Mishany »

Может ноги к vcc резисторами притянуть?
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

Долго не отвечал, т.к. ждал новый камень

Vov123 писал(а):Отключи fuse JTAG.

Отключил, без изменений все.

Сейчас такой код залит в МК:

Код: Выделить всё

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

int main (void)
{

   DDRB |= (1<<PB0) | (1<<PB6); // Порт B на выход   
   PORTB = 0x00;

   DDRE &= ~((1<<PE3) | (1<<PE6)); // Порт E на вход
   PORTE |= (1<<PE3) | (1<<PE6); // включаем подтяжки на порте E

   EIMSK = (1<<PCIE0); // включение прерываний PCINT7..0   

   PCMSK0 |= (1<<PE3) | (1<<PE6); //маска прерываний на порт E
   
   sei();// Разрешаем прерывания глобально.   
   
   
   while(1) {
      if (!(PINE & (1<<PE6)))
         PORTB ^= (1<<PB6);
         
      //if (!(PINE & (1<<PE3)))
         //PORTB ^= (1<<PB0);

   };
}


ISR(PCINT0_vect) {   
   PORTB ^= (1<<PB6);
   PORTB ^= (1<<PB0);
}


На PE3 и PE6 висят кнопки, а на PB0 и PB6 светодиоды. При опросе в цикле все работает, на прерываниях - нет.

Фьюзы такие:
LOW: 0x62
HIGH: 0xD9
EXTENDED: 0xFF

Lock Bits: 0x3F
Vov123
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Re: Пробема с прерываниями

Сообщение Vov123 »

Код: Выделить всё

PCMSK0 = (1<<PCINT3) | (1<<PCINT6); //маска прерываний на порт E
EIFR = (1<<PCIF0);
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

Vov123 писал(а):

Код: Выделить всё

PCMSK0 = (1<<PCINT3) | (1<<PCINT6); //маска прерываний на порт E
EIFR = (1<<PCIF0);

Не помогло(

У меня был регулятор теплого пола с дисплеем на этом МК и я его прошивал - прерывания срабатывали. А развел свою плату, так все работает кроме прерываний PCINT

Уже грешу на разводку платы, хотя она и не сложная. Плату прилагаю
Вложения
SS.lay6
Печатная плата
(116.74 КБ) 292 скачивания
Аватара пользователя
dr.doc
Это не хвост, это антенна
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Re: Пробема с прерываниями

Сообщение dr.doc »

When the BOOTRST Fuse is unprogrammed
0x1C04 jmp PCINT0 ; PCINT0 Handler Читайте внимательно datasheet на странице 48 и 268.
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

dr.doc писал(а):When the BOOTRST Fuse is unprogrammed
0x1C04 jmp PCINT0 ; PCINT0 Handler Читайте внимательно datasheet на странице 48 и 268.

Запрограммировал BOOTRST Fuse, HIGH Fuse стал 0xD8, ситуация не изменилась. Или я Вас неправильно понял?
Аватара пользователя
dr.doc
Это не хвост, это антенна
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Re: Пробема с прерываниями

Сообщение dr.doc »

По умолчанию BOOTRST - unprogrammed. При этом вектор прерываний от EXT_INT0 начинается с адреса 0x1C04. В случае запрограммированного fuse BOOTRST вектор прерываний от EXT_INT0 смещается на адрес 0x0004. По fuse должно работать.

Добавлено after 21 minute 26 seconds:
Возможно, но не факт - от четного числа импульсов дребезга процедура ИСКЛЮЧАЮЩЕЕ ИЛИ для выводов может возвращать состояние выхода на исходное. В то же время работа при опросе в цикле выполняется несколько иначе (прерывания срабатывают по спаду сигнала на входе). Тонкий момент тут - наличие четного числа импульсов дребезга.
Выполните тест, зажигая светодиод при первом же попадании в прерывание. Таким образом проверите их отработку.
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

dr.doc писал(а):Выполните тест, зажигая светодиод при первом же попадании в прерывание. Таким образом проверите их отработку.

Вы имеете ввиду сделать так:

Код: Выделить всё

ISR(PCINT0_vect) {   
   PORTB |= (1<<PB6);
   PORTB |= (1<<PB0);
}

Тоже результата нет.

Все больше и больше склоняюсь с тому, что есть ошибки в разводке платы (хоть и не понимаю как это может быть связано), т.к. прерывания на макетке с тем же камнем и фьюзами работают...
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Пробема с прерываниями

Сообщение akl »

dr.doc писал(а):По умолчанию BOOTRST - unprogrammed. При этом вектор прерываний от EXT_INT0 начинается с адреса 0x1C04. В случае запрограммированного fuse BOOTRST вектор прерываний от EXT_INT0 смещается на адрес 0x0004. По fuse должно работать.
Строго наоборот.
Table 111. Boot Reset Fuse(1)
BOOTRST_____________________________Reset Address
___1_______________________Reset Vector = Application Reset (address 0x0000)
___0_______________________Reset Vector = Boot Loader Reset (see Table 113 on page 264)
Note: 1. “1” means unprogrammed, “0” means programmed
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

Добавил прерывания на INT0 и PCINT1 чтобы исключить неправильную адресацию

Код: Выделить всё

EICRA = (1<<ISC00); //Any logical change on INT0 generates an interrupt request.
PCMSK0 = (1<<PCINT3) | (1<<PCINT6); //PE3 и PE6
PCMSK1 = (1<<PCINT13); //PB5

EIMSK = (1<<PCIE0) | (1<<PCIE1) | (1<<INT0);

ISR(PCINT1_vect) {   
   PORTB ^= (1<<PB6);
}

ISR(INT0_vect) {   
   PORTB ^= (1<<PB6);
}

По INT0 прерывание вызывается, по PCINT1 - нет
Аватара пользователя
dr.doc
Это не хвост, это антенна
Сообщения: 1368
Зарегистрирован: Вс мар 28, 2010 12:52:22
Откуда: Беларусь

Re: Пробема с прерываниями

Сообщение dr.doc »

Верно, ошибся. Но! Поигравшись в студии на Асьме нашел, что бит PCIE0 записывается в регистр только командой out. Команда sts не записывает бит в студии! Попробуйте сделать ассемблерную вставку
Спойлерldi r16,(1<<PCIE0)
;sts EIMSK,r16
out EIMSK,r16
«Еще я хотел бы, чтобы наши ученые изобрели какой-то новый источник энергии, чтобы мы на коленях не ползали даже перед нашими братьями, умоляя их и выпрашивая тонну нефти или кубометр газа», — рассказал белорусский президент.
vk_31
Первый раз сказал Мяу!
Сообщения: 37
Зарегистрирован: Чт май 19, 2016 11:22:52

Re: Пробема с прерываниями

Сообщение vk_31 »

dr.doc писал(а):Попробуйте сделать ассемблерную вставку
Спойлерldi r16,(1<<PCIE0)
;sts EIMSK,r16
out EIMSK,r16

Я пишу в WinAVR. Посмотрел его дизассемблер - присвоение идет out'ом

Код: Выделить всё

   EIMSK = (1<<PCIE0) | (1<<PCIE1) | (1<<INT0); // включение прерываний PCINT7..0   
  a6:   81 ec          ldi   r24, 0xC1   ; 193
  a8:   8d bb          out   0x1d, r24   ; 29

Все же сделал вставку, но это не помогло.
С ассемблером на Вы, поэтому выкладываю код
Спойлер

Код: Выделить всё


main.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0c 94 2e 00    jmp   0x5c   ; 0x5c <__ctors_end>
   4:   0c 94 77 00    jmp   0xee   ; 0xee <__vector_1>
   8:   0c 94 59 00    jmp   0xb2   ; 0xb2 <__vector_2>
   c:   0c 94 65 00    jmp   0xca   ; 0xca <__vector_3>
  10:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  14:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  18:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  1c:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  20:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  24:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  28:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  2c:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  30:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  34:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  38:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  3c:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  40:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  44:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  48:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  4c:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  50:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  54:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>
  58:   0c 94 38 00    jmp   0x70   ; 0x70 <__bad_interrupt>

0000005c <__ctors_end>:
  5c:   11 24          eor   r1, r1
  5e:   1f be          out   0x3f, r1   ; 63
  60:   cf ef          ldi   r28, 0xFF   ; 255
  62:   d4 e0          ldi   r29, 0x04   ; 4
  64:   de bf          out   0x3e, r29   ; 62
  66:   cd bf          out   0x3d, r28   ; 61
  68:   0e 94 3a 00    call   0x74   ; 0x74 <main>
  6c:   0c 94 89 00    jmp   0x112   ; 0x112 <_exit>

00000070 <__bad_interrupt>:
  70:   0c 94 00 00    jmp   0   ; 0x0 <__vectors>

00000074 <main>:
#include <avr/interrupt.h>

int main (void)
{

   DDRB |= (1<<PB0) | (1<<PB6); // Порт B на выход   
  74:   84 b1          in   r24, 0x04   ; 4
  76:   81 64          ori   r24, 0x41   ; 65
  78:   84 b9          out   0x04, r24   ; 4
   PORTB &= ~((1<<PB0) | (1<<PB6)); //  0x00;
  7a:   85 b1          in   r24, 0x05   ; 5
  7c:   8e 7b          andi   r24, 0xBE   ; 190
  7e:   85 b9          out   0x05, r24   ; 5
   
   DDRB &= ~(1<<PB5); // Порт B на выход   
  80:   25 98          cbi   0x04, 5   ; 4
   PORTB |= (1<<PB5); //  0x00;
  82:   2d 9a          sbi   0x05, 5   ; 5
   
   DDRD &= ~(1<<PD1); // Порт D на вход
  84:   51 98          cbi   0x0a, 1   ; 10
   PORTD |= (1<<PD1); // включаем подтяжки на порте D
  86:   59 9a          sbi   0x0b, 1   ; 11

   DDRE = 0x00; // Порт E на вход
  88:   1d b8          out   0x0d, r1   ; 13
   PORTE = 0xFF; // включаем подтяжки на порте E
  8a:   9f ef          ldi   r25, 0xFF   ; 255
  8c:   9e b9          out   0x0e, r25   ; 14
   
   EICRA = (1<<ISC00);//Any logical change on INT0 generates an interrupt request.
  8e:   81 e0          ldi   r24, 0x01   ; 1
  90:   80 93 69 00    sts   0x0069, r24
   PCMSK0 = 0xff; //маска прерываний на порт E
  94:   90 93 6b 00    sts   0x006B, r25
   PCMSK1 = (1<<PCINT13); //PB5
  98:   80 e2          ldi   r24, 0x20   ; 32
  9a:   80 93 6c 00    sts   0x006C, r24
   
   EIMSK = (1<<PCIE0) | (1<<PCIE1) | (1<<INT0); // включение прерываний PCINT7..0   
  9e:   81 ec          ldi   r24, 0xC1   ; 193
  a0:   8d bb          out   0x1d, r24   ; 29

   //EIFR = (1<<PCIF0) | (1<<PCIF1) | (1<<INTF0);
   
   sei();// Разрешаем прерывания глобально.   
  a2:   78 94          sei
   
   
   while(1) {
      if (!(PINE & (1<<PE6)))
         PORTB ^= (1<<PB6);
  a4:   90 e4          ldi   r25, 0x40   ; 64
   
   sei();// Разрешаем прерывания глобально.   
   
   
   while(1) {
      if (!(PINE & (1<<PE6)))
  a6:   66 99          sbic   0x0c, 6   ; 12
  a8:   fe cf          rjmp   .-4         ; 0xa6 <main+0x32>
         PORTB ^= (1<<PB6);
  aa:   85 b1          in   r24, 0x05   ; 5
  ac:   89 27          eor   r24, r25
  ae:   85 b9          out   0x05, r24   ; 5
  b0:   fa cf          rjmp   .-12        ; 0xa6 <main+0x32>

000000b2 <__vector_2>:

   };
}


ISR(PCINT0_vect) {   
  b2:   1f 92          push   r1
  b4:   0f 92          push   r0
  b6:   0f b6          in   r0, 0x3f   ; 63
  b8:   0f 92          push   r0
  ba:   11 24          eor   r1, r1
   PORTB |= (1<<PB6);
  bc:   2e 9a          sbi   0x05, 6   ; 5
   PORTB |= (1<<PB0);
  be:   28 9a          sbi   0x05, 0   ; 5
}
  c0:   0f 90          pop   r0
  c2:   0f be          out   0x3f, r0   ; 63
  c4:   0f 90          pop   r0
  c6:   1f 90          pop   r1
  c8:   18 95          reti

000000ca <__vector_3>:

ISR(PCINT1_vect) {   
  ca:   1f 92          push   r1
  cc:   0f 92          push   r0
  ce:   0f b6          in   r0, 0x3f   ; 63
  d0:   0f 92          push   r0
  d2:   11 24          eor   r1, r1
  d4:   8f 93          push   r24
  d6:   9f 93          push   r25
   PORTB ^= (1<<PB6);
  d8:   85 b1          in   r24, 0x05   ; 5
  da:   90 e4          ldi   r25, 0x40   ; 64
  dc:   89 27          eor   r24, r25
  de:   85 b9          out   0x05, r24   ; 5
}
  e0:   9f 91          pop   r25
  e2:   8f 91          pop   r24
  e4:   0f 90          pop   r0
  e6:   0f be          out   0x3f, r0   ; 63
  e8:   0f 90          pop   r0
  ea:   1f 90          pop   r1
  ec:   18 95          reti

000000ee <__vector_1>:

ISR(INT0_vect) {   
  ee:   1f 92          push   r1
  f0:   0f 92          push   r0
  f2:   0f b6          in   r0, 0x3f   ; 63
  f4:   0f 92          push   r0
  f6:   11 24          eor   r1, r1
  f8:   8f 93          push   r24
  fa:   9f 93          push   r25
   PORTB ^= (1<<PB6);
  fc:   85 b1          in   r24, 0x05   ; 5
  fe:   90 e4          ldi   r25, 0x40   ; 64
 100:   89 27          eor   r24, r25
 102:   85 b9          out   0x05, r24   ; 5
 104:   9f 91          pop   r25
 106:   8f 91          pop   r24
 108:   0f 90          pop   r0
 10a:   0f be          out   0x3f, r0   ; 63
 10c:   0f 90          pop   r0
 10e:   1f 90          pop   r1
 110:   18 95          reti

00000112 <_exit>:
 112:   f8 94          cli

00000114 <__stop_program>:
 114:   ff cf          rjmp   .-2         ; 0x114 <__stop_program>
Ответить

Вернуться в «AVR»