📄 msp430x20x1_rc_ta_uart slider.c
字号:
//******************************************************************************
// F2011 demo code for RC charge/discharge demo
//
// Version 0-00: 10-20-2006
//
// Single touch position along 4 Key Slider
// This version TX's all data to the PC: Measured, Base and Position
// Sensor results are normalized to 16 steps per key and linearized across
// 0 to 64 steps. Base capacitance is tracked for changes and slider max
// endpoint is handled for no backoff or back in position detections.
//
// Only position is TX'd to the PC
//
// Testing using 0.5mm insulated keys. At 16MHz, ~130counts are achieved.
// TX baud is 57600 and Icc is ~ 40uA, ~15uA of which is due to the UART.
// Sensors are sampled ~16 times per second when a key is pressed; and
// ~3 times per second when no key is pressed after ~2 seconds. Current
// Consumption in this case is ~ 20uA, with ~ 15uA due to RS232 comm.
//
// For demonstration, LED gradient is included.
//
// 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"
// Must be less than step_size
#define max_cnt 100 // Set below actual max delta expected for given setup
#define num_steps 16 // How many steps per key?
#define step_size (max_cnt/num_steps) // Step size used to determine position
// 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
// Conditions for 9600 Baud SW TX-only UART, SMCLK = 1MHz
//#define Bitime 0x0068 // x us bit length ~ x baud
// Conditions for 57600 Baud SW TX-only UART, SMCLK = 4MHz
//#define Bitime 0x0045 // x us bit length ~ x baud
// Conditions for 57600 Baud SW TX-only UART, SMCLK = 8MHz
#define Bitime 0x008A // x us bit length ~ x baud
// Conditions for 115200 Baud SW TX-only UART, SMCLK = 8MHz
//#define Bitime 0x0045 // x us bit length ~ x baud
// Conditions for 115200 Baud SW TX-only UART, SMCLK = 16MHz
//#define Bitime 0x008A // x us bit length ~ x baud
#define TXD 0x40 // TXD on P2.6
#define UART_HDR (0x0A5) // UART data header
#define UART_FTR (0x05A) // UART data footer
unsigned int RXTXData;
unsigned char BitCnt;
unsigned char TX_MSB, TX_LSB;
// Global variables for sensing
unsigned int base_cnt[Num_Sen];
unsigned int meas_cnt[Num_Sen];
int delta_cnt[Num_Sen];
unsigned int key_pos[Num_Sen];
unsigned int key_pos_old[Num_Sen];
unsigned char key_press[Num_Sen];
char key_pressed;
unsigned int position, position_old;
int cycles;
unsigned int timer_count;
// System Routines
void initialize(void); // Configure modules & control Registers
void measure_count(void); // Measures each capacitive sensor
void TX_Byte (unsigned char TX_DATA); // Transmits bytes using Timer_A
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 = BUZZ + 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)
{
position = 0; // Reset position
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] > max_cnt) // If count exceeds preset upper delta
delta_cnt[i] = max_cnt; // limit to setpoint for position determination
key_pos[i] = delta_cnt[i]/step_size; // Determine individual "position" of each sensor
if (key_pos[i] > 0) // If the key is "pressed", calculate position
position = key_pos[i] + num_steps*(i); // Position = 0 to 16, offset for each key
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 max end of slider
if (key_press[3] && position_old == Num_Sen*num_steps) // Is the last key pressed and previous position = max?
{
if (key_pos[2] < key_pos_old[2] || key_pos[2] == key_pos_old[2]) // ... and next-to-last key delta decreasing?
position = Num_Sen*num_steps; // Means finger is moving beyond the max position, hold at max
}
else if (key_press[3] && position_old == 0 && !key_press[2]) // Is the last key pressed and previous position = 0,
position = Num_Sen*num_steps; // ... and next-to-last key is not pressed: Set to max, finger approach from max
// 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
// Save key & position history
for (i = 0; i<Num_Sen; i++)
{
key_pos_old[i] = key_pos[i];
}
position_old = position;
//Transmit measured data
TX_Byte(UART_HDR);
TX_LSB = position;
TX_MSB = position >> 8;
TX_Byte(TX_MSB);
TX_Byte(TX_LSB);
TX_Byte(UART_FTR);
if (position > 0)
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)
{
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 = (position*625/64)*position; // time for led to be on
P2OUT |= LED_1;
TACTL = TACLR + TASSEL_2 + ID_3 + MC_1;// + TAIE; // SMCLK, up mode, int enabled
_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
TACTL = TACLR;
P2OUT &= ~LED_1;
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
}
// Function Transmits Character from RXTXData Buffer
void TX_Byte (unsigned char TX_DATA)
{
BCSCTL1 = (BCSCTL1 &0x0F0) + CALBC1_8MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_8MHZ; // 1MHz used for UART comm
// BCSCTL2 |= DIVS_1; // SMCLK = DCO/2, 4MHz for UART
CCTL1 = OUT; // TXD Idle as Mark
TACTL = TASSEL_2 + MC_2; // SMCLK, continuous mode
P1SEL |= TXD;
P1DIR |= TXD;
BitCnt = 0xA; // Load Bit counter, 8data + ST/SP
CCR1 = TAR; // Current state of TA counter
CCR1 += Bitime; // Some time till first bit
RXTXData = TX_DATA;
RXTXData |= 0x100; // Add mark stop bit to RXTXData
RXTXData = RXTXData << 1; // Add space start bit
CCTL1 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle
while ( CCTL1 & CCIE )
{
LPM0;
}
P1SEL &= ~TXD;
// BCSCTL2 &= ~DIVS_1; // SMCLK = DCO
BCSCTL1 = (BCSCTL1 &0x0F0) + CALBC1_16MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_16MHZ; // 1MHz used for UART comm
}
// Timer A1 interrupt service routine
#pragma vector=TIMERA1_VECTOR
__interrupt void Timer_A1 (void)
{
if (CCTL1 & CCIS0) // TX on CCI0B?
{
CCR1 += Bitime; // Add Offset to CCR0
if ( BitCnt == 0)
CCTL1 &= ~ CCIE; // All bits TXed, disable interrupt
else
{
if (RXTXData & 0x01)
CCTL1 &= ~ OUTMOD2; // TX Mark
else
CCTL1 |= OUTMOD2; // TX Space
RXTXData = RXTXData >> 1;
BitCnt --;
}
CCTL1 &= ~ CCIFG;
}
else // for LED gradient only
TACCTL1 &= ~CCIE; // interrupt disbled
LPM0_EXIT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -