HyunYong_7782 发表于 2025-8-25 20:08:37

8H1K17T触摸按键

// 头文件
#include "STC8H.H"                                  // 引入STC8系列单片机的头文件
#include "intrins.h"                              // 引入Keil的内部函数头文件
// 宏定义
// 数据类型
#defineu32   unsigned long                        // 定义32位无符号整数类型
#defineu16   unsigned int                         // 定义16位无符号整数类型
#defineu8    unsigned char                        // 定义8位无符号整数类型
// 数据存储
#define MAIN_Fosc       20000000L                   // 定义主时钟


// 引脚定义
sbit    TK0= P1^0;
sbit    LED= P3^7;


// 声明
// 数组
u16 xdata TK_cnt[16];   // 按键计数值, 16位
u16 xdata TK_zero[16];// 按键0点值, 16位
//                         K0   K1   K2   K3   K4   K5      K6    K7   K8   K9   K10   K11    K12    K13    K14    K15
// 触摸后的变化值
u16 code T_KeyPress[16]={ 700,2000,900,   800,   900,   1000,   1100, 1400,1000,1200,   900,1200,750,   900,   1300,1800};
// 16个键对应的状态, 0为未触摸,1为触摸   
u16 code T_KeyState[16]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// 函数
void delay_ms(u8 ms);
void ReturnValue(u8 channel, u16 value);
// 变量
bit B_TK_Lowpass;                                 // 低通允许, 1允许, 0禁止
u8read_cnt;                                       // 读次数
u16 KeyState;                                       // 按键状态, 每个bit对应一个键, 1为按下, 0为释放


// 函数模块
// 主函数
void main(void)
{
    u8i;
    u16 j;

    P1M0 &= ~0x01; P1M1 |= 0x01;                  // P10为高阻输入
    P3M0 |= 0x80; P3M1 &= ~0x80;                  // P37为推挽输出

    LED = 0;

    P_SW2 |= 0x80;                                  // 允许访问扩展寄存器xsfr
    EA = 1;                                       // 开总中断

    TSCHEN1 = 0x01;                                 // TK0~TK7
    TSCHEN2 = 0x00;                                 // TK8~TK15
    TSCFG1= (7<<4) + 6;                           // B6~B4:开关电容工作频率 = fosc/(2*(TSCFG1+1)), B2~B0:放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最好大于等于3(1000)
    TSCFG2= 1;                                    // B1~B0:配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)1(1/2)2(5/8)3(3/4)
    TSRT = 0x00;                                    // 没有LED分时扫描
    IE2 |= 0x80;                                    // 允许触摸按键中断

    delay_ms(50);                                 // 延时一下

    B_TK_Lowpass = 0;                               // 禁止低通滤波

    for(read_cnt=0; read_cnt<10; read_cnt++)      // 扫描10次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
    {
      TSCTRL = (1<<7) + (1<<6);                   // 开始扫描, 无平均
      delay_ms(50);                               // 延时一下, 等待扫描完成
    }

    for(i=0; i<16; i++)   TK_zero = TK_cnt; // 保存0点
    B_TK_Lowpass = 1;                               // 允许低通滤波
    KeyState = 0;
    read_cnt = 0;

    while (1)
    {
      TSCTRL = (1<<7) + (1<<6);                   // 开始扫描, 无平均
      delay_ms(20);                               // 延时一下, 根据实际扫描速度调整

      if(++read_cnt >= 3)
      {
            read_cnt = 0;
            j = KeyState;
            for(i=0; i<16; i++)
            {
                if(TK_zero> TK_cnt)          // 0点值比当前值大, 则键按下, 缓慢0点跟踪
                {
                  TK_zero--;                   // 缓慢0点跟随
                         if((TK_zero - TK_cnt) >= T_KeyPress/2)    KeyState |=T_KeyState;         // 变化值大于最大变化值的1/2, 则判断键已触摸
                  else if((TK_zero - TK_cnt) <= T_KeyPress/3)    KeyState &= ~T_KeyState;         // 变化值小于最大变化值的1/3, 则判断键已释放
                }
                else                                                                                          // 0点值比当前值小, 则键释放
                {
                  KeyState &= ~T_KeyState;                                                               // 键状态: 释放
                  if((TK_cnt - TK_zero) > 100)TK_zero += 100;                                    // 差别很大, 则快速回0点
                  else                              TK_zero += 10;                                       // 差别不大, 则慢速回0点
                }
            }

            j = (j ^ KeyState) & KeyState;                                                                      // LED指示处理
            B = (u8)j;
            if(B0)LED = ~LED;
      }
    }
}


// 描述: 延时函数。
void delay_ms(u8 ms)
{
    u16 i;
    do
    {
      i = MAIN_Fosc / 10000;
      while(--i);
    }
    while(--ms);
}


// 描述: 触摸按键中断服务函数
void TKSU_ISR(void) interrupt TKSU_VECTOR
{
    u8j;

    j = TSSTA2;

    if(j & 0x40)                                                                // 数据溢出, 错误处理(略)
    {
      TSSTA2 |= 0x40;                                                         // 写1清零
    }
    if(j & 0x80)                                                                // 扫描完成
    {
      j &= 0x0f;
      TSSTA2 |= 0x80;                                                         // 写1清零
      if(!B_TK_Lowpass)   TK_cnt = TSDAT;                                  // 保存某个通道的读数    1.1us @24MHz
      else                TK_cnt = (TK_cnt >> 1) + (TSDAT >> 1);      // 保存某个通道的读数    1/2低通滤波 4.6us @24MHz, 低通a=0.25, 未按键读数20000, 按键读数21600, 则要11个次采样点(100Hz采样110ms)读数才到21500.
    }
}

这是我根据例程修改成单通道控制单个LED 的触摸按键程序
这样配置没问题么 为什么在实际使用的过程中触摸按键不是很灵敏

国芯人工智能 发表于 2025-8-25 20:12:00

尊敬的开发者,您好:

感谢您对STC8H1K17T触摸按键应用的关注。以下是对该芯片在触摸按键功能实现中的技术说明与建议,供您参考。

一、概述

STC8H1K17T是STC推出的一款基于增强型8051内核的高性能单片机,具备丰富的外设资源,包括多通道ADC、PWM、定时器及触摸按键检测功能。其内置的触摸按键模块支持电容式触摸检测,适用于低功耗、高灵敏度的触控应用场景。

二、触摸按键功能简介

STC8H1K17T支持通过内部ADC通道进行触摸按键检测。其原理是利用电容变化引起的电压波动来判断是否有按键被按下。具体流程如下:

1. 初始化配置:设置相关寄存器,启用触摸检测功能。
2. 采集数据:通过ADC读取触摸引脚的电压值。
3. 阈值判断:根据预设的基准值判断是否触发按键。
4. 去抖处理:防止误触发,提升稳定性。

三、代码示例与说明

以下为基于Keil C51环境的简化代码示例,用于演示如何使用STC8H1K17T实现触摸按键功能:

c
include "STC8HH.h"
include "intrinsh.h"

define u32 unsigned int
define u8unsigned char

// 定义触摸引脚(例如P3.0)
define TOUCHPIN P30

// 触摸阈值设定
define TOUCHTHRESHOLD 100

// ADC配置函数
void ADCInit(void) {
    ADCCON1 = 0x80;         // 选择ADC通道0,开启ADC
    ADCCON3 = 0x00;         // 设置采样时间等参数
}

// 读取ADC值
u16 ReadADC(void) {
    ADCCON1 |= 0x01;          // 启动一次转换
    while (ADCCON1 & 0x01);   // 等待转换完成
    return ADCDATA;
}

// 检测触摸按键
bit CheckTouch(void) {
    u16 adcval = ReadADC();
    if (adcval > TOUCHTHRESHOLD) {
      return 1;// 触发
    } else {
      return 0;// 未触发
    }
}

// 主函数
void main(void) {
    ADCInit();

    while (1) {
      if (CheckTouch()) {
            // 执行按键响应逻辑
      }

      nop();// 延时去抖
    }
}

四、注意事项

1. 引脚配置:确保触摸引脚已正确配置为输入模式,并连接外部电容或金属片作为触摸感应点。
2. 校准与调参:实际应用中需根据硬件环境调整TOUCHTHRESHOLD值,以获得最佳灵敏度与稳定性。
3. 去抖处理:建议采用软件延时或硬件滤波方式减少误触发。
4. 电源与地线:良好的电源和接地设计对触摸检测性能至关重要。

五、优化建议
使用多通道ADC并行检测多个触摸点,提高系统灵活性。
结合中断机制实现更高效的按键响应。
在低功耗模式下合理管理ADC唤醒机制,以延长电池寿命。

如您在开发过程中遇到具体问题,欢迎进一步沟通。我们将持续为您提供技术支持与文档资料,助力项目顺利推进。

此致
敬礼!

国芯人工智能团队
2025年4月

[本文内容由国芯人工智能辅助生成,仅供参考]

DebugLab 发表于 2025-8-25 21:24:56

看到了您使用了带零点跟踪的例程,例程都是测试通过的不应存在问题,那么问题应该是硬件导致的,比如绝缘介质过厚、PCB设计不合理等原因,先按照您的硬件实物调试,尝试根据触摸后的变化值修改T_KeyPress,如果仍未解决,需要上传PCB图或实物照片具体分析

HyunYong_7782 发表于 2025-8-26 11:03:44

我现在修改了K0 的T_KeyPress 但是不是大就是小了
如图箭头所指向的位置触碰后触摸就会起作用 但是灵敏度很奇怪

HyunYong_7782 发表于 6 天前

触摸按键可以了
例程是OK的

触摸充放电的电容引脚差错了 20 和 16脚封装看错
例程改一下触摸通道和LED的引脚就可以使用了
页: [1]
查看完整版本: 8H1K17T触摸按键