Прерывания по 6 входам - помехи(ардуино Nano)
- Войдите на сайт для отправки комментариев
Делаю приспособление для намотки бумаги на рулон. Натяжение обеспечивается качающейся рамкой. Рулонов 2, моторов 2, рамки 2 шт. Положение рамки отслеживается оптодатчиками(использую Sharp от Canon 1215).
Датчиков по 3 на рамку(средний вспомогательный). Отслеживается срабатывание нижнего положения по нему вкючаю мотор, по достижении верхнего положения мотор выключаю.
Все сделал на прерываниях, датчики верхнего положения на честных прерываниях(D2 D3), датчики нижнего положения - на прерываниях по изменению состояния порта. Использовал библиотеку (мог и сам написать но смысла не видел пока делалось для теста)
Все работает как ожидалось с одним существенным исключением - иногда происходит прерывание без события. Т.е например дошли до нижнего положения надо включить мотор - он включается, но тут же выключается или может выключиться рядом уже работающий мотор.
Я грешу на помехи от двигателей. (конденсатор на двигателе есть, ферритовые кольца на проводах двигателя и датчиков тоже есть.
Вопрос как можно побороть это явление кроме как усложнением логики работы программы, т.е. уменьшив вероятность проскакивания помех?
код привожу ниже
#include <Arduino.h>
#include <MsTimer2.h>
#include "PinChangeInterrupt.h"
#define ON LOW
#define OFF HIGH
#define MANUAL 1
#define AUTO 2
// Назначение портов
#define UF_MIDDLE A1//
#define UF_LOW A0//
#define UPF_MIDDLE A3//
#define UPF_LOW A2//
const byte LOW_HIGHPOS=2; // port for higgh pos low position sensor (under frame)
const byte FWD1=8; //2
const byte RWD1=4; //4
const byte ENB1=9; // 3 можно использовать порты 3 5 6 10 11 тк используем PWM
const byte FWD2=5; // второй канал L298
const byte RWD2=7;
const byte ENB2=6; // с таймером 2 не работает
const byte LOW_POS=1; // dancer at bottom
const byte HIGH_POS=2; // dancer at top (stop rotate stepper)
const byte UNDEF_POS=3; // dancer at middle
const byte MOVES_UP=4; // stepper tights roll
const byte MOVES_DOWN=5; // Printer print roll
const byte Now_LOW=9;
const byte Now_UP=10;
const byte Now_Middle=11;
const byte UP=1;
const byte DOWN=2;
int DANCER_STATE=UNDEF_POS;
int current_state=Now_Middle;
int MAXSPEED=234;
int SPD=200;
byte oldLOWPOS,oldHIGHPOS,oldMIDDLEPOS,oldLOWPOS1,oldHIGHPOS1,oldMIDDLEPOS1;
volatile unsigned int timerCount3=0;
volatile boolean TIMEOUT=false;
volatile boolean EXPIRED=false;
unsigned int DELAY=1300;
void timerInterupt() {
if(TIMEOUT){
timerCount3++; // + 1 к счетчику таймера 3
if ( timerCount3 >= DELAY ) {
timerCount3= 0; // сброс счетчика
TIMEOUT=false; EXPIRED=true;
// код программы вызывается каждые ???? мс
}
}
}
// UP FRAME (RIGHT DANCER)
void UPF_TOP_POS(void) {
// stop motor1
digitalWrite(FWD2,LOW);digitalWrite(RWD2,LOW);digitalWrite(ENB2,LOW);
}
void UPF_LOW_ACT(void) {
// start motor1
cli();
digitalWrite(FWD2,LOW);digitalWrite(RWD2,HIGH);digitalWrite(ENB2,HIGH);
for(int i=0; i<20; i++) {}
sei();
}
void UPF_MD_ACT(void) {
analogWrite(ENB2,150);
}
// Under frame (LEFT DANCER)
void UF_TOP_POS(void) {
// stop motor 2
digitalWrite(FWD1,LOW);digitalWrite(RWD1,LOW);digitalWrite(ENB1,LOW);
}
void UF_LOW_ACT(void) {
// start motor 2
cli();
digitalWrite(FWD1,LOW);digitalWrite(RWD1,HIGH);digitalWrite(ENB1,HIGH);
for(int i=0; i<20; i++) {}
sei();
}
void UF_MD_ACT(void) {
analogWrite(ENB1,150);
}
//disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTock));
//enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick));
void setup() {
Serial.begin(9600);
Serial.println("test L298");
pinMode(A6,INPUT); pinMode(A7,INPUT);
pinMode(A0,INPUT_PULLUP); // low pos under frame
pinMode(A1,INPUT_PULLUP); // middle pos under frame
pinMode(A2,INPUT_PULLUP);pinMode(A3,INPUT_PULLUP);
pinMode(2,INPUT_PULLUP);pinMode(3,INPUT_PULLUP);
pinMode (FWD1,OUTPUT);pinMode (RWD1,OUTPUT);
pinMode (ENB1,OUTPUT);pinMode (FWD2,OUTPUT);
pinMode (RWD2,OUTPUT); pinMode (ENB2,OUTPUT);
digitalWrite(FWD1,LOW); // Brake motor
digitalWrite(RWD1,LOW);
digitalWrite(FWD2,LOW); // Brake motor
digitalWrite(RWD2,LOW);
Serial.println("Continue");
#ifdef TIMER_2
MsTimer2::set(2, timerInterupt); // задаем период прерывания по таймеру 2 мс
MsTimer2::start();
Serial.print("Timer2 started");
#endif
oldLOWPOS=0;oldHIGHPOS=0;oldMIDDLEPOS=0;oldLOWPOS1=0;oldHIGHPOS1=0;oldMIDDLEPOS1=0;
// вся логика в прерывании по ФРОНТУ
attachInterrupt (digitalPinToInterrupt (2), UF_TOP_POS, RISING);
attachInterrupt (digitalPinToInterrupt (3), UPF_TOP_POS, RISING);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(UF_MIDDLE), UF_MD_ACT, RISING);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(UF_LOW), UF_LOW_ACT, RISING);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(UPF_MIDDLE), UPF_MD_ACT, RISING);
attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(UPF_LOW), UPF_LOW_ACT, RISING);
}
byte STATE=MANUAL;
byte keystate=OFF;
byte keypress=LOW;
int sensorValue = 0;
byte LOWPOS,HIGHPOS,MIDDLEPOS,LOWPOS1,HIGHPOS1,MIDDLEPOS1;
void loop() {
// Кроме чтения ничего не делаем
HIGHPOS=digitalRead(2);
HIGHPOS1=digitalRead(3);
MIDDLEPOS=digitalRead(A1);
MIDDLEPOS1=digitalRead(A3);
LOWPOS=digitalRead(A0);
LOWPOS1=digitalRead(A2);
#ifdef SPRINT
if(HIGHPOS != oldHIGHPOS) {Serial.print("(UNDERFRAME HIGH)D2=");Serial.println(HIGHPOS); oldHIGHPOS=HIGHPOS;}
if(HIGHPOS1 != oldHIGHPOS1) {Serial.print("(HIGHFRAME HIGH)D3=");Serial.println(HIGHPOS1); oldHIGHPOS1=HIGHPOS1;}
if(MIDDLEPOS != oldMIDDLEPOS) {Serial.print("UF-A1=");Serial.println(MIDDLEPOS); oldMIDDLEPOS=MIDDLEPOS;}
if(MIDDLEPOS1 != oldMIDDLEPOS1) {Serial.print("HF-A3=");Serial.println(MIDDLEPOS1); oldMIDDLEPOS1=MIDDLEPOS1;}
if(LOWPOS != oldLOWPOS) {Serial.print("UF-A0=");Serial.println(LOWPOS); oldLOWPOS=LOWPOS;}
if(LOWPOS1 != oldLOWPOS1) {Serial.print("HF-A2=");Serial.println(LOWPOS1); oldLOWPOS1=LOWPOS1;}
#endif
}
А осциллогаф видит помехи?
А осциллогаф видит помехи?
Налицо типовое идеологическое противостояние между быстродействующим низковольтным микроконтроллером (да ещё и настроенным на срабатывание по фронтам!) и грубой реальностью в виде электодвигателей с их широкополосными ("по непредсказуемой траектории") помехами при коммутации.
Помеха может лезть по питанию датчика, по проводу от датчика к ардуине, по питанию ардуины или по любому сочетанию. Нужно с реальной схемой разбираться.
Ну и подумать об отказе от прерываний по фронтам и аппаратных + программных защитах от "дребезга". Плюс некоторые варианты срабатывания датчиков контроллер должен признавать явно ошибочными и соответственно обрабатывать, а не тупо дергать двигатели.
Да я конечно понимаю что придется внести некоторое усложнение в код с целью отсечения как помех так и неправильных ситуаций. Но сначала хочу точно выяснить что может происходить
Вот схема с указанием пространственных размеров
На голый провод в 2 метра вы прерыванием наловите даже включение паяльника в розетку. Я ловил на простой 20см дюпонт, лежащий около провода удлинителя. Щелкаешь выключателем настольной лампы - в течении 200ns помехи летят в пин. МК их отлично засекает.
можете оценить на какое время срабатывают датчики : секунда, 100мс, 10мс, 10мкс и т.д.
может он просто остается в таклм состоянии, пока мотор не включится
т.е. в засимости от условий можно использовать разные методы.
а старая добрая схема на двух микропереключателях чем не устроила?
таузен, мильёнен конденсаторов было намотано, работало годами
Концевички это не гибко и не интересно. Там еще и другие функции иногда нужны бывают
Концевички это не гибко
Бывают и гибкие. Например, https://www.etm.ru/cat/nn/548417/
Уберите нафиг прерывания, сделайте переопросы датчиков.
Концевички это не гибко и не интересно. Там еще и другие функции иногда нужны бывают
ага, стоял механический программируемый счетчик оборотов, сколько слоёв (метров) мотаем...