Buttons - and LEDs :D
by Martyn on Apr.04, 2009, under Microcontrollers, Micromouse, News, Robots
Buttons are cool, so are menu’s. So with the help of a button, a few leds and a dspic I have a menu system (also note that this is blocking, the idea is that its used to start / stop the robot, so the robot does not move while the menu is active), first lets look at the switch circuit and then at the dspic set up (c30 compiler, using a dspic33fj128gp804):
/* Setup the IO Pin Assignment */ __builtin_write_OSCCONL(OSCCON & ~(1<<6)); RPINR7bits.IC1R = 5; // Switch Input Capture __builtin_write_OSCCONL(OSCCON | (1<<6)); /* Switch Input Capture Setup */ IC1CONbits.ICM = 0x02; // Capture on falling edge _IC1IF = 0; _IC1IE = 1; /* CPU Time Clock */ T1CONbits.TCKPS = 0x02; // 40.5504Mhz / 64 TMR1 = 0x00; PR1 = 634*4; // Int at 1.000631313ms*4 _T1IF = 0; _T1IE = 1; T1CONbits.TON = 1;
The code is fairly simple: first attach the switch input to the input capture (ic1) peripheral, set up ic1 to trigger an interrupt on the falling edge and then there is the set up for my main timer loop, this occurs at ~250Hz, and yes I am using a weird value crystal.
Next lets look at the global variables (well global to the scope of the interrupts)
// Switch input vars int sw_counter = 0; int sw_on = 0; // Menu vars int menu_counter = 0; int menu_on = 0; int menu_value = 0;
Next the interrupt for the input capture routine
void __attribute__((__interrupt__)) _NOPSV _IC1Interrupt(void)
{
_IC1IF = 0; // Clear the interrupt
_IC1IE = 0; // Disable the interrupt
_RED = 1; // Show the user the button pressed
sw_on = 1; // Enable the debounce counter
// If the menu is on already, increment the menu value
// Otherwise turn the menu on and set the menu value to
//default
if (menu_on)
{
menu_val ++;
menu_counter = 0;
}
else
{
menu_on = 1;
menu_val = 0;
}
}
And then the interrupt for the timer:
void __attribute__((__interrupt__)) _NOPSV _T1Interrupt(void)
{
// Handle switch
if (sw_on) // If a switch 'event' is ongoing
{
sw_counter ++;
if (sw_counter > 50) // 50x 1/250 = 200ms debounce
{
sw_on = 0; // Switch no longer on
sw_counter = 0; // Counter to zero
_IC1IF = 0; // Clear the bounces
_IC1IE = 1; // Enable more switches
_RED = 0; // Led off
}
}
// Menu
if (menu_on) // If menu is on
{
menu_counter ++; // Increment counter
// Leave menu active for 1s after last click
if (menu_counter > 250)
{
menu_on = 0; // Menu off
menu_counter = 0; // Reset
// Menu complete - do stuff
switch (menu_val)
{
case 0:
_RED = 0;
Nop(); // Required if RED and GREEN
// On same port
_GREEN = 1;
break;
case 1:
_RED = 1;
Nop(); // Required if RED and GREEN
// On same port
_GREEN = 0;
break;
default:
break;
}
}
}
}
And thats it, google _NOPSV to find the macro for that (sometimes required to compile using c30). Also _RED and _GREEN are port bits, so something like #define _RED _RB1 to make _RED = 1 turn Port B pin 1 on. All quite useful, maybe…
:button, dspic, led, Micromouse, robot, switch
