PCINT0, PCINT1, PCINT2 и т. д. на ATtiny45/85

Согласно техническому описанию:

мы могли бы подумать, что если мы хотим иметь прерывание смены контакта для 3 контактов, мы должны создать несколько экземпляров:

ISR(PCINT0_vect){
   ...
}

ISR(PCINT1_vect){
   ...
}

ISR(PCINT2_vect){
   ...
}

void setup(){
  GIMSK = 0b00100000;
  PCMSK = 0b00000111; 
}

Однако это не работает, и я прочитал здесь и здесь мы должны определить только одну функцию прерывания:

ISR(PCINT0_vect){
   if (digitalRead(0) == LOW) 
     ...
   if (digitalRead(1) == LOW) 
     ...
   if (digitalRead(2) == LOW) 
     ...
}

Почему так? Для чего тогда сделан PCINT1, 2, 3, ... в этой схеме распиновки, если нам не нужно его использовать?

, 👍2


3 ответа


Лучший ответ:

3

Вы путаете контакты прерывания смены контакта с векторами прерывания смены контакта. Они очень разные.

Многие контакты прерывания смены контакта связаны только с одним вектором прерывания смены контакта.

Вы используете номер pin (значение, указанное в распиновке), чтобы решить, хотите ли вы, чтобы этот контакт реагировал или нет. Вы используете вектор для ответа на любой из контактов, назначенных этому вектору.

В чипах ATTiny, поскольку существует так мало контактов прерывания по смене контакта (8 или менее), вам нужен только один вектор прерывания по смене контакта для их обработки.

Вы можете узнать, соответствует ли "PCINT4" выводе или вектору по контексту. Если вы видите это на выводе, то это вывод. Если вы видите его в коде с _vect после него, то это вектор.

,

Идеальный ответ, спасибо!, @Basj


1

Вы можете включить/выключить прерывания смены контакта для отдельных контактов, используя регистр маски смены контакта PCMSK.

Имена контактов сопоставляют бит в PCMSK с физическим контактом.

Дополнительную информацию см. в разделе 9.3.4 на стр. 10. 52 в Техническом описании ATtiny85

,

Я сделал это с PCMSK = 0b00000111. Но почему бы нам не использовать PCINT1_vect? В схеме распиновки упоминается «PCINT1», почему бы нам не использовать его?, @Basj

В разделе 9.1 перечислены все доступные векторы прерываний. Прерывания по изменению контакта сгруппированы, чтобы не тратить ресурсы. Только INTx предназначен для одного контакта. Он также намного мощнее, так как его можно запускать по нарастанию или спаду фронта вместо каждого изменения. ATtiny85 имеет только один выделенный контакт с INT0 для этого., @Kwasmich

Я понимаю, что они сгруппированы, чтобы не тратить ресурсы @Kwasmich, но тогда, если все контакты могут быть обработаны только с помощью PCINT0_vect, не является ли это ошибкой в схемах писать PCINT0, PCINT1, ..., PCINT5?, @Basj

Нет, опять же, это для того, чтобы показать вам, какой бит в PCMSK соответствует какому физическому контакту. В противном случае вы бы не знали, какой контакт затронут. Название неоднозначное, конечно., @Kwasmich


4

Это просто разница между внешним прерыванием INTx и прерыванием смены контакта PCINT. Первый — это прерывание для одного вывода. Второй — это прерывание для полной группы выводов. Обычно эта группа представляет собой полный порт. Поскольку Attiny85 имеет только один порт, здесь дело обстоит именно так. Таким образом, вся группа представляет собой только один источник прерывания. Таким образом, он имеет только один вектор прерывания с именем PCINT0_vect.

Прерывание смены контакта срабатывает, когда изменяется любой из контактов, находящихся под его контролем. Вы можете убрать контакты из-под контроля, замаскировав их регистром PCMSK.

Таким образом, вектор прерывания PCINT_vect будет запускаться при каждом изменении на любом из незамаскированных выводов. Вам решать, какой из них изменил свой уровень.


На более крупных микроконтроллерах больше контактов, и в большинстве случаев большинство из них подключены к прерыванию смены контакта. Здесь в основном каждый полный порт подключен к одному прерыванию смены контакта. Таким образом, соответствующие регистры дополнительно помечаются числом (PCINT0_vect как вектор прерывания для первого порта, ...)

,

Итак, на самом деле для ATtiny45 PCINT0_vect работает для всех контактов 0..5? Тогда зачем на схеме распиновки ставить "PCINT1", "PCINT2"? Тогда PCINT0_vect следует называть PCINT_vect0, вы так не думаете? Потому что это «первый» вектор прерываний смены вывода... С таким именем, как PCINTx_vect, мы могли бы подумать, что он относится к выводу x, поскольку схема распиновки показывает PCINTx для каждого вывода x=0..5., @Basj

Я не могу сказать, почему они так назвали их, это известно только Атмелу. PCINT_vect0 не существует, потому что их соглашение об именах - <Имя прерывания>_vect для векторов прерывания. Что касается описания пина, я думаю, они хотели, чтобы оно было коротким. Однако на более крупных микроконтроллерах контакты PCINT полностью пронумерованы, поэтому на Atmega328P (от Uno) есть контакты до PCINT20., @chrisl

В основном вам нужно понимать, что такое прерывания смены контакта. Эти вещи обычно довольно подробно объясняются в техническом описании. Например, это предложение из раздела «Внешние прерывания» таблицы данных: «Прерывания по смене контакта PCI сработает, если какой-либо включенный контакт PCINT [5: 0] переключится»., @chrisl

Я знаю, что это такое, и я понимаю, что они сгруппированы, но я не понимаю названия..., @Basj

Например, для 328p PCINT0_vect какую группу контактов покрывает? То же самое для PCINT1_vect? Я могу себе представить, что они могут обрабатывать до 8 контактов каждый?, @Basj

Если вы посмотрите на описание регистра для соответствующих регистров маски в таблице данных, вы увидите, что каждый бит маски помечен соответствующим именем вывода. Также в описании битов разрешения PCI вы найдете информацию о том, для каких выводов они используются, а также какой регистр маски., @chrisl

Давайте [продолжим это обсуждение в чате](https://chat.stackexchange.com/rooms/101275/discussion-between-chrisl-and-basj)., @chrisl