xxkj2010 发表于 2023-12-28 11:44:53

(已解决)移植例程16个触摸按键16个灯-8个共阴-8个共阳数码管显示程序失败,不知道是

本帖最后由 xxkj2010 于 2023-12-29 10:45 编辑

单片机使用STC8H1K17T,程序从例程16个触摸按键16个灯-8个共阴-8个共阳数码管显示程序中修改,
当前目的是想用触摸开关控制接在P54的LED灯亮灭,
移植失败,不知道是硬件问题还是软件问题,请大佬赐教,谢谢!


神农鼎 发表于 2023-12-28 12:00:42

你先把原理图,PCB, 源程序,按3个楼层贴出来,大家一起来帮忙

xxkj2010 发表于 2023-12-28 12:02:04

主要电路原理图


xxkj2010 发表于 2023-12-28 12:07:03

PCB






xxkj2010 发表于 2023-12-28 12:07:47

/*
单片机:STC8H1K17T
使用触摸引脚:TK3、TK6、TK7
*/

#include        "STC8Hxxx.h"
#include <intrins.h>
#include <stdio.h>

/*************        功能说明        *************
读取16个触摸按键
触摸按键的读数本来是16位的, 由于使用了滤波算法, 滤波后数据为14位的.
参考电容的选取, 未按键时读数是满量程的1/3~1/2比较好, 兼顾灵敏度, 量产时又允许一定的平偏差.
程序会做缓慢的0点跟踪, 所以本例不合适长按处理, 长按处理还要有别的算法.
P1.0-->TK0,P1.1-->TK1, P5.4-->TK2, P1.3-->TK3, P1.4-->TK4,P1.5-->TK5, P1.6-->TK6, P1.7-->TK7,
P5.0-->TK8,P5.1-->TK9, P5.2-->TK1, P5.3-->TK1, P0.0-->TK1,P0.1-->TK1, P0.2-->TK1, P0.3-->TK1,
******************************************/

/*************        本地常量声明        **************/
#define        DIS_BLACK        0x1A
#define        DIS_                0x1B
#define LED P54            //LED
#define ws2812b_IO    P35      //WS2812信号输入口
#define MAIN_Fosc          24000000L        //定义主时钟 11059200
#define BAUD      (65536 - MAIN_Fosc/4/115200)   //定义串口波特率重装值
bit fBusy;                                     //串口发送忙标志

/*************        本地变量声明        **************/
u16        xdata TK_cnt;        // 键计数值
u16        xdata TK_zero;        // 0点读数
u16        KeyState;                //键状态
u8        KeyCode;                //键码 1~16
bit        B_TK_Lowpass;        //允许低通
bit        B_ReadKeyOk;        //标志已转换完成16个键
u8        TrigLimit;                //触发转换限时
u8        KeyValue;                //显示参数的键号, 0~15
u8        read_cnt;

/*************        本地函数声明        **************/
voiddelay_ms(u8 ms);
u8                CheckKey(u16 j);
/****************外部函数声明和外部变量声明 *****************/
        u16 code T_KeyState   = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
//        u16 code T_KeyPress   = {400,300,200,200, 400,300,200,200, 400,300,200,200, 400,300,200,200};        //读数无平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
        u16 code T_KeyPress   = {200,150,100,100, 200,150,100,100, 200,150,100,100, 200,150,100,100};        //读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同

/**********************************************/
void main(void)
{
        u8        i;
        u16        j;
                fBusy = 0;
        P_SW2 |= 0x80;        //允许访问XSFR(扩展特殊功能寄存器)
//        XOSCCR = 0xc0;         //启动外部晶振
//        while (!(XOSCCR & 1));   //等待时钟稳定
//        CLKDIV = 0x00;         //时钟不分频
//        CKSEL = 0x01;            //选择外部晶振

        P0M0 = 0x00;        P0M1 = 0x00;
//        P1M0 = 0x00;        P1M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;
        P5M0 = 0x10; P5M1 = 0x00;        

    AUXR = 0x40;                              //使用定时器1作为串口波特率发生器
    TMOD = 0x00;
    TL1 = BAUD;
    TH1 = BAUD >> 8;
    TR1 = 1;
    SCON = 0x50;
    ES = 1;
       
        P1n_pure_input(0xff);        //Touch Key设置为高阻

//        TSCHEN = 0xffff;        //TK0~TK15
        TSCHEN1 = 0xff;                //TK0~TK7
//        TSCHEN2 = 0xff;                //TK8~TK15
        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)
//        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, B7: TSGO,B6: SINGLE,B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
//        TSRT = 0x00;                //没有LED分时扫描
        IE2 |= 0x80;                //允许触摸按键中断
        EA = 1;

        delay_ms(50);
//        B_TK_Lowpass = 0;        //禁止低通滤波
        B_TK_Lowpass = 1;        //允许低通滤波
        for(read_cnt=0; read_cnt<40; read_cnt++)                //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
        {
        //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
        //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                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");
        while (1)
        {
                delay_ms(1);
               
                if(++TrigLimit >= 100)        //触发转换
                {
                        TrigLimit = 0;
                //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                        TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
                //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                }
               
                if(B_ReadKeyOk)                        // 16个键都转换完毕
                {
                        B_ReadKeyOk = 0;
                        TrigLimit = 100;
//                        printf("B_ReadKeyOk!\r\n");

                        j = KeyState;                //读入上一次键状态
                        for(i=0; i<16; 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~16                               
                                printf("KeyCode:%d\r\n",KeyCode);
                                if(KeyCode == 3)
                                {
                                        LED=!LED;
                                }
                        }
                }
        }
}
/**********************************************/

voiddelay_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<16; i++)
        {
                if(j & 0x0001)        break;
                j >>= 1;
        }
        return (i+1);        //键码1~16
}


u8        isr_index;

void        AUXR_ISR(void) interrupt 13
{
        u8        j;
       
        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 == 15)        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;
//      CheckCustomCmd(SBUF);                   //检测命令序列
    }
}

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



xxkj2010 发表于 2023-12-28 12:11:58

本帖最后由 xxkj2010 于 2023-12-28 13:21 编辑

实物图:





xxkj2010 发表于 2023-12-29 10:38:17

自己弄好了,main代码如下:

/*
单片机:STC8H1K17T
使用触摸引脚:TK3、TK6、TK7
*/

#include        "STC8Hxxx.h"
#include <intrins.h>
#include <stdio.h>

/*************        功能说明        *************
读取16个触摸按键
触摸按键的读数本来是16位的, 由于使用了滤波算法, 滤波后数据为14位的.
参考电容的选取, 未按键时读数是满量程的1/3~1/2比较好, 兼顾灵敏度, 量产时又允许一定的平偏差.
程序会做缓慢的0点跟踪, 所以本例不合适长按处理, 长按处理还要有别的算法.
P1.0-->TK0,P1.1-->TK1, P5.4-->TK2, P1.3-->TK3, P1.4-->TK4,P1.5-->TK5, P1.6-->TK6, P1.7-->TK7,
P5.0-->TK8,P5.1-->TK9, P5.2-->TK1, P5.3-->TK1, P0.0-->TK1,P0.1-->TK1, P0.2-->TK1, P0.3-->TK1,
******************************************/

/*************        本地常量声明        **************/
#define        DIS_BLACK        0x1A
#define        DIS_                0x1B
#define LED P54            //LED
#define ws2812b_IO    P35      //WS2812信号输入口
#define MAIN_Fosc          24000000L        //定义主时钟 11059200
#define BAUD      (65536 - MAIN_Fosc/4/115200)   //定义串口波特率重装值
bit fBusy;                                     //串口发送忙标志
u16 AUXR_ISR_YN=0;
/*************        本地变量声明        **************/
u16        xdata TK_cnt;        // 键计数值
u16        xdata TK_zero;        // 0点读数
u16        KeyState;                //键状态
u8        KeyCode;                //键码 1~16
bit        B_TK_Lowpass;        //允许低通
bit        B_ReadKeyOk;        //标志已转换完成16个键
u8        TrigLimit;                //触发转换限时
u8        KeyValue;                //显示参数的键号, 0~15
u8        read_cnt;

/*************        本地函数声明        **************/
voiddelay_ms(u8 ms);
u8                CheckKey(u16 j);
/****************外部函数声明和外部变量声明 *****************/
        u16 code T_KeyState   = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
//        u16 code T_KeyPress   = {400,300,200,200, 400,300,200,200, 400,300,200,200, 400,300,200,200};        //读数无平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
        u16 code T_KeyPress   = {200,150,100,100, 200,150,100,100, 200,150,100,100, 200,150,100,100};        //读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同

/**********************************************/
void main(void)
{
        u8        i;
        u16        j;
                fBusy = 0;
        P_SW2 |= 0x80;        //允许访问XSFR(扩展特殊功能寄存器)
//        XOSCCR = 0xc0;         //启动外部晶振
//        while (!(XOSCCR & 1));   //等待时钟稳定
//        CLKDIV = 0x00;         //时钟不分频
//        CKSEL = 0x01;            //选择外部晶振

        P0M0 = 0x00;        P0M1 = 0x00;
//        P1M0 = 0x00;        P1M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;
        P5M0 = 0x10; P5M1 = 0x00;        

    AUXR = 0x40;                              //使用定时器1作为串口波特率发生器
    TMOD = 0x00;
    TL1 = BAUD;
    TH1 = BAUD >> 8;
    TR1 = 1;
    SCON = 0x50;
    ES = 1;
       
        P1n_pure_input(0xff);        //Touch Key设置为高阻

//        TSCHEN = 0xffff;        //TK0~TK15
        TSCHEN1 = 0xff;                //TK0~TK7
//        TSCHEN2 = 0xff;                //TK8~TK15
        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)
//        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, B7: TSGO,B6: SINGLE,B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
//        TSRT = 0x00;                //没有LED分时扫描
        IE2 |= 0x80;                //允许触摸按键中断
        EA = 1;

        delay_ms(50);
//        B_TK_Lowpass = 0;        //禁止低通滤波
        B_TK_Lowpass = 1;        //允许低通滤波
        for(read_cnt=0; read_cnt<40; read_cnt++)                //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
        {
        //        TSCTRL = (1<<7) + (1<<6) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
        //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                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");
        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) +3;        //开始扫描, 4次平均, 读数大约为无平均的一半
                        TSCTRL = (1<<7) + (1<<6) +1;        //开始扫描, 2次平均, 读数大约为无平均的一半
                //        TSCTRL = (1<<7) + (1<<6);                //开始扫描, 只转换1次, 无平均
                }
               
                if(B_ReadKeyOk)                        // 16个键都转换完毕
                {
                        B_ReadKeyOk = 0;
                        TrigLimit = 100;
                        //printf("B_ReadKeyOk!\r\n");

                        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 == 4)
                                {
                                        LED=!LED;
                                }
                        }
                }
        }
}
/**********************************************/

voiddelay_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
}


u8        isr_index;

void        AUXR_ISR(void) interrupt 13
{
        u8        j;
       
        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;
//      CheckCustomCmd(SBUF);                   //检测命令序列
    }
}

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




zpzobcna 发表于 2025-4-11 18:21:41

xxkj2010 发表于 2023-12-29 10:38
自己弄好了,main代码如下:

这个可以直接烧录测试吗
STC8H1K17T
大佬

xxkj2010 发表于 2025-4-11 19:44:01

zpzobcna 发表于 2025-4-11 18:21
这个可以直接烧录测试吗
STC8H1K17T
大佬

自己试试吧,反正不行还可以重新下载,又不会损坏MCU
页: [1]
查看完整版本: (已解决)移植例程16个触摸按键16个灯-8个共阴-8个共阳数码管显示程序失败,不知道是