PinChange прерывает проблему с весами DRO

Я пытаюсь считать значения с двух отдельных шкал УЦИ (цифрового считывания), которые чаще всего используются на токарном и фрезерном оборудовании, ЧПУ или любом столе X, Y, Z.

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

Чтобы обойти наличие только двух выводов прерывания (D2, D3), я хочу использовать прерывания PinChange на двух других выводах.

Код, который у меня есть на данный момент, компилируется, и последовательный монитор отображает измерения с контактов D2, D3, но я ничего не получаю с контактов D4, D5.

Я хочу узнать, как вызывать прерывания PinChange на D4, D5 для считывания данных с весов.

Я не хочу покупать другую плату с большим количеством контактов прерывания, так как у меня есть плата на NANO, которую я хочу использовать, и она поместится в имеющееся пространство. Для считывания значения шкалы выводам требуются прерывания. Шкала только инкрементальная.

/*


pinA, pinB are for dro scale 1
pinC, pinD1 are for dro scale 2

D2 = pinA - Hardware Interupt - Scale 1 clk
D3 = pinB - Hardware Interupt - scale 1 data
D4 = pinC - Pinchange Interupt - scale 2 clk
D5 = pinD1 -Pinchange Interupt - scale 2 data

counter1 = scale 1
counter2 = scale 2

*/

const int pinA = 2, pinB = 3, phaseLookup1[] = {0,-1,1,-1,1,0,-1,-1,-1,1,0,1,1,1,-1,0};
const int pinC = 4, pinD1 = 5, phaseLookup2[] = {0,-1,1,-1,1,0,-1,-1,-1,1,0,1,1,1,-1,0};  // seperat lookup tables for each scale

volatile bool A = false, B = false,C = false, D1 = false, updated = false;
volatile int scale1 = 0, phase1 = 0, scale2 = 0, phase2 = 0;


void setup()
{
  Serial.begin(9600);
  
  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  pinMode(pinC, INPUT);
  pinMode(pinD1, INPUT);

  PCICR |= B00000100;// Enable PCIE2 Bit3 = 1 (Port D)
  PCMSK2 |= B00110000;// Enable PCINT20  & PCINT21 (Pins D4 & D5)
  //ISR (PCINT2_vect);
  
  attachInterrupt(digitalPinToInterrupt(pinA), trig, CHANGE);
  attachInterrupt(digitalPinToInterrupt(pinB), trig, CHANGE);
  attachInterrupt(digitalPinToInterrupt(pinC), trig, CHANGE);
  attachInterrupt(digitalPinToInterrupt(pinD1), trig, CHANGE);
}
ISR (PCINT2_vect);

void loop()
//
{
  if (updated)
  {
    Serial.println(String(scale1));
    Serial.println(String(scale2));
    updated = false;
  }
}

void trig()
{
  A = digitalRead(pinA);//Scale 1 
  B = digitalRead(pinB);//  "
  C = digitalRead(pinC);// Scale 2
  D1 = digitalRead(pinD1);// "

  phase1 <<= 1;//Scale 1
  phase1 |= A;
  phase1 <<= 1;
  phase1 |= B;
  phase1 &= 0xF;

  phase2 <<= 1;//Scale 2
  phase2 |= C;
  phase2 <<= 1;
  phase2 |= D1;
  phase2 &= 0xF;

  scale1 += phaseLookup1[phase1];
  scale2 += phaseLookup2[phase2];
  updated = true;
  
}

, 👍1

Обсуждение

Добро пожаловать в SE/Arduino! Ознакомьтесь с [туром], чтобы узнать, как работает этот сайт, и прочтите раздел «[спросить]». Пожалуйста, [редактируйте] свой вопрос, чтобы уточнить его, это не форум., @the busybee

Почему вы используете только один обработчик прерываний (ISR) для всех фронтов? Рассматривали ли вы возможность использования отдельных обработчиков прерываний (ISR), чтобы избежать усложнения? Или, поскольку [квадратурное кодирование](https://en.wikipedia.org/wiki/Incremental_encoder#Quadrature_outputs) никогда не допускает одновременного появления фронтов на обоих сигналах, следует использовать два отдельных ISP для каждого датчика?, @the busybee

Короче говоря, вы спрашиваете, как использовать прерывания по смене состояния контактов для четырёх контактов одновременно или как заставить прерывания по смене состояния контактов работать на контактах 4 и 5? Если последнее, то экспериментировали ли вы с упрощённым скетчем специально для этой цели?, @the busybee

Я заметил, что эта проблема уже решена на arduino.cc. Пожалуйста, отметьте этот вопрос, чтобы никто не тратил время на ответы, которые у вас уже есть. Пожалуйста, не публикуйте кросспосты в будущем. Это пустая трата времени. В обоих случаях одна и та же группа людей. Вы просто показываете людям, что не цените их усилия, из-за чего многие не хотят вам помогать., @Delta_G

Delta. Да, я понимаю твою точку зрения. Я ценю и дорожу сообществом. Прошло много времени, и я уже заржавел. Я выложу код из этого обсуждения на Github вместе с проектом. Надеюсь, он пригодится другим., @DucatoboyStu 750


2 ответа


1

Функция Arduino attachInterrupt() работает только с так называемыми «внешние прерывания», которые в Nano доступны только контакты 2 и 3. Для любого другого контакта, digitalPinToInterrupt() возвращает константу NOT_AN_INTERRUPT (-1) и attachInterrupt() ничего не делает. Если вы хотите работать с прерываниями по изменению контактов, вам нужно нужно либо найти библиотеку, которая предоставляет им хороший API, либо сделать это низкоуровневый, установив себе регистры управления оборудованием и определение настоящего ISR.

Поскольку вы устанавливаете и PCICR, и PCMSK2, вы следуете Низкоуровневый подход, и вы почти у цели. Единственное, чего не хватает, определяет ISR, который действительно делает что-то полезное. Возможно, просто это:

ISR(PCINT2_vect) { trig(); }

Пока вы этим заняты, удалите два нерелевантных вызова attachInterrupt(). Кроме того, я бы не стал читать обе шкалы каждый раз. одна шкала посылает импульс: вам нужно прочитать только одну шкалу, которая дала пульс. Таким образом, можно разделить trig() на одну функцию для каждой шкалы, затем в setup():

attachInterrupt(digitalPinToInterrupt(pinA), trig_scale_1, CHANGE);
attachInterrupt(digitalPinToInterrupt(pinB), trig_scale_1, CHANGE);

И тогда ISR будет:

ISR(PCINT2_vect) { trig_scale_2(); }

Это должно сэкономить вам довольно много циклов в контексте прерывания, и таким образом уменьшить задержку прерывания и сделать всю программу более надежной.

,

0

Спасибо всем.

У меня есть решение с форума Arduino.

Я выложу код на Github, чтобы все могли его увидеть и поделиться.

/*
  Pins require interrupts to read scale value. Scale is incremental only.
  pinA, pinB are for dro scale 1
  pinC, pinD1 are for dro scale 2

  D2 = pinA - Hardware Interrupt - Scale 1 clk
  D3 = pinB - Hardware Interrupt - scale 1 data
  D4 = pinC - Pinchange Interrupt - scale 2 clk
  D5 = pinD -Pinchange Interrupt - scale 2 data
*/
#include <avr/interrupt.h>
const int pinA = 2, pinB = 3, phaseLookup1[] = {0, -1, 1, -1, 1, 0, -1, -1, -1, 1, 0, 1, 1, 1, -1, 0};
const int pinC = 4, pinD = 5, phaseLookup2[] = {0, -1, 1, -1, 1, 0, -1, -1, -1, 1, 0, 1, 1, 1, -1, 0}; // seperate lookup tables for each scale

volatile bool A = false, B = false, C = false, D = false, updated = false;
volatile int scale1 = 0, phase1 = 0, scale2 = 0, phase2 = 0;


void setup()
{
  Serial.begin(9600);
  Serial.println("T.I.S.M"); // Google it
  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  pinMode(pinC, INPUT);
  pinMode(pinD, INPUT);
  cli();
  PCICR |= B00000100;// Enable PCIE2 Bit3 = 1 (Port D)
  PCMSK2 |= B00111100;// Enable PCINT20  & PCINT21 (Pins D4 & D5) + D2 + D3

  sei();
}

void loop() {
  if (updated)
  {
    Serial.println(String(scale1*2));
    Serial.println(String(scale2*2));
    updated = false;
  }
}

ISR (PCINT2_vect)
{
  static byte oldState = 0;
  byte newState = PIND & B111100;
  if (newState != oldState) {
    A = (newState & 1 << pinA) > 0; //Scale 1
    B = (newState & 1 << pinB) > 0; //  "
    C = (newState & 1 << pinC) > 0; // Scale 2
    D = (newState & 1 << pinD) > 0; // "
    if ((newState & B1100) != (oldState & B1100)) {
      phase1 <<= 1;//Scale 1
      phase1 |= A;
      phase1 <<= 1;
      phase1 |= B;
      phase1 &= 0xF;
      scale1 += phaseLookup1[phase1];
    }
    if ((newState & B110000) != (oldState & B110000)) {
      phase2 <<= 1;//Scale 2
      phase2 |= C;
      phase2 <<= 1;
      phase2 |= D;
      phase2 &= 0xF;
      scale2 += phaseLookup2[phase2];
    }
    updated = true;
  }
}
,

Ссылка на соответствующую страницу форума или пост?, @Greenonline

Вы попробовали предложенные мной решения?, @Edgar Bonet

Эдгар — Пока что я не пробовал ваше решение, но оно мне пригодится, когда я буду добавлять другие функции, которые хочу попробовать., @DucatoboyStu 750

https://github.com/MorryStu?tab=repositories, @DucatoboyStu 750