This is the second part of the ARM software debouncing tutorial. In this video, we are going to take the pseudo-code written in the first part and turn it into real code. Then we will test the software debouncing in-circuit using the ARM Microcontroller.
In the first part, I explained the concept of software debouncing and how mechanical push button create a bounce when the button is pressed. We also wrote some pseudo-code to explain how the flow would happen in the program.
We will start with the variables. The pseudo-code for the variables looked like this:
// Initialize Button Pressed Variable
// Initialize Button Pressed Confidence Level
// Initialize Button Released Confidence Level
The use of the volatile keyword is so that the variables do not get optimized out. We want these variables to be dynamic as they are going to constantly change. the use of the variable type char is that it's the smallest common type at only 8-bits. We are only going to store a 0 and 1 in this variable type. This variable type can be either signed or unsigned. If it is signed, it can store values of -128 to +128, otherwise, it will store the unsigned values of 0 to 255. All of the variables will be initialized to 0.
The buttonPressedConfidenceLevel will be an int (integer) since it is a variable that will count the samples of ones (high digital signal level). The samples count can get very high if you let it. Also, another variable is introduced to store the confidence threshold. It is important to mention that the number that you use for the confidence threshold should be changed is the processor speed is faster or slower. The number here should really be based on a variable that contains the main processor speed and the confidence threshold number can be some divisor or coefficient of that.
// Initialize Button Pressed Variable
volatile char buttonPressed = 0;
// Initialize Button Pressed Confidence Level
volatile int buttonPressedConfidenceLevel = 0;
// Initialize Button Released Confidence Level
volatile int buttonReleasedConfidenceLevel = 0;
// Initialize confidence threshold level
volatile int confidenceThreshold = 200;
In the while loop, we can start by changing the buttonPressed variable conditions. If the buttonPressed is equal to zero, then we can add a few updates to variables: the buttonPressedConfidenceLevel can be incremented and the opposite, the buttonReleasedConfidenceLevel can be zero since there is a one at the input pin. However, this needs to be put in the else code block if the confidence level has not reached the threshold. The reason for this is that we don't want the confidence level to increment unnecessarily.
Just because we are updating these confidence level variables doesn't mean that the button is pressed. We can only state the button is pressed if the confidence level becomes greater than the threshold we set.
The same concept is being applied to the area within the buttonPressed == 1 condition, just opposite as we are considering the released rather than the pressed confidence level.
// If the button is pressed (IDR - input data register)
if (GPIOB->IDR & GPIO_IDR_1)
{
// once the Button Pressed Confidence has passed the confidence threshold
if (buttonPressedConfidenceLevel > confidenceThreshold)
{
// Update the Button Pressed variable to 1
buttonPressed = 1;
}
else
{
// Increase the Button Pressed Confidence Level
buttonPressedConfidenceLevel ++;
buttonReleasedConfidenceLevel = 0;
}
}
else
{
// Once the button Release Confidence Level had been achieved
if (buttonReleasedConfidenceLevel > confidenceThreshold)
{
// Update the Button Pressed variable to 0
buttonPressed = 0;
}
else
{
// Increase the button Released Confidence Level
buttonReleasedConfidenceLevel ++;
buttonPressedConfidenceLevel = 0;
}
}
}
Since we are using the BSRR register to set the on and set the off state of the pin, we need to create a condition to remember the on or off state of the output pin and change that state at the appropriate time rather than just using the toggle bitwise operation. This is necessary because the setting and resetting the pin state is always putting a 1 in the bit for both set and reset and the bits are located in different parts of the register. With that said, the ODR register can be set and reset from the same bit positions, but in this example, we are using the BSRR and this also provides an alternative to the bitwise toggle operator (^).
Let's take a look at how to toggle the LEDs, or the output pin. First we'll need to add a new variable that remembers the LED state (if it is on or off).
// LED list state
LEDState = 0;
Now we can focus on the actual toggle code. If the LED state is not lit (0), then change the state to lit (1) and light the LED (or set that pin to a high state). Otherwise, change the state to not lit (0) and turn off the LED (reset the output pin).
// Toggle LEDs
if (LEDState == 0)
{
LEDState = 1;
// Turn On LED
GPIOC ->BSRR |= GPIO_BSRR_BS_6;
}
else
{
// Turn off LED
GPIOC ->BSRR |= GPIO_BSRR_BR_6;
}
This can be added to the rest of the program:
button is pressed (IDR - input data register)
if (GPIOB->IDR & GPIO_IDR_1)
{
// once the Button Pressed Confidence has passed the confidence threshold
if (buttonPressedConfidenceLevel > confidenceThreshold)
{
// Toggle LEDs
if (LEDState == 0)
{
LEDState = 1;
// Turn On LED
GPIOC ->BSRR |= GPIO_BSRR_BS_6;
}
else
{
// Turn off LED
GPIOC ->BSRR |= GPIO_BSRR_BR_6;
}
// Update the Button Pressed variable to 1
buttonPressed = 1;
}
else
{
// Increase the Button Pressed Confidence Level
buttonPressedConfidenceLevel ++;
buttonReleasedConfidenceLevel = 0;
}
}
else
{
// Once the button Release Confidence Level had been achieved
if (buttonReleasedConfidenceLevel > confidenceThreshold)
{
// Update the Button Pressed variable to 0
buttonPressed = 0;
}
else
{
// Increase the button Released Confidence Level
buttonReleasedConfidenceLevel ++;
buttonPressedConfidenceLevel = 0;
}
}
}