Страница 1 из 3
Пробема с прерываниями
Добавлено: Пн окт 17, 2016 20:38: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);
}
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 06:27:41
pyzhman
Просимулировал в протеусе. Работает согласно программе. А в реальном устройстве обратите внимание на то, что у кнопок есть дребезг контактов, от которого нужно всегда избавляться.
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 12:31:20
vk_31
pyzhman писал(а):Просимулировал в протеусе. Работает согласно программе. А в реальном устройстве обратите внимание на то, что у кнопок есть дребезг контактов, от которого нужно всегда избавляться.
С дребезгом все равно был бы какой-нибудь результат, тем более что опрос кнопки в цикле работает (решение избавления от дребезга уже есть, только все уперлось в прерывания)
Может кто сталкивался с ошибками в разводке платы при которых не срабатывали прерывания? Есть еще подозрение на китайский МК, но если была бы подделка он не прошивался бы...
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 13:19:47
B@R5uk
Когда ничего не работает, то начинать надо сначала:
1) проверить наличие питания.
2) помигать светодиодом без всяких кнопок (я вместо этого обычно таймер на выход включаю и звук слушаю, за одно можно системную частоту проверить) а то вдруг генератор не завёлся.
3) проверять уже программу, вставляя всевозможные системные выводы в разные места: переключить ножку, отправить введённый с порта байт по USART и так далее.
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 13:37:02
vk_31
B@R5uk писал(а):Когда ничего не работает, то начинать надо сначала:
1) проверить наличие питания.
2) помигать светодиодом без всяких кнопок (я вместо этого обычно таймер на выход включаю и звук слушаю, за одно можно системную частоту проверить) а то вдруг генератор не завёлся.
3) проверять уже программу, вставляя всевозможные системные выводы в разные места: переключить ножку, отправить введённый с порта байт по USART и так далее.
1) питание есть
2) светодиод моргает по таймеру и по нажатию на кнопку если ее опрашивать в цикле программы
3) программу специально упростил для примера
Все работает, таймер тикает, LCD завелся, порты окрашиваются и устанавливаются все кроме этого прерывания.
Уже не знаю где ошибка. Может адрес вектора прерывания МК изменен, а WinAvr со старыми работает? Даташит имеется для ATMega169, а у меня ATMega169pa-au, хотя врят ли это имеет большое значение
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 14:09:22
Vov123
Отключи fuse JTAG.
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 14:19:42
Z_h_e
Тоже такая мысль в голову пришла. Глянул ДШ, он там на порте F висит. Вроде как не при делах.
vk_31, попробуйте прерывание с других пинов запустить. Может стоит глянуть в дезассемблере вектора прерываний

.
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 16:24:10
vk_31
Z_h_e писал(а):Тоже такая мысль в голову пришла. Глянул ДШ, он там на порте F висит. Вроде как не при делах.
vk_31, попробуйте прерывание с других пинов запустить. Может стоит глянуть в дезассемблере вектора прерываний

.
На все портах E одинакова ситуация(
Дизассемблер попробую посмотреть
Re: Пробема с прерываниями
Добавлено: Вт окт 18, 2016 21:03:30
Mishany
Может ноги к vcc резисторами притянуть?
Re: Пробема с прерываниями
Добавлено: Сб ноя 26, 2016 19:22:21
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
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 01:52:06
Vov123
Код: Выделить всё
PCMSK0 = (1<<PCINT3) | (1<<PCINT6); //маска прерываний на порт E
EIFR = (1<<PCIF0);
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 09:18:42
vk_31
Vov123 писал(а):Код: Выделить всё
PCMSK0 = (1<<PCINT3) | (1<<PCINT6); //маска прерываний на порт E
EIFR = (1<<PCIF0);
Не помогло(
У меня был регулятор теплого пола с дисплеем на этом МК и я его прошивал - прерывания срабатывали. А развел свою плату, так все работает кроме прерываний PCINT
Уже грешу на разводку платы, хотя она и не сложная. Плату прилагаю
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 09:47:17
dr.doc
When the BOOTRST Fuse is unprogrammed
0x1C04 jmp PCINT0 ; PCINT0 Handler Читайте внимательно datasheet на странице 48 и 268.
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 12:06:21
vk_31
dr.doc писал(а):When the BOOTRST Fuse is unprogrammed
0x1C04 jmp PCINT0 ; PCINT0 Handler Читайте внимательно datasheet на странице 48 и 268.
Запрограммировал BOOTRST Fuse, HIGH Fuse стал 0xD8, ситуация не изменилась. Или я Вас неправильно понял?
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 12:54:32
dr.doc
По умолчанию BOOTRST - unprogrammed. При этом вектор прерываний от EXT_INT0 начинается с адреса 0x1C04. В случае запрограммированного fuse BOOTRST вектор прерываний от EXT_INT0 смещается на адрес 0x0004. По fuse должно работать.
Добавлено after 21 minute 26 seconds:
Возможно, но не факт - от четного числа импульсов дребезга процедура ИСКЛЮЧАЮЩЕЕ ИЛИ для выводов может возвращать состояние выхода на исходное. В то же время работа при опросе в цикле выполняется несколько иначе (прерывания срабатывают по спаду сигнала на входе). Тонкий момент тут - наличие четного числа импульсов дребезга.
Выполните тест, зажигая светодиод при первом же попадании в прерывание. Таким образом проверите их отработку.
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 14:50:02
vk_31
dr.doc писал(а):Выполните тест, зажигая светодиод при первом же попадании в прерывание. Таким образом проверите их отработку.
Вы имеете ввиду сделать так:
Код: Выделить всё
ISR(PCINT0_vect) {
PORTB |= (1<<PB6);
PORTB |= (1<<PB0);
}
Тоже результата нет.
Все больше и больше склоняюсь с тому, что есть ошибки в разводке платы (хоть и не понимаю как это может быть связано), т.к. прерывания на макетке с тем же камнем и фьюзами работают...
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 14:53:06
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
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 16:55:53
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 - нет
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 17:02:13
dr.doc
Верно, ошибся. Но! Поигравшись в студии на Асьме нашел, что бит PCIE0 записывается в регистр только командой out. Команда sts не записывает бит в студии! Попробуйте сделать ассемблерную вставку
Спойлер
ldi r16,(1<<PCIE0)
;sts EIMSK,r16
out EIMSK,r16
Re: Пробема с прерываниями
Добавлено: Вс ноя 27, 2016 17:19:07
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>