1

enter image description here

i build my small project from a few component as this photo after finish code and project . i work run for Proteus and then the project not run perfectly because my code need toggle for data entered . i cant work toggle for data .i want help .please

this my code 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
   }
10
  • what does toggle mean?
    – jsotola
    Commented Dec 31, 2019 at 18:59
  • For ex when run this code and then press first button the led not save state high . But the led state high and then low quickly . I want save state led when press click Commented Dec 31, 2019 at 19:56
  • @jsotola did you understand me Commented Dec 31, 2019 at 21:12
  • i understand that you are using a shift register for input and a shift register for an output .... you expect to read the state of a switch and affect the state of a corresponding LED .... you want to be able to press a switch, have an LED light up, and release the switch and have the LED stay lit
    – jsotola
    Commented Dec 31, 2019 at 21:38
  • @jsotola Yes, it is true that you started to understand what I want. Don't forget to that I used Bluetooth as you see in the picture to do the same button work Commented Dec 31, 2019 at 21:53

1 Answer 1

1

Currently you are shifting in the button states and directly shifting them out again to the LEDs. Thus the state of the LEDs follows exactly the state of the buttons.

As jsotola explained in the comments, you need to seperate what you get as input (buttons and serial) from what you set as output. For this you need 1 or more variables to hold the state of the LEDs (your output) and the state of each input (for example each button). The last is what you have in the copy variable. It resembles the state of the buttons input. Now create a new variable byte ledstates;. The shift_out() function has to be called with this variable instead of with copy.

Now that input and output are seperated, you can look at the desired behavior for the input. As 1 button press (pressing and releasing) should toggle the state of the corresponding LED, you have to look for a LOW-to-HIGH transition. A common way is to save the current state of the buttons in a variable. Then, in the next execution of shift_in() you can check, if the previous state (as saved in the variable) and the new measured state do a LOW-to-HIGH transition (previously LOW, now HIGH). This is a button press, that you can use to toggle the corresponding LED bit in the newly created ledstates variable. Save the new measured state in the copy variable. (Btw: You should rename the copy variable to something more describing)

Also you need to consider a mechanism, that you haven't had to bother with the previous code: Button bouncing. A mechanical switch or button will not make one single clean transition, when being pressed. The mechanical contact will bounce a bit, resulting in very fast HIGH-LOW transitions, until the button is settled. If you don't consider that in your program, you will get many transitions and thus toggling the LED many times with only one button press. There are many ways to tackle this (and all of them can be easily googled). I would go with the "don't sense any further transitions after the first for a fixed time" way. This can be done by a simple delay() call at the end of your shift_in() function (not so elegant with some caveats) or by using millis() to create a non-blocking timeout (in the best case for each button individually) (Look at the BlinkWithoutDelay example, that comes with the Arduino IDE. It is worth learning this principle).

So you have something like this (not the full code, just some hints):

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
}

As mentioned above we have seperated input and output. Now it is easy to also implement a fitting bluetooth control. You want the corresponding light go on on serial input (through bluetooth) and go out after a specific time automatically. For such a thing using millis() with a timestamp is the best option. First we take the message() function. We define 2 variables at the global scope (outside of any function at the start of the program) to hold the timestamp of our last serial communication and a byte to hold the LEDs, that where activated via serial. In the message() function we now set the corresponding bit in this last variable. If the serial data was not valid, we simply return from the function (this makes the code shorter). At the end of the function we ensure, that every LED that was set in our variable gets also set in our ledstates variable, which then will be shifted out. And lastly we save a timestamp with the millis() function, which returns the number of milliseconds since the startup.

unsigned long bt_leds_timestamp=0;
byte bt_leds_activated=0;

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();
}

Now the corresponding LEDs get turned on, but not off. So we need to put the following code in the main loop() function:

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

This code checks, if any LED was activated via bluetooth (the first part of the if condition evaluates to true, if bt_leds_activated is different than zero) and if a certain time (here 2s aka 2000ms) has passed since the timestamp was taken. When the time has come, then the LED bits from bt_leds_activated, which we set earlierare cleared inledstatesto turn the LEDs off. Then this is shifted out to set the actual state of the LEDs for us to see. Finally we resetbt_leds_activated` to zero, since we don't have any more LEDs to turn of automatically, until new data arrives.

This has 1 caveat: When you send new data over bluetooth within these 2s, the timeout for the LEDs previously activated via bluetooth will also be resetted, so that they will light longer. The way around that is to use 1 timestamp for each LED, but I thought this as to complicated for now. Don't want this, you can implement that part yourself just like I did with all of them together.

Note: I haven't tested this code in any way.

5
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – VE7JRO
    Commented Jan 1, 2020 at 19:53
  • firstly : now done edit my code in this question in the top page . after run the new code by Bluetooth when send A the LEDs get turned on, but not off. after send A what is the mean (main loop())?? i but in (if condition) in the [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; } Commented Jan 1, 2020 at 21:16
  • 1
    Please use the chat for further communication. All the comments clutter up the comment space
    – chrisl
    Commented Jan 1, 2020 at 22:02
  • @chrisl when use millis() function im main loop the leds turn on just 2 sec and then turn off not perfect ansewr Commented May 17, 2020 at 19:54
  • @KhalidAbu-Khadija What are you talking about? I don't understand. Please rephrase your comment
    – chrisl
    Commented May 17, 2020 at 20:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.