Arduino+IR+Servo

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Написал такой скетч:

#include "IRremote.h"

IRrecv irrecv(11);
decode_results results;

#include <Servo.h>
Servo LXservo;
const char SERVO_MIDDLE_ANGLE = 90; // угол сервы при котором колеса выставлены прямо
int servoAngle = SERVO_MIDDLE_ANGLE;
int lastButton = 0;                   

void setup()
{
 LXservo.attach(8);   
 Serial.begin(9600); // Выставляем скорость COM порта
 irrecv.enableIRIn(); // Запускаем прием
}

void loop()                     
{
if (digitalRead(11) == LOW) servoAngle = SERVO_MIDDLE_ANGLE;

LXservo.write(servoAngle);

  if (irrecv.decode(&results))
  {
      int res = results.value;
      int lastButton ;
      Serial.println(res, HEX);
      if(res==0x48B7) || res==0xFFFFC837)// Если нажата кнопка "LEFT" или "RIGHT"
      {
         lastButton=res;
      }
      else if(res==0xFFFFFFFF)// Если кнопку удерживают
      {
         if(lastButton==0x48B7) servoAngle = 115;// Удерживают "LEFT"
         if(lastButton==0xFFFFC837)servoAngle = 75; // Удерживают "RIGHT"   
      }
      irrecv.resume();
      delay (100);
  }

}

 

Задумка такая, что при отсутствии управляющего сигнала серва возвращается в положение 90 град. После включения схемы серва становится в 90 градусов и все. На пульт не реагирует. Светодиод на плате мигает во время нажатия на кнопки,  но серва стоит. Если изменить функцию loop следующим образом образом:

vvoid loop()                     
{
//if (digitalRead(11) == LOW) servoAngle = SERVO_MIDDLE_ANGLE;

LXservo.write(servoAngle);

  if (irrecv.decode(&results))
  {
      int res = results.value;
      int lastButton ;
      Serial.println(res, HEX);
      if(res==0x48B7)
      {
         servoAngle = 115;
      }
      else if(res==0xFFFFC837)
      {
         servoAngle = 75;  
      }
      else if(res==0x708F)
      {
         servoAngle = 90;  
      }
      irrecv.resume();
      delay (100);
  }

}

то так все работает, но мне так не надо)). Где грабли в первом коде?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Впредь обязательно уважайте правила форума - http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

Обе библиотеки (Servo и IRremote) используют один и тот же таймер-счётчик №1. Возникает конфликт. Отсюда и проблема.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Прошу прощения за обращение не по форме.  Почему же тогда во втором случае все работает? Как решить проблему со счетчиком?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, откуда мне знать, почему работает - конфликт оборудования вещь непредсказуемая.

Проблему решить можно по-разному. Зависит от Вашего желания и квалификации.

1. точно не помню, но кажется (не уверен), что библиотеке IRremote можно сказать каким счётчиком ей пользоваться. Если можно, то это простейшее решение.

Если же нельзя, то

2. Можно искать библиотеки, которые используют другие счётчики.

3. Можно взять существующую библиотеку и переделать её на другой счётчик. С Servo это сделать сложно, а с  IRremote попроще.

4. Можно вообще отказаться от бибилотек (или от одной из них) и написать свой код.

Выбирайте.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Прикольно. А попроще никак?:-)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

baklan пишет:

Прикольно. А попроще никак?:-)

Можно, конечно. Например, пойти в соответсвующий раздел форума и там Вам это сделают за некоторое скромное вознаграждение.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

За вознаграждение я готовую игрушку купил бы. Дело в принципе: сделать все самостоятельно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, так, вперёд. Четыре пункта выше.

Начните с первого, если с ним повезёт, то всё просто. Откройте тексты библиотеки IRremote  и постарайтесь понять можно ли там указать каким таймером пользоваться. Если можно, то это задаётся константами. По умолчанию используется первый таймер, Вам нужно перейти на второй.

Если же нет, смотрите что именно делает таймер и напишите тоже самое для второго. Я это недавно делал для библиотеки VirtualWire (она использует первый таймер, а у меня он ещё и в другом месте использовался). Там оказалось всё просто. Таймер просто отбивал тактирование, а написал такое же тактирование ( с той же частотй) для второго таймера и проблема снялась.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Дело не в таймерах, вот часть кода из библиотеки ServoTimers.h (см. последний "абзац" - мой случай):

// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega32U4__)
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;

#else  // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif

Авот часть кода из библиотеки IRremoteInt.h (см. также последний "абзац"):

// define which timer to use
//
// Uncomment the timer you wish to use on your board.  If you
// are using another library which uses timer2, you have options
// to switch IRremote to use a different timer.

// Arduino Mega
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  //#define IR_USE_TIMER1   // tx = pin 11
  #define IR_USE_TIMER2     // tx = pin 9
  //#define IR_USE_TIMER3   // tx = pin 5
  //#define IR_USE_TIMER4   // tx = pin 6
  //#define IR_USE_TIMER5   // tx = pin 46

// Teensy 1.0
#elif defined(__AVR_AT90USB162__)
  #define IR_USE_TIMER1     // tx = pin 17

// Teensy 2.0
#elif defined(__AVR_ATmega32U4__)
  //#define IR_USE_TIMER1   // tx = pin 14
  //#define IR_USE_TIMER3   // tx = pin 9
  #define IR_USE_TIMER4_HS  // tx = pin 10

// Teensy++ 1.0 & 2.0
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
  //#define IR_USE_TIMER1   // tx = pin 25
  #define IR_USE_TIMER2     // tx = pin 1
  //#define IR_USE_TIMER3   // tx = pin 16

// Sanguino
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
  //#define IR_USE_TIMER1   // tx = pin 13
  #define IR_USE_TIMER2     // tx = pin 14

// Atmega8
#elif defined(__AVR_ATmega8P__) || defined(__AVR_ATmega8__)
  #define IR_USE_TIMER1   // tx = pin 9

// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc
#else
  //#define IR_USE_TIMER1   // tx = pin 9
  #define IR_USE_TIMER2     // tx = pin 3
#endif

Из чего понятно что библиотека Servo.h использует таймер №1, а библиотека IRremoteInt.h таймер №2. Грабли где-то в другом месте.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ага, т.е. как я и предполагал, в  IRremote можно настраивать таймер и у Вас настроено на второй (у меня-то на первый, потому я так и писал).

Отлично! Эту причину исключили. Надо смотреть дальше.

Посмотрел. Кажется, понятно. Вы ставите серву по "нулю на пине" ресивера. Но ноль на пине - не есть отсутствие сигнала. Давайте всё-таки сделаем точно как Вы написали словами - есть сигнал выставляем углы, нет сигнала - выставляем на фиксированный угол.

Код получается примерно такой. Попробуйте.

void loop() {
  if (irrecv.decode(&results)) {
    int res = results.value;
    int lastButton ;
    Serial.println(res, HEX);
    if (res == 0x48B7) {
      servoAngle = 115;
    }
    else if (res == 0xFFFFC837) {
      servoAngle = 75;
    }
    else if (res == 0x708F) {
      servoAngle = 90;
    }
    irrecv.resume();
    delay (100);
  } else {
    servoAngle = SERVO_MIDDLE_ANGLE;
  }
  LXservo.write(servoAngle);
}

Вы бы всё-таки публиковали код по правилам. Дело тут не в "не по форме", как Вы изволили выразиться, а в том, что я вот хочу сказать что-то по коду. Если бы он был нормально опубликован, там бы были номера строк, а так их нет. Ну, и как мне Вам что-то говорить?

В общем, сегодня я добрый, но вообще, согласитесь, создавать неудобства тому, кто хочет Вам помочь - не лучшая идея.

 

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Исправляюсь:

#include "IRremote.h"

IRrecv irrecv(11);
decode_results results;

#include <Servo.h>
Servo LXservo;
const char SERVO_MIDDLE_ANGLE = 90; // угол сервы при котором колеса выставлены прямо
int servoAngle = SERVO_MIDDLE_ANGLE;
int lastButton = 0;                   

void setup()
{
 LXservo.attach(8);   
 Serial.begin(9600); // Выставляем скорость COM порта
 irrecv.enableIRIn(); // Запускаем прием
}

void loop()                     
{
if (digitalRead(11) == LOW) servoAngle = SERVO_MIDDLE_ANGLE;

LXservo.write(servoAngle);

  if (irrecv.decode(&results))
  {
      int res = results.value;
      int lastButton ;
      Serial.println(res, HEX);
      if(res==0x48B7) || res==0xFFFFC837)// Если нажата кнопка "LEFT" или "RIGHT"
      {
         lastButton=res;
      }
      else if(res==0xFFFFFFFF)// Если кнопку удерживают
      {
         if(lastButton==0x48B7) servoAngle = 115;// Удерживают "LEFT"
         if(lastButton==0xFFFFC837)servoAngle = 75; // Удерживают "RIGHT"   
      }
      irrecv.resume();
      delay (100);
  }

}

 

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Как вы написали я так уже пробовал. Для верности перепопробовал еще раз))...Не помогло. Все тоже самое.  Хех... Видно придется вращать серву "вручную" как тут предлагают http://coolcode.ru/arduino-upravlenie-servoprivodom-bez-biblioteki-servo-h/

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, нет, оно должно работать, надо просто спокойно разбираться в чём дело.

Например, попробуйте в моём коде, после строки 20 поставить задержку, ну для начала в полсекунды (я понимаю, что она неприемлема в конечно коде),  но мы пока проблему ищем. Изменилось что-то?

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Я извиняюсь, вот так как в вашем примере заработало. Я просто не досмотрел что этот код на основе второго варианта моего кода.  Но второй вариант и был рабочим. А мне надо чтобы было именно по удержанию кнопки. Мне кажется что-то не так именно с удержанием кнопки т.е. с приемом 0хFFFFFFFF. Ведь серва гарантировано стоит в 90 градусах как будто нет приема...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так, стоп. То, что заработал - хорошо. Но, тогда я не очень понимаю, Чего Вам надо.

Ну, серва-то гарантированно стоит просто потому, что Вы её туда ставите. LOW на пине появляется постоянно и при наличие сигнала тоже. А Вы как увидите LOW, так и ставите - это стопудово неправильно.

Вас интересует нажатие и удержание кнопки на ПДУ, так? Правильно? Ответьте. Причём ответьте толком - типа "пока удерживаю, делается то-то ...". Если так, то это надо по другому обрабатывать.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Я попробовал вот так:

#include "IRremote.h"

IRrecv irrecv(11);
decode_results results;



#include <Servo.h>
Servo LXservo;
const char SERVO_MIDDLE_ANGLE = 90; // угол сервы при котором колеса выставлены прямо
int servoAngle = SERVO_MIDDLE_ANGLE;
int lastButton = 0;                   

void setup()
{
 LXservo.attach(8);   
 Serial.begin(9600); // Выставляем скорость COM порта
 irrecv.enableIRIn(); // Запускаем прием
}



void loop()                     
{
//if (digitalRead(11) == LOW) servoAngle = SERVO_MIDDLE_ANGLE; 

  if (irrecv.decode(&results)) 
  {
      int res = results.value;
      int lastButton ;
      Serial.println(res, HEX);
      if(res==0x48B7 || res==0xFFFFC837)// Если нажата кнопка "LEFT" или "RIGHT"
      {
         lastButton=res;
      }
      else if(res==0xFFFFFFFF)// Если кнопку удерживают
      {
         if(lastButton==0x48B7) servoAngle = 115;// Удерживают "LEFT"
         if(lastButton==0xFFFFC837)servoAngle = 75; // Удерживают "RIGHT"   
      }
      irrecv.resume();
      delay (100);
  }
  else {servoAngle = SERVO_MIDDLE_ANGLE;}
  LXservo.write(servoAngle);
}

Т.е. вставил  строки 44 45 из вашего примера. Т.е. не по LOW тоже не работает.

Что мне надо:

1. При нажатии  и дальнейшем удержании кнопки LEFT происходит поворот влево (115 градусов).

2. При нажатии и дальнейшем удержании кнопки RIGHT происходит поворот вправо (75 градусов).

3. При отпускании кнопок серва становится в нейтральное положение (SERVO_MIDDLE_ANGLE).

Удержание надо чтобы в дальнейшем реализовать плавный поворот в зависимости от длительности удержания (чем дольше держишь кнопку тем на больший угол происходит поворот), но это другая история. Покачто пусть оно заработает в простом варианте.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Хорошо, для начала, давайте посмотрим, что выдаёт Ваш приёмник. Запустите скетч:

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

#include "IRremote.h"

IRrecv irrecv(11);

void setup() {
	Serial.begin(115200);
	irrecv.enableIRIn();
}
 
void loop() {
	decode_results results;
 	if (irrecv.decode(&results)) {
		Serial << "Signal: " << results.value << ", time:" << millis() << "\n";
		irrecv.resume(); // Попробуйте С этой строкой и БЕЗ неё
	} else {
		Serial << "NO Signal: time:" << millis() << "\n";
  }
}

Нажмите кнопку и немного подержите, затем отпустите.

Посмотрите на результат. Заодно скопируйте результат сюда (кусок от "нажатия - пару строк", до "отпускания + пару строк"), я тоже посмотрю.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Нажатие и удержание Лево, право с irrecv.resume()

Нажатие и удержание Лево, право без irrecv.resume()

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Скорость уменьшил до 300, ато на 115200 голова заболела)). Еще во втором случае (без irrecv.resume();) после одного нажатия сигнал не прекращался после отпускания кнопки.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Так, ну сами-то посмотрели? Видите, с resume у Вас в то время, когда кнопка нажата сигнал постоянно то появляется. то пропадает (а кнопку-то никто не отпускал!) Этого Ваша программа не обрабатывает.

Без resume сигнал чистый. Пока держите - идёт постоянно. 

Можно попробовать запустить основной код без resume и посмотреть что будет (хотите, попробуйте). Но я бы сначала попробовал более чистый эксперимент. Дело в том, что вывод в сериал очень длительная и сложная процедура. Давайте поставим такой эсепримент, а потом уж будем думать что делать с кодом.

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

#include "IRremote.h"

IRrecv irrecv(11);

void setup() {
	Serial.begin(115200);
	Serial << "Fun begins!!!\n";
	irrecv.enableIRIn();
}

enum STATES { BTN_PRESSED, BTN_RELEASED };

void loop() {
	static STATES state = BTN_RELEASED;
	decode_results results;
	
 	if (irrecv.decode(&results)) {
		if (state == BTN_RELEASED) {
			state = BTN_PRESSED;
			Serial << "Button pressed\n";
		}
		irrecv.resume(); // Опять пробуйте С этим и БЕЗ этого
	} else {
		if (state == BTN_PRESSED) {
			state = BTN_RELEASED;
			Serial << "Button released\n";
		}
  }
}

По идее, в этом тесте при нажатии кнопки должно однократно появлятья сообщение pressed, а при отпускании - released. Если же в процессе, пока кнопка нажата, будет появляться то released, то pressed, мы должны понимать, что сигнал самопроизвольно пропадает и учитывать это в программе.

Сделайте и скажите как получилось с resume и как без resume.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

baklan пишет:

сигнал не прекращался после отпускания кнопки.

А! Это важно. Запомним. Сделайте пока второй тест, который я только что выложил.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, что там, как оно? Попробовали? У меня просто нет под рукой ничего (я еду в машине (не за рулём) с ноутбуком на коленях), а то я бы давно сам провёл все свои эксперименты.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

С irrecv.resume() нажатие и удержание. То есть сигнал сам пропадает???

Без irrecv.resume() после одного нажатия программа перестает реагировать на манипуляции с пультом.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Окей. Промежуточные выводы

1. Забываем про вариант без resume. resume нужен и точка.

2. Я проавильно понял, что цепочка pressed-released появлялась в процессе постоянного удержания кнопки? Так? Значит сигнал периодически пропадает.

В Вашей программе факт пропадания сигнала не обрабатывался никак. А обрабатывать надо.

Значит, делаем так. Сейчас мы выясним на какое время прпадает сигнал, а потом будем думать можно ли с этим бороться.

Время которое мы печатали в первом тест не подойдёт, т.к. там была ОЧЕНЬ тормозная операция вывода в Serial. Нам нужно измерить время более чисто. Сейчас я модивифицирую тест. 

Минутку.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

#include "IRremote.h"

IRrecv irrecv(11);

void setup() {
	Serial.begin(115200);
	Serial << "Fun begins!!!\n";
	irrecv.enableIRIn();
}

enum STATES { BTN_PRESSED, BTN_RELEASED };

void loop() {
	static unsigned long times[20];
	static int8_t counter = 0; 
	static STATES state = BTN_RELEASED;
	decode_results results;

	if (counter >= 20) return;
	
 	if (irrecv.decode(&results)) {
		if (state == BTN_RELEASED) {
			state = BTN_PRESSED;
			times[counter++] = millis();
		}
		irrecv.resume(); 
	} else {
		if (state == BTN_PRESSED) {
			state = BTN_RELEASED;
			times[counter++] = millis();
		}
  }

	if (counter >= 20) {
		unsigned long lastVal = 0;
		for (int8_t i = 0; i < 10; i++) {
			Serial << "Pressed: " << times[i*2];
			if (lastVal) Serial << "; Interval: " << (times[i*2] - lastVal) << '\n';
			Serial << "\nReleased: " << times[i*2 + 1] << '\n';
			lastVal = times[i*2 + 1]; 
		}
	}
}

Запустите. Нажмите кнопку и держите пока не вылезет "отчёт". После этого можете отпускать, больше там ничего происходить не будет.

В отчёте после каждого "pressed" (кроме первого) будет написан временной интервал с предыдущего "released". Так мы узнаем на какое время пропадает сигнал.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кстати, мне попробовать не на чем, так что если где лопухнулся - опишите внятно ошибку, я поправлю.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Теперь понятно почему все работает при однократном нажатии и не работает при удержании. Получается передатчик шлет прерывистый сигнал и серва просто не успевает повернуться как сигнал опять пропадает.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ага, ну, вот, теперь понятно.

Т.е. при постоянно нажатой кнопке сигнал на самом деле появляется на очень короткий интервал (время между pressed и последующим released везде меньше миллисекунды, а затем пропадает примерно на 110 мс. Затем снова появляется на такой же короткий интервал, затем снова пропадает на 110 мс и т.д.

Теперь понятно, почему у Вас ничерта не работало? Вы просто считали, что там постоянно "высокий уровень", а он идёт "короткими пиками" - это я о сигнале.

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

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

1. Когда зафиксировали первое нажатие, запомнили время.
2. Ждём того, что случится раньше: появится следующее нажатие или истекут 120мс.
   3) если раньше появилось следующее нажатие, запоминаем время и переходим к п.2
   4) если раньше истёк интервал в 120мс, фиксируем факт отпускания кнопки.

Вот как-то так должно нормально работать. Вы согласны с такой логикой?

Попробуйте её реализовать без меня. Постарайтесь - всё у Вас получится. Если уж совсем зашьётесь ....

Но про предварительное исследование аппаратуры (как раз то, чем мы полдня занимались) - это общее правило! Всегда с этого начинайте - сначала найти все грабли, а потом уж ходить по грядке.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

ОК. Спасибо. Логика понятна. Буду пробовать.

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Вот както так, уже с плавным ходом сервы по длительности удержания. Более менее стабильно работает только с такими значениями "millis() - Time" и "дэлэем" в конце loop-а. Более менее стабильно потому, что при быстром попеременном и многократном нажатии LEFT и RIGHT происходит зависание МК, а шестилетний пользователь данного устройства гарантировано так делать будет и часто)). Помогает кнопка РЕЗЕТ. В двух предыдущих проектах была защита от зависаний по "watch dog timer". Но здесь он почему-то не работает плюс добавляет глюков в работу схемы. Вероятно виноваты таймеры... Буду ковыряться дальше...



//#include <avr/wdt.h>// библиотека watch dog timer для защиты от зависания

#include "IRremote.h"
IRrecv irrecv(11);
decode_results results;


#include <Servo.h>
Servo LXservo;
const char SERVO_MIDDLE_ANGLE = 90; // угол сервы при котором колеса выставлены прямо
int servoAngle = SERVO_MIDDLE_ANGLE;
int res ; // код приема при нажатии кнопки
int lastButton = 0 ; // код последней кнопки
bool buttonPressed = false ; // факт удерживания кнопки                  
int Time = 0; // переменная для хранения времени предыдущего приема сигнала

void setup()
{
//  wdt_enable(WDTO_60MS);    // если произойдет зависание, то контроллер будет перезагружен через 60 мс
 LXservo.attach(8);   
 Serial.begin(19200); // Выставляем скорость COM порта
 irrecv.enableIRIn(); // Запускаем прием
}



void loop()                     
{
  //  wdt_reset();
  if (irrecv.decode(&results)) 
  {
      res = results.value ;
      Serial.println(res, HEX) ;
      if(res==0x48B7 || res==0xFFFFC837)// Если нажата кнопка "LEFT" или "RIGHT"
      {
         lastButton=res;
       }
      else if(res==0xFFFFFFFF)// Если получен сигнал FFFFFFFF
      {
           buttonPressed = true; 
           Time = millis(); // запоминаем время предыдущего сигнала FFFFFFFF для следующего цикла loop
       }
      irrecv.resume();
    }
   else // если сигнал не получен ->
   {
     if (millis() - Time > 125) buttonPressed = false ; // -> более 125 мс, то кнопка отпущена
   }
  
   if (buttonPressed == true )
   {
     if(lastButton == 0x48B7 && servoAngle < 130) servoAngle ++;// Удерживают "LEFT"
     else if(lastButton==0xFFFFC837 && servoAngle > 50)servoAngle --; // Удерживают "RIGHT" 
     }
   else if (buttonPressed == false)
   {
     if(servoAngle > SERVO_MIDDLE_ANGLE) servoAngle --;
     if(servoAngle < SERVO_MIDDLE_ANGLE)servoAngle ++;     
     }
   LXservo.write(servoAngle);
   delay (5);
}


 

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Переделал часть кода на операторе switch (стр. 50 -61). Перестало работать. В чем ошибка?

//#include <avr/wdt.h>// библиотека watch dog timer для защиты от зависания

#include "IRremote.h"
IRrecv irrecv(11);
decode_results results;


#include <Servo.h>
Servo LXservo;
const char SERVO_MIDDLE_ANGLE = 90; // угол сервы при котором колеса выставлены прямо
int servoAngle = SERVO_MIDDLE_ANGLE;
int res ; // код приема при нажатии кнопки
int lastButton = 0 ; // код последней кнопки
bool buttonPressed = false ; // факт удерживания кнопки                  
int Time = 0; // переменная для хранения времени предыдущего приема сигнала

void setup()
{
//  wdt_enable(WDTO_60MS);    // если произойдет зависание, то контроллер будет перезагружен через 60 мс
 LXservo.attach(8);   
 Serial.begin(19200); // Выставляем скорость COM порта
 irrecv.enableIRIn(); // Запускаем прием
}



void loop()                     
{
  if (irrecv.decode(&results)) 
  {
      res = results.value ;
      Serial.println(res, HEX) ;
      if(res==0x48B7 || res==0xFFFFC837)// Если нажата кнопка "LEFT" или "RIGHT"
      {
         lastButton=res;
       }
      else if(res==0xFFFFFFFF)// Если получен сигнал FFFFFFFF
      {
           buttonPressed = true; 
           Time = millis(); // запоминаем время предыдущего сигнала FFFFFFFF для следующего цикла loop
       }
      irrecv.resume();
    }
   else // если сигнал не получен ->
   {
     if (millis() - Time > 125) buttonPressed = false ; // -> более 125 мс, то кнопка отпущена
   }


   switch (buttonPressed)
   {
      case true: 
           switch (lastButton)
           {
              case 0x48B7: if(servoAngle < 130) servoAngle ++;
              case 0xFFFFC837: if(servoAngle > 50)servoAngle --;
           }
      case false: 
           if(servoAngle > SERVO_MIDDLE_ANGLE) servoAngle --;
           if(servoAngle < SERVO_MIDDLE_ANGLE)servoAngle ++;     
   }

   LXservo.write(servoAngle);
   delay (5);
}

 

baklan
baklan аватар
Offline
Зарегистрирован: 06.09.2016

Разобрался. Забыл про оператор break  после каждого case.