DGWJL2024 发表于 2024-5-24 08:45:07

编译通过,仿真时进不了触摸按键中断 | 已解决

我移植了触摸按键驱动程序,现在编译可以通过,但仿真时进入不了触摸按键的中断服务函数,请大家指点


//普通IO口控制数码管
/*******************接口说明*********************
P2.0~P2.7: 接SEG0~SEG7
P3.4~P3.7: 接COM0~COM3
P1.0-->TK0,P1.1-->TK1, P5.4-->TK2, P1.3-->TK3
************************************************/
#define MAIN_Fosc      1200000L      //定义主时钟
#include      "STC8Hxxx.h"

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;
u8      isr_index;

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};      //读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同

//---------------------------------------------------------------------------------------------
             //    0    1    2    3    4    5    6    7    8    9
u8 FontCode[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//字形码
         //P3.4P3.5 P3.6 P3.7
u8 Tab[] = {0x10,0x20,0x40,0x80};       //位码
u8 Dispbuf;   //显示缓存区
u8 Num = 0;      //显示位数计数器
//---------------------------------------------------------------------------------------------
/****************** 检测 计算键码 **************************************/
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
}

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 TM0_Isr() interrupt 1
{
//    P14 = !P14;                                 //????
    P3 = P3&0x0f;         
          P3 = P3|Tab;      //高位按位数置1 低4位不变
          P2 = FontCode];
          Num++;
          if(Num>3)
                         Num = 0;
}

voiddelay_ms(u8 ms)
{
      u16 i;
      do
      {
                i = MAIN_Fosc / 10000;
                while(--i)      ;
      }
      while(--ms);
}

void main()
{
          u8      i;
         u16      j;

         P_SW2 |= 0x80;      //允许访问XSFR(扩展特殊功能寄存器)
      
                P0M0 = 0x00;                   //准双向口,传统8051模式         
                P0M1 = 0x00;
                P1M0 = 0x00;
                P1M1 = 0x00;
//    P2M0 = 0x00;
//    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
      
          P2n_push_pull(0xff);      //P2口数码管段码设置为推挽输出
          P3n_push_pull(0xf0);            //位码(P3.4~P3.7)线设置为推挽输出
          P1n_pure_input(0x0f);            //Touch Key设置为高阻
                P5n_pure_input(0x10);       //P5.4设置为高阻
      
          P2DR = 0x00;                      //段码线设置为强电流驱动0 强电流驱动
          P3DR = 0x0f;                      //位码线设置为强电流驱动
               
                TSCHEN1 = 0x0f;                        //TK0~TK3 按键扫描通道
                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)
          TSRT = 0x00;                //没有LED分时扫描
          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) +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<4; i++)               
         TK_zero = TK_cnt;      //保存0点
      
      B_TK_Lowpass = 1;      //允许低通
      KeyState = 0;
      read_cnt = 0;
      
      B_ReadKeyOk = 0;
      KeyValue = 10;
      KeyCode = 0;
//-----------------------------------------------------------------------------------
    TMOD = 0x00;                     //16位自动重载模式受TR0控制 对内部震荡器计数
    TL0 = 0x66;                                 //65536-11.0592M/12/1000
    TH0 = 0xfc;
    TR0 = 1;                                    //启动定时器
    ET0 = 1;                                    //使能定时器0中断
//    EA = 1;
               
                //P3 = P3&0x0f;         //P3.4~P3.7高4位清0低4位不变

          Dispbuf = 3;
                Dispbuf = 4;
                Dispbuf = 8;
                Dispbuf = 9;
         
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;
//                        ShowValue(KeyValue);      //显示读数

                        j = KeyState;                //读入上一次键状态
                        for(i=0; i<4; 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
                              
                        }
                }
      }
}

下面的isr.asm文件加入到工程中了

EXTRN DATA      (isr_index)

      CSEG      AT      0103H                ;32ºÅ ²¨Ðη¢ÉúÆ÷5 ÖжÏÈë¿Ú
      MOV                isr_index, #32      ;±ê¼ÇÖжϺÅ32
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      010BH                ;33ºÅ ²¨Ðη¢ÉúÆ÷Òì³£2 ÖжÏÈë¿Ú
      MOV                isr_index, #33      ;±ê¼ÇÖжϺÅ33
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0113H                ;34ºÅ ²¨Ðη¢ÉúÆ÷Òì³£4 ÖжÏÈë¿Ú
      MOV                isr_index, #34      ;±ê¼ÇÖжϺÅ34
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      011BH                ;35ºÅ ´¥Ãþ°´¼ü ÖжÏÈë¿Ú
      MOV                isr_index, #35      ;±ê¼ÇÖжϺÅ35
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0123H                ;36ºÅ RTC ÖжÏÈë¿Ú
      MOV                isr_index, #36      ;±ê¼ÇÖжϺÅ36
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      012BH                ;37ºÅ P0¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #37      ;±ê¼ÇÖжϺÅ37
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿

      CSEG      AT      0133H                ;38ºÅ P1¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #38      ;±ê¼ÇÖжϺÅ38
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      013BH                ;39ºÅ P2¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #39      ;±ê¼ÇÖжϺÅ39
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0143H                ;40ºÅ P3¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #40      ;±ê¼ÇÖжϺÅ40
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      014BH                ;41ºÅ P4¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #41      ;±ê¼ÇÖжϺÅ41
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0153H                ;42ºÅ P5¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #42      ;±ê¼ÇÖжϺÅ42
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      015BH                ;43ºÅ P6¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #43      ;±ê¼ÇÖжϺÅ43
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0163H                ;44ºÅ P7¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #44      ;±ê¼ÇÖжϺÅ44
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      016BH                ;45ºÅ P8¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #45      ;±ê¼ÇÖжϺÅ45
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      CSEG      AT      0173H                ;46ºÅ P9¿ÚÖжÏÈë¿Ú
      MOV                isr_index, #46      ;±ê¼ÇÖжϺÅ46
      LJMP      006BH                        ;Ìø×ªµ½ÖжϺÅ13µÄÏòÁ¿
      
      
      END

神农鼎 发表于 2024-5-24 13:45:02

触摸按键唤醒,演示程序见附件,1uA/1个键/1秒唤醒,
===STC8H4K64TLCD触摸MCU, 唤醒【主时钟停振/省电模式】
===STC8H4K64TL触摸MCU, 唤醒【主时钟停振/省电模式】
===STC8H1K08T触摸MCU, 唤醒【主时钟停振/省电模式】
触摸按键1秒唤醒一次, 1uA/一个键 + 2.4uA/32K振荡器需要电流,16个键<20uA
====增加1个键就是增加约1个uA
         1个键参与唤醒就是:      3.4uA = 2.4uA/32K振荡器需要电流 + 1uA/一个键
         2个按键参与唤醒就是:【2.4uA+1uA * 2】= 4.4uA
         3个按键参与唤醒就是:【2.4uA+1uA * 3】= 5.4uA
         4个按键参与唤醒就是:【2.4uA+1uA * 4】= 6.4uA
         5个按键参与唤醒就是:【2.4uA+1uA * 5】= 7.4uA
         ......
         16个按键参与唤醒就是:【2.4uA+1uA*16】= 18.4uA <=20uA
====如果2秒唤醒一次,电流再减半

STC的触摸按键是比较省电的,MCU进入睡眠后,主时钟关闭,自动启动内部的32KHz时钟,按设定的时间间隔扫描按键,
扫描结果自动比较阈值,超过阈值的键就会唤醒MCU。

MCU睡眠后,32KHz时钟启动,睡眠电流典型值2.4uA。例子为一秒检测一次按键。
如果允许检测16个按键,则每隔一秒自动检测一次所有16个触摸按键,任意一个触摸按键超过阈值均能唤醒MCU,
触摸的时间最长为1秒即可唤醒。

本例程序运行于24MHz,16键唤醒,睡眠时间967ms,睡眠电流为2.4uA左右@4V(一节锂电池),
检测触摸耗时16ms(每个按键1ms),电流1.1mA,则平均电流 = 2.4+1100*16/1000=20uA。
如果只允许一个按键,则检测一个按键时间为1ms,平均电流 = 2.4+1100*1/1000=3.5uA。

所以N个键唤醒,睡眠平均电流 = 2.4 + 1.1*N,单位uA。


触摸按键唤醒,1uA/1个键/1秒唤醒,STC触摸MCU, 唤醒【主时钟停振/省电模式】 - 触摸按键/80mA大电流LED数码管自动刷新显示/段码LCD/RTC实时时钟/低功耗 国芯技术交流网站 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)

国学芯用 发表于 2024-5-24 09:02:35

打包发上来

DGWJL2024 发表于 2024-5-24 10:01:04

附件为程序

乘风飞扬 发表于 2024-5-24 10:35:57

硬件仿真操作步骤参考演示视频:
https://www.stcaimcu.com/plugin.php?id=x7ree_v:x7ree_v&code_7ree=1&id_7ree=63
我看你项目设置里面选择的是软件模拟仿真,没有选择硬件仿真,这样是收不到硬件中断的

DGWJL2024 发表于 2024-5-24 11:06:03

乘风 你好,谢谢您的提醒。我没设置硬件仿真,现在改过来了。初始化中读零点键值成功了,但在主程序循环中进不了触摸按键中断,B_ReadKeyOk始终为0,不能进入判断键值程序。

DGWJL2024 发表于 2024-5-24 11:17:45

可以进入触摸按键中断,我用了4个按键,中断中扫描个数改成3B_ReadKeyOk=1 就对了,能进判断键值程序了
页: [1]
查看完整版本: 编译通过,仿真时进不了触摸按键中断 | 已解决