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;
}
2 ответа
Функция 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(); }
Это должно сэкономить вам довольно много циклов в контексте прерывания, и таким образом уменьшить задержку прерывания и сделать всю программу более надежной.
Спасибо всем.
У меня есть решение с форума 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
- Использование millis() и micros() внутри процедуры прерывания
- Подсчет импульсов с прерыванием
- Как работают прерывания на Arduino Uno и аналогичных платах?
- Устранение дребезга кнопки с помощью прерывания
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Программа arduino выдаёт ошибку expected //primary-expression before ')' token error: //expected ';' before '}' token E
- Как сгенерировать аппаратное прерывание в mpu6050 для пробуждения Arduino из режима SLEEP_MODE_PWR_DOWN?
- Использование поворотных энкодеров с прерываниями смены контактов
Добро пожаловать в 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