- /*
- 单片机: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[16]; // 键计数值
- u16 xdata TK_zero[16]; // 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 ADCval; //ADC测量结果
-
- /************* 本地函数声明 **************/
- void delay_ms(u8 ms);
- u8 CheckKey(u16 j);
- /**************** 外部函数声明和外部变量声明 *****************/
- u16 code T_KeyState[16] = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
- // u16 code T_KeyPress[16] = {400,300,200,200, 400,300,200,200, 400,300,200,200, 400,300,200,200}; //读数无平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
- u16 code T_KeyPress[16] = {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;
- P3M0 = 0x00; P3M1 = 0x08; //设置P33为ADC输入口
-
- ADCTIM = 0x3f; //设置ADC内部时序
- P_SW2 &= 0x7f;
- ADCCFG = 0x0f; //设置ADC时钟为系统时钟/2/16
- ADC_CONTR = 0x8B; //开启ADC电源,选择第11通道ADC
- EADC = 1; //使能ADC中断
- // EA = 1;
- ADC_CONTR |= 0x40; //启动AD转换
-
-
- 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[6:4]+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[i] = TK_cnt[i]; //保存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[i] > TK_cnt[i]) //计算与0点的差值
- {
- TK_zero[i]--; //缓慢0点跟随
- if((TK_zero[i] - TK_cnt[i]) >= T_KeyPress[i]/2)
- KeyState |= T_KeyState[i]; // 大于按键读数变量的1/2就是按下
- else if((TK_zero[i] - TK_cnt[i]) <= T_KeyPress[i]/3)
- KeyState &= ~T_KeyState[i]; // 小于按键读数变量的1/3就是释放
- }
- else
- {
- KeyState &= ~T_KeyState[i];
- if((TK_cnt[i] - TK_zero[i]) > 100)
- TK_zero[i] += 50; //差别很大, 则快速回0点
- else TK_zero[i] += 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;
- printf("ADC:0x%x\r\n",(u16)ADCval);
- }
- }
- }
- }
- }
- /**********************************************/
-
- 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
- }
-
-
- 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[j] = TSDAT/4; //保存某个通道的读数 无低通滤波
- else TK_cnt[j] = ((TK_cnt[j] * 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); //检测命令序列
- }
- }
-
- void ADC_Isr() interrupt 5
- {
- ADC_CONTR &= ~0x20; //清中断标志
- ADCval = ADC_RES; //读取ADC结果
- ADC_CONTR |= 0x40; //继续AD转换
- }
-
- char putchar(char dat) //重定义putchar系统函数
- {
- while (fBusy);
- fBusy = 1;
- SBUF = dat;
- return dat;
- }
-
复制代码
|