button that turns off all features - c++

I am new to coding and embedded systems and I wanted to make a button that turns off and on a LED and at the same time turn off all other futures in the system.
So far I had the button turn off and on but I cant seem to get it to also update the Potentiometer. For some reason the code would check if the button is pressed and if so then the LED would turn on and then check if the LED is on and if so then turn on the other LEDs but when I change the value of the Potentiometer( which should switch to other LEDs) it would not update and stay on the same LED. So my question is how can I put another if statement that would keep updating in the while loop?
the code that I wanted to keep updating while the first LED is on is the "else if code"
Hope that made sense.
:)
note:
I don't know if my approach is right as I am looking at the LED and not the button it self, as my code checks if the LED is on rather then if the button is pressed.
(btw its not a switch which would have made my life a lot easier :( )
#include "mbed.h"
DigitalIn userButton (PC_10);
DigitalOut led (PC_0);
bool buttonDown = false;
BusOut leds_bus (PC_1, PB_0, PA_4);
AnalogIn pot1 (PA_5);
void init_leds ();
int cntl_val = 0;
int main ()
{
cntl_val = pot1.read_u16 () / 32768;
while (true)
{
// run forever
if (userButton.read () == true)
{
// button is pressed
if (!buttonDown)
{
// a new button press
led = !led; // toogle LED
buttonDown = true; // record that the button is now down so we don't count one press lots of times
ThisThread::sleep_for (100);
}
else if (led.read () == true)
{
if (cntl_val < 1 / 3)
{
leds_bus.write (4);
}
if (cntl_val > (1 / 3) && cntl_val < (2 / 3))
{
leds_bus.write (2);
}
if (cntl_val > (2 / 3))
{
leds_bus.write (1);
}
}
}
else
{
// button isn't pressed
buttonDown = false;
}
}
}

You need to fix your math. int cntl_val is an integer so comparing it with the fractions 1/3 and 2/3 is not going to do what you expect. And cntl_val = pot1.read_u16()/32768; can set cntl_val to only 0 or 1. If the max value returned by pot.read_u16() is less than 32768 then cntl_val will only be 0.
You could maybe change cntl_val to a float but that's probably not the best option.
Instead, try setting cntl_val = pot1.read_u16(); (don't divide by 32768). And then compare cntl_val with (32768/3) and (32768*2/3). That's still ugly but better.

It is not clear from your description, but I am assuming that you have:
An on/off indicator LED
A three-LED level indicator
A momentary action button for on/off control
A potentiometer to control the input level.
And that when the system is in the "on" state you wish to indicate the potentiometer level on the level indicator? That being the case, I suggest:
Deal with button input/debounce separately from LED state determination.
Simplify the level setting; you have a level 0, 1 or 2 which you can calculate by unsigned level = (InputLevel * 3) / 32768 ;. You can then use that level value in a bit-shift (1 << level) to determine the LED to be set. Note that you had the low level set the high bit in your LED level indicator - that would require (4 >> level), which is somewhat clumsy if you were to ever increase the number of LEDs. It is easier to reverse the order of the GPIO in the BusOut object.
Additional advice:
Apply the rule of "minimal scope", localising variables to the minimum necessary scope (you have a number of unnecessary globals.
In "big-loop" scheduling, avoid thread delays during which useful work might otherwise be done. Your debounce delay unnecessarily determines the rate at which other work can be done in the loop. The advice would be different if you were polling the button and setting the LEDs in separate threads.
For example (not this is coded blind/untested - treat it as illustrative of the general principles - it may need debugging):
#include "mbed.h"
int main ()
{
static const unsigned DEBOUNCE_MS = 20u ;
static const unsigned NUMBER_OF_LEVELS = 3u ;
DigitalIn OnOffButton( PC_10 ) ;
DigitalOut OnOffLed( PC_0 ) ;
BusOut LevelIndicator( PA_4, PB_0, PC_1 ) ;
AnalogIn InputLevel( PA_5 ) ;
bool isOn = false ;
int previous_button_state = OnOffButton ;
std::uint64_t button_change_time = 0 ;
for(;;)
{
// If debounce time expired check for button state change
if( Kernel::get_ms_count() - button_change_time > DEBOUNCE_MS )
{
int current_button_state = OnOffButton ;
// If button state changed
if( current_button_state != previous_button_state )
{
// If button-down
if( current_button_state != 0 )
{
// Toggle isOn
isOn = !isOn ;
}
// Change of state and debounce update
previous_button_state = current_button_state ;
button_change_time = Kernel::get_ms_count() ;
}
}
// Set the LEDs depending on On/Off state and input level
if( isOn )
{
OnOffLed = 1 ;
// Set level indicator
LevelIndicator = 1 << (InputLevel.read_u16() * NUMBER_OF_LEVELS / 32768u) ;
}
else
{
// System inactive (Off)
LevelIndicator = 0 ;
OnOffLed = 0 ;
}
}
}
You might also consider separating out the button and indicator processing into separate functions to increase cohesion, minimise coupling, simplify testing and improve maintainability and comprehensibility.
#include "mbed.h"
void updateIndicators( bool isOn ) ;
bool getOnOffState() ;
int main ()
{
for(;;)
{
updateIndicators( getOnOffState() ) ;
}
}
bool getOnOffState()
{
static const unsigned DEBOUNCE_MS = 20u ;
static DigitalIn OnOffButton( PC_10 ) ;
static bool state = false ;
static int previous_button_state = OnOffButton ;
static std::uint64_t button_change_time = 0 ;
// If debounce time expired check for button state change
if( Kernel::get_ms_count() - button_change_time > DEBOUNCE_MS )
{
int current_button_state = OnOffButton ;
// If button state changed
if( current_button_state != previous_button_state )
{
// If button-down
if( current_button_state != 0 )
{
// Toggle isOn
state = !state ;
}
// Change of state and debounce update
previous_button_state = current_button_state ;
button_change_time = Kernel::get_ms_count() ;
}
}
return state ;
}
void updateIndicators( bool isOn )
{
static const unsigned NUMBER_OF_LEVELS = 3u ;
static DigitalOut OnOffLed( PC_0 ) ;
static BusOut LevelIndicator( PA_4, PB_0, PC_1 ) ;
static AnalogIn InputLevel( PA_5 ) ;
// Set the LEDs depending on On/Off state and input level
if( isOn )
{
OnOffLed = 1 ;
// Set level indicator
LevelIndicator = 1 << (InputLevel.read_u16() * NUMBER_OF_LEVELS / 32768u) ;
}
else
{
// System inactive (Off)
LevelIndicator = 0 ;
OnOffLed = 0 ;
}
}

Related

Update speed while going to position

Need to update potentiometer values all time not only once, try different ways but nothing works :(
I think that main problem is that this function while(digitalRead(gotoPositionAPin)); blocks
Now it's read value and save speed
workflow of code
press button right save position a
press button left save position b
update pot speed (set speed)
update pot acceleration (set accel)
press button go to position A (its going with previous set of speed and acceleration)
press button go to position B (its going with previous set of speed and acceleration)
#include <AccelStepper.h>
// Define some steppers and the pins the will use
AccelStepper stepper1(1, 12, 11);
#define stepsPerRev 1600
#define stepPin 12
#define dirPin 11
#define ledPin 13
#define rotateLeftPin 7
#define rotateRightPin 6
#define savePositionAPin 5
#define savePositionBPin 4
#define gotoPositionAPin 3
#define gotoPositionBPin 2
#define maxSpeedPin 0
#define accelPin 1
// Set this to zero if you don't want debug messages printed
#define printDebug 0
// These are the constants that define the speed associated with the MaxSpeed pot
#define MAX_STEPS_PER_SECOND 1000 // At 200 s/r and 1/8th microstepping, this will be 333 rev/minute
#define MIN_STEPS_PER_SECOND 27 // At 200 steps/rev and 1/8th microstepping, this will be 1 rev/minute
// Change this value to scale the acceleration pot's scaling factor
#define ACCEL_RATIO 1
int buttonState = 0;
int stepNumber = 0;
int curSpeed = 100;
int dir = 0;
int maxSpeed = 0;
int accel = 0;
long savedPosA = 0;
long savedPosB = 0;
int loopCtr = 0;
float fMaxSpeed = 0.0;
float fStepsPerSecond = 0.0;
void setup()
{
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(rotateLeftPin, INPUT);
pinMode(rotateRightPin, INPUT);
pinMode(savePositionAPin, INPUT);
pinMode(savePositionBPin, INPUT);
pinMode(gotoPositionAPin, INPUT);
pinMode(gotoPositionBPin, INPUT);
if (printDebug)
{
// Initialize the Serial port
Serial.begin(9600);
}
// blink the LED:
blink(2);
stepper1.setMaxSpeed(800.0);
stepper1.setAcceleration(600.0);
// Grab both speed and accel before we start
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
accel = analogRead(accelPin)/ACCEL_RATIO;
}
void loop()
{
// First, we need to see if either rotate button is down. They always take precidence.
if(digitalRead(rotateLeftPin))
{
stepper1.setSpeed(-fStepsPerSecond);
while(digitalRead(rotateLeftPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(-fStepsPerSecond);
}
}
else if (digitalRead(rotateRightPin))
{
stepper1.setSpeed(fStepsPerSecond);
while(digitalRead(rotateRightPin))
{
CheckPots();
stepper1.runSpeed();
stepper1.setSpeed(fStepsPerSecond);
}
}
// Go see if we need to update our analog conversions
CheckPots();
// Check to see if user is trying to save position A or B
if(digitalRead(savePositionAPin))
{
savedPosA = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved A at :");
Serial.println(savedPosA);
}
while(digitalRead(savePositionAPin));
}
if(digitalRead(savePositionBPin))
{
savedPosB = stepper1.currentPosition();
if (printDebug)
{
Serial.print("Saved B at :");
Serial.println(savedPosB);
}
while(digitalRead(savePositionBPin));
}
// Check to see if the user wants to go to position A or B
if (digitalRead(gotoPositionAPin))
{
if (printDebug)
{
// Yup, let's go to position A
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to A = ");
Serial.println(savedPosA);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosA);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionAPin));
}
else if (digitalRead(gotoPositionBPin))
{
// Yup, let's go to position B
if (printDebug)
{
Serial.print("cur pos = ");
Serial.println(stepper1.currentPosition());
Serial.print("Going to B = ");
Serial.println(savedPosB);
Serial.print("Speed = ");
Serial.println(fStepsPerSecond);
Serial.print("Accel = ");
Serial.println(accel);
}
stepper1.setAcceleration(0);
stepper1.runToNewPosition(stepper1.currentPosition());
stepper1.setMaxSpeed(fStepsPerSecond);
stepper1.setAcceleration(accel);
stepper1.runToNewPosition(savedPosB);
if (printDebug)
{
Serial.print("new pos = ");
Serial.println(stepper1.currentPosition());
}
while(digitalRead(gotoPositionBPin));
}
}
// Blink the reset LED:
void blink(int howManyTimes)
{
int i;
for (i=0; i < howManyTimes; i++)
{
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
}
void CheckPots(void)
{
loopCtr++;
// Only read these once in a while because they take a LONG time
if (loopCtr == 100)
{
maxSpeed = analogRead(maxSpeedPin);
// Do the math to scale the 0-1023 value (maxSpeed) to
// a range of MIN_STEPS_PER_SECOND to MAX_STEPS_PER_SECOND
fMaxSpeed = maxSpeed / 1023.0;
fStepsPerSecond = MIN_STEPS_PER_SECOND + (fMaxSpeed * (MAX_STEPS_PER_SECOND - MIN_STEPS_PER_SECOND));
if (fStepsPerSecond > 1000)
{
fStepsPerSecond = 1000;
}
}
// Read in the acceleration analog value
// This needs to be scaled too, but to what?
if (loopCtr >= 200)
{
accel = analogRead(accelPin)/ACCEL_RATIO;
loopCtr = 0;
}
}
If you're looking into "continuous operation" but don't want to introduce interrupts into your code (which will have special requirements in and of itself) there are a couple of things you need to get rid of:
Endless loops like: while(digitalRead(savePositionAPin));
System waits like: delay(200); as in your blink()
and instead use state variables. State variables are more or less what the name says: variables that hold the state of something, so you know what value the button, or timer, or counter had last time.
So, instead of a while-loop waiting for a button to be released, just set a global or static boolean that knows what state you were in the last time loop() ran, so you don't trigger the button action again. You need one boolean flag for each button.
And instead of delays, either create a state variable that holds "passed time" which you can get from millis() for example. So don't wait but instead you should just check if a certain amount of time has passed so you can toggle the state of the LED.
Adding a blinking LED to loop() - (untested example):
#define LEDWAIT 300
unsigned long myTime = 0;
bool onoff = false;
loop()
{
if (myTime == 0)
myTime = millis();
if ((millis() - myTime) > LEDWAIT) {
digitalWrite(ledPin, onoff ? HIGH : LOW);
onoff = !onoff;
myTime = millis();
}
// do other things
}
It is not entirely clear to me what your program is supposed to do and what the error is, so please correct me if I am wrong: You want to update a value based on which button is pressed? What is your opinion on using interrupts for triggering the updates?
You may want to edit the formating of your question.

Arduino millis() print values one after other

I don't know if someone else asked this before.
I'm trying to print in Serial screen the number 1 - 6, ONE number every 5 seconds (I'm trying only with number 1 and number 2 for smaller and easier to undestand and modify code). I could use delay function, but i want to use millis function, because i don't want to block the code using delay in loop.
This code problem is a part of bigger project.
I tryied to print the numbers using different interval times (eventTime_1 and eventTime_2), but it didn't work.
The code is
/* Two independant timed evenets */
const unsigned long eventTime_1 = 1000; // interval in ms
const unsigned long eventTime_2 = 5000;
unsigned long previousTime_1 = 0;
unsigned long previousTime_2 = 0;
void setup() {
// To Do: Serial communication
Serial.begin(9600);
}
void loop() {
/* Updates frequently */
unsigned long currentTime = millis();
// To Do: Event 1 timing
/* This is event 1 stuff */
if ( currentTime - previousTime_1 >= eventTime_1 ) {
Serial.println (" 1 ");
// Serial.println(currentTime);
// Serial.println(previousTime_1);
/* Update the timing for the next event */
previousTime_1 = currentTime;
}
// To Do: Event 2 timing
/* This is event 2 stuff */
if (currentTime - previousTime_2 >= eventTime_2 ) {
Serial.println ("2");
// Serial.println( analogRead(tempSensor) );
/* Update the timing for the next event */
previousTime_2 = currentTime;
}
}
As a result, prints 5 times the number 1 and after 5 seconds 1 time the number 2.
This is what i ecpect:
12:16:53.212 -> 1
12:16:58.225 -> 2
12:17:03.233 -> 1
12:17:08.238 -> 2
12:17:13.203 -> 1
12:17:18.272 -> 2
This is the final working code. From this code you can print 1 and 2 alternating every X second (x depends from you, in eventTime = X ; In my code is 5000).
// To Do: Variables for Timed Events
/* Create timed evenets */
const unsigned long eventTime = 5000;
unsigned long previousTime = 0;
/* Create a flag */
boolean flag1 = false;
void setup() {
// To Do: Serial communication
Serial.begin(9600);
}
void loop() {
/* Updates frequently */
unsigned long currentTime = millis();
if (currentTime - previousTime >= eventTime ) {
if (flag1 == false) {
Serial.println("1");
flag1 = true;
}
else if (flag1 == true) {
Serial.println ("2");
flag1 = false;
}
/* Update the timing for the next event */
previousTime = currentTime;
}
}
And the results are:
15:32:46.342 -> 1
15:32:51.402 -> 2
15:32:56.327 -> 1
15:33:01.325 -> 2
15:33:06.328 -> 1
15:33:11.325 -> 2
15:33:16.327 -> 1

Global variable doesn't update prior to next loop

I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}

Why does debounce code not work with 2 or more objects?

I have written a debounce class to debounce inputs.
The idea was that a state of a certain input may be ON, OFF, FALLING or RISING.
the object.debounceInputs() is to be called with a fixed interval
With the the function object.readInput() the correct state of the object could be read in. A FALLING or RISING state only lasts for 1 interval time (usually set at 20ms) and these states can only be read once.
Ofcourse I tested the software and it worked without flaw, now I started using the software in other projects and a peculiar bug came to light.
The software works perfectly fine... if you have just one input object. If you debounce more than 1 object, the inputs are affecting each other which should not be possible as every object uses private variables.
The source code:
#include "debounceClass.h"
Debounce::Debounce(unsigned char _pin) {
pinMode(_pin, INPUT_PULLUP); // take note I use a pull-up resistor by default
pin = _pin;
}
unsigned char Debounce::readInput() {
byte retValue = state;
if(state == RISING) state = ON; // take note I use a pull-up resistor
if(state == FALLING) state = OFF; // rising or falling may be returned only once
return retValue;
}
void Debounce::debounceInputs() {
static bool oldSample = false, statePrev = false;
bool newSample = digitalRead(pin);
if(newSample == oldSample) { // if the same state is detected atleast twice in 20ms...
if(newSample != statePrev) { // if a flank change occured return RISING or FALLING
statePrev = newSample ;
if(newSample) state = RISING;
else state = FALLING;
}
else { // or if there is no flank change return PRESSED or RELEASED
if(newSample) state = ON;
else state = OFF;
}
}
oldSample = newSample;
return 255;
}
The corresponding header file:
#include <Arduino.h>
#ifndef button_h
#define button_h
//#define
#define ON 9 // random numbers, RISING and FALLING are already defined in Arduino.h
#define OFF 10
class Debounce {
public:
Debounce(unsigned char _pin);
unsigned char readInput();
void debounceInputs();
private:
unsigned char state;
unsigned char pin;
};
#endif
I have had this bug with 2 separate projects, so the fault definitely lies in my Debounce class.
An example program to illustrate the program:
#include "debounceClass.h"
const int pin3 = 3 ;
const int pin4 = 4 ;
Debounce obj1( pin3 ) ;
Debounce obj2( pin4 ) ;
byte previousState1, previousState2;
unsigned long prevTime = 0, prevTime1 = 0, prevTime2 = 0;
void setup()
{
Serial.begin( 115200 ) ;
// CONSTRUCTOR OF OBJECTS SETS THE PINMODE TO INPUT_PULLUP
pinMode( pin3, OUTPUT ) ;
pinMode( pin4, OUTPUT ) ;
}
const int interval = 20, interval1 = 1000, interval2 = 2000;
void loop() {
unsigned long currTime = millis() ;
if( currTime > prevTime + interval ) {
prevTime = currTime ;
obj1.debounceInputs(); // comment one of these 2 out, and the other debounces perfectly
obj2.debounceInputs();
#define printState(x) case x: Serial.print(#x); break
byte state = obj1.readInput() ;
if( state != previousState1 ) {
previousState1 = state ;
Serial.print("state of obj1 = ") ;
switch ( state ) {
printState( ON ) ;
printState( OFF ) ;
printState( RISING ) ;
printState( FALLING ) ;
}
Serial.println();
}
state = obj2.readInput() ;
if( state != previousState2 ) {
previousState2 = state ;
Serial.print("state of obj2 = ") ;
switch ( state ) {
printState( ON ) ;
printState( OFF ) ;
printState( RISING ) ;
printState( FALLING ) ;
}
Serial.println();
}
}
if( currTime > prevTime1 + interval1 ) {
prevTime1 = currTime ;
digitalWrite( pin3, !digitalRead( pin3 ) );
}
if( currTime > prevTime2 + interval2 ) {
prevTime2 = currTime ;
digitalWrite( pin4, !digitalRead( pin4 ) );
}
}
This program automatically toggles both pins so you do not need physical inputs. If you comment out one of the indicated lines, you'll see that the other pin is debounced just fine. But when both pins are debounced the result is catastrophic. There is a weird link between the 2 objects which I cannot explain. I have reached a point at which I start doubting the compiler, so that was the moment I realized that I need to ask others.
Why is this happening and what did I do wrong here?
I found the problem.
I cannot use a static variable within a class method. These static variables are seen by all objects which caused the problem.
I moved the static variables to the private variable section

Embedded C counter between two values

Please help with my issue.
I am trying to avoid going out of the limit between 0 to 100 for the count up/down value in the program below;
I am using an 8051 microcontroller and 2x16 LCD to display a value between 0 and 100. when pressing the UP button the number increased by one, while when pressing down button it decreased by one.
my code keeps incrementing the value above 100 and less 0.
// This is a code in Embedded C written on MikroC compiler for 8051 microcontroller
// The microcontroller shall count up / down on the LCD when press up / down button.
unsigned int cntr=0; // counter value
char lcdv[6]; // Value to displau on lcd
sbit UP at P3.B7; // declare button UP at port 3 Bit 7.
sbit DN at P3.B6; // declare button UP at port 3 Bit 6.
// LCD module connections
sbit LCD_RS at P2_0_bit; // Declare LCD reset pin.
sbit LCD_EN at P2_1_bit; // Declare LCD Enable pin.
sbit LCD_D4 at P2_2_bit; // Declare LCD D4 pin.
sbit LCD_D5 at P2_3_bit; // Declare LCD D5 pin.
sbit LCD_D6 at P2_4_bit; // Declare LCD D6 pin.
sbit LCD_D7 at P2_5_bit; // Declare LCD D7 pin.
// End LCD module connections
char text[16]; // this is stored in RAM
void main() { // Main program
P3 = 255; // Configure PORT3 as input
Lcd_Init(); // Initialize LCD
cntr=0; // Starting counter value
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
while(1) {
while ((cntrset<=100)&&(cntrset>=0)) // Not sure how to limit Min and Max value.
{
wordTostr(cntrset,volset);
LCD_Out(2,1,volset);
if (UP==0)
cntrset ++;
while (UP==0);
if (DN==0)
cntrset=--;
while (DN==0);
}
}
}
if (UP==0 && cntrset < 100 ) cntrset++;
while (UP==0);
if (DN==0 cntrset > 0 ) cntrset--;
while (DN==0);
You may still have an issue with switch bounce causing a single press to result in the counter changing by more than one count. But that is a different question.
Regarding comment: If the increment is not by-one and the current value need not be a multiple of the increment, then it is easier to apply saturation instead:
if( UP == 0 ) cntrset += increment;
while (UP==0);
if( DN == 0 ) cntrset -= increment ;
while (DN==0);
if( cntrset < 0 ) cntrset = 0 ;
else if( cntrset > MAX_CNTRSET ) cntrset = MAX_CNTRSET ;
For that to work however you must change cntrset to signed int. If you'd rather not do that then (assuming 16 bit unsigned):
...
if( (cntrset & 0x8000u) != 0 ) cntrset = 0u ;
else if( cntrset > MAX_CNTRSET ) cntrset = MAX_CNTRSET ;