Странные результаты, пытаясь подсчитать импульсы

Я теперь безнадежно застрял и нуждаюсь в помощи, пожалуйста.

Я создаю автоматизированную обсерваторию и сейчас на стадии попытки контролировать поворот купола обсерватории. Купол поворачивается с помощью шагового двигателя, и он отлично работает. Вращение купола также поворачивает поворотный кодер, чтобы дать независимую проверку, что купол движется. Хотя RE является квадратурным типом, я просто подсчитываю RE-тики с обоих каналов, так как мне не нужна информация о направлении.

То, что я пытаюсь сделать сейчас, - подсчитать, сколько импульсов возбуждения двигателя происходит между каждой парой RE-тиков. Причиной этого является отслеживание движения купола и обнаружение заклинивания. Фактические импульсы двигателя будут использоваться для всех расчетов положения купола.

Для этого я создал небольшую плату с инвертирующим буфером ULN2803A и Arduino Nano. Nano использует прерывания смены контактов на выводах D11 и D12 для подсчета тиков RE. Pin D7 также будет использоваться для наблюдения за датчиком Home Position, хотя в настоящее время этого не существует. Импульсы двигателя отправляются через буфер на контакт D2 (INT0), а направление двигателя отправляется через буфер для вывода D3 (INT1). Внешние прерывания затем используются для подсчета импульсов двигателя, вверх или вниз в зависимости от направления двигателя.

Для получения информации есть еще одна плата - планка Velleman VM110 USB, которая также получает тики вращающегося кодировщика. Это дает мне простой способ проверить, что моя плата дает тот же ответ, когда я вращаю вал вращающегося энкодера вручную.

ОК - извините, это так долго наматывается, но теперь это становится странным.

Когда я вращаю RE без двигателя работает все нормально. Я получаю в четыре раза больше импульсов, чем плата Velleman, поскольку я использую Pin Changes, срабатывающие при каждом повышении и понижении, а не в полных циклах кодировщика. Это происходит, как и было предсказано, и все хорошо и стабильно.

НО - когда я запускаю двигатель, я получаю сотни тиков RE каждый раз, когда я перемещаю кодировщик, и иногда я получаю увеличение тиков RE, не касаясь кодера вообще.

Очевидным ответом является некоторая форма RFI, но я сделал все, что в моих силах, чтобы устранить это. Драйвер двигателя и плата Nano, которая питает его, находятся в защищенном корпусе, кабель к двигателю - экранированный кабель, и у меня есть 10uH дроссели на каждом из четырех проводов двигателя. Наконец, я установил фильтр для входящего источника питания в коробку двигателя, чтобы свести к минимуму любые RFI, возвращающиеся вниз по линиям электропередач.

Использование буфера ULN2803A было моей последней попыткой сделать эту работу. Ранее сигналы поступали непосредственно на контакты Nano. С буфером я использовал подтягивания 20k на стороне входа и подтягивания 10k на выходах. Это была прямая копия входной схемы платы Velleman, которую я знал без проблем.

Я посмотрел на импульсы двигателя на входном штыре на Nano на моем прицеле, и они выглядят красиво, острыми краями импульсов длительностью 70 мкс и частотой 497 Гц. Неплохо, поскольку я установил частоту пульса, используя библиотеку Accelstepper, до 500 Гц.

Теперь я подозреваю, что это проблема программного обеспечения. Меня это не удивило бы, поскольку я очень новичок во всем этом, просто пытаясь учиться на каждом этапе, чтобы делать то, что мне нужно. Я прикрепил код - это урезанная версия без большого количества материалов I2C, которые не имеют отношения к моим проблемам.

Опять же, для информации. Я пробовал использовать функцию attachInterrupt() и напрямую настраивал соответствующие регистры - без разницы!

Во всяком случае, я действительно очень надеюсь, что кто-то поможет мне разобраться в этом.

С уважением, Хью

/*          
ABoard3  
ROTATION MONITORING AND POSITION
Version AB3_stripped
*****************************PURPOSE*****************************************
This sketch is used on an Arduino Nano to count the motor pulses from ABoard1
and the Rotary Encoder ticks. The motor pulse count between encoder ticks is
used to detect dome jamming.
****************************INPUTS*******************************************
PIN CHANGE INTERRUPTS
**********ROTARY ENCODER INPUT*********
The rotary encoder is a Bourns ENA1J-B28 L00064L 1139M MEX 64 cycle per turn
optical encoder. This is connected to ABoard3 Pins D11 and D12. These pins
connect to Channel A and Channel B respectively. Pin change interrupts are used
to receive the rotary encoder output.
(The output pulses from the rotary encoder is also sent to the Velleman board
for use by LesveDomeNet for finding dome position)
*********HOME POSITION INPUT*********
The home position sensor is an Omron EESX671 Optical Sensor.
The sensor output is connected to ABoard3 Pin D7.
Pin change interrupt PCINT21 records activation/deactivation of the sensor.
EXTERNAL INTERRUPTS
*********MOTOR PULSE INPUT***********
The pulses sent to the G251X stepper driver are also sent to Aboard3 Pin D2.
This pin is the External Interrupt pin, vector INT0
*********MOTOR DIRECTION INPUT********
Motor direction is input to ABoard3 from ABoard2. ABoard2 pin, pnVmInRotMotor
(AB2:A0{54}) is connected to Velleman pins DI4 and DO2 and also to AB3:D3.
AB3:D3 is an External Interrupt pin, vector INT1.
*/

#include                        
#include "streaming.h"                        
#include "I2C_AnythingHEG.h"   
#include                     

//CONSTANTS                       
//PIN ASSIGNMENTS For ABOARD3
const uint8_t pnMotorPulse = 2;      //Port PD2, INT0, ISR(INT0_vect){}
const uint8_t pnMotorDirection = 3;  //Port PD3, INT1, ISR(INT1_vect){}
const uint8_t pnDomeAtHome = 7;      //Port PD7, PCINT23,ISR(PCINT2_vect){}
const uint8_t pnREChanA = 11;        //Port PB3, PCINT3, ISR(PCINT0_vect){}
const uint8_t pnREChanB = 12;        //Port PB4, PCINT4, ISR(PCINT0_vect){}

//*****************EXPERIMENTAL STUFF FOR PULSE COUNTING*******************************                  
uint16_t volatile myTest = 0;
int32_t volatile ratioCount = 0L;
int32_t volatile totalCount = 0L;
int32_t volatile tickCount = 0L;
uint8_t volatile halftickCount = 0;
int32_t volatile addPulse = 0L; 

void setup() {
  //**********************************SERIAL FOR DEBUG ONLY************************
  Serial.begin(115200);
  //*************************INPUT PIN MODE SETUP**********************************
  //NOTE Set all UNUSED PCINT0:5 pins (D8, D9, D10, D11) to OUTPUT.
  //and set the value to LOW
  //The actual pins used to receive interrupts have external 10k pull-ups.
  //This is to reduce susceptibility to interference causing false triggering.
  pinMode(pnMotorPulse, INPUT); //D2
  pinMode(pnMotorDirection, INPUT); //D3
  pinMode(pnDomeAtHome, INPUT); //D7
  pinMode(pnREChanA, INPUT); //D11
  pinMode(pnREChanB, INPUT); //D12
  pinMode(4, OUTPUT); //D4
  digitalWrite(4, LOW);
  pinMode(8, OUTPUT); //D8
  digitalWrite(8, LOW);
  pinMode(9, OUTPUT); //D9
  digitalWrite(9, LOW);
  pinMode(10, OUTPUT); //D10
  digitalWrite(10, LOW);
  //******************SET UP AddPulse According to Motor Direction******************
  //This is needed to make sure the pulse counting starts in the correct direction
  //as the direction is only checked in the ISR after a change has occurred.
  //If Motor Direction is AntiClockwise, change to Subtract a pulse
  if( digitalRead(pnMotorDirection)) {
    addPulse = 1L;
  } else {
    addPulse = -1L;
  }
  //**************************SET UP PIN CHANGE INTERRUPTS**************************
  //Set the Pin Change Interrupt Masks
  //Clear all bits to start with
  PCMSK0 &= 0b00000000; //Clear all bits
  PCMSK1 &= 0b00000000; //Clear all bits
  PCMSK2 &= 0b00000000; //Clear all bits
  //Mask for PCINTs 0 through 7 is PCMSK0 (Rotary Encoder Pulses)
  //Need to allow interrupts on PCINT3 and PCINT4, so set bits 3 and 4
  //PCINT3 is Nano  pin D11 and PCINT4 is Nano pin D12
  //Use a compound bitwise OR to set the bits
  PCMSK0 |= 0b00011000; //Enable PCINT3 ONLY (bit 3)
  //Interrupt on pins 11 and 12, RE Ticks
  //Mask for PCINTs 16through 23 is PCMSK2 (Home Position)
  //Need to allow interrupts on PCINT23 so set bit 7
  PCMSK2 |= 0b10000000; //Interrupt on pin 7, Home Position Sensor activated
  //Now enable the interrupts (TURN THEM ON) by setting bits in PCICR
  //PCICR is Pin Change Interupt Control Register.Set bit 0 (PCIE0)  
  //to enable interrupts PCINT0:7 This catches PCINT3 and 4 - RE Ticks
  //Set bit 2 (PCIE2) to enable interrupts PCINT16:23. Catches PCINT21 - Home Position Sensor
  PCICR &= 0b00000000; //Clear PCICR register 
  PCICR |= 0b00000001; //Set bit 0 - Catches PCINT3 & PCINT4 - RE Ticks
  PCICR |= 0b00000100; //Set bit 2 - Catch PCINT21 - Home Position Sensor
  //**************************SET UP 'EXTERNAL INTERRUPTS'**************************
  //Interupts on External Interrupt Pins D2 (INT0) and D3 (INT1).
  //INT0 (Nano pin D2)occurs when a stepper motor driver pulse is received
  //INT1 (Nano pin D3)occurs when the ABoard2 pin, pnVmInRotMotor toggles 
  //indicating a motor direction change.
  //To use the 'External Interrupts' the following registers need to be set-up:         
  //EICRA External Interrupt Control Register A       
  //Need to set Interrupt Sense Control bits ISC11 .. ISC00 (bits 3:0 in EICRA)
  //ISC01     ISC00 (INT0)    Interrupt
  //ISC11     ISC01 (INT1)    Generated by
 // 0         0             Low level on Pin
 // 0         1             Any Logical Change
 // 1         0             Falling Edge
 // 1         1             Rising Edge
  //First clear all bits, then set as follows:  
  //For INT1 - Motor Direction - Generate on ANY LOGICAL CHANGE     
  //bit 3 ISC11 0     
  //bit 2 ISC10 1 This combination = Any logical change causes interrupt 
  //For INT0 - Stepper Motor Pulses  - Generate on RISING EDGE      
  //bit 1 ISC01 1     
  //bit 0 ISC00 1 This combination = Rising edge of pulse causes interrupt
  //NOTE: To provide some immunity to RFI, Aboard3:Pins 2 & 3 are pulled high
  //using 10k resistors. 
  //So, code is
  EICRA &= 0b00000000; //Clear EICRA register
  EICRA |= 0b00000111;//Set bits 0,1 and 2 in EICRA register
  //EIMSK External Interrupt Mask Register        
  //Need to set External Interrupt Request Enables INT1 & INT0  (bits 1:0)          
  //First clear both bits, then set as follows: 
  //bit 1  INT1  1 External interrupt pin (D3) enabled   
  //bit 0  INT0  1 External interrupt pin (D2) enabled   
  //So, code is
  EIMSK &= 0b00000000; //Clear EIMSK register
  EIMSK |= 0b00000011;//Set bits 0 and 1 in EIMSK register
  //NOTE: Setting EIMSK TURNS ON THE EXTERNAL INTERRUPTS
  //************VARIABLE INITIALISATION*********
  myCommand = 0;
  myTest = 0;
  tickCount = 0L;
  totalCount = 0L;
} //END of setup

void loop() {
  //******************************COMMAND ACTIONS******************************
  if (myTest == 3) (
    //RE tick
    Serial << "Tick Count = " << tickCount << "  totalCount = " << totalCount << "\n";
    myTest = 0;
  }
}
//*************************FUNCTIONS/ISRs FROM HEREON*************************
ISR(INT0_vect) {
  //Triggered by stepper motor drive pulse from ABoard1
  totalCount = totalCount + addPulse;
}
ISR(INT1_vect) {
  //Triggered by a change in motor direction
  if(digitalRead(pnMotorDirection)) {
    addPulse = 1L;
  } else {
    addPulse = -1L;
  }
}
ISR(PCINT0_vect) {
  //Triggered by a ROTARY ENCODER TICK
  halftickCount++;
  if (halftickCount == 2) {
    //Make count same as Velleman
    tickCount++;
    halftickCount = 0;
    myTest = 3;
  }
}
ISR(PCINT2_vect) {
  //Triggered by activation of Home Position Sensor
  myTest = 4;
}
0
1) У вас есть область действия, вы использовали ее для просмотра импульсов двигателя. Вы тоже смотрели на импульсы энкодера? Как они выглядят? 2) В квадратурном кодере я ожидал бы, что максимум один канал будет «оживленным» в любой момент времени. Затем, если вы используете кодировщик обычным способом, вы должны получить последовательность +1, -1, +1, -1 ... с добавлением нуля. 3) Стандартная идиома для установки регистров ввода/вывода AVR: PCMSK0 = _BV (PCINT3) | _BV (PCINT4); , который выглядит более четким, чем PCMSK0 & = 0b00000000; PCMSK0 | = 0b00011000; , по крайней мере, тем, кто знаком с программированием AVR.
добавлено автор Sprogz, источник
PCMSK0 & = 0b00000000;//Очистить все биты - не будет PCMSK0 = 0; будет намного понятнее? Между тем я согласен с ответом Гербена. Попробуйте «защитить» ваш доступ к многобайтовым переменным, установленным прерываниями. См. Прерывания .
добавлено автор Nick Gammon, источник
Есть ли у вас надлежащая общая земля между выходами квадратурного кодировщика и Arduino? Если это так, то @EdgarBonet прав. Квадратурные энкодеры могут отскакивать как сумасшедшие, поэтому вам действительно нужно правильно прочитать кодировщик, определить направление шагов и все от каждого чтения. Таким образом, если он отскакивает +1, а затем -1 или любую другую последовательность, 100 раз подряд, вы в конечном итоге знаете, что такое новое местоположение, и тем самым вы также отменили его. Попытайтесь добавить колпачок 2.2uF на каждый квадратурный выход, чтобы немного помочь в аппаратном debouncing.
добавлено автор meepsh, источник
Правильное чтение кодировщика - это дезадаптация программного обеспечения, в которой вы действительно нуждаетесь.
добавлено автор meepsh, источник
Является ли ваш вращающийся датчик электрическим или оптическим? Я спрашиваю, интересно ли у вас проблемы с откатом переключателя или, возможно, с оптическим приемником, включающим и выключенным на границе. Если это так, один из способов, который может помочь в его решении, - правильно декодировать квад-кодированные импульсы. Это сообщение в блоге показывает надежный способ декодирования квад-кодированных импульсов: thewanderingengineer.com/2014/08/11/… Регады,
добавлено автор CMaster, источник
Альтернативой выполнению debounce в процессоре является использование микросхемы, предназначенной для этой цели. Вот то, что может быть подходящим: elmelectronics.com/ic/elm402 С уважением,
добавлено автор CMaster, источник

1 ответы

Нет необходимости использовать int32_t для некоторых переменных. Проблема с использованием переменных размером более 8 бит на 8-битном процессоре заключается в том, что для получения значения для процессора требуется 4 чтения. В середине этих чтений может произойти прерывание, в результате чего будет иметь значение, имеющее некоторые биты старого значения, и некоторые биты нового.

Некоторым переменным нужны только 8 бит.

uint8_t volatile myTest = 0;
int32_t volatile totalCount = 0L;
int32_t volatile tickCount = 0L;
uint8_t volatile halftickCount = 0;
int8_t volatile addPulse = 0L; 

Следующее - сделать чтение атома.

void loop()                                             
{                                               
//******************************COMMAND ACTIONS******************************  

if (myTest == 3)   //RE tick
{
    noInterrupts();
    int32_t tickCountCopy = tickCount;
    int32_t totalCountCopy = totalCount;
    interrupts();
    Serial << "Tick Count = " << tickCountCopy << "  totalCount = " << totalCountCopy << "\n"; 
    myTest = 0; 
}
}   

PS. это не обязательно ответ, но он не вписывался в комментарии.

1
добавлено
Здесь нет реального отскока, но, вероятно, не столь ясный переход, как вы ожидали. Мое предположение - триггер schmitt, который будет работать. Несмотря на то, что мой ответ не решает вашу проблему, он все же указывает на проблему, которую вы могли бы учитывать в своем коде.
добавлено автор Al., источник
Привет, и спасибо Гербен и Ник. Я внес изменения, которые вы рекомендовали, но на самом деле они, похоже, ухудшали ситуацию, а не лучше, потому что даже без запуска шагового двигателя я получал многократное срабатывание на каждом из каналов RE.
добавлено автор SeaDrive, источник
Oops - хотел новую строку и нажал кнопку возврата, но отправил комментарий, прежде чем закончил. Итак, извините отсутствие форматирования с этого момента. Теперь я пришел к выводу, что мне нужно отказаться от Rotary Encoder. Я ПРИНИМАЛ, что, поскольку это оптический кодировщик, это не потребует отладки, но теперь я думаю, что мое предположение было неправильным. Я собираюсь сделать небольшой аппаратный debouncer с использованием RC-синхронизации и 74HC14-шестнадцатеричным инвертирующим триггером Шмитта. Надеюсь, шляпа решит проблему. Хорошей новостью является то, что фактические импульсные импульсы двигателя подсчитываются без каких-либо проблем. Спасибо, Хью.
добавлено автор SeaDrive, источник
Привет, я попытался использовать свой объем, чтобы посмотреть выходные данные кодера, но я не знаю, как правильно его использовать и не смог получить значимых результатов. Я сделал плату debouncer, используя задержку около 5 мс на каждом канале кодировщика, и, наконец, все работает так, как предполагается. Сначала я столкнулся с этой проблемой в начале декабря, так что все это время нужно было решить. Фактически купил мой объем, чтобы помочь с этой конкретной проблемой. Еще раз спасибо всем, кто ответил и прокомментировал. С уважением Хью
добавлено автор SeaDrive, источник
@HughGilhespie, если проблема решена сейчас, отправьте ответ на свой вопрос и отметьте его как решенный.
добавлено автор meepsh, источник
Анархическая электроника
Анархическая электроника
1 510 участник(ов)

[около] электронные темы. без переходов на личности, стен стикеров, политики, непрошенной рекламы и всякого такого Основной чат у нас в @ru_electronics Общий информационный канал @ru_electronics_feed

Про электронику
Про электронику
1 461 участник(ов)

QA чат для решения вопросов, связанных с электроникой. без стикеров, непрошенной рекламы и игр в русский форум оформляйте вопрос в одно сообщение вопросы со словом «кто» игнорируются don't ask for ask Правила http://telegra.ph/ru-electronics-rulz-11-11

Embedded Group
Embedded Group
873 участник(ов)

Все про Embedded и электронику. Осторожно, бывают нотификейшены. #вопросподелу - Для поиска вопросов и ответов #devtools - фотки рабочих железок Работа: @rabotaembedded http://embedded.group http://vk.com/embedded_space

Hardware & Radio
Hardware & Radio
155 участник(ов)

Разговоры об электронике, микроконтроллерах, низкоуровневом программировании, реверс-инжиниринге, FPGA, квадрокоптерах, 3D-печати, Software Defined Radio, любительском радио, и всяком таком.

ARDUINO [RU]
ARDUINO [RU]
60 участник(ов)

Обсуждение Электронного конструктора Arduino. Проблемы и их решения. Ссылки на интересные статьи и проекты. ВК: https://vk.com/arduino_esp Realtek: http://vk.com/rtl8711 Чаты: IOT https://t.me/ProIOT esp8266 https://t.me/Proesp8266