Изменить стиль страницы

#define заменяются компилятором перед трансляцией кода в исполняемую программу.

В следующей программе val используется для хранения результата функции digitalRead(); что-бы ни получала Arduino со входа попадает в переменную и остаётся там до тех пор, пока другая строка кода не изменит её. Отметьте, что эти переменные хранятся в оперативной памяти, называемой (RAM). Она очень быстрая, но когда вы выключите свою плату, все данные в оперативной памяти будут потеряны (что означает что все переменные будут сброшены в начальные значения при включании платы). Ваша программа хранится во флеш-памяти (такой-же тип памяти используется в сотовых телефонах для хранения записной книжки) которая не изменяется при отключении платы от питания.

Давайте используем другую переменную для запоминания должен-ли светодиод оставаться включённым когда мы отпускаем кнопку. Пример 4-3 - это наша первая попытка:

Пример 4-3. Включить светодиод при нажатии кнопки и оставить его включённым при отпускании кнопки

#define LED  13  // the pin for the LED

#define BUTTON 7 // the input pin where the

                 // pushbutton is connected

int val = 0; // val will be used to store the state

                 // of the input pin

int state = 0; // 0 = LED off while 1 = LED on

void setup() {

  pinMode(LED, OUTPUT); // tell Arduino LED is an output

  pinMode(BUTTON, INPUT); // and BUTTON is an input

}

void loop() {

  val = digitalRead(BUTTON); // read input value and store it

  // check if the input is HIGH (button pressed)

  // and change the state

  if (val == HIGH) {

    state = 1 - state;

  }

  if (state == 1) {

    digitalWrite(LED, HIGH); // turn LED ON

  } else {

    digitalWrite(LED, LOW);

  }

}

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

Посмотри на интересную часть кода: state - это переменная, которая хранит значение 0 или 1 для запоминания включён светодиод или нет. После отпускания кнопки мы устанавливаем её в 0 (светодиод выключен).

Далее мы считываем текущее состояние кнопки, и если она нажата (val == HIGH), мы изменяем state с 0 на 1, или наоборот. Поскольку state может быть равна только 1 или 0, используем небольшой трюк. Он заключается в маленьком математическом выражении, идея которого состоит в том, что 1 - 0 = 1, а 1 - 1 = 0:

state = 1 - state;

Такая строка не имеет смысла в математике, но он есть при программировании. Знак "=" означает "присвоить результат выражения после меня переменной передо мной" - в данном случае, новое значение state будет вычислено как единица минус старое значение state.

Далее в программе вы видите, что мы используем state для выяснения должен-ли светодиод быть включён или выключен. Как я говорил, это приводит к странному результату.

Результат странный из-за способа считывания кнопки. Arduino очень быстрая; она выполняет свои команды со скоростью 16 миллионов в секунду - вполне может быть, что и несколько миллионов строк кода за секунду. Это означает что пока ваш палец нажимает кнопку, Arduino может снять данные с кнопки несколько сотен раз и изменить столько-же раз состояние светодиода. Результат непредсказуем; светодиод может остаться выключённым когда вы хотите его включить и наоборот. Поскольку даже сломанные часы показывают верное время дважды в день, программа может выдавать верный результат каждый раз какое-то время, но и долгое время - неправильный.

Как ним исправить эту ситуацию? Требуется определить момент нажатися конпки - именно в этот момент следует изменять state. Способ, который мне нравится, таков - хранить старое значение val перед считыванием нового; это позволяет мне сравнить текущее положение кнопки с предыдущим и изменить state только когда кнопка стала "HIGH" после того, как была "LOW".

Пример 4-4 содержит следующий код:

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

#define LED  13   // the pin for the LED

#define BUTTON 7  // the input pin where the

                  // pushbutton is connected

int val = 0; // val will be used to store the state

                  // of the input pin

int old_val = 0; // this variable stores the previous

                  // value of "val"

int state = 0; // 0 = LED off and 1 = LED on

void setup() {

  pinMode(LED, OUTPUT); // tell Arduino LED is an output

  pinMode(BUTTON, INPUT); // and BUTTON is an input

}

void loop(){

  val = digitalRead(BUTTON); // read input value and store it

                             // yum, fresh

  // check if there was a transition

  if ((val == HIGH) && (old_val == LOW)){

    state = 1 - state;

  }

  old_val = val;  // val is now old, let's store it

  if (state == 1) {

    digitalWrite(LED, HIGH); // turn LED ON

  } else {

    digitalWrite(LED, LOW);

  }

}

Попробуйте код, мы почти закончили!

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

Когда кнопка "дребезжит", Arduino видит быструю последовательность сигналов включения и выключения. Существует множество видов антидребезга, но для нашего, простого кода, я заметил что достаточно добавить 10...50-миллисекундную задержку чтобы код определил изменение.

Окончательный код показан в примере 4-5.

Пример 4-5. Включить светодиод при нажатии кнопки и оставить его включённым после отпускания кнопки, включая простой антидребезг. Теперь с новой, улучшенной формулой!

#define LED  13   // the pin for the LED

#define BUTTON 7  // the input pin where the

                  // pushbutton is connected

int val = 0; // val will be used to store the state

                  // of the input pin

int old_val = 0; // this variable stores the previous

                  // value of "val"

int state = 0; // 0 = LED off and 1 = LED on

void setup() {

  pinMode(LED, OUTPUT); // tell Arduino LED is an output

  pinMode(BUTTON, INPUT); // and BUTTON is an input

}

void loop(){

  val = digitalRead(BUTTON); // read input value and store it

                              // yum, fresh

  // check if there was a transition

  if ((val == HIGH) && (old_val == LOW)){

    state = 1 - state;

    delay(10);

  }

  old_val = val; // val is now old, let's store it

  if (state == 1) {

    digitalWrite(LED, HIGH); // turn LED ON

  } else {

    digitalWrite(LED, LOW);

  }