Application Note
/ANxxxx
Simple Button Count
By: Lynn NguyenAssociated Project: Yes
Associated Part Family: CY8C24894
PSoC Designer Version: 4.4
Referenced Application Notes: None
Summary
This application note makes use of several onboard resources to display to the LCD the number of times a button is pushed. It will explain the two types of drive modes that a pin can use, so that even if the developer does not have a push button pin available, a mock pin may be created using wires and a breadboard.
Introduction
A very simple use and a common introduction project for microcontroller is to use the pushbuttons that are usually provided on board and an LCD to display the number of times a button is pushed. This is simple because it requires a minimal amount of hardware to implement and it familiarizes the user with the board. The board that we use for this application note, CY3214 USBEval Board, comes with an LCD and 2 pushbuttons onboard. However, after explaining the different drive modes that a pin may have, we will see how to implement a button using a breadboard and wires.
Page | 5
Ports and Pins
What exactly is a pin? It’s been mentioned several times already in this application note and if you are new to embedded systems, this term is also new. Basically, a pin is used to connect the microcontroller to something else. This something else may be a button, a switch, and LED… you get the picture. Pins may be input or output pins but for the sake of simplicity, we are only dealing with input pins in this application note. An input pin is one in which an outside resource is connected to the pin and the microcontroller reads from that pin to get certain information. A group of 8 pins is collectively called a port. Recall also that a goup of 8 bits is called a byte. Thus a port can read or write a byte at a time depending on whether it is an input or an output port, respectively.
Figure 1 – Port on Board
On this PSoC microcontroller, you can see that we have 6 ports, each with pins labeled 0-7. P0[1] is a conventional short hand labeling of the pin, and you can read this as, “Port 0, pin 1.” When reading a value from a pin to know what the peripheral attached to it is doing, we access the values through the port registers PRT0DR, PRT1DR, PRT2DR, PRT3DR, PRT4DR, or PRT5DR. You can think of these registers as variables that store the value a peripheral is sending. This value is sent as a voltage.
In code, when accessing the values from the port, each port variable, PRTxDR (where x represents a port number such as 0, 1, 2, 3, 4, or 5), is one byte. One byte is 8 bits. Each bit in the byte corresponds to a pin on a port. Just imagine the image in Figure 1 to be a byte in memory, as laid out in Figure 2. So, if you wanted to get the value of pin 3 on a port, you would just mask the port variable to isolate the bit.
7 / 6 / 5 / 4 / 3 / 2 / 1 / 0Figure 2 – Byte In Memory
Pull-up and Pull-down
In PSoC Designer, there are 8 different ways to connect to a pin. They are Strong, Strong Slow, High Z, High Z Analog, Pull-up, Pull-down, Open Drain High, and Open Drain Low. Each of these is used to connect to different types of devices. In this project, we are connecting buttons to the device and so we will be using the Pull-up or Pull-down mode. Technically these are considered pull-up or pull-down resistors. That is because, if you configure the pin to pull-down, PSoC internally connects a resistor from the pin to ground, or Vss. Externally, a pushbutton is connected between the pin and a positive supply voltage. This means, when the button is not pushed, the pin will read 0 volts due to the resistor. When the button is pushed, the voltage on the pin will be at Vdd (positive supply voltage) and you will read a 1 into the program. The opposite applies to pull-up resistors. When the button is pushed, the pin will read 0 and when the button is not pushed, the pin will read 1. Basically, we will be able to determine the state of the button (pushed/not pushed) by reading from the pin.
Figure 3 – Pull-up and Pull-down Resistors
Set-up
Now we will begin creating the project. Open up PSoC Designer and create a new project. We will be using part CY8C24894-24LFXI and generating the main file using C. Once that is done, we will be at the user module selection screen of the Device Editor. We will only be using one, the LCD. This can be found under Misc Digital. Select this user module and go to the Interconnect View.
Figure 4 – Selecting the LCD
Now we will set the User Module Paramters of the LCD. This can be done on the left hand side in the middle window. We want to set the value of the LCDPort to Port_4.By connecting the LCD to the port, we will be able to actually use this module in our project. We will be using the LCD to display a count of how many times a certain button is pushed. An eccentricity of this board is that the LCD cannot be connected to just any port. It must be connected to Port_4 in order to display correctly.
Figure 5 – Configuring the LCD
Also, we will want to set the drive mode of the button. We will first do pull-down mode. To do this, we will set Port_3_7 or P3[7] to have Pull Down mode. To do so, locate Port_3_7 in the window, and go to the Drive column. There, click on the cell and a drop down menu will appear. From the options, choose Pull Down. Also, we’ll just rename it from Port_3_7 to Button. This can be configured in the window just under the window where we set the LCD configuration.
Figure 6 – Setting P3[7]
This means that we will be connecting a pushbutton to P3[7] and the program will read the value of the button from that pin. Now, click the Generate Application button and go on to the Application Editor view of PSoC Designer.
Writing the Code
Open up main.c. This is where will we be writing the source code necessary for the LCD to display the count of a button push.
void main() {
1. unsigned char button_pushed;
2. int counter = 0;
3. LCD_1_Start();
4. LCD_1_Position(0,0);
5. LCD_1_PrCString("Counter Program");
6. LCD_1_Position(1,11);
7. LCD_1_PrHexInt(counter);
8. PRT3DR &= ~0x80;
9. while (1) {
10. int i, j;
11. button_pushed = PRT3DR & 0x80;
12. if (button_pushed) {
13. ++counter;
14. LCD_1_Position(1,11);
15. LCD_1_PrHexInt(counter);
16. for(i =0; i < 40; i++ ){
17. for(j =0; j < 250; j++ );
}
}
}
Figure 7 – Source Code
And that’s it! Of course, don’t worry, I’ll explain what’s going on in the code. This is the main function, and the only code that you will have to add in order to get this program up and running.
· Line-1 declares our button_pushed variable. This variable will be used to read from P3[7] and will be used to determine whether the pin was pushed (if button_pushed == 1) or if it was not pushed (if button_pushed == 0).
· Line-2 declares our counter variable. This variable will be used to keep track of how many times the button connected to P3[7] is pushed and the value of this variable will be displayed on the LCD.
· Line-3 is required because we need to actually start the module before using any of its APIs.
· Line-4 and Line-6 tells us where we want text on the LCD to be displayed. We can think of the LCD as a grid of 2 rows where (0,0) is the top left corner of the LCD. So, the text that is first displayed on the screen will begin on the top row.
· Line-5 and Line-7 tell the LCD what to print. Line-5 tells the LCD to print the string “Counter Program” whereas Line-7 tells the LCD to print the hex value of Counter.
· Line-8 enables the pull-down resistor. You may think we may have already enabled the pull-down resistor when we set the drive mode of P3[7] in the Device Editor, but PSoC pins are different from other microcontrollers in that they must also be enabled in the code. The Device Editor only sets the drive mode then when we have to enable it in the code. To enable pull-down resistor, we have to write 0 to the pin. This is done using bitwise AND.
· Line-9 tells the program to continuously poll the pin for any changes in button state.
· Line-10 is just variable declarations for a nested loop used later on.
· Line-11 is where we actually read a value from the pin which will determine the button state. We read the value by masking PRT3DR to find the 7th bit. This 7th bit will be 1 if the button is pushed and 0 if not pushed because we are using a pull-down resistor.
· Line-12 to Line-15 tells the LCD to update the button count on the screen if the button was pushed. Also, the Counter variable needs to be incremented because it is the value of this variable that keeps track of the button pushes.
· Line-16 and Line-17 are used to create a little delay when reading from the pin. Unfortunately, in microcontrollers, when a button is pushed, or when any metal surfaces have contact with each other, a “bounce” is created. It is when the metal contacts bounce against each other before settling. So, the program will consider these tiny extra bounces as actual button pushes. To avoid that, we set up a tiny delay in the loop so that the program doesn’t take into account these extra bounces.
Once you’ve added this code to the main method, build the code (Build->Rebuild All) and program it onto your board (Program->Program Part…)! Remember to connect a wire from a button to P3[7]. Turn the microcontroller on and push away!
Figure 8 – Hardware Configuration
Some Modifications
Now that we know this works, let’s vary things a little bit. Let’s pretend that none of the pushbuttons on the board work (oh no!) but we still want to test the code to be sure everything is okay. Well, remember in the code that we saw that the button was pushed if button_pushed == 1. We can replicate this using the breadboard and power supply. If the button read 1, that meant that the voltage was at Vdd. So if we set up the connections like in the following figure, we can get the jumper wire to act like a button!
Figure 9 – Mock Pull Down Button
Also, since we spent so much time learning about pull-up and pull-down resistors, let’s configure the project to read from the pin when it is using the pull-up mode instead.
Using Pull-up Mode
Go to the Device Editor view of PSoC Designer and configure P3[7] (which we had renamed to Button) to use Pull Up mode. Click the Generate Application button again and go back to the Application Editor view. We will have to make some modifications to the source code to enable the pin to read pull up.
void main() {
1. unsigned char button_pushed;
2. int counter = 0;
3. LCD_1_Start();
4. LCD_1_Position(0,0);
5. LCD_1_PrCString("Counter Program");
6. LCD_1_Position(1,11);
7. LCD_1_PrHexInt(counter);
8. PRT3DR |= 0x80;
9. while (1) {
10. int i, j;
11. button_pushed = PRT3DR ^ 0x80;
12. if (button_pushed) {
13. ++counter;
14. LCD_1_Position(1,11);
15. LCD_1_PrHexInt(counter);
16. for(i =0; i < 40; i++ ){
17. for(j =0; j < 250; j++ );
}
}
}
Figure 10 – Pull Up Code
Notice that the only changes we made to the original code were to Line-8 and Line-11.
· In Line-8, by doing the bitwise OR operation, we are writing a 1 to the register—thus enabling the pull up resistor on Port_3_7. Previously, we had written a 0 to P3[7] to enable pull down.
· Line-11 is still reading from the pin. But because we are using a pull up resistor, the pin will now read 0 if the button is pushed. To keep with the logic of “button_pushed == 1” (where 1 is logically equivalent to True) then we do a XOR to flip the bit. Thus if we read 0 from the pin, that means that the button is pushed, so by XOR’ing the bit, we will now have a 1 for button_pushed.
Once that is done, rebuild it and program it onto microcontroller. Unfortunately, if we use this method, the program will not work if we connect the pushbuttons provided onboard to P3[7]. I can only assume that Cypress has the 2 buttons (S1 and S2) automatically tied to Vdd. However, we can test this code by using the mock buttons that we implemented previously with jumper wires. This time, we want to connect the wires to the negative supply source (on J11) as shown below.
Figure 11 – Mock Pull Up Button
Challenge Yourself
Now try wiring in another button that will decrement the button push count! Or try to implement code where holding down the button for a long period of time is equivalent to one button push instead of multiple little ones.