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. 编译并下载
浙公网安备 33010602011771号