|
|
View previous topic :: View next topic |
Author |
Message |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Button command for CCS |
Posted: Sat Jul 30, 2005 12:04 am |
|
|
For PicBasicPro Compiler users, here is a CCS version of
the Button command. This program is intended for users
of PBPro who want to translate their programs to CCS.
The button() function and a test program are shown below.
This code was tested with the PCM and PCH compilers,
for the 16F877 and 18F452.
---------------------------------------------
Edit:
The button code in this post polls the buttons in a while() loop
in main() with a 10ms delay statement in the loop for debouncing.
The link below has an improved version which calls the button()
function in a timer interrupt every 10 ms, and puts the button
presses in a circular buffer (similar to Ex_sisr.c):
http://www.ccsinfo.com/forum/viewtopic.php?t=39585&start=1
----------------------------------------------
Here is the test program for the button() function. It uses
the Microchip PicDem2-Plus board. Jumper J6 (for the LEDs)
should be removed during this test, though it may work with
the jumper installed.
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
// These are the "Bvar" variables.
int8 A4 = 0; // For the button on pin A4
int8 B0 = 0; // For the button on pin B0
#include <Button.c>
// Function parameters:
//
// button(pin, DownState, Delay, Rate, BVar, Action)
//
// Returns: The value of the Action variable (normally
// set = 1) is returned when the button is
// pressed. When the button isn't pressed,
// the opposite value is returned (normally 0).
//======================================
void main()
{
printf("\n\rStart: ");
set_tris_a(0x10); // Set Pin A4 as input
set_tris_b(0x01); // Set Pin B0 as input
// This shows how to do a button loop. The PicDem2-Plus
// board has buttons on pins RA4 and RB0. There is one
// button() function below for each button. When the
// button on RB0 is pressed, "B" is displayed on the
// terminal window. When the RA4 button is pressed, "A"
// is displayed. If you hold the buttons down for more
// than 1/2 second, they will auto-repeat 10 times per
// second.
while(1)
{
if(button(PIN_B0, 0, 50, 10, B0, 1))
printf("B");
if(button(PIN_A4, 0, 50, 10, A4, 1))
printf("A");
// You must use a delay statement in the loop.
// A good value to use is 10 ms.
delay_ms(10);
}
} |
This is the button() function code. It should be saved in
a file named "button.c".
Code: |
// Button.c
//====================================
// Differences between this function and the PicBasicPro
// compiler function:
// 1. The PBP button function requires a "GOTO" label for
// the last parameter. I didn't implement this feature
// because while in Basic it's considered OK to use
// GOTO statements, we don't normally use them in C.
// Instead, I have the button() function return the
// value of the "Action" parameter. (1 or 0).
// So if Action parameter is 1, and the button is
// pressed, the return value is 1. If the button
// isn't pressed the function will return 0.
// 2. The PBP button function has an internal debounce
// delay in the auto-repeat code which can optionally
// be disabled. This internal delay isn't necessary
// so I didn't include it in my version of the button
// function. The external delay explained in item 3
// below, takes care of all debouncing.
// 3. A delay_ms(10) statement is required in the loop
// in your main program that calls the button()
// function. Actually, PBP also requires this.
// All their examples show a PAUSE 10 or PAUSE 100
// statement in a loop. But I'm explicitly stating
// that it is required.
// 4. The PBP function allows the Pin parameter to be
// a number from 0-15 or a port.bit value. I didn't do
// it that way. With the CCS compiler, we like to use
// CCS pin numbers, which are defined in the .H file
// for your PIC. So for the pin parameter you must
// use values such as PIN_B0, PIN_C1, PIN_E0, etc.
// The pin parameter can be passed in a variable.
// It doesn't have to be passed to the function as a
// constant.
// 5. The PBP function sets the TRIS for the specified pin
// so it's an input. Currently I don't do that, so you
// have to set it with the set_tris_x() function. If I
// can decide on a clean way to do it, I may add that
// feature later.
//====================================
// Description of function parameters:
// Pin:
// This must be a CCS-style pin number, such as PIN_B0.
// Downstate:
// This is the logic level of the button when it's pressed.
// For a circuit with a Normally-Open switch and a pull-up
// resistor, this parameter will be 0.
// Delay:
// This is the initial delay before auto-repeat begins.
// Example: A Delay value of 50 means a 500 ms auto-repeat
// delay.
// Rate:
// This is the auto-repeat interval.
// Example: A Rate value of 10 gives a 100 ms interval,
// which means an auto-repeat rate of 10 keys per second.
// Bvar:
// This an 8-bit variable that must be declared in the main
// program, and it must be initialized to zero. There must
// be a separate variable for each button that you use.
// Example: Declare the variable for pin B0 as int8 B0 = 0;
// See the demo program for more examples. Note that Bvar
// is a "reference variable" (it has a "&" in front of it).
// This is intentional. It's done so the button function
// can directly access the Bvar variable which is declared
// outside the function, without having to pass a pointer
// to it. This keeps the function interface simple.
//====================================
// Action:
// This is the value that's returned when the button is
// pressed. Normally you set this = 1.
// Return value:
// When the button is pressed, the value of the Action
// parameter will be returned. When the button is not
// pressed, the opposite value will be returned.
// Normally, you set the Action parameter = 1, and so
// if the button is pressed, the function will return 1.
// If it's not pressed, it will return 0. So you just
// poll the function every 10 ms in a loop, and check the
// return value with an if() statement. If it's non-zero
// then the button is pressed and you can take appropriate
// action.
//=====================================
// The following macro is used by the Button function.
#define read_bit_var(x) bit_test(*(int8 *)(x >> 3), x & 7)
//=====================================
int8 button(int16 pin, int8 downstate, int8 delay,
int8 rate, int8 &BVar, int8 action)
{
int8 pin_value;
// Read the button pin.
pin_value = read_bit_var(pin);
// Check if the button is pressed. It's pressed if the
// pin value is the same as the "downstate". If it's not
// pressed, then zero the Bvar and return "Not pressed".
if(pin_value != downstate)
{
Bvar = 0;
return(!action);
}
// The button is pressed. Check to see if it's a new
// keypress. We can tell if it's a new keypress by
// checking if BVar = 0. If so, load the counter with
// the initial auto-repeat delay and return "Pressed".
// (If the delay has been set to 0, then load a non-zero
// value to allow the function to operate properly).
if(Bvar == 0)
{
if(delay == 0)
Bvar = 255;
else
Bvar = delay;
return(action);
}
// Decrement the auto-repeat counter.
Bvar--;
// Check if we just counted down to 0. If so, then load
// the counter with the auto-repeat interval and return
// "Pressed". If the delay is set to 0 or 255, it means
// that auto-repeat is disabled, so fall through and
// return "Not Pressed".
if(BVar == 0)
{
BVar = rate;
if((delay != 0) && (delay != 255))
return(action);
}
// If the counter is positive, then it means an auto-repeat
// is still pending, so return "Not Pressed".
return(!action);
} |
|
|
|
M.Yasser
Joined: 26 Jul 2011 Posts: 9
|
|
Posted: Tue Jul 24, 2012 9:48 pm |
|
|
Hi,
I’m trying to understand the mechanism of the Button function. What does the following Macro do?
Code: | #define read_bit_var(x) bit_test(*(int8 *)(x >> 3), x & 7) |
Can someone describe the ideas behind this Button function?
Regards. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 25, 2012 11:11 am |
|
|
Quote: |
I’m trying to understand the mechanism of the Button function.
What does the following Macro do?
#define read_bit_var(x) bit_test(*(int8 *)(x >> 3), x & 7)
|
That line reads the input state of an PIC i/o pin.
The read_bit_var() function expects a CCS pin number constant as
the input parameter. The CCS pin number encodes two things in it.
It encodes the i/o Port address, and the bit number of the i/o pin.
If we want to read an i/o pin, we need to extract those two things
from the packed byte and use them to read the pin.
Here is an explanation of read_bit_var():
It decodes the packed bits of a CCS pin constant into the Port register
address and the bit number. If you look in the 16F877.h file, you will see
this line:
Convert it binary and it becomes 0b00110000. The lower 3 bits are the
bit number. Because it's pin B0, the bit number is 0. The upper bits
are the Port address. For PortB on the 16F877, this address is 6. This
value is given in the 16F877 data sheet in the section on SFR registers.
The diagram below shows how the bits are packed:
Code: |
Binary: 00110 000
Decimal: 6 0
|
The part of the code shown below isolates the lower 3 bits, and gives us
the bit number (0 to 7) on the port:
This part below gives us the Port register address. It moves bits 7 to 3
from their packed bits location, so the value becomes right-justified and
then it becomes the Port address of 6:
In other words, 00110000 becomes 00000110 (which is 6).
The part shown in bold below, tells the compiler to treat the Port number
as a pointer to a byte in RAM, and then it gets the value of the byte at
that address:
That's because PortB is in the RAM memory space of the PIC. It has a
RAM address of 6. So we can read the value with pointer.
So we have the value of PortB (which is a byte), and we have the bit
number that we want to use. These two items are given to the CCS
bit_test() function as parameters. The bit_test() function will then return
the value of the specified bit (0 or 1). Look in the CCS manual for a
description of the bit_test() function.
If you have any other questions about the button command, try to put
them all in one post, so that I can answer them all at once. |
|
|
M.Yasser
Joined: 26 Jul 2011 Posts: 9
|
|
Posted: Thu Jul 26, 2012 9:27 am |
|
|
Hi PCM Programmer,
You were perfectly clear in your explanation. I appreciate it.
Code: | int8 button(int16 pin, int8 downstate, int8 delay,
int8 rate, int8 &BVar, int8 action) |
1.The use of ‘&BVar’ is confusing. If I declare the BVar outside the main function can I use BVar instead of &BVar in the function Button?
2.The purpose of the button function is to eliminate the effect of mechanical bouncing. It is not clear to me how is that done in the function (lots of examples only use a delay or implement a capacitor parallel to the button switch in addition).
3.What is the role of the auto-repeat?
Regards |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 26, 2012 2:58 pm |
|
|
Quote: |
1.The use of ‘&BVar’ is confusing. If I declare the BVar outside the main
function can I use BVar instead of &BVar in the function Button?
|
It doesn't affect how you use the button() function. Look at the example
program that calls it. You just pass it the variable name, the same as
you normally do. The '&' is in there because I am using a CCS feature
called "Reference parameters". Look it up in the manual. I think I did
it because it reduces the size of the output code, as shown in the .LST file.
Quote: |
2.The purpose of the button function is to eliminate the effect of
mechanical bouncing. It is not clear to me how is that done in the function
(lots of examples only use a delay or implement a capacitor parallel to
the button switch in addition).
|
The debounce delay is in the while() loop in the test program. It's not
part of the driver. It must be added externally. Look at the test program
which is included with the driver in the original post. The original post
also has a link to another thread which shows how to use a timer interrupt
to do the 10 ms debounce delay.
Quote: |
3.What is the role of the auto-repeat?
|
It's the same thing as on your PC keyboard. When you press a character
key on your PC keyboard, there is a short delay and then the keyboard
repeats the character at an interval. Like if I press the 'a' key and hold
it down, I get aaaaaaaaaaaaaaaa. |
|
|
M.Yasser
Joined: 26 Jul 2011 Posts: 9
|
|
Posted: Fri Jul 27, 2012 4:19 pm |
|
|
Thank you PCM Programmer, you were very helpful |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|