3
\$\begingroup\$

as my primary thing with electronics is hardware, I am having some difficulties learning programming. Unfortunately, my college where I study offers no such course so for my project this year I decided to incorporate some, to force myself to learn it, however, I am struggling to understand some of it! I have been building up separate parts of my code and most of it is working, however, I am trying to display a count on an LCD, and each time a button is pressed, I want it to increment by 1.

I managed to do this successfully on an Arduino (as there are many example sketches out there) but I want to do my project using an STM Nucleo (F103RB). I tried to transfer the example code over, and edit it using commands the online mbed IDE would understand, but it would not work. I then found a few different examples and each gave me different results. I eventually came up with my own code following a guide in adding/subracting in the book 'C Programming: A mordern approach'. The code I have come up with is here:

#include "mbed.h"
#include "TextLCD.h"

DigitalIn ip(D7);
TextLCD lcd(A0, A1, A2, A3, A4, A5);

int i =0;

int main() {
    lcd.cls();
    lcd.locate(0,0);
    lcd.printf("COUNT:");
    lcd.locate(0,1);
    lcd.printf("%d",i);
    while(1) {
    if (ip ==1) {
    lcd.locate(0,1);
    lcd.printf("%d", ++i);
        }
    }

And finally, the count started responding when I pushed the button. However, the issue I am having, is that the count increments all the time I have the button pressed, so even a small press will increase the count by 50-80 (depending how quickly you press it) and I want it to increment by 1 each press.

I have tried structuring it differently, having the 'while' statement at the beginning etc, but that just caused the LCD to oscillate strangely.

I've been stuck on this for about 6 hours now before getting to this point! Would really appreciate if someone could give me some pointers in the right direction!

In case anyone is needing it, my (simplified) schematic is here:

schematic

simulate this circuit – Schematic created using CircuitLab

So you can see it really is very simple. But I have just zero knowledge of C programming and have never been taught how to do it properly, so any solutions will need to be explained!

\$\endgroup\$
2
\$\begingroup\$

The main reason your counter increases so quickly is that you probably hold it down for about 1 second and the while loop is executed about 100 times during that time. So it will increase the counter by about 100.

What you really want is to only increase the counter once each time it's pressed down. A solution is shown below. The while loop remembers the last state of the button. The if clause is then only executed if the state goes from 0 to 1. It will no longer be executed when the previous value is 1, i.e. the button state hasn't changed but was just kept pressed down.

#include "mbed.h"
#include "TextLCD.h"

DigitalIn ip(D7);
TextLCD lcd(A0, A1, A2, A3, A4, A5);

int i = 0;
int lastButtonValue = 0;

int main() {
    lcd.cls();
    lcd.locate(0,0);
    lcd.printf("COUNT:");
    lcd.locate(0,1);
    lcd.printf("%d",i);

    while(1) {
        if (lastButtonValue == 0 && ip == 1) {
            lcd.locate(0,1);
            lcd.printf("%d", ++i);
        }
        lastButtonValue = ip;
    }
}
\$\endgroup\$
  • \$\begingroup\$ thank you very much for your reply! I had seen an example sketch using the lastButtonState command for the Arduino, and when I tried to convert it to work with mbed I just couldn't get it to work! Kept throwing all sorts of rubbish at me! Thank you very much for this. I have uploaded this to my Nucleo and it seems to work now! Thanks alot! \$\endgroup\$ – MCG Nov 19 '17 at 16:38
  • 2
    \$\begingroup\$ You might still have problems with getting lots of increments on a single button press because of switch contact bounce. When a switch is opened or closed, rather than a single transition there is a short period of high frequency oscillation. You can use a software counter to make the code insensitive to additional changes for a little while after each transition. maximintegrated.com/en/app-notes/index.mvp/id/287 \$\endgroup\$ – Dean Franks Nov 19 '17 at 18:14
  • \$\begingroup\$ If all you are doing is monitoring the switch, put a wait_ms(20); after the printf that displays the counter. You may find that the lcd.printf is slow enough to create the necessary delay by itself which would result in the code working with the debug code in and then not working once you take the printf out. \$\endgroup\$ – Dean Franks Nov 19 '17 at 21:21
  • \$\begingroup\$ @DeanFranks I had done my debounce with hardware for this, just to get it working, so luckily I am not getting any debouncing issues. Once I have got my head around this bit, I shall move on to software debouncing. Currently I am trying to put this piece of code and add it to a previous bit I had working. Not working right now but I have a couple more things to try before asking for more help here! Lol \$\endgroup\$ – MCG Nov 20 '17 at 8:18
1
\$\begingroup\$

Typically you do not want to busy loop when waiting for button presses, but rather wait for an interrupt to happen on the button, and then change the counter. With Mbed OS you can use the InterruptIn class for this, and put a callback on the fall method. Here's a demo in the Mbed simulator.

Because this runs in an ISR (interrupt service routine), you want to yield back to your main thread to update the LCD (see here).

For example, this would work:

#include "mbed.h"
#include "TextLCD.h"

TextLCD lcd(A0, A1, A2, A3, A4, A5);
InterruptIn btn(D7);

EventQueue ev_queue;

int i = 0;

// This is now executed on the event loop, thus it's safe to block here...
void btn_press() {
    lcd.locate(0, 0);
    lcd.printf("COUNT: %d", ++i);
}

int main() {
    Thread ev_thread;
    ev_thread.start(callback(&ev_queue, &EventQueue::dispatch_forever));

    lcd.cls();
    lcd.locate(0, 0);
    lcd.printf("COUNT: %d", i);

    btn.fall(ev_queue.event(&btn_press));

    wait(osWaitForever);
}

Note, if you need debouncing in software, check out DebounceInterruptIn, just change InterruptIn into a DebounceInterruptIn.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer, I'll look into this. This will eventually have to be doing a lot more, so I shall see which one works best when integrating the rest of my code \$\endgroup\$ – MCG Nov 21 '17 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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