📄 msp430x20x1_rc keys.c
字号:
//******************************************************************************
// F2011 demo code for RC charge/discharge demo
//
// Version 0-00: 10-21-2006
//
// Single key detection
// This version determines if one of 4 keys has been pressed. Base capacitance
// is tracked for changes and slider max endpoint is handled for no backoff
// or back in position detections.
//
// Testing using 3.5mm insulated keys. At 16MHz, ~20counts are achieved.
// Icc is ~10uA. Sensors are sampled ~20 times per second when a key is pressed;
// and ~6 times per second when no key is pressed after ~2 seconds. Current
// Consumption in this case is ~ 5uA.
//
// For demonstration, LEDs show position of finger.
// Last "Key" maintains LED status
//
// Zack Albus
//******************************************************************************
#include "msp430x20x1.h"
// Define User Configuration values //
//----------------------------------//
// Defines WDT ACLK interval for delay between measurement cycles
#define WDT_delay_setting (DIV_ACLK_512)
// Sensor settings
#define Num_Sen 4 // Defines number of sensors
#define KEY_lvl 5 // Defines the min count for a "key press"
// Set to ~ half the max delta expected
// Definitions for use with the WDT settings
#define DIV_ACLK_32768 (WDT_ADLY_1000) /* ACLK/32768 */
#define DIV_ACLK_8192 (WDT_ADLY_250) /* ACLK/8192 */
#define DIV_ACLK_512 (WDT_ADLY_16) /* ACLK/512 */
#define DIV_ACLK_64 (WDT_ADLY_1_9) /* ACLK/64 */
#define DIV_SMCLK_32768 (WDT_MDLY_32) /* SMCLK/32768 */
#define DIV_SMCLK_8192 (WDT_MDLY_8) /* SMCLK/8192 */
#define DIV_SMCLK_512 (WDT_MDLY_0_5) /* SMCLK/512 */
#define DIV_SMCLK_64 (WDT_MDLY_0_064) /* SMCLK/64 */
#define S_1 (0x01) // Sensor 1 P1.0
#define S_2 (0x02) // Sensor 2 P1.1
#define S_3 (0x04) // Sensor 3 P1.2
#define S_4 (0x08) // Sensor 4 P1.3
#define LED_1 (0x80) // P2.7
#define LED_2 (0x40) // P2.6
#define BUZZ (0x80) // Buzzer on P2.7
// Global variables for sensing
unsigned int base_cnt[Num_Sen];
unsigned int meas_cnt[Num_Sen];
int delta_cnt[Num_Sen];
unsigned char key_press[Num_Sen];
char key_pressed, key_loc;
int cycles;
unsigned int timer_count;
// System Routines
void initialize(void); // Configure modules & control Registers
void measure_count(void); // Measures each capacitive sensor
void pulse_LED(void); // LED gradient routine (for demo only)
// Main Function
void main(void)
{ volatile unsigned int i,j;
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_16MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_16MHZ;
BCSCTL1 |= DIVA_1; // ACLK/(0:1,1:2,2:4,3:8)
BCSCTL3 |= LFXT1S_2; // LFXT1 = VLO
IE1 |= WDTIE; // enable WDT interrupt
P1OUT = 0x00; // P1.x = 0
P1DIR = 0xFF; // P1.x = output
P2OUT = 0x00; //
P2DIR = LED_1 + LED_2; // P2.6, P2.7 = outputs
P2SEL = 0x00; // No XTAL
_EINT(); // Enable interrupts
measure_count(); // Establish an initial baseline capacitance
for (i = 0; i<Num_Sen; i++)
base_cnt[i] = meas_cnt[i];
for(i=15; i>0; i--) // Repeat and average base measurement
{ measure_count();
for (j = 0; j<Num_Sen; j++)
base_cnt[j] = (meas_cnt[j]+base_cnt[j])/2;
}
// Main loop starts here
while (1)
{
key_pressed = 0; // Assume no keys are pressed
measure_count(); // Measure all sensors
for (i = 0; i<Num_Sen; i++)
{ delta_cnt[i] = meas_cnt[i] - base_cnt[i]; // Calculate delta: c_change
// Handle baseline measurment for a base C decrease
if (delta_cnt[i] < 0) // If negative: result decreased
{ // below baseline, i.e. cap decreased
base_cnt[i] = (base_cnt[i]+meas_cnt[i]) >> 1; // Re-average baseline down quickly
delta_cnt[i] = 0; // Zero out delta for position determination
}
if (delta_cnt[i] > KEY_lvl) // Determine if each key is pressed per a preset threshold
{
key_press[i] = 1; // Specific key pressed
key_pressed = 1; // Any key pressed
}
else
key_press[i] = 0;
}
// Delay to next sample, sample more slowly if no keys are pressed
if (key_pressed)
{
BCSCTL1 = (BCSCTL1 & 0x0CF) + DIVA_0; // ACLK/(0:1,1:2,2:4,3:8)
cycles = 20;
}
else
{
cycles--;
if (cycles > 0)
BCSCTL1 = (BCSCTL1 & 0x0CF) + DIVA_0; // ACLK/(0:1,1:2,2:4,3:8)
else
{
BCSCTL1 = (BCSCTL1 & 0x0CF) + DIVA_3; // ACLK/(0:1,1:2,2:4,3:8)
cycles = 0;
}
}
WDTCTL = WDT_delay_setting; // WDT, ACLK, interval timer
// Handle baseline measurment for a base C increase
if (!key_pressed) // Only adjust baseline up if no keys are touched
{
for (i = 0; i<Num_Sen; i++)
base_cnt[i] = base_cnt[i] + 1; // Adjust baseline up, should be slow to
} // accomodate for genuine changes in sensor C
pulse_LED();
LPM3;
}
} // End Main
// Measure count result (capacitance) of each sensor
// Routine setup for four sensors, not dependent on Num_Sen value!
void measure_count(void)
{ unsigned char i;
char active_key;
TACTL = TASSEL_2+MC_2; // SMCLK, cont mode
for (i = 0; i<Num_Sen; i++)
{
active_key = 1 << i; // define bit location of active key
//****************************************************************************
// Negative cycle
//****************************************************************************
P1OUT &=~(BIT0+BIT1+BIT2+BIT3); // everything is low
/* Take the active key high to charge the pad */
P1OUT |= active_key;
/* Allow a short time for the hard pull high to really charge the pad */
_NOP();
_NOP();
_NOP();
// Enable interrupts (edge set to low going trigger)
// set the active key to input (was output high), and start the
// timed discharge of the pad.
P1IES |= active_key; //-ve edge trigger
P1IE |= active_key;
P1DIR &= ~active_key;
/* Take a snaphot of the timer... */
timer_count = TAR;
LPM0;
/* Return the key to the driven low state, to contribute to the "ground" area
around the next key to be scanned. */
P1IE &= ~active_key; // disable active key interrupt
P1OUT &= ~active_key; // switch active key to low to discharge the key
P1DIR |= active_key; // switch active key to output low to save power
meas_cnt[i]= timer_count;
//****************************************************************************
// Positive Cycle
//****************************************************************************
P1OUT |= (BIT0+BIT1+BIT2+BIT3); // everything is high
/* Take the active key low to discharge the pad */
P1OUT &= ~active_key;
/* Allow a short time for the hard pull low to really discharge the pad */
_NOP();
_NOP();
_NOP();
// Enable interrupts (edge set to high going trigger)
// set the active key to input (was output low), and start the
// timed discharge of the pad.
P1IES &= ~active_key; //+ve edge trigger
P1IE |= active_key;
P1DIR &= ~active_key;
/* Take a snaphot of the timer... */
timer_count = TAR;
LPM0;
/* Return the key to the driven low state, to contribute to the "ground" area
around the next key to be scanned. */
P1IE &= ~active_key; // disable active key interrupt
P1OUT &= ~active_key; // switch active key to low to discharge the key
P1DIR |= active_key; // switch active key to output low to save power
P1OUT &=~(BIT0+BIT1+BIT2+BIT3); // everything is low
meas_cnt[i] = (meas_cnt[i] + timer_count) >> 1; // Average the 2 measurements
}
}
#pragma vector=PORT1_VECTOR
__interrupt void port_1_interrupt(void)
{
P1IFG = 0; // clear flag
timer_count = TAR - timer_count; // find the charge/discharge time
LPM3_EXIT; // Exit LPM3 on reti
}
void pulse_LED(void)
{ char i;
BCSCTL1 = (BCSCTL1 &0x0F0) + CALBC1_8MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_8MHZ;
TACTL = TACLR; // SMCLK, up mode, int enabled
TACCTL1 = CCIE; // interrupt enabled
TACCR0 = 40001; // max leftover counts in one pass though of main
TACCR1 = 40000; // time for led to be on
if (key_pressed)
{
for (i = 0; i<Num_Sen; i++)
{
if (key_press[i])
key_loc = i+1;
}
}
switch (key_loc)
{
case 1: P2OUT = 0;
TACCR1 = 1;
break;
case 2: P2OUT = LED_1;
break;
case 3: P2OUT = LED_2;
break;
case 4: P2OUT = LED_1 + LED_2;
break;
default:
break;
}
TACTL = TACLR + TASSEL_2 + ID_3 + MC_1; // SMCLK, up mode, int enabled
_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
TACTL = TACLR;
P2OUT &= ~(LED_1 + LED_2);
BCSCTL1 = (BCSCTL1 &0x0F0) + CALBC1_16MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_16MHZ;
}
// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
TACCTL1 ^= CCIS0; // Create SW capture of CCR1
LPM3_EXIT; // Exit LPM3 on reti
}
// Timer A1 interrupt service routine
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A1 (void)
{
TACCTL1 &= ~CCIE; // interrupt disbled
LPM0_EXIT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -