Не получается работа с прерыванием PCINT1 у Atmega162

Обсуждаем контроллеры компании Atmel.
Ответить
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Добрый день!

Учусь работать с AVR, сейчас пробую работу с прерыванием PCINT1 у Atmega162.
Код на С, пишу в CVAVR 1.25.9, проверяю в VMLAB.

В VMLAB подключаю клавиатуру 4*4 к порту С, LCD экран к порту А.
Когда нажимаю кнопку на клавиатуре - не срабатывает прерывание, хотя по осцилографу происходит смена 1 на 0 на пине порта С.

Помогите понять - в чем проблема? Даташит читал-ковырял, но проблему не нашел.

Спасибо заранее!

ПС самой программы нет, сейчас пытаюсь разобраться с этим прерыванием, программу допишу
ППС сознательно скопипастил весь код, который сгенерировал CVAVR... знаю, что он большой, но боюсь упустить что-то важное. Извиняюсь за некий оверквотинг.

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


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.9 Standard
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 19.12.2014
Author  : F4CG                           
Company : F4CG                           
Comments:


Chip type           : ATmega162
Program type        : Application
Clock frequency     : 4,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/

#include <mega162.h>
#include <stdio.h>
#include <delay.h>
#include <ctype.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>

int test, cnt0;


// Pin change 8-15 interrupt service routine
interrupt [PCINT1] void pin_change_isr1(void)
 
  {
   switch (cnt0)
   
    {
     case 0:
      test++;   
      PORTC ^= 0xFF;
      DDRC ^= 0xFF;
      cnt0++;
      break;
   
     case 1:
      cnt0--;
      break;
    }
   
  }
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here

}

// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here

}

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 100
char rx_buffer0[RX_BUFFER_SIZE0];

#if RX_BUFFER_SIZE0<256
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
#else
unsigned int rx_wr_index0,rx_rd_index0,rx_counter0;
#endif

// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;

// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer0[rx_wr_index0]=data;
   if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
   if (++rx_counter0 == RX_BUFFER_SIZE0)
      {
      rx_counter0=0;
      rx_buffer_overflow0=1;
      };
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0[rx_rd_index0];
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm("cli")
--rx_counter0;
#asm("sei")
return data;
}
#pragma used-
#endif



// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0b11110000;
DDRC=0b00001111;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Port E initialization
// Func2=In Func1=In Func0=In
// State2=T State1=T State0=T
PORTE=0x00;
DDRE=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// Timer/Counter 3 initialization
// Clock value: Timer 3 Stopped
// Mode: Normal top=FFFFh
// Noise Canceler: Off
// Input Capture on Falling Edge
// OC3A output: Discon.
// OC3B output: Discon.
// Timer 3 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR3A=0x00;
TCCR3B=0x00;
TCNT3H=0x00;
TCNT3L=0x00;
ICR3H=0x00;
ICR3L=0x00;
OCR3AH=0x00;
OCR3AL=0x00;
OCR3BH=0x00;
OCR3BL=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: On
// INT1 Mode: Falling Edge
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: On
GICR|=0xD0;
PCMSK1=0xFF;
MCUCR=0x0A;
EMCUCR=0x00;
GIFR=0xD0;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;
ETIMSK=0x00;

// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud Rate: 9600
UCSR0A=0x00;
UCSR0B=0x98;
UCSR0C=0x86;
UBRR0H=0x00;
UBRR0L=0x19;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
 
 
  /*
//
// LCD module initialization
//   

printf("LCD init ...\n");
lcd_init(16);
printf("LCD init complete!");
printf("\n");
 
*/

// Global enable interrupts
#asm("sei")

test = 0;
while (1)

      {
     
/*       lcd_gotoxy(1,0);
       f_sprintf(test);
*/       
      };
}


Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

При инициализации в main у вас присутствует вот эта строка:

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

PCMSK1=0xFF;

Этот регистр определяет какие выводы 1-й группы прерываний будут использоваться для генерации прерываний. Вы выбрали ВСЕ! Любое изменение любого пина порта C вызовет прерывание. Может прерывание не вызывается, а вызывается только первый раз, т.к. в прерывании вы

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

PORTC ^= 0xFF;
DDRC ^= 0xFF;

вывод кнопки сделали выходом. Так не делают, это как минимум странно...
Короче, для начала в регистре PCMSK1 выберите только пин кнопки, а дальше не делайте пин кнопки выходом
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Спасибо за совет.

Все пины использую, потому что хочу подключить матричную клавиатуру 4*4, но не опрашивать её по таймеру, а считывать по прерыванию.
Переключение в прерывании пока уберу, для начала попробую разобраться как его вызывать... а так была идея сначала проверить, в каком ряду нажата кнопка, потом переключиться и проверить, в каком столбце.
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

eess9 писал(а):вывод кнопки сделали выходом. Так не делают, это как минимум странно...
Короче, для начала в регистре PCMSK1 выберите только пин кнопки, а дальше не делайте пин кнопки выходом


Ммм... На счет изменения статуса кнопок в прерывании - при инициализации у меня 4 пина - входы, 4 пина - выходы. В прерывании этими двумя командами я меняю их местами:

PORTC ^= 0xFF;
DDRC ^= 0xFF;

Т.е. это не присваивание им нового значения, а "исключающее или".
Или я не правильно делаю?

Если было так: PORTC 0b11110000
А после этого сделать: PORTC ^= 0b11111111
Должно получиться: PORTC 0b00001111
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

да, только если у вас, к примеру, кнопка была на PC0 и было DDRC = 0b11111110 и вы сделали в прерывании DDRC ^= 0xFF; то получите DDRC = 0b00000001.
Магическим образом пин станет выходом и его состояние уже будет определяться не состоянием кнопки, а состоянием бита 0 регистра PORTC
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Да, я это понимаю. Так и задумано. При следующем срабатывании прерывания (от другой кнопки), эта кнопка опять активируется.
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Посмортите, пожалуйста, сейчас? Повырезал всё, что посчитал лишним, убрал изменения портов. Включил UART что бы видеть в терминале срабатывание прерывания.
Осциллографи показывает изменение 0 на 1 на PORTC0, прерывания нет.

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

#include <mega162.h>
#include <stdio.h>

interrupt [PCINT1] void pin_change_isr1(void)
  {
   printf("Hello!\n");
  }




void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

 


PORTC=0b11111110;
DDRC=0b00000001;





// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: On
GICR|=0x10;
PCMSK1=0x01;
MCUCR=0x00;
EMCUCR=0x00;
GIFR=0x10;



// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: Off
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud Rate: 9600
UCSR0A=0x00;
UCSR0B=0x08;
UCSR0C=0x86;
UBRR0H=0x00;
UBRR0L=0x19;


   
#asm("sei")
printf("start\n");

while (1)
      {
       };
}


Подключение кнопки в VMLAB:
K0 VSS PC0
R4 VDD PC0 10M


---

Сейчас ввел переменную и в бесконечном цикле разместил строку
k = PORTC.0;
А значение переменной смотрю в окне watch VMLAB-a. Переменная меняется при нажатии кнопки, прерывания не происходит :(
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

Я скажу более, моделирую в протеус и ... прерывания тоже нет. Странно как то, ищем корень проблемы далее.
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

Фьюз JTAGEN отключен?
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

JTAGEN вероятно запрограмирован (0), т.к. это заводская настройка, судя по даташиту.
В VMLAB у меня пока что не получилось его отключить (задать 1)... но вообще в хелпе к VMLAB написано, что на симуляцию влияют только 2 фьюза:

The following fuses have the corresponding effect in the simulation, provided that the micro support them.

· BOOTRST. If set to zero, the reset vector will be moved to the bootload area, according to the datasheets info.

· BOOTSZ, in combination with BOOTRST.

The rest of fuses have no effect in the simulation, but if they are defined, will be transferred as default values to the STK500 interface. This allows to define the right set of fuses for a given application directly in the Project File.



А в Протеуса отключение фьюза помогло?

ПС Протеус очень тяжел в освоении для зеленых новичков?
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

Нет не тяжел.

Фьюз JTAGEN используется для заводской отладки и проверки кристалла (например, для калибровки внутреннего осциллятора на заводе). Если он установлен (как с завода), то вы не управляете выводами PC4 - PC7. Т.е. вы не запустите никогда клавиатуру с этим фьюзом.

В протеусе все работает кроме PC4. По этому пину не генерируется прерывание, остальные 7 пинов работают нормально. Возможно глюк протеуса, т.к. интерфейс внешней памяти выключен, а больше у меня мыслей нет.
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Спасибо за помощь!
Пока попробую подобрать другой МК, а на будущее еще Протеусом займусь.
glaz73
Первый раз сказал Мяу!
Сообщения: 34
Зарегистрирован: Пн дек 01, 2014 23:33:05

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение glaz73 »

Может я что позабыл, но "DDRC=0b00000001;" скажет, что все кроме нулевого входы (нулевой - выход)
"PCMSK1=0x01;" - ловим прерывание на нулевом (на выходе?!?!)
поправьте меня, если я туплю
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение eess9 »

Именно об этом я выше и писал http://radiokot.ru/forum/viewtopic.php?p=2215757#p2215757
glaz73
Первый раз сказал Мяу!
Сообщения: 34
Зарегистрирован: Пн дек 01, 2014 23:33:05

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение glaz73 »

Я про кусок в посте viewtopic.php?p=2215883#p2215883
там не используется побитовая инверсия
Там прямое присванивание
Аватара пользователя
Zont
Родился
Сообщения: 15
Зарегистрирован: Сб дек 20, 2014 11:26:14

Re: Не получается работа с прерыванием PCINT1 у Atmega162

Сообщение Zont »

Пропустил ответы :(
Сейчас уже не вспомню, почему я именно так настраивал пин и прерывания, но... проблему решил :)
Минимально для этого освоил Proteus и там всё написал для Atmega88, там же отладил и даже в жизни всё заработало
Ответить

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