1

I want to configure my button and configure LED blink speed so that when I press the button the first time the LEDs blink slower. When I press a second time the LEDs blink more slowly still, When I press a third time and LEDs blink the slowest.

After all when I press the button a fourth time I want to LEDs off (i.e. not blink until I press the button). I thought I can do this with mod operator (a % 3 == 0 ???)

Here is my code after update :

unsigned int rate = 1000000;
int NUM_STATES = 4 ;
unsigned int counter=1;
for(;;)
{
  if( buttonPressed() )
  {
    rate += 2000000;
    counter++;
  }
  if(counter  % 4 == 0)
  {
  rate = 0;
  }

  flashSequence(rate);
}
}
int buttonPressed(void)
{
    if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
   return 1;
else
 return 0;
}
void flashSequence (int rating)
{              
          if (rating == 0)
            GPIO_ResetBits(GPIOD, 
 GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
        else
          {
            /* PD12 to be toggled */
            GPIO_SetBits(GPIOD, GPIO_Pin_12);
            /* Insert delay */
            Delay(rating);
            /* PD13 to be toggled */
            GPIO_SetBits(GPIOD, GPIO_Pin_13); 
            /* Insert delay */
            Delay(rating);
            /* PD14 to be toggled */
            GPIO_SetBits(GPIOD, GPIO_Pin_14);
            /* Insert delay */
            Delay(rating); 
            /* PD15 to be toggled */
            GPIO_SetBits(GPIOD, GPIO_Pin_15);     
            /* Insert delay */
            Delay(rating);
            GPIO_ResetBits(GPIOD, 
 GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
            Delay(rating);
          }
  }
  • You can implement this with a state machine. – Burstful Oct 14 '17 at 17:48
  • 1
    I cannot write a code for it but I can suggest. You need to interface the button on External Interrupt pin of the uC, set-up the ISR for external interrupt, inside the ISR increment a global variable. In main function keep checking the value of that global variable depending on the global variable value use Timer 0 or Any timer to generate a delay and use that delay to blink the LED. – Gaurav Pathak Oct 14 '17 at 17:53
  • If you expect others to read your code, it is just polite ot format and indent it in some conventional manner. Questions on SO are persistent; starting off saying your "new here" serves no purpose, neither does explicitly asking for help - that is what we are all here for. Fixed that for you; but next time, consider this. – Clifford Oct 14 '17 at 18:13
  • You have posted code that presumably does not do what you want it to; it would be helpful if you were to explain what it does do or how you expected it to work. – Clifford Oct 14 '17 at 18:19
  • In the first press, you say tit should blink "slower". _Slower_ than what? What should the LED be doing before the first press? – Clifford Oct 14 '17 at 18:21
  • Beginning is not important. We can assume leds can blink 1 sec for the first the time – Jason Ozbek Oct 14 '17 at 18:25
  • Thanks for the edit btw. I will be more careful after that – Jason Ozbek Oct 14 '17 at 18:25
  • @Gaurav Pathak - never advice it for the devices which bounce (actually all mechanical switches) - it is a wrong approach, timer interrupts should be used for this task – 0___________ Oct 14 '17 at 19:13
  • @PeterJ_01 I got it. "Debouncing issues related to mechanical switches", it totally slipped from my mind. – Gaurav Pathak Oct 15 '17 at 07:38

2 Answers2

0

counter % 3 will yield 0, 1 or 2, but you have described four states, so counter % 4 would be needed. Actually you did not describe the state before the first press, so perhaps there are 5.

If the number of states is not a power of 2, using modulo n will cause a discontinuity when the counter wraps around. With an unsigned int counter this may not be a practical limit, but it is at least a latent bug.

The code fragment you have posted will not work because (amongst other issues) counter is not modified in the loop, so it will never exit, and never change the flash rate.

You need something of the following form:

int rate = 0 ;  // Off
#define NUM_STATES = 4 ; (0 to 3)
for(;;)
{
    if( buttonPressed() )
    {
        rate++ ;
        rate %= NUM_STATES ;
    }

    flashSequence( rate ) ;
}

The flashSequence() is a function that flashes at a rate proportional to rate, with zero(0) being a special case of "OFF".

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • so it looks like i need 2 function named flashSequence and buttonPressed. buttonPressed will control the button is pressed or not and flashsequence will set the leds blink time right ? – Jason Ozbek Oct 14 '17 at 18:55
  • You don't _need_ to do that at all; that is just one way of structuring it to aid clarity of thought lacking in your code. You cannot _control_ a button, you _detect_ it. And the flashSequence function does not set the rate, it performs a single sequence at the requested rate. The solution is simple but not ideal because the button polling rate is determined by the flash sequence length. Better to detect in a thread or interrupt. – Clifford Oct 14 '17 at 19:03
  • The real structural difference between mine and yours is that `flashSequence()` runs to completion in one flash cycle whereas yours has a loop that won't terminate. You should at least remove the inner loop and retain just the flash sequence block (i.e. it should run only once. I used functions as "pseudocode" to highlight just the important parts that answer your question and to make the answer generic and not specific to your hardware. – Clifford Oct 14 '17 at 19:15
  • yes interrupt will be more useful but i just want to know how we can do this without interrupt because it looks like i cant always detect when i pressed button. It is some kinda common problem when we use if(buttonPressed) right ? – Jason Ozbek Oct 14 '17 at 19:23
  • look at my edit i can slow down now. But after the third press i cant turn off the leds are on like the program starts – Jason Ozbek Oct 14 '17 at 19:30
  • There is no reason why `buttonPressed()` might not read some state flag set by an interrupt rather then directly reading the GPIO. Switch debouncing is a different question. Not necessarily a problem here because the delay between polling is relatively large, but equally it is possible to press the button briefly and for it to be ignored. There are solutions to that - a state machine has already been suggested. Rather then delays, you poll a timer to determine whether it is time to switch and LED on or off while continuously polling the button (and debouncing). – Clifford Oct 14 '17 at 19:30
  • yeah i know interrupt are more useful for this task. But assume that i press the button briefly :) my last code after the edit solved my speed problem. I just cant turn off the leds :/ – Jason Ozbek Oct 14 '17 at 19:34
  • @JasonOzbek : Do not change your question to match the answers given; it make the answers nonsense because it looks like I am telling you to do exactly what you have already done! If an answer is useful, you can accept it or up-vote it, but don't change your question. It is now very difficult to advise because SO is a Q&A not a forum, and you are moving the goal post. Yiu code does not follow mine; `counter` is unnecessary; use `rate`, then multiply it by 2000000 in flashSequence() or better in `Delay()` – Clifford Oct 14 '17 at 19:40
0

I afraid it is a bit too much to explain but LED blinking patterns and key readings should be done in the timer interrupt and do not block the normal program flow.

Imagine the situation if after the keypress you need to blink a LED but program needs to execute as normally.

You can take look on my code for it:

LED - https://www.diymat.co.uk/arm-blinking-led-driver/

Button - https://www.diymat.co.uk/arm-three-function-click-double-and-long-click-button-library-timer-interrupt-driven/

PS my page is in a permanent under construction state :).

0___________
  • 60,014
  • 4
  • 34
  • 74
  • they i think interrupt is more useful because i cant always detech the button press but i want to know how we can do it in normal program flow :) – Jason Ozbek Oct 14 '17 at 19:30
  • You need to debounce. Otherwise you will detect many consecutive presses and releases in 10 20ms. There is no good way of doing it in the main loop as you do not have any time base. Avoid using any delays as it is one of the worst programming habits – 0___________ Oct 14 '17 at 19:34
  • 1
    This is overstating things a bit. Many systems operate their blinking from the main program loop - as long as it runs at a stable rate that is a multiple of the needed one, that can work well. Note that debouncing can perhaps be folded into such a periodic evaluation quite easily. – Chris Stratton Oct 14 '17 at 21:17
  • @Chris Stratton `Many systems operate their blinking from the main program loop` - most of them are led blinking programs :). This is the recipe 'how to write the "banana" code'. I would like to see any serious written by the professional coder program which blinks the LED in the main loop (and more general such a asynchronous & periodic tasks) – 0___________ Oct 14 '17 at 21:47
  • 2
    @PeterJ_01 : Who knows what "banana code" might be? But managing indicators in this way need not lead to poor code organisation. Moreover in a hard real-time system with critical tasks to perform at precise timing, wasting interrupts on handling non-time critical tasks might be detrimental - adding unwanted jitter to more critical processes. The hypothetical "professional coder" you introduce might well use a low priority thread for UI indications. – Clifford Oct 14 '17 at 22:14
  • @Clifford priority system is for it. LED jitter is not important. Show me how interrupt driven LED driver can affect the the higher priority interrupts jitter? main loop coding of similar task is the source of the permanent problems. – 0___________ Oct 14 '17 at 22:20
  • 1
    @PeterJ_01 - plenty of serious systems use a main loop running at a fixed frequency - when what the system has to do is quite repetitive (for example PID control loops in an aircraft stabilization computer running 500 or 1000 times per second) this makes more sense than putting *everything* in an ISR. Having random interrupts firing is a detriment to timing consistency and determinism - and blinking LEDs is not critical anyway. So putting the LED blink in the main loop makes a lot of sense. – Chris Stratton Oct 14 '17 at 23:39
  • `main loop running at a fixed frequency` and how can you assure that fixed frequency of the main loop? Delays maybe? And what if you add something to main loop? (BTW I do not know if you know that int the aviation industry RTOS-es are avoided like a plaque because of the certification problems). Programming the "main loop" way is absolutely horrible practise - maybe acceptable in the arduino hobby projects. – 0___________ Oct 14 '17 at 23:59