编译通过,仿真时进不了触摸按键中断 | 已解决
我移植了触摸按键驱动程序,现在编译可以通过,但仿真时进入不了触摸按键的中断服务函数,请大家指点//普通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
触摸按键唤醒,演示程序见附件,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)
打包发上来 附件为程序
硬件仿真操作步骤参考演示视频:
https://www.stcaimcu.com/plugin.php?id=x7ree_v:x7ree_v&code_7ree=1&id_7ree=63
我看你项目设置里面选择的是软件模拟仿真,没有选择硬件仿真,这样是收不到硬件中断的
乘风 你好,谢谢您的提醒。我没设置硬件仿真,现在改过来了。初始化中读零点键值成功了,但在主程序循环中进不了触摸按键中断,B_ReadKeyOk始终为0,不能进入判断键值程序。 可以进入触摸按键中断,我用了4个按键,中断中扫描个数改成3B_ReadKeyOk=1 就对了,能进判断键值程序了
页:
[1]