📄 msp430x20x1_ro_ta_uart slider.c
字号:
//******************************************************************************
// F2011 demo code for relaxation osc demo
//
// Version 0-00: 10-20-2006
//
// Single touch 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 1MHz/8/512, ~400counts are achieved.
// TX baud is 57600 and Icc is ~75uA, 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 ~ 25uA, with ~ 15uA due to RS232 comm.
//
// For demonstration, LED gradient is included.
//
// Zack Albus
//******************************************************************************
#include "msp430x20x1.h"
// Define User Configuration values //
//----------------------------------//
// Defines WDT SMCLK interval for sensor measurements
#define WDT_meas_setting (DIV_SMCLK_512)
// 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 20 // Defines the min count for a "key press"
// Must be less than step_size
#define max_cnt 300 // 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 Hardware Inputs/Outputs
#define CA_Out (0x80) // Comparator output on P1.7
#define CA_Ref (0x02) // Comparator reference on P1.1
#define TA_Clk (0x01) // Timer_A clock input on P1.0
#define Ref_En (0x40) // External CA+ ref enable on P1.6
#define S_1 (0x04) // Sensor 1 P1.2
#define S_2 (0x08) // Sensor 2 P1.3
#define S_3 (0x10) // Sensor 3 P1.4
#define S_4 (0x20) // Sensor 4 P1.5
#define CA_1 (P2CA4) // Mux settings: CA+ Vref at CA1
#define CA_2 (P2CA2) // Mux settings: Sensor 1 at CA2
#define CA_3 (P2CA1+P2CA2) // Mux settings: Sensor 2 at CA2
#define CA_4 (P2CA3) // Mux settings: Sensor 3 at CA2
#define CA_5 (P2CA1+P2CA3) // Mux settings: Sensor 4 at CA2
#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;
// 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_1MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_1MHZ;
BCSCTL1 |= DIVA_0; // 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 = 0xFE; // P1.0 = TACLK input
P1SEL |= 0x81; // P1.0 = TACLK input, P1.7 = CAOUT
P2OUT = 0x00; //
P2DIR = BUZZ + LED_2; // P2.6, P2.7 = outputs
P2SEL = 0x00; // No XTAL
CAPD = CA_Ref; // disable input buffer for CA+ ref input
CACTL2 = CA_1; // CA1 = CA+ Vref
_EINT(); // Enable interrupts
P1OUT |= Ref_En; // Enable CA+ external reference
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;
}
P1OUT &= ~Ref_En; // Disable CA+ external reference
// 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] = base_cnt[i] - meas_cnt[i]; // Calculate delta: c_change
// Handle baseline measurment for a base C decrease
if (delta_cnt[i] < 0) // If negative: result increased
{ // beyond baseline, i.e. cap decreased
base_cnt[i] = (base_cnt[i]+meas_cnt[i]) >> 1; // Re-average baseline up 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 down if no keys are touched
{
for (i = 0; i<Num_Sen; i++)
base_cnt[i] = base_cnt[i] - 1; // Adjust baseline down, 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)
{ char i;
TACTL = TASSEL_0+MC_2; // TACLK, cont mode
TACCTL1 = CM_3+CCIS_2+CAP; // Pos&Neg,GND,Cap
P1OUT |= Ref_En; // Turn on CA ref ladder
CACTL1 |= CAON; // Turn on comparator
BCSCTL2 |= DIVS_3; // SMCLK = DCO/8, maximize counts
for (i = 0; i<Num_Sen; i++)
{
switch (i)
{
case 0: // Sensor 1
CAPD = CA_Ref+S_1; // Diable I/Os for CA1 ref, 1st sensor
CACTL2 = CA_1+CA_2; // CA1 ref, CAx sensor
break;
case 1: // Sensor 2
CAPD = CA_Ref+S_2; // Diable I/Os for CA1 ref, 2nd sensor
CACTL2 = CA_1+CA_3; // CA1 ref, CAx sensor
break;
case 2: // Sensor 3
CAPD = CA_Ref+S_3; // Diable I/Os for CA1 ref, 3rd sensor
CACTL2 = CA_1+CA_4; // CA1 ref, CAx sensor
break;
case 3: // Sensor 4
CAPD = CA_Ref+S_4; // Diable I/Os for CA1 ref, 4th sensor
CACTL2 = CA_1+CA_5; // CA1 ref, CAx sensor
break;
}
WDTCTL = WDT_meas_setting; // Set duration of sensor measurment
TACTL |= TACLR; // Clear Timer_A TAR
LPM0; // Wait for WDT interrupt
meas_cnt[i] = TACCR1; // Save result
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
}
BCSCTL2 &= ~DIVS_3; // SMCLK = DCO
// End Sequence
P1OUT &= ~Ref_En; // Turn off CA ref ladder
CACTL1 &= ~CAON; // Turn off comparator
CAPD = CA_Ref; // Re-init Mux: all sensors = GND
CACTL2 = CA_1; // Only CA Ref connected
}
void pulse_LED(void)
{
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 + MC_1; // SMCLK, up mode, int enabled
_BIS_SR(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
TACTL = TACLR;
P2OUT &= ~LED_1;
}
// 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;
CCTL1 = OUT; // TXD Idle as Mark
TACTL = TASSEL_2 + MC_2; // SMCLK, continuous mode
P2SEL |= TXD;
P2DIR |= 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;
}
P2SEL &= ~TXD;
// BCSCTL2 &= ~DIVS_1; // SMCLK = DCO
BCSCTL1 = (BCSCTL1 &0x0F0) + CALBC1_1MHZ; // Set DCO to 1, 8, 12 or 16MHz
DCOCTL = CALDCO_1MHZ;
}
// 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 + -