This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Push button S2 & S3 in ARM9

Hello

I am trying to assign a function to each S2 and S3 push buttons. ( port 3.5 & 3.6 ) I want to get a display that the button S2 is pressed when it is pressed.
But i always get the message " S2 not Pressed". any ideas??

I did the following ( just the important things). These come inside the void main (void).


unsigned short Read_value2;

//*******************************
// Buttons 5 and 6 on Port 3
//*******************************

  SCU_APBPeriphClockConfig(__GPIO3,ENABLE);
  SCU_APBPeriphReset(__GPIO3,DISABLE);

  GPIO_StructInit(&GPIO_InitStruct);
  GPIO_InitStruct.GPIO_Pin= GPIO_Pin_5 | GPIO_Pin_6;
  GPIO_InitStruct.GPIO_Direction=GPIO_PinInput;
  GPIO_InitStruct.GPIO_Type=GPIO_Type_PushPull;
  GPIO_InitStruct.GPIO_IPInputConnected = GPIO_IPInputConnected_Enable;
  GPIO_Init(GPIO3,&GPIO_InitStruct);

Read_value2= GPIO_Read(GPIO3);
if ((Read_value2 && 0x20) == 0x00)// checking whether the push button is pressed
{
    lcd_clear();
    lcd_print (" S2 Pressed ");
}
else
{
lcd_clear();
lcd_print (" S2 Not pressed ");
}

Parents
  • Oh yeah.. Thnx ... "&" worked. But there is a problem.

    Now i can see the result when you press the S2 or S3 button. But the problem is I have to keep pressing the buttons for a long time to see the result. How is it possible to get the output from S2 instantaneously?? I would like to press it only just once after the "Press Start" message and not pressing it continously for a long time.

    any ideas?

Reply
  • Oh yeah.. Thnx ... "&" worked. But there is a problem.

    Now i can see the result when you press the S2 or S3 button. But the problem is I have to keep pressing the buttons for a long time to see the result. How is it possible to get the output from S2 instantaneously?? I would like to press it only just once after the "Press Start" message and not pressing it continously for a long time.

    any ideas?

Children
  • You only sample the digit once / iteration.

    So the time it takes to clear the LCD and print a message will decide how often you check the buttons. There isn't a reason to print to the display if the button state is the same as the previous check. So you could buffer the previous state and compare with current state.

    Next thing is that you print current value - if you let go of the button, the next scan will detect and change the displayed text. If you want to latch the button, then you will have to store the change to a variable. The question then is - should the variable constantly remember that you have pressed, or should every press (with a release between) toggle the state? Decisions, decisions.

    In the end, you (!) must figure out exactly what problem you want to solve. Then write code that does exactly what you intended. If you want your code to have "memory", then you must make use of variables to store state information. If you want your code to be fast, then you must avoid doing things that takes time - or at least optimize so you only do things when it does matter.

  • So you say that i have to check whether the button is pressed, then store this change of value to a variable and check whether it is changed every second. Yes the variable then will have to constantly remember that i have pressed.

    Actually I dont want to print anything when the button S2 is pressed. I just started it like that so as to know whether it works and to make things easy to get the final result. All i want is to blink the LED for 3 times ( from left to right) with a random time interval, in between. Button S2 is like a start button , that initiates this process.

  • So if S2 is a start button, then it sounds like you should design a state machine.

    If state is zero and you see the button pressed, then you change state to 1.

    Then your main loop constantly check the state of the state machine to decide what to do.
    If zero, then it shoulnd't do anything - you are waiting for the S2 button press.
    If non-zero, then do whatever the state demands, and then step the state (with potential delay between state changes).

    When you have run through all your states, you either park your state machine permanently at an "end" state, or you switch it back to state zero again, arming your code in wait for another S2 press.

  • Thanks Westermark!! I introduced a state machine and now it works. When ever i press S2 or S3 it shows the display message.

    How is it possible to stop an activity when one button is pushed??. For example When S2 is pressed , the LEDs blink ,lest say, 5 times. When i press S3 in between ( lets say afte 2nd time) , the LEDs should stop . I tried putting a case within a case , so that when the second case comes, it will be executed. But it does not work.

    while (1)
    {
    .....
      switch (state_S2)
      {
        case 0x00:
    
        for ( k = 0; k <= 3;k++)
        {
         switch (state_S3)
         {
          case 0x00:
          /*if S3 is pressed, it should stop, Otherwise continue blinking
         }
    
           /*code for LED blinking */
    
        }
      }
    }
    

  • A state machine shouldn't use a for loop like that. It should use the state variable (or a sub-state variable) to count the number of blinks.

    That means that it should at all times continue to evaluate the main state. So a detection of the second button should be able to jump to a "clear" state.

    The important thing here is that the state machine should always evaluate current state and stimuli and make a decision. Then do an optional quick action and then return back to evaluate current state and stimuli again.

    If you are on the way to park your car, and a friend come running and ask if you can take the car and help him pick up some gear, you want to be able to make a decision directly. You do not continue to park the car. Get out of it. Close the garage door. Get into your apartment. Then decide if you should help him out. You always run the "main loop" and when you get an important stimuli you directly decide to change into a different state.

  • Also known as Finite State Machines (FSM), or Finite State Automata (Note that "Automata" is the plural of "Automaton")

    Try these terms in your favourite internet search engine...

  • How is it possible to evaluate the main state all the time?

    I was thinking of more or less similar idea. To use a counter when ever button S3 is pressed. And to compare whether the value of counter has changed. This comparion has to be done inside the S2 Button case, so that if there is a change in counter, it will stop the S2 button action ( break)
    But i am not sure of the counter i used. Does it count all the time when ever i press S3?? because i am reading S3 and incrementing count inside the S2 case 0x00.

    I tried the following. But Not getting the result. Can some1 help me??

    Thnx

    while (1)
    {
            count=0;
            Read_value3=GPIO3->DR[0x3FC];  // Reading all the values from port 3
            new_state3 = ((Read_value3 & 0x40) >> 0x00);// checking whether Button S3 is pressed
            count++;// counting
            Read_value2=GPIO3->DR[0x3FC];  // Reading all the values from port 3
            new_state2 = ((Read_value2 & 0x20) >> 0x00);// checking whether Button S2 is pressed
    
            switch (new_state2)
            {
                    case 0x00:
                    {
    
                            Read_value3_after=GPIO3->DR[0x3FC];//Reading all the values from port 3 AGAIN
                            new_state3_after = ((Read_value3_after & 0x40) >> 0x00);// checking whether Button S3 is pressed AGAIN
                            count++;// counter increases again
                            new_count= count;
                            if((new_count != count))
                            {
                                    lcd_clear();
                                    lcd_print (" S3 Pressed ");
                                    lcd_clear();
                                    lcd_print ("STOP is Pressed");
                                    set_cursor (2, 1);
                                    lcd_print ("Start Again");
                                    GPIO_Write(GPIO7, 0xFF);
                                    break;
                            }
                            else
                            {
    
                                    lcd_clear();
                                    lcd_print (" S2 Pressed ");
                                    for ( k = 0; k <= 3;k++)
                                    {
                                            for (n = 0x01; n <= 0xFF; n <<= 1)     /*On0e LED moving from 7.0 to 7.7*/
                                            {
                                                    wait_LED();
                                                    GPIO7->DR[0x3FC] = n;            /* Turn on LED */
                                            }
                                    }
                            }
                            break;
                    }
            }
    }
    
    
    

  • Can be made simpler too.

    One alternative (inside your infinite loop):

    switch (state) {
        case STATE_IDLE:
            if (s2_pressed) state = STATE_BLINK0;
            break;
        case STATE_BLINK0:
        case STATE_BLINK2:
        case STATE_BLINK4:
            if (s3_pressed) {
                led_off();
                state = STATE_IDLE;
            } else {
                led_on();
                state++;
            }
            break;
        case STATE_BLINK1:
        case STATE_BLINK3:
        case STATE_BLINK5:
            led_off();
            if (s3_pressed || state == STATE_BLINK5) {
                state = STATE_IDLE;
            } else {
                state++;
            }
            break;
        default:
            // bummer - invalid state encountered.
            led_off();
            state = STATE_IDLE;
    }
    

    or you could do:

    for (;;) {
        if (s3_pressed) {
            led_off();
            state = STATE_IDLE;
        }
        switch (state) {
            case STATE_IDLE:
                if (s2_pressed) state = STATE_BLINK0;
                break;
            ...
        }
    }
    

    Of course, you don't need to waste 6 states for generating 3 blinks. You could use a counter as sub-state information, to keep track of number of blinks performed.

    One thing I glossed over in above code is the delay during LED on and LED off.

    This is easy to handle by have the states check if there are time remaining before they may either perform their action, or before they may change state to the next state in the blink sequence. This delay code should be bypassed in regards to detection of the s3 button since you want s3 to instantly reset the sequence.

  • sorry Westermark. I could not follow your codes.
    First of all , i think you have mistaken about the LED blinking.
    The code below makes one light to move through the LEDs with a specified time gap in between. i.e 7.0 glows- goes out, 7.2 glows- goes out... 7.7 glows-goes out. This whole one length takes aprrox 1 -2 sec. This length to lenght LED glow takes place 3 times.

    for ( k = 0; k <= 2;k++)
    {
      for (n = 0x01; n <= 0xFF; n <<= 1) /*One LED moving from 7.0 to 7.7*/
      {
         wait_LED();
         GPIO7->DR[0x3FC] = n;            /* Turn on LED */
      }
    }
    

    And what i am tying to do is this:

    If S2 is pressed ,this( the above code) process starts. In between the LED run, if i press S3, LED blinking should stop. i.e it should also interrupt the running LED and all LEDs off.

    Your first option ( in ur previous reply), i could not follow it.
    I tried the Second option,but it just gives the same output. i.e
    if S2 is pressed--> LEDs run,
    if S3 is pressed in between S2 function --> Nothing happens
    If S3 is pressed alone -->all LEDs OFF

  • You should implemenent a state machine that evaluates the state information and optionally performs any action quickly, and then returns to reevaluate the state information again. And again. And again.

    You should not implement a huge loop in the middle, with a huge delay. If you create a single close block that takes 1 second to run, then it obviously will not look at the key presses during that second, unless you sprinkle your code with new key tests.

    So you may have any numbers of LEDs. Then it would be state information what LED to light. And you have a delay. Then you shouldn't lock the state machine while the delay executes. You should have your state machine start a software or hardware timer. Then your state machine should - in a specific state - constantly check if that timer has run the full time or if there are any other stimuli that motivates the state machine to jump out of that state.

    With your code, wait_LED() will wait whatever long time without caring about any button presses. And when you return, your for loop will continue with next LED pattern to output, without caring about any state information or button presses.

    My code did show an example where the state machine did flash a single LED three times. It should be too hard to figure out a state machine that did count 0 to 255 on 8 LED using an 8-bit counter as sub-state information. So

    ...
    case STATE_IDLE:
        if (button_s3_pressed()) {
            // Ignore looking at s2 for starting a new sequence as long as
            // the S3 - reset - button is detected. Would be meaningless
            // to try to jump for first display state just to instantly
            // see S3 pressed and return back to the idle state...
        } else if (button_s2_pressed()) {
            // S2 button requests us to start displaying our LED pattern
            // sequence.
            led_pattern = 0;
            state = STATE_SHOW_LED_PATTERN;
        }
        break;
    case STATE_SHOW_LED_PATTERN:
        // The state machine spends too little time in this state - it directly jumps
        // to a delay state - so let's ignore checking for any buttons or other
        // stimuli that might request state-machine changes.
        // Only safe to do if button presses are cached, or if the buttons are
        // processed by an interrupt handler, or if the state machine loop runs
        // fast enough that it has time to perform all work in this state and
        // return back for next iteration of the state machine loop and scan
        // buttons in less time than the button press detection code requires
        // to catch the shortest allowed button press.
        set_led_pattern(led_pattern);
        delay_t0 = timer_now();
        state = STATE_WAIT_LED_PAUSE:
        break;
    case STATE_WAIT_LED_PAUSE:
        if (button_s3_pressed()) {
            // Button S3 pressed - exit from our pattern output and reset state
            // machine to idle again.
            set_led_pattern(0);
            state = STATE_IDLE;
        } else if ((timer_now() - delay_t0) >= LED_DELAY_TICKS) {
            // OK - current LED pattern have shown for long enough time. Now
            // check if all 256 patterns have been shown, or if we should
            // step to next pattern.
            if (led_pattern == 255) {
                // Full 256-step sequence shown - back to idle until s2 pressed again.
                set_led_pattern(0);
                state = STATE_IDLE;
            } else {
                // Should show next LED pattern.
                led_pattern++;
                state = STATE_SHOW_LED_PATTERN;
            }
        }
        break;
    ...
    

  • ufff.. thnx Per Westermark!! i hv been fighting with your explanation for a while. But at last it worked. I had to make it simpler by breaking down into simpler pieces.

    Also i changed a bit from what u mentioned. I used seperate IF loops like you said but without any case structures(state machines).

    Anyway now it is working.. both buttons work and i can interrupt each other

    thnx again