я не могу работать над своим небольшим проектом

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

это мой код arduino

#define CLK 10
#define CLKI 9
#define LD 8
#define SO 11
#define SER 12

byte ledstates;
byte copy=0;
int rec=0;
unsigned long bt_leds_timestamp=0;
byte bt_leds_activated=0;

void setup(){
Serial.begin(9600);
pinMode(CLK,OUTPUT);
pinMode(CLKI,OUTPUT);
pinMode(LD,OUTPUT);
pinMode(SO,INPUT);
pinMode(SER,OUTPUT); 
}

void loop(){
if (Serial.available()>0){
message();
}
if(bt_leds_activated && millis()-bt_leds_timestamp > 2000){
ledstates &= ~bt_leds_activated;
shift_out(ledstates);
bt_leds_activated = 0;
}
shift_In();
shift_out(ledstates);
}

void message(){
if(Serial.available()){      // Send data only when you receive data:
char data = Serial.read();        //Read   the incoming data & store into data
Serial.print(data);          //Print Value inside data in Serial monitor

switch (data){
  case 'A' :
    bt_leds_activated |= 1;
    break; 
  case 'B' :
    bt_leds_activated |= 2;
    break;
  case 'C' :
    bt_leds_activated |= 4;
    break;
  case 'D' :
    bt_leds_activated |= 8;
    break;
  case 'E' :
    bt_leds_activated |= 16;
    break;
  case 'F' :
    bt_leds_activated |= 32 ;
    break;
  case 'G' :
    bt_leds_activated |= 64;
    break;
  case 'H' :
    bt_leds_activated |= 128;
    break;
  default   : return; }    
  }
  ledstates |= bt_leds_activated;
  shift_out(ledstates);
  bt_leds_timestamp = millis();

  } 

  void shift_out (byte copy){
  digitalWrite(LD, LOW);
  shiftOut(SER,CLK,MSBFIRST,copy);
  digitalWrite(LD, HIGH);
  delay(100);
  }

  void shift_In(){
  digitalWrite(CLKI,HIGH);
  digitalWrite(LD,HIGH);
  digitalWrite(LD,LOW);
  digitalWrite(LD,HIGH);
  digitalWrite(CLK,HIGH);
  digitalWrite(CLKI,LOW);
  byte buttonstates = shiftIn(SO,CLK,MSBFIRST); //read button states in a local variable
  digitalWrite(CLKI,HIGH);
  for(int i=0;i<8;i++){ // loop through all 8 bits of the buttonstates
    if(!(copy & (1<<i)) && (buttonstates & (1<<i))){ // check if old button state (in copy) is zero and new buttonstate is 1 (for the currently check bit)
        ledstates ^= 1<<i; // toggle the corresponding bit in the ledstates variable (will be shifted out later in the loop() function)
    }
  }
  copy = buttonstates;
  delay(10); // delay for debouncing
   }

, 👍1

Обсуждение

что значит переключиться?, @jsotola

Например, когда запустите этот код, а затем нажмите первую кнопку, светодиод не сохранит состояние high . Но светодиодное состояние то высоко, то быстро опускается . Я хочу сохранить состояние светодиода при нажатии кнопки click, @Khalid Abu-Khadija

@jsotola ты меня понял, @Khalid Abu-Khadija

я понимаю, что вы используете регистр сдвига для ввода и регистр сдвига для вывода .... вы ожидаете прочитать состояние переключателя и повлиять на состояние соответствующего светодиода .... вы хотите иметь возможность нажать переключатель, загореться светодиодом, отпустить переключатель и заставить светодиод гореть, @jsotola

@jsotola Да, это правда, что вы начали понимать, чего я хочу. Не забывайте, что я использовал Bluetooth, как вы видите на картинке, чтобы сделать ту же работу кнопки, @Khalid Abu-Khadija

вы должны понимать, что считывание состояния коммутатора и получение данных по Bluetooth полностью отделены от освещения светодиода ... вы пытаетесь объединить функции ввода и вывода в одну, и это не работает, потому что свет следует за состоянием переключателя .... вам нужно разделить переключатель/bluetooth и светодиодное освещение на две отдельные функции с сообщением, идущим между ними .... продолжение следует, @jsotola

подумайте о двух комнатах ... в первой комнате человек отвечает на телефонные звонки, а также проверяет положение 8 рычагов ... есть также лоток с 8 отделениями ... человек смотрит на каждый рычаг, и если он поднят, то он кладет черный шарик в соответствующее отделение лотка ... человек также проверяет наличие сообщений на телефоне ... сообщения состоят из одной буквы ... он/она кладет черный шарик в одно из отделений лотка в зависимости от сообщения ... затем человек передает поднос в другую комнату ...., @jsotola

человек в другой комнате смотрит на каждый отсек в лотке и включает один из 8 огней, если в отсеке есть шарики, @jsotola

первая комната может состоять из 20 комнат, каждая из которых добавляет мрамор на поднос, @jsotola

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


1 ответ


1

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

Как объяснил jsotola в комментариях, вам нужно отделить то, что вы получаете в качестве ввода (кнопки и последовательный), от того, что вы задаете в качестве вывода. Для этого вам понадобится 1 или более переменных для хранения состояния светодиодов (вашего выхода) и состояния каждого входа (например, каждой кнопки). Последнее - это то, что у вас есть в переменной копирования. Это похоже на состояние ввода кнопок. Теперь создайте новую переменную byte ledstates;. Функция shift_out() должна вызываться с помощью этой переменной, а не с помощью copy.

Теперь, когда ввод и вывод разделены, вы можете посмотреть на желаемое поведение для ввода. Поскольку нажатие 1 кнопки (нажатие и отпускание) должно переключать состояние соответствующего светодиода, вам нужно искать переход от НИЗКОГО уровня к ВЫСОКОМУ. Распространенный способ - сохранить текущее состояние кнопок в переменной. Затем при следующем выполнении функции shift_in() вы можете проверить, выполняется ли переход от НИЗКОГО к ВЫСОКОМУ предыдущему состоянию (сохраненному в переменной) и новому измеренному состоянию (ранее НИЗКОЕ, теперь ВЫСОКОЕ). Это нажатие кнопки, которую вы можете использовать для переключения соответствующего бита светодиода во вновь созданной переменной ledstates. Сохраните новое измеренное состояние в переменной копирования. (Кстати: вам следует переименовать переменную копирования во что-то более описывающее)

Также вам нужно рассмотреть механизм, с которым вам не пришлось возиться с предыдущим кодом: отскок кнопки. Механический переключатель или кнопка не сделают ни одного чистого перехода при нажатии. Механический контакт немного отскочит, что приведет к очень быстрым переходам от ВЫСОКОГО к НИЗКОМУ, пока кнопка не будет установлена. Если вы не учтете это в своей программе, вы получите множество переходов и, таким образом, будете много раз переключать светодиод только одним нажатием кнопки. Есть много способов решить эту проблему (и все они могут быть легко прогуглены). Я бы пошел по пути "не чувствую никаких дальнейших переходов после первого в течение определенного времени". Это может быть сделано простым вызовом функции delay() в конце вашей функции shift_in () (не так элегантно, с некоторыми оговорками) или с помощью millis() для создания неблокирующего тайм-аута (в лучшем случае для каждой кнопки в отдельности) (Посмотрите на пример BlinkWithoutDelay, который поставляется с Arduino IDE. Стоит изучить этот принцип).

Итак, у вас есть что-то вроде этого (не полный код, просто некоторые подсказки):

byte copy;
byte ledstates;

void loop(){
    if (Serial.available()>0){
        message();
    }
    shift_In();
    shift_out(ledstates);
}

void shift_in(){
    digitalWrite(CLKI,HIGH);
    digitalWrite(LD,HIGH);
    digitalWrite(LD,LOW);
    digitalWrite(LD,HIGH);
    digitalWrite(CLK,HIGH);
    digitalWrite(CLKI,LOW);
    byte buttonstates = shiftIn(SO,CLK,MSBFIRST); //read button states in a local variable
    digitalWrite(CLKI,HIGH);
    for(int i=0;i<8;i++){ // loop through all 8 bits of the buttonstates
        if(!(copy & (1<<i)) && (buttonstates & (1<<i))){ // check if old button state (in copy) is zero and new buttonstate is 1 (for the currently check bit)
            ledstates ^= 1<<i; // toggle the corresponding bit in the ledstates variable (will be shifted out later in the loop() function)
        }
    }
    copy = buttonstates;
    delay(10); // delay for debouncing
}

Как упоминалось выше, мы разделили ввод и вывод. Теперь легко также реализовать подходящее управление Bluetooth. Вы хотите, чтобы соответствующий индикатор включался на последовательном входе (через Bluetooth) и автоматически гас через определенное время. Для этого лучше всего использовать millis() с меткой времени. Сначала мы возьмем функцию message (). Мы определяем 2 переменные в глобальной области (вне любой функции в начале программы) для хранения метки времени нашей последней последовательной связи и байта для хранения светодиодов, которые активируются через последовательный. В функции message() мы теперь устанавливаем соответствующий бит в этой последней переменной. Если последовательные данные были неверными, мы просто возвращаемся из функции (это делает код короче). В конце функции мы гарантируем, что каждый светодиод, установленный в нашей переменной, также будет установлен в нашей переменной ledstates, которая затем будет смещена. И, наконец, мы сохраняем метку времени с помощью функции millis (), которая возвращает количество миллисекунд с момента запуска.

unsigned long bt_leds_timestamp=0;
byte bt_leds_activated=0;

void message(){
  if(Serial.available()){      // Отправляйте данные только тогда, когда вы получаете данные:
    char data = Serial.read();        //Считывание входящих данных и сохранение в данные
    Serial.print(data);          //Значение печати внутри данных в последовательном мониторе

    switch (data){
      case 'A' :
        bt_leds_activated |= 1;
        break; 
      case 'B' :
        bt_leds_activated |= 2;
        break;
      case 'C' :
        bt_leds_activated |= 4;
        break;
      case 'D' :
        bt_leds_activated |= 8;
        break;
      case 'E' :
        bt_leds_activated |= 16;
        break;
      case 'F' :
        bt_leds_activated |= 32 ;
        break;
      case 'G' :
        bt_leds_activated |= 64;
        break;
      case 'H' :
        bt_leds_activated |= 128;
        break;
      default   : return; }    
  }
  ledstates |= bt_leds_activated;
  shift_out(ledstates);
  bt_leds_timestamp = millis();
}

Теперь соответствующие светодиоды включаются, но не выключаются. Поэтому нам нужно поместить следующий код в функцию main loop ():

if(bt_leds_activated && millis()-bt_leds_timestamp > 2000){
  ledstates &= ~bt_leds_activated;
  shift_out(ledstates);
  bt_leds_activated = 0;
}

Этот код проверяет, был ли активирован какой-либо светодиод через Bluetooth (первая часть условия if принимает значение true, если значение bt_leds_activated отличается от нуля) и прошло ли определенное время (здесь 2 секунды, или 2000 мс) с момента снятия метки времени. Когда придет время, то биты светодиодов из bt_leds_activated, которые мы установили ранее, будут очищены вledstates, чтобы выключить светодиоды. Затем это смещается, чтобы установить фактическое состояние светодиодов, чтобы мы могли видеть. Наконец, мы сбрасываемзначение bt_leds_activated` до нуля, так как у нас больше нет светодиодов, которые можно было бы автоматически включать, пока не поступят новые данные.

У этого есть 1 предостережение: когда вы отправляете новые данные по Bluetooth в течение этих 2 секунд, время ожидания для светодиодов, ранее активированных по Bluetooth, также будет сброшено, чтобы они горели дольше. Способ обойти это-использовать 1 метку времени для каждого светодиода, но я подумал, что сейчас это сложно. Не хотите этого, вы можете реализовать эту часть самостоятельно, как я сделал со всеми ними вместе.

Примечание: Я никоим образом не тестировал этот код.

,

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перенесен в chat](https://chat.stackexchange.com/rooms/102771/discussion-on-answer-by-chrisl-i-cant-work-toggle-for-my-small-project)., @VE7JRO

во-первых : теперь отредактируйте мой код в этом вопросе на верхней странице . после запуска нового кода по Bluetooth при отправке A светодиоды включаются, но не выключаются. ? i but in (if condition) in [void loop () ]as in top code in this if(bt_leds_activated && millis()-bt_leds_timestamp > 2000){ ledstates &= bt_leds_activated; shift_out(ledstates); bt_leds_activated = 0; }, @Khalid Abu-Khadija

Пожалуйста, используйте чат для дальнейшего общения. Все комментарии загромождают пространство комментариев, @chrisl

@chrisl при использовании функции millis() im main loop светодиоды включаются всего на 2 секунды, а затем выключаются не идеально ansewr, @Khalid Abu-Khadija

@KhalidAbu-Хадиджа, о чем ты говоришь? Я не понимаю. Пожалуйста, перефразируйте свой комментарий, @chrisl