MSP430G2553 电容触摸按键控制LED灯源码

一、硬件连接

1.1 引脚分配

引脚 功能 连接
P1.0 LED1 接LED+220Ω电阻到GND
P1.3 触摸按键1 触摸电极
P1.6 LED2 接LED+220Ω电阻到GND
P1.7 触摸按键2 触摸电极

1.2 触摸电极设计

触摸电极设计建议:
1. 使用PCB铜箔或弹簧
2. 电极尺寸:10mm×10mm
3. 电极到MCU连线尽量短
4. 在电极周围铺地屏蔽

二、完整源码实现

2.1 主程序 (main.c)

/**
 * MSP430G2553 电容触摸按键控制LED
 * 使用 Timer_A 捕获模式测量RC充电时间
 * 支持两个触摸按键,控制两个LED
 */

#include <msp430g2553.h>
#include <stdint.h>
#include <stdbool.h>

// 引脚定义
#define TOUCH_PIN1   BIT3   // P1.3
#define TOUCH_PIN2   BIT7   // P1.7
#define LED1_PIN     BIT0   // P1.0
#define LED2_PIN     BIT6   // P1.6

// 触摸检测参数
#define SAMPLE_NUM   16     // 采样次数
#define THRESHOLD    30     // 触摸阈值
#define DEBOUNCE_CNT 5      // 消抖计数

// 全局变量
volatile uint16_t touch1_count = 0;
volatile uint16_t touch2_count = 0;
volatile uint8_t touch1_state = 0;
volatile uint8_t touch2_state = 0;
volatile uint8_t touch1_debounce = 0;
volatile uint8_t touch2_debounce = 0;

// 函数声明
void GPIO_Init(void);
void TimerA_Init(void);
void Touch_Init(void);
uint16_t Touch_Measure(uint8_t channel);
void Touch_Process(void);
void System_Init(void);

/**
 * 主函数
 */
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;   // 停止看门狗
    System_Init();              // 系统初始化
    
    __enable_interrupt();       // 开启全局中断
    
    while(1) {
        Touch_Process();        // 触摸处理
        __delay_cycles(10000);  // 短暂延时
    }
}

/**
 * 系统初始化
 */
void System_Init(void) {
    // 配置时钟
    BCSCTL1 = CALBC1_1MHZ;      // 设置DCO为1MHz
    DCOCTL = CALDCO_1MHZ;
    
    // 初始化外设
    GPIO_Init();
    TimerA_Init();
    Touch_Init();
    
    // 初始化LED
    P1OUT &= ~(LED1_PIN | LED2_PIN);  // LED初始关闭
}

/**
 * GPIO初始化
 */
void GPIO_Init(void) {
    // 设置LED引脚为输出
    P1DIR |= LED1_PIN | LED2_PIN;
    P1OUT &= ~(LED1_PIN | LED2_PIN);
    
    // 设置触摸引脚为输入
    P1DIR &= ~(TOUCH_PIN1 | TOUCH_PIN2);
    
    // 使能内部上拉电阻
    P1REN |= TOUCH_PIN1 | TOUCH_PIN2;
    P1OUT |= TOUCH_PIN1 | TOUCH_PIN2;
}

/**
 * 定时器A初始化
 */
void TimerA_Init(void) {
    // 停止定时器
    TA0CTL = 0;
    
    // 配置定时器
    TA0CTL = TASSEL_2 | ID_0 | MC_2;  // SMCLK, 不分频, 连续计数模式
    TA0CTL |= TACLR;                  // 清除定时器
    
    // 捕获模式配置
    TA0CCTL0 = CM_3 | CCIS_0 | SCS | CAP;  // 双边沿捕获, CCIxA, 同步捕获
    TA0CCTL1 = CM_3 | CCIS_0 | SCS | CAP;  // 双边沿捕获, CCIxB, 同步捕获
}

/**
 * 触摸初始化
 */
void Touch_Init(void) {
    // 校准值
    static uint16_t touch1_base = 0;
    static uint16_t touch2_base = 0;
    
    // 进行10次测量取平均值作为基准值
    uint32_t sum1 = 0, sum2 = 0;
    
    for(uint8_t i = 0; i < 10; i++) {
        sum1 += Touch_Measure(1);
        sum2 += Touch_Measure(2);
        __delay_cycles(1000);
    }
    
    touch1_base = sum1 / 10;
    touch2_base = sum2 / 10;
    
    // 保存基准值
    touch1_count = touch1_base;
    touch2_count = touch2_base;
}

/**
 * 测量触摸通道
 * @param channel 触摸通道 (1或2)
 * @return 测量计数值
 */
uint16_t Touch_Measure(uint8_t channel) {
    uint16_t count = 0;
    
    if(channel == 1) {
        // 配置P1.3为输出,拉低
        P1DIR |= TOUCH_PIN1;
        P1OUT &= ~TOUCH_PIN1;
        
        // 短暂延时,确保放电
        __delay_cycles(10);
        
        // 配置为输入,使能上拉电阻
        P1DIR &= ~TOUCH_PIN1;
        P1REN |= TOUCH_PIN1;
        P1OUT |= TOUCH_PIN1;
        
        // 启动定时器
        TA0CTL |= TACLR;
        TA0CTL |= MC_2;
        
        // 等待引脚变高
        while(!(P1IN & TOUCH_PIN1)) {
            if(TA0R > 60000) break;  // 超时保护
        }
        
        count = TA0R;  // 记录充电时间
        TA0CTL &= ~MC_2;  // 停止定时器
    }
    else if(channel == 2) {
        // 配置P1.7为输出,拉低
        P1DIR |= TOUCH_PIN2;
        P1OUT &= ~TOUCH_PIN2;
        
        // 短暂延时
        __delay_cycles(10);
        
        // 配置为输入,使能上拉电阻
        P1DIR &= ~TOUCH_PIN2;
        P1REN |= TOUCH_PIN2;
        P1OUT |= TOUCH_PIN2;
        
        // 启动定时器
        TA0CTL |= TACLR;
        TA0CTL |= MC_2;
        
        // 等待引脚变高
        while(!(P1IN & TOUCH_PIN2)) {
            if(TA0R > 60000) break;
        }
        
        count = TA0R;
        TA0CTL &= ~MC_2;
    }
    
    return count;
}

/**
 * 触摸处理函数
 */
void Touch_Process(void) {
    static uint8_t sample_count1 = 0;
    static uint8_t sample_count2 = 0;
    static uint16_t samples1[SAMPLE_NUM] = {0};
    static uint16_t samples2[SAMPLE_NUM] = {0};
    static uint8_t index1 = 0;
    static uint8_t index2 = 0;
    
    // 通道1采样
    samples1[index1] = Touch_Measure(1);
    index1 = (index1 + 1) % SAMPLE_NUM;
    sample_count1 = (sample_count1 < SAMPLE_NUM) ? sample_count1 + 1 : SAMPLE_NUM;
    
    // 计算平均值
    uint32_t sum1 = 0;
    for(uint8_t i = 0; i < sample_count1; i++) {
        sum1 += samples1[i];
    }
    uint16_t avg1 = sum1 / sample_count1;
    
    // 通道2采样
    samples2[index2] = Touch_Measure(2);
    index2 = (index2 + 1) % SAMPLE_NUM;
    sample_count2 = (sample_count2 < SAMPLE_NUM) ? sample_count2 + 1 : SAMPLE_NUM;
    
    uint32_t sum2 = 0;
    for(uint8_t i = 0; i < sample_count2; i++) {
        sum2 += samples2[i];
    }
    uint16_t avg2 = sum2 / sample_count2;
    
    // 检测触摸
    if(avg1 > touch1_count + THRESHOLD) {
        if(touch1_debounce < DEBOUNCE_CNT) {
            touch1_debounce++;
        } else {
            touch1_state = 1;
        }
    } else {
        if(touch1_debounce > 0) {
            touch1_debounce--;
        } else {
            touch1_state = 0;
        }
    }
    
    if(avg2 > touch2_count + THRESHOLD) {
        if(touch2_debounce < DEBOUNCE_CNT) {
            touch2_debounce++;
        } else {
            touch2_state = 1;
        }
    } else {
        if(touch2_debounce > 0) {
            touch2_debounce--;
        } else {
            touch2_state = 0;
        }
    }
    
    // 控制LED
    if(touch1_state) {
        P1OUT |= LED1_PIN;  // 触摸1点亮LED1
    } else {
        P1OUT &= ~LED1_PIN; // 松开关闭LED1
    }
    
    if(touch2_state) {
        P1OUT |= LED2_PIN;  // 触摸2点亮LED2
    } else {
        P1OUT &= ~LED2_PIN; // 松开关闭LED2
    }
    
    // 自适应基准值
    if(!touch1_state) {
        // 缓慢更新基准值
        touch1_count = (touch1_count * 15 + avg1) / 16;
    }
    
    if(!touch2_state) {
        touch2_count = (touch2_count * 15 + avg2) / 16;
    }
}

2.2 使用Timer_A捕获模式的优化版本

/**
 * MSP430G2553 电容触摸 - Timer_A捕获模式
 * 更精确的测量方法
 */

#include <msp430g2553.h>
#include <stdint.h>

// 引脚定义
#define TOUCH_PIN1   BIT3
#define TOUCH_PIN2   BIT7
#define LED1_PIN     BIT0
#define LED2_PIN     BIT6

// 触摸参数
#define THRESHOLD    50
#define SAMPLE_RATE  10
#define TIMEOUT      5000

// 全局变量
volatile uint16_t capture1_time = 0;
volatile uint16_t capture2_time = 0;
volatile uint8_t capture1_done = 0;
volatile uint8_t capture2_done = 0;
volatile uint8_t touch1_active = 0;
volatile uint8_t touch2_active = 0;

/**
 * 定时器A0中断服务程序
 */
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void) {
    static uint16_t timeout_counter1 = 0;
    static uint16_t timeout_counter2 = 0;
    
    // 通道1超时检测
    if(timeout_counter1++ > TIMEOUT) {
        capture1_time = 0xFFFF;
        capture1_done = 1;
        timeout_counter1 = 0;
    }
    
    // 通道2超时检测
    if(timeout_counter2++ > TIMEOUT) {
        capture2_time = 0xFFFF;
        capture2_done = 1;
        timeout_counter2 = 0;
    }
    
    // 清除中断标志
    TA0CTL &= ~TAIFG;
}

/**
 * 定时器A0 CCR1中断(通道1捕获)
 */
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR(void) {
    switch(TA0IV) {
        case 2:  // CCR1捕获
            capture1_time = TA0CCR1;
            capture1_done = 1;
            break;
            
        case 4:  // CCR2捕获
            capture2_time = TA0CCR2;
            capture2_done = 1;
            break;
            
        default:
            break;
    }
}

/**
 * 初始化定时器A
 */
void TimerA_Init_Capture(void) {
    // 停止定时器
    TA0CTL = 0;
    
    // 配置为SMCLK,连续模式
    TA0CTL = TASSEL_2 | ID_0 | MC_2 | TAIE;
    
    // 配置CCR1为捕获模式(P1.3)
    TA0CCTL1 = CM_2 | CCIS_0 | SCS | CAP | CCIE;
    
    // 配置CCR2为捕获模式(P1.7)
    TA0CCTL2 = CM_2 | CCIS_0 | SCS | CAP | CCIE;
}

/**
 * 开始充电测量
 */
void Start_Charge_Measurement(uint8_t channel) {
    if(channel == 1) {
        // 放电
        P1DIR |= TOUCH_PIN1;
        P1OUT &= ~TOUCH_PIN1;
        __delay_cycles(10);
        
        // 重新配置为输入
        P1DIR &= ~TOUCH_PIN1;
        P1REN |= TOUCH_PIN1;
        P1OUT |= TOUCH_PIN1;
        
        // 清除标志
        capture1_done = 0;
        TA0CTL |= TACLR;
        
        // 使能上升沿捕获
        TA0CCTL1 = CM_1 | CCIS_0 | SCS | CAP | CCIE;
    }
    else if(channel == 2) {
        // 放电
        P1DIR |= TOUCH_PIN2;
        P1OUT &= ~TOUCH_PIN2;
        __delay_cycles(10);
        
        // 重新配置为输入
        P1DIR &= ~TOUCH_PIN2;
        P1REN |= TOUCH_PIN2;
        P1OUT |= TOUCH_PIN2;
        
        // 清除标志
        capture2_done = 0;
        TA0CTL |= TACLR;
        
        // 使能上升沿捕获
        TA0CCTL2 = CM_1 | CCIS_0 | SCS | CAP | CCIE;
    }
}

/**
 * 主函数 - 捕获模式版本
 */
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;
    
    // 时钟配置
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    
    // GPIO初始化
    P1DIR |= LED1_PIN | LED2_PIN;
    P1OUT &= ~(LED1_PIN | LED2_PIN);
    
    // 定时器初始化
    TimerA_Init_Capture();
    
    __enable_interrupt();
    
    // 基准值测量
    uint16_t base1 = 0, base2 = 0;
    for(uint8_t i = 0; i < 10; i++) {
        Start_Charge_Measurement(1);
        while(!capture1_done);
        base1 += capture1_time;
        
        Start_Charge_Measurement(2);
        while(!capture2_done);
        base2 += capture2_time;
    }
    base1 /= 10;
    base2 /= 10;
    
    // 主循环
    while(1) {
        // 测量通道1
        Start_Charge_Measurement(1);
        while(!capture1_done);
        
        if(capture1_time > base1 + THRESHOLD) {
            touch1_active = 1;
            P1OUT |= LED1_PIN;
        } else {
            touch1_active = 0;
            P1OUT &= ~LED1_PIN;
        }
        
        // 自适应更新基准值
        if(!touch1_active) {
            base1 = (base1 * 15 + capture1_time) / 16;
        }
        
        // 测量通道2
        Start_Charge_Measurement(2);
        while(!capture2_done);
        
        if(capture2_time > base2 + THRESHOLD) {
            touch2_active = 1;
            P1OUT |= LED2_PIN;
        } else {
            touch2_active = 0;
            P1OUT &= ~LED2_PIN;
        }
        
        // 自适应更新基准值
        if(!touch2_active) {
            base2 = (base2 * 15 + capture2_time) / 16;
        }
        
        __delay_cycles(10000);
    }
}

2.3 使用比较器A的版本(更高灵敏度)

/**
 * MSP430G2553 电容触摸 - 使用比较器A
 * 更灵敏的检测方法
 */

#include <msp430g2553.h>
#include <stdint.h>

// 引脚定义
#define TOUCH_PIN1   BIT3
#define TOUCH_PIN2   BIT7
#define LED1_PIN     BIT0
#define LED2_PIN     BIT6

// 比较器参考电压
#define COMPARE_VREF 0.5  // VCC/2

// 全局变量
volatile uint16_t comp_count1 = 0;
volatile uint16_t comp_count2 = 0;
volatile uint8_t comp_ready1 = 0;
volatile uint8_t comp_ready2 = 0;

/**
 * 比较器A中断
 */
#pragma vector=COMPARATORA_VECTOR
__interrupt void COMPARATORA_ISR(void) {
    if(CACTL2 & CAIFG) {
        if(CACTL2 & CAOUT) {
            // 比较器输出高
            if(P1IN & TOUCH_PIN1) {
                comp_ready1 = 1;
            }
            if(P1IN & TOUCH_PIN2) {
                comp_ready2 = 1;
            }
        }
        CACTL2 &= ~CAIFG;  // 清除中断标志
    }
}

/**
 * 初始化比较器A
 */
void Comparator_Init(void) {
    // 使用内部参考电压
    CACTL1 = CAREF_1 | CAON;  // 0.5Vcc, 使能比较器
    CACTL2 = P2CA0 | P2CA1 | CAF;  // CA1输入, 使能输出滤波器
    
    // 配置中断
    CACTL2 |= CAIE;
}

/**
 * 使用比较器测量充电时间
 */
uint16_t Touch_Measure_Comp(uint8_t channel) {
    uint16_t count = 0;
    
    if(channel == 1) {
        // 放电
        P1DIR |= TOUCH_PIN1;
        P1OUT &= ~TOUCH_PIN1;
        __delay_cycles(10);
        
        // 配置为比较器输入
        P1DIR &= ~TOUCH_PIN1;
        P1REN |= TOUCH_PIN1;
        P1OUT |= TOUCH_PIN1;
        
        // 启动定时器
        TA0CTL |= TACLR;
        TA0CTL |= MC_2;
        
        comp_ready1 = 0;
        
        // 等待比较器输出高
        while(!comp_ready1) {
            if(TA0R > 60000) break;
        }
        
        count = TA0R;
        TA0CTL &= ~MC_2;
    }
    else if(channel == 2) {
        // 放电
        P1DIR |= TOUCH_PIN2;
        P1OUT &= ~TOUCH_PIN2;
        __delay_cycles(10);
        
        // 配置为比较器输入
        P1DIR &= ~TOUCH_PIN2;
        P1REN |= TOUCH_PIN2;
        P1OUT |= TOUCH_PIN2;
        
        // 启动定时器
        TA0CTL |= TACLR;
        TA0CTL |= MC_2;
        
        comp_ready2 = 0;
        
        // 等待比较器输出高
        while(!comp_ready2) {
            if(TA0R > 60000) break;
        }
        
        count = TA0R;
        TA0CTL &= ~MC_2;
    }
    
    return count;
}

/**
 * 主函数 - 比较器版本
 */
int main(void) {
    WDTCTL = WDTPW | WDTHOLD;
    
    // 时钟配置
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    
    // GPIO初始化
    P1DIR |= LED1_PIN | LED2_PIN;
    P1OUT &= ~(LED1_PIN | LED2_PIN);
    
    // 定时器初始化
    TA0CTL = TASSEL_2 | ID_0 | MC_0;
    
    // 比较器初始化
    Comparator_Init();
    
    __enable_interrupt();
    
    // 主循环
    uint16_t base1 = 0, base2 = 0;
    uint8_t touch1 = 0, touch2 = 0;
    
    // 初始化基准值
    for(uint8_t i = 0; i < 10; i++) {
        base1 += Touch_Measure_Comp(1);
        base2 += Touch_Measure_Comp(2);
        __delay_cycles(1000);
    }
    base1 /= 10;
    base2 /= 10;
    
    while(1) {
        // 测量通道1
        uint16_t measure1 = Touch_Measure_Comp(1);
        
        if(measure1 > base1 + 100) {  // 阈值设为100
            touch1 = 1;
            P1OUT |= LED1_PIN;
        } else {
            touch1 = 0;
            P1OUT &= ~LED1_PIN;
        }
        
        // 自适应基准值
        if(!touch1) {
            base1 = (base1 * 7 + measure1) / 8;
        }
        
        // 测量通道2
        uint16_t measure2 = Touch_Measure_Comp(2);
        
        if(measure2 > base2 + 100) {
            touch2 = 1;
            P1OUT |= LED2_PIN;
        } else {
            touch2 = 0;
            P1OUT &= ~LED2_PIN;
        }
        
        // 自适应基准值
        if(!touch2) {
            base2 = (base2 * 7 + measure2) / 8;
        }
        
        __delay_cycles(50000);
    }
}

2.4 简化版本(适用于简单应用)

/**
 * MSP430G2553 电容触摸按键 - 简化版本
 * 适用于单个触摸按键
 */

#include <msp430g2553.h>

#define TOUCH_PIN    BIT3
#define LED_PIN      BIT0
#define THRESHOLD    20

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;     // 停止看门狗
    
    // 设置时钟
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    
    // 配置LED引脚
    P1DIR |= LED_PIN;
    P1OUT &= ~LED_PIN;
    
    // 触摸检测变量
    unsigned int count = 0;
    unsigned int baseline = 0;
    
    // 初始化基准值
    for(int i = 0; i < 10; i++) {
        // 放电
        P1DIR |= TOUCH_PIN;
        P1OUT &= ~TOUCH_PIN;
        __delay_cycles(10);
        
        // 充电
        P1DIR &= ~TOUCH_PIN;
        P1REN |= TOUCH_PIN;
        P1OUT |= TOUCH_PIN;
        
        // 测量充电时间
        unsigned int charge_time = 0;
        while(!(P1IN & TOUCH_PIN)) {
            charge_time++;
            if(charge_time > 30000) break;
        }
        
        baseline += charge_time;
        __delay_cycles(1000);
    }
    baseline /= 10;
    
    while(1) {
        // 放电
        P1DIR |= TOUCH_PIN;
        P1OUT &= ~TOUCH_PIN;
        __delay_cycles(10);
        
        // 充电
        P1DIR &= ~TOUCH_PIN;
        P1REN |= TOUCH_PIN;
        P1OUT |= TOUCH_PIN;
        
        // 测量充电时间
        count = 0;
        while(!(P1IN & TOUCH_PIN)) {
            count++;
            if(count > 30000) break;
        }
        
        // 检测触摸
        if(count > baseline + THRESHOLD) {
            P1OUT |= LED_PIN;    // 触摸时点亮LED
        } else {
            P1OUT &= ~LED_PIN;   // 松开时关闭LED
        }
        
        // 缓慢更新基准值
        if(count < baseline + THRESHOLD) {
            baseline = (baseline + count) / 2;
        }
        
        __delay_cycles(10000);
    }
}

三、高级功能扩展

3.1 触摸灵敏度调节

/**
 * 触摸灵敏度配置
 */

// 灵敏度等级
typedef enum {
    SENSITIVITY_LOW = 0,
    SENSITIVITY_MEDIUM = 1,
    SENSITIVITY_HIGH = 2
} SensitivityLevel;

// 灵敏度参数
typedef struct {
    uint16_t threshold;      // 触摸阈值
    uint8_t  sample_num;     // 采样次数
    uint8_t  debounce;       // 消抖计数
} SensitivityConfig;

// 灵敏度配置表
const SensitivityConfig sensitivity_config[3] = {
    {20, 8, 3},   // 低灵敏度
    {30, 16, 5},  // 中灵敏度
    {50, 32, 8}   // 高灵敏度
};

// 设置灵敏度
void Set_Touch_Sensitivity(SensitivityLevel level) {
    uint16_t threshold = sensitivity_config[level].threshold;
    uint8_t sample_num = sensitivity_config[level].sample_num;
    uint8_t debounce = sensitivity_config[level].debounce;
    
    // 应用配置
    // ... 这里应用配置到触摸检测逻辑
}

3.2 触摸事件回调

/**
 * 触摸事件回调机制
 */

// 触摸事件类型
typedef enum {
    TOUCH_EVENT_NONE = 0,
    TOUCH_EVENT_PRESS,      // 按下
    TOUCH_EVENT_RELEASE,    // 释放
    TOUCH_EVENT_LONG_PRESS, // 长按
    TOUCH_EVENT_DOUBLE_TAP  // 双击
} TouchEventType;

// 触摸回调函数类型
typedef void (*TouchCallback)(uint8_t channel, TouchEventType event);

// 触摸通道结构
typedef struct {
    uint8_t         channel;        // 通道号
    uint8_t         state;          // 当前状态
    uint8_t         last_state;     // 上次状态
    uint32_t        press_time;     // 按下时间
    uint32_t        last_release;   // 上次释放时间
    TouchCallback   callback;       // 回调函数
} TouchChannel;

// 触摸通道数组
TouchChannel touch_channels[2];

// 初始化触摸通道
void Touch_Channel_Init(uint8_t channel, TouchCallback callback) {
    if(channel < 2) {
        touch_channels[channel].channel = channel;
        touch_channels[channel].callback = callback;
        touch_channels[channel].state = 0;
        touch_channels[channel].last_state = 0;
        touch_channels[channel].press_time = 0;
        touch_channels[channel].last_release = 0;
    }
}

// 触摸处理
void Touch_Event_Process(void) {
    static uint32_t tick_counter = 0;
    
    for(uint8_t i = 0; i < 2; i++) {
        // 检测状态变化
        if(touch_channels[i].state != touch_channels[i].last_state) {
            if(touch_channels[i].state) {
                // 按下事件
                touch_channels[i].press_time = tick_counter;
                if(touch_channels[i].callback) {
                    touch_channels[i].callback(i, TOUCH_EVENT_PRESS);
                }
            } else {
                // 释放事件
                uint32_t press_duration = tick_counter - touch_channels[i].press_time;
                
                if(press_duration > 1000) {  // 长按1秒
                    if(touch_channels[i].callback) {
                        touch_channels[i].callback(i, TOUCH_EVENT_LONG_PRESS);
                    }
                } else {
                    if(touch_channels[i].callback) {
                        touch_channels[i].callback(i, TOUCH_EVENT_RELEASE);
                    }
                }
                
                touch_channels[i].last_release = tick_counter;
            }
            touch_channels[i].last_state = touch_channels[i].state;
        }
    }
    
    tick_counter++;
}

3.3 低功耗模式

/**
 * 低功耗触摸检测
 */

#include <msp430g2553.h>

// 低功耗模式触摸检测
void LowPower_Touch_Detect(void) {
    // 进入低功耗模式前
    __disable_interrupt();
    
    // 配置唤醒源
    P1IE |= TOUCH_PIN1 | TOUCH_PIN2;  // 使能引脚中断
    P1IES &= ~(TOUCH_PIN1 | TOUCH_PIN2);  // 上升沿触发
    P1IFG &= ~(TOUCH_PIN1 | TOUCH_PIN2);  // 清除中断标志
    
    // 进入LPM3
    __bis_SR_register(LPM3_bits | GIE);
    
    // 唤醒后处理
    if(P1IFG & TOUCH_PIN1) {
        // 通道1触摸
        P1OUT ^= LED1_PIN;  // 切换LED1
        P1IFG &= ~TOUCH_PIN1;  // 清除标志
    }
    
    if(P1IFG & TOUCH_PIN2) {
        // 通道2触摸
        P1OUT ^= LED2_PIN;  // 切换LED2
        P1IFG &= ~TOUCH_PIN2;  // 清除标志
    }
}

// 引脚中断服务程序
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void) {
    // 退出低功耗模式
    __bic_SR_register_on_exit(LPM3_bits);
}

四、调试和校准

4.1 串口调试输出

/**
 * 通过串口输出触摸值,用于调试
 */

#include <msp430g2553.h>

// 初始化串口
void UART_Init(void) {
    P1SEL |= BIT1 + BIT2;  // P1.1=TX, P1.2=RX
    P1SEL2 |= BIT1 + BIT2;
    
    UCA0CTL1 |= UCSSEL_2;  // SMCLK
    UCA0BR0 = 104;         // 9600 baud @ 1MHz
    UCA0BR1 = 0;
    UCA0MCTL = UCBRS0;
    UCA0CTL1 &= ~UCSWRST;  // 初始化UART
}

// 发送一个字符
void UART_SendChar(char c) {
    while(!(IFG2 & UCA0TXIFG));
    UCA0TXBUF = c;
}

// 发送字符串
void UART_SendString(const char *str) {
    while(*str) {
        UART_SendChar(*str++);
    }
}

// 发送触摸值
void Send_Touch_Value(uint8_t channel, uint16_t value) {
    char buffer[20];
    
    // 格式化输出
    if(channel == 1) {
        sprintf(buffer, "Touch1: %d\r\n", value);
    } else {
        sprintf(buffer, "Touch2: %d\r\n", value);
    }
    
    UART_SendString(buffer);
}

4.2 校准程序

/**
 * 自动校准程序
 */

void Touch_Calibration(void) {
    uint16_t min1 = 0xFFFF, max1 = 0;
    uint16_t min2 = 0xFFFF, max2 = 0;
    uint16_t baseline1, baseline2;
    
    UART_SendString("Starting calibration...\r\n");
    UART_SendString("Please do not touch sensors for 5 seconds.\r\n");
    
    // 收集100个样本
    for(int i = 0; i < 100; i++) {
        uint16_t val1 = Touch_Measure(1);
        uint16_t val2 = Touch_Measure(2);
        
        if(val1 < min1) min1 = val1;
        if(val1 > max1) max1 = val1;
        if(val2 < min2) min2 = val2;
        if(val2 > max2) max2 = val2;
        
        // 计算平均值
        baseline1 += val1;
        baseline2 += val2;
        
        __delay_cycles(50000);
    }
    
    baseline1 /= 100;
    baseline2 /= 100;
    
    // 输出结果
    char msg[50];
    sprintf(msg, "Channel1: min=%d, max=%d, avg=%d\r\n", min1, max1, baseline1);
    UART_SendString(msg);
    sprintf(msg, "Channel2: min=%d, max=%d, avg=%d\r\n", min2, max2, baseline2);
    UART_SendString(msg);
    
    // 保存基准值
    touch1_count = baseline1;
    touch2_count = baseline2;
    
    UART_SendString("Calibration complete.\r\n");
}

参考代码 基于msp430G2553的电容触摸按键控制LED灯的源码 www.youwenfan.com/contentcnv/103255.html

五、硬件优化建议

5.1 PCB布局建议

/**
 * PCB设计注意事项:
 * 1. 触摸电极使用填充铜
 * 2. 电极尺寸10x10mm
 * 3. 电极周围铺地屏蔽
 * 4. 走线尽量短
 * 5. 使用0.1uF去耦电容
 * 6. 避免高压信号靠近
 */

5.2 外部电容优化

/**
 * 增加外部电容提高稳定性:
 * 1. 在触摸引脚加1-10pF电容到地
 * 2. 在VCC和GND之间加0.1uF电容
 * 3. 使用屏蔽线连接触摸电极
 */

5.3 环境适应

/**
 * 环境适应处理:
 * 1. 定期自动校准
 * 2. 温度补偿
 * 3. 湿度补偿
 * 4. 电源电压监测
 */

六、测试程序

6.1 完整测试程序

/**
 * 电容触摸按键完整测试程序
 * 功能:按下时LED亮,松开时LED灭
 * 包含:基准值自动校准、去抖动、自适应
 */

#include <msp430g2553.h>

#define TOUCH1_PIN  BIT3
#define TOUCH2_PIN  BIT7
#define LED1_PIN    BIT0
#define LED2_PIN    BIT6

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;
    
    // 时钟配置
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;
    
    // GPIO初始化
    P1DIR |= LED1_PIN | LED2_PIN;
    P1OUT &= ~(LED1_PIN | LED2_PIN);
    
    // 触摸检测变量
    unsigned int count1, count2;
    unsigned int base1 = 0, base2 = 0;
    
    // 初始化基准值
    for(int i = 0; i < 20; i++) {
        // 测量通道1
        P1DIR |= TOUCH1_PIN;
        P1OUT &= ~TOUCH1_PIN;
        __delay_cycles(10);
        P1DIR &= ~TOUCH1_PIN;
        P1REN |= TOUCH1_PIN;
        P1OUT |= TOUCH1_PIN;
        
        count1 = 0;
        while(!(P1IN & TOUCH1_PIN) && count1 < 30000) count1++;
        base1 += count1;
        
        // 测量通道2
        P1DIR |= TOUCH2_PIN;
        P1OUT &= ~TOUCH2_PIN;
        __delay_cycles(10);
        P1DIR &= ~TOUCH2_PIN;
        P1REN |= TOUCH2_PIN;
        P1OUT |= TOUCH2_PIN;
        
        count2 = 0;
        while(!(P1IN & TOUCH2_PIN) && count2 < 30000) count2++;
        base2 += count2;
        
        __delay_cycles(10000);
    }
    
    base1 /= 20;
    base2 /= 20;
    
    while(1) {
        // 检测通道1
        P1DIR |= TOUCH1_PIN;
        P1OUT &= ~TOUCH1_PIN;
        __delay_cycles(10);
        P1DIR &= ~TOUCH1_PIN;
        P1REN |= TOUCH1_PIN;
        P1OUT |= TOUCH1_PIN;
        
        count1 = 0;
        while(!(P1IN & TOUCH1_PIN) && count1 < 30000) count1++;
        
        if(count1 > base1 + 30) {
            P1OUT |= LED1_PIN;  // 触摸时点亮
        } else {
            P1OUT &= ~LED1_PIN; // 松开时熄灭
        }
        
        // 自适应更新基准值
        if(count1 < base1 + 20) {
            base1 = (base1 + count1) / 2;
        }
        
        // 检测通道2
        P1DIR |= TOUCH2_PIN;
        P1OUT &= ~TOUCH2_PIN;
        __delay_cycles(10);
        P1DIR &= ~TOUCH2_PIN;
        P1REN |= TOUCH2_PIN;
        P1OUT |= TOUCH2_PIN;
        
        count2 = 0;
        while(!(P1IN & TOUCH2_PIN) && count2 < 30000) count2++;
        
        if(count2 > base2 + 30) {
            P1OUT |= LED2_PIN;  // 触摸时点亮
        } else {
            P1OUT &= ~LED2_PIN; // 松开时熄灭
        }
        
        // 自适应更新基准值
        if(count2 < base2 + 20) {
            base2 = (base2 + count2) / 2;
        }
        
        __delay_cycles(20000);
    }
}

七、编译和下载

7.1 编译命令

# 使用MSP430-GCC编译
msp430-gcc -mmcu=msp430g2553 -Os -o touch_led.elf main.c
msp430-objcopy -O ihex touch_led.elf touch_led.hex

7.2 下载到MSP430

# 使用MSP430 Flasher
mspdebug rf2500
> prog touch_led.hex

7.3 CCS工程配置

1. 创建新CCS工程
2. 选择MSP430G2553
3. 添加源文件
4. 设置编译器选项
5. 编译并下载
posted @ 2026-06-05 09:36  yijg9998  阅读(5)  评论(0)    收藏  举报