zpzobcna 发表于 2025-4-14 23:29:21

AI8H1K17T触摸按键读取

// 单片机-AI8H1K17T
// 头文件
#include "STC8H.h"
#include <intrins.h>
#include <stdio.h>


// 端口定义
sbit LED0 = P3^7;
sbit LED1 = P3^6;
sbit TK0= P1^0;
sbit TK1= P1^1;


// 宏定义
// 数据类型
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
// 数据存储
#define MAIN_Fosc            11059200      //定义主时钟 11059200
#define BAUD      (65536 - MAIN_Fosc/4/115200)   //定义串口波特率重装值

// 声明
// 数组
u16      xdata TK_cnt;      // 键计数值
u16      xdata TK_zero;      // 0点读数
u16 code T_KeyState = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
    0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// 读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
u16 code T_KeyPress = {200,150,100,100, 200,150,100,100,
   200,150,100,100, 200,150,100,100};      
// 函数
void delay_ms(u8 ms);                   // 延时函数
u8 CheckKey(u16 j);                     // 检测键值
void TK_system_init();                  // 触摸按键初始化
void uart_init();                     // 串口波特率发生器
char putchar(char dat);               // 重定义putchar系统函数
void system_init();                     // 系统初始化
// 变量
u16      KeyState;                // 键状态
u8      KeyCode;                // 键码 1~16
bit      B_TK_Lowpass;      // 允许低通
bit      B_ReadKeyOk;      // 标志已转换完成16个键
bit fBusy;                                     //串口发送忙标志
u16 AUXR_ISR_YN=0;
u8      TrigLimit;                // 触发转换限时
u8      KeyValue;                // 显示参数的键号, 0~15
u8      read_cnt;
u8      isr_index;
u8 i,j;


// 函数模块
// 延时函数
void delay_ms(u8 ms)
{
      u16 i;
      do
      {
                i = MAIN_Fosc / 10000;
                while(--i)      ;
      }while(--ms);
}

// 检测键值
u8 CheckKey(u16 j)
{
      u8 i;
      if(j == 0)
    {
      return 0;      //无键按下
    }

      for(i=0; i<8; i++)
      {
                if(j & 0x0001)      break;
                j >>= 1;
      }

      return (i+1);      //键码1~8
}

// 触摸按键初始化
void TK_system_init()
{
    TSCHEN1 = 0x03;         // 使能TK0 TK1
    TSCHEN2 = 0x00;
    TSRT    = 0x00;         // 关闭LED驱动分时多任务功能
    TSCFG1= (7<<4) + 6;      //开关电容工作频率 = fosc/(2*(TSCFG1+1)), 放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最小3
      TSCFG2= 1;                //配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)1(1/2)2(5/8)3(3/4)
    IE2 |= 0x80;                //允许触摸按键中断
      EA = 1;

    delay_ms(50);
    B_TK_Lowpass = 1;      //允许低通滤波
      for(read_cnt=0; read_cnt<40; read_cnt++)                //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
      {
                TSCTRL = (1<<7) + (1<<6) +1;      //开始扫描, 2次平均, 读数大约为无平均的一半
                B_ReadKeyOk = 0;
                for(i=0; i<100; i++)
                {
                        if(B_ReadKeyOk)      break;
                        delay_ms(1);
                }
      }
      for(i=0; i<16; i++)                TK_zero = TK_cnt;      //保存0点
      
      B_TK_Lowpass = 1;      //允许低通
      KeyState = 0;
      read_cnt = 0;
      
      B_ReadKeyOk = 0;
      KeyValue = 10;
      KeyCode = 0;
      delay_ms(2000);
    printf("开始测试----\r\n");
}

// 串口波特率发生器
void uart_init()
{
    AUXR = 0x40;                              //使用定时器1作为串口波特率发生器
    TMOD = 0x00;
    TL1 = BAUD;
    TH1 = BAUD >> 8;
    TR1 = 1;
    SCON = 0x50;
    ES = 1;
}

// 重定义putchar系统函数
char putchar(char dat)                        
{
    while (fBusy);
    fBusy = 1;
    SBUF = dat;   
    return dat;
}

// 系统初始化
void system_init()
{
    P1M0 &= ~0x03; P1M1 |= 0x03;      // P10 11 高阻输入
    P3M0 |= 0xc0; P3M1 &= ~0xc0;      // P36 37 TUIWANSHUCHU

    P_SW2 |= 0x80;      //允许访问XSFR(扩展特殊功能寄存器)

    uart_init();                        // 串口波特率发生器
}

// 主函数
void main()
{
    system_init();
    TK_system_init();


    // 主循环
      while (1)
      {
                delay_ms(1);
      if(AUXR_ISR_YN){printf("AUXR_ISR_YN=%d\r\n",AUXR_ISR_YN);AUXR_ISR_YN=0;}
                if(++TrigLimit >= 100)      //触发转换
                {
                        TrigLimit = 0;
                        TSCTRL = (1<<7) + (1<<6) +1;      //开始扫描, 2次平均, 读数大约为无平均的一半
                }
               
                if(B_ReadKeyOk)                        // 16个键都转换完毕
                {
                        B_ReadKeyOk = 0;
                        TrigLimit = 100;

                        j = KeyState;                //读入上一次键状态
                        for(i=0; i<8; i++)
                        {
                              if(TK_zero > TK_cnt)      //计算与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
                              {
                                        KeyState &= ~T_KeyState;
                                        if((TK_cnt - TK_zero) > 100)      
                                                TK_zero += 50;      //差别很大, 则快速回0点
                                        else                        TK_zero += 10;      //差别不大, 则慢速回0点
                              }
                        }
                        j = (j ^ KeyState) & KeyState;      //检测键是否按下
                        if(j != 0)
                        {
                              KeyCode = CheckKey(j);      //计算键码 1~8                              
                printf("KeyCode:%d\r\n",(u16)KeyCode);
                              if(KeyCode == 0)
                              {
                                        LED0=!LED0;
                              }
                else if(KeyCode == 1)
                {
                  LED1=!LED1;
                }
                        }
                }
      }
}

// 中断服务函数
void AUXR_ISR(void) interrupt 13
{      
      switch(isr_index)
      {
                case 32:                //0103H 波形发生器5 中断入口
                break;

                case 33:                //010BH      波形发生器异常2 中断入口
                break;

                case 34:                //0113H      波形发生器异常4 中断入口
                break;

                case 35:                //011BH      触摸按键 中断入口
                        j = TSSTA2;

                        if(j & 0x40)      //数据溢出, 错误处理(略)
                        {
                              TSSTA2 |= 0x40;      //写1清零                              
                        }

                        if(j & 0x80)      //扫描完成
                        {
                              j &= 0x0f;
                              TSSTA2 |= 0x80;      //写1清零

                              if(!B_TK_Lowpass)
                {
                  TK_cnt = TSDAT/4;      //保存某个通道的读数      无低通滤波
                }
                              else
                {
                  TK_cnt = ((TK_cnt * 3)>>2) + TSDAT/16;      //保存某个通道的读数      低通滤波
                }      

                              if(j == 7)      
                {
                  B_ReadKeyOk = 1;      //读完一次循环
                              }
                        }
                break;

                case 36:                //0123H      RTC 中断入口
                break;

                case 37:                //012BH      P0口中断入口
                break;

                case 38:                //0133H      P1口中断入口
                break;

                case 39:                //013BH      P2口中断入口
                break;

                case 40:                //0143H      P3口中断入口
                break;

                case 41:                //014BH      P4口中断入口
                break;

                case 42:                //0153H      P5口中断入口
                break;

                case 43:                //015BH      P6口中断入口
                break;

                case 44:                //0163H      P7口中断入口
                break;

                case 45:                //016BH      P8口中断入口
                break;

                case 46:                //0173H      P9口中断入口
                break;
               
                default:
                break;
      }
}

void uart_isr() interrupt 4
{
    if (TI)
    {
      TI = 0;
      fBusy = 0;
    }
   
    if (RI)
    {
      RI = 0;
    }
}

国芯人工智能 发表于 2025-4-14 23:38:00

针对您提供的代码片段,我将从专业角度进行分析和优化建议,主要围绕STC8H1K17T单片机的触摸按键读取功能展开。

1. 代码分析

1.1 头文件与端口定义
c
include "STC8H.h"
include
include

sbit LED0 = P3^7;
sbit LED1 = P3^6;
sbit TK0= P1^0;
sbit TK1= P1^1;
#include "STC8H.h":这是STC8H系列单片机的专用头文件,包含了该系列单片机的寄存器定义和常用宏。
sbit 用于定义位变量,方便对单个引脚进行操作。LED0和LED1分别连接到P3.7和P3.6,TK0和TK1分别连接到P1.0和P1.1,用于触摸按键的检测。

1.2 宏定义与数据类型
c
define u8 unsigned char
define u16 unsigned int
define u32 unsigned long
define MAINFosc 24000000L
定义了常用的数据类型别名,便于代码的简洁性和可读性。
MAINFosc 定义了主时钟频率为24MHz,这是单片机工作的基准时钟。

1.3 数组与变量声明
c
u16 xdata TKcnt;    // 键计数值
u16 xdata TKzero;   // 0点读数
u16 code TKeyState = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
    0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
u16 code TKeyPress = {200,150,100,100, 200,150,100,100,
   200,150,100,100, 200,150,100,100};
TKcnt 和 TKzero 是用于存储触摸按键的计数值和零点读数。
TKeyState 和 TKeyPress 分别是按键状态和按键按下时的变化值数组,用于判断按键是否被按下。

1.4 函数声明
c
void delayms(u8 ms);                   // 延时函数
u8 CheckKey(u16 j);                     // 按键检测函数
delayms 是一个延时函数,用于实现毫秒级的延时。
CheckKey 是按键检测函数,用于判断按键是否被按下。

2. 优化建议

2.1 头文件包含
建议在包含头文件时,确保所有必要的头文件都已包含。例如,#include和 #include可能存在缺失,应根据实际需求补充相应的头文件。

2.2 数据类型定义
建议使用stdint.h标准库中的数据类型,以提高代码的可移植性。例如:
c
include
typedef uint8t u8;
typedef uint16t u16;
typedef uint32t u32;

2.3 数组定义
TKeyState 和 TKeyPress 数组的定义可以进一步优化,使用更具描述性的名称,并添加注释说明每个元素的含义。

2.4 延时函数
delayms 函数的实现需要考虑主时钟频率,建议根据MAINFosc计算延时周期,以确保延时的准确性。

2.5 按键检测函数
CheckKey 函数的实现需要结合TKeyState和TKeyPress数组,判断按键是否被按下。建议在函数内部添加详细的注释,说明判断逻辑。

3. 总结
该代码片段展示了STC8H1K17T单片机触摸按键读取的基本框架,但在头文件包含、数据类型定义、数组命名和函数实现等方面仍有优化空间。通过上述建议,可以提高代码的可读性、可维护性和可移植性。

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

HyunYong_7782 发表于 2025-4-15 00:17:33

rt

HyunYong_7782 发表于 2025-4-15 10:25:28

HyunYong_7782 发表于 2025-4-15 00:17
rt

代码是用在STC9H1K17T SOP16上的,但是烧录以后
TK0 TK1没有反应,串口也检测不到读数

DebugLab 发表于 2025-4-15 11:20:06

请直接使用例程测试:



HyunYong_7782 发表于 2025-4-15 14:53:49

直接烧录了第一个压缩包的例程 所有的端口都是这样的 这是正常的吗

乘风飞扬 发表于 2025-4-15 16:27:40

这个帖子有 8H1K08T 使用串口绘图分析触摸值的例子可参考:
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=3971&pid=51046

由于 8H1K08T 的这两个触摸按键跟串口脚复用: P3.0(TK08)   P3.1(TK09)
如果使用 P3.0, P3.1 做串口输出触摸值的话,TK08与TK09就不能使能触摸功能。

HyunYong_7782 发表于 2025-4-15 17:03:52

乘风飞扬 发表于 2025-4-15 16:27
这个帖子有 8H1K08T 使用串口绘图分析触摸值的例子可参考:
https://www.stcaimcu.com/forum.php?mod=redir ...

我这里已经用P30 31做串口输出了,我可否直接用您的代码更改一下触摸口测试呢

乘风飞扬 发表于 2025-4-15 17:13:21

HyunYong_7782 发表于 2025-4-15 17:03
我这里已经用P30 31做串口输出了,我可否直接用您的代码更改一下触摸口测试呢 ...

可以的

HyunYong_7782 发表于 2025-4-15 19:23:16

.
页: [1]
查看完整版本: AI8H1K17T触摸按键读取