Работа двигателя в течение 3 секунд непрерывно с прерыванием и без него
Я подключил двигатель постоянного тока и ИК-датчик к своему nano. Двигатель постоянного тока должен работать только в том случае, если ИК-датчик обнаруживает препятствие. Теперь я пытаюсь заставить двигатель выключаться, если он непрерывно блокируется в течение 3 секунд, и выходить из прерывания (в случае первого кода с прерыванием) и снова ждать, пока датчик снова станет низким (падающий фронт). Я реализовал это с помощью millis(), но код, похоже, не работает последовательно, так как время, кажется, пошло на бросок (случайное поведение; иногда он продолжает работать непрерывно, а иногда останавливается). Может ли кто-нибудь на этом форуме просмотреть его и предложить мне исправление. Кроме того, можно ли для этого использовать триггер LOW вместо заднего фронта?
#include <LowPower.h>
const int out1 = 5; //двигатель
const int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
const int LED = 6; // подключаем светодиод к контакту 9 Arduino
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;
volatile bool flag=false;
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(9600);
pinMode(out1,OUTPUT);
//pinMode(out1,OUTPUT);
pinMode (IRSensor, INPUT); // вывод датчика INPUT
pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
pinMode(Switch, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(IRSensor),IRinterrupt,FALLING);
}
void loop() {
// поместите сюда ваш основной код для многократного запуска:
LowPower.powerDown(SLEEP_FOREVER , ADC_OFF, BOD_OFF);
delay (100);
if (flag==true){
//Serial.println("true");
switchSensor = digitalRead (Switch);
//Serial.println("zloop");
statusSensor = digitalRead (IRSensor);
//Serial.println(statusSensor);
if (count1==1)
{ prevTime = millis();
Serial.println(prevTime);
}
if (millis() - prevTime >= 1000)
{ doSomethingElse();
Serial.println("going to else");
}
}
//prevState = digitalRead(IRSensor);
doSomething();
}
void IRinterrupt(){
flag=true;
}
void doSomething(){
buttonstatus();
if (statusSensor == 0 and switchSensor == 0 and count3==0){
analogWrite(out1,Mspeed);
// цифровая запись (out1, HIGH);
count1=count++;
Serial.println(count);
digitalWrite(LED, LOW);
}
else if (statusSensor == 0 and switchSensor == 1) {
// цифровая запись (out1, LOW);
digitalWrite(LED, HIGH);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
}
else if (statusSensor == 1 and switchSensor == 0) {
// цифровая запись (out1, LOW);
digitalWrite(LED, LOW);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
}
else {
//Serial.println("высокий уровень");
// цифровая запись (out1, LOW);
digitalWrite(LED, HIGH);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
buttonstatus();
}
}
void doSomethingElse(){
//Serial.println("ir high else");
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
count2++;
count3=count2;
// аналоговая запись (out1,0);
}
void buttonstatus(){
buttonstate=digitalRead (IRSensor);
if (buttonstate != lastbuttonstate) {
// если состояние изменилось,
if (buttonstate == LOW) {
count3=0;
}
delay(50);
}
lastbuttonstate = buttonstate;
}
Я написал еще один фрагмент кода без прерываний. Как мне добиться такой же временной части и для этого?
int out1 = 5; //двигатель
int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
int LED = 6; // подключаем светодиод к контакту 9 Arduino
int Switch = 2;
int statusSensor=1;
int switchSensor=1;
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(9600);
pinMode(out1,OUTPUT);
//pinMode(out1,OUTPUT);
pinMode (IRSensor, INPUT); // вывод датчика INPUT
pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
pinMode(Switch, INPUT_PULLUP);
}
void loop() {
// поместите сюда ваш основной код для многократного запуска:
switchSensor = digitalRead (Switch);
//Serial.println(SwitchSensor);
statusSensor = digitalRead (IRSensor);
//Serial.println(statusSensor);
delayStart = millis();
//Serial.println("с прерыванием");
if (statusSensor == 0 and switchSensor == 0){
Serial.println ("ir low");
analogWrite(out1,120);
digitalWrite(LED, LOW);
}
else {
Serial.println ("ir high");
analogWrite(out1,0);
}
}
EDIT: теперь я успешно реализовал код (без прерываний) с временной частью в приведенном ниже коде. Кроме того, я обновил первый код в сообщении с прерываниями, но я не могу заставить работать временную часть. Может кто-нибудь, пожалуйста, помогите мне, как теперь можно сделать синхронизацию с прерываниями, чтобы arduino nano находился в спящем режиме, пока не получит задний фронт на выводе прерывания от ИК-датчика, чтобы он мог обработать следующую часть. Я считаю, что при этом я сэкономлю электроэнергию, так как она постоянно включена.
const int out1 = 5; //двигатель
const int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
const int LED = 6; // подключаем светодиод к контакту 9 Arduino
const int Switch = 2;
const int Mspeed = 175;//0-255
const int Mtime =1500;//500-1000
int statusSensor=1;
int switchSensor=1;
unsigned long prevTime;
volatile int count =0;
volatile int count1=0;
volatile int count2 =0;
volatile int count3=0;
volatile int buttonstate=0;
volatile int lastbuttonstate=0;
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(9600);
pinMode(out1,OUTPUT);
pinMode (IRSensor, INPUT); // вывод датчика INPUT
pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
pinMode(Switch, INPUT_PULLUP);
}
void loop() {
// поместите сюда ваш основной код для многократного запуска:
delay(100);
switchSensor = digitalRead (Switch);
statusSensor = digitalRead (IRSensor);
if (count1==1)
{ prevTime = millis();
Serial.println(prevTime);
}
if (millis() - prevTime >= Mtime)
{ doSomethingElse();
//Serial.println("идем к другому");
}
doSomething();
}
void doSomething(){
buttonstatus();
if (statusSensor == 0 and switchSensor == 0 and count3==0){
analogWrite(out1,Mspeed);
// цифровая запись (out1, HIGH);
count1=count++;
Serial.println(count);
digitalWrite(LED, LOW);
}
else if (statusSensor == 0 and switchSensor == 1) {
// цифровая запись (out1, LOW);
digitalWrite(LED, HIGH);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
}
else if (statusSensor == 1 and switchSensor == 0) {
// цифровая запись (out1, LOW);
digitalWrite(LED, LOW);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
}
else {
//Serial.println("высокий уровень");
// цифровая запись (out1, LOW);
digitalWrite(LED, HIGH);
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
buttonstatus();
}
}
void doSomethingElse(){
//Serial.println("ir high else");
analogWrite(out1,0);
count=0;
count1=0;
prevTime = millis();
count2++;
count3=count2;
// аналоговая запись (out1,0);
}
void buttonstatus(){
buttonstate=digitalRead (IRSensor);
if (buttonstate != lastbuttonstate) {
// если состояние изменилось,
if (buttonstate == LOW) {
count3=0;
}
delay(50);
}
lastbuttonstate = buttonstate;
}
@user3796354, 👍-1
Обсуждение2 ответа
Я часто использую цикл таймера для считывания показаний датчиков. Я приложил код, который компилируется, но датчика у меня нет.
Кстати. Я предполагаю, что это однократный ИК-датчик, который возвращает 0, если что-то обнаружено.
int out1 = 5; //двигатель
int IRSensor = 3; // подключаем инфракрасный датчик к контакту 6 Arduino
int LED = 6; // подключаем светодиод к контакту 9 Arduino
int Switch = 2;
int statusSensor=1;
int switchSensor=1;
unsigned long IRMillis;
int IRInterval = 100;
void setup() {
// поместите сюда код установки для однократного запуска:
Serial.begin(9600);
pinMode(out1,OUTPUT);
//pinMode(out1,OUTPUT);
pinMode (IRSensor, INPUT); // вывод датчика INPUT
pinMode (LED, OUTPUT); // Светодиодный вывод ВЫХОД
pinMode(Switch, INPUT_PULLUP);
IRMillis = millis();
}
void loop() {
updateIR();
switchSensor = digitalRead (Switch);
if ((statusSensor == 0) && (switchSensor == 0)) {
IRInterval = 3000; // 3 секунды
statusSensor = 1;
Serial.println ("ir low");
analogWrite(out1,120);
digitalWrite(LED, LOW);
} else {
Serial.println ("ir high");
analogWrite(out1,0);
}
}
void updateIR() {
if (millis() - IRMillis > IRInterval) {
//продолжать
} else {
return;
}
IRMillis = millis();
IRInterval = 100;
statusSensor = digitalRead (IRSensor);
}
Да, возвращает 0., @user3796354
Ваш код прерывания выглядит разумным, за исключением того, что, установив для флага значение true, вы больше никогда не вернете его обратно в значение false. Вам нужен способ определить, что ИК-датчик больше не активен.
Возможно, изменить ваше прерывание, чтобы оно срабатывало при изменении состояния, и установить флаг в значение true, когда оно переключается в LOW (как будто нет), и в false, когда оно переключается обратно в состояние high? Мне нужно больше узнать о вашем ИК-датчике, чтобы точно сказать вам, что делать, но я могу сказать вам, что ваш код в настоящее время записывается, как только вы обнаружите первый спадающий фронт на выводе IRSensor, ваш флаг переключится на true и никогда не менять обратно на false.
Я также не понимаю, что должна делать вся логика if/else if/else if, поэтому не могу точно сказать, есть ли у вас какие-либо ошибки в коде.
Я использую ИК-датчик, который отключается только при обнаружении препятствия. Существует также поплавковый выключатель (датчик переключения), который, когда он поднимается (бак пустой), должен выключаться и включать светодиод. Вот почему существует несколько операторов if else. Тот же код без части прерывания (флажка) работает нормально, при этом двигатель останавливается, если он непрерывно работает в течение 1,5 секунд. Но с прерыванием временная часть не работает., @user3796354
Опять же, ваш код устанавливает flag=true в коде прерывания, но никогда не устанавливает flag=false. Это не правильно., @Duncan C
- Использование прерывания внутреннего таймера для чтения аналогового датчика
- Прерывания таймера Arduino для PID
- Проблема с прескалером таймера Elegoo Nano
- Arudino получает команду прерывания ДО перехода в спящий режим, из-за чего он не получает никаких команд прерывания для пробуждения.
- Как указать имя таймера в зависимости от чипа, в который он будет компилироваться?
- Не удалось получить показания для "Двигателя с энкодером"
- Использование millis() и micros() внутри процедуры прерывания
- Arduino непрерывно считывает значение АЦП с помощью прерывания
Комментарии не для расширенного обсуждения; этот разговор был [перенесен в чат](https://chat.stackexchange.com/rooms/108619/discussion-on-question-by-user3796354-running-a-motor-for-a-3-seconds-continuous) ., @VE7JRO