使用STC15W408AS的ADC做的电容感应触摸键
#include #include #define MAIN_Fosc 24000000UL //定义主时钟 typedef unsigned char u8; typedef unsigned int u16; typedef unsigned long u32; #define Timer0_Reload (65536UL -(MAIN_Fosc / 600000)) //Timer 0 重装值, 对应300KHZ sfr P1ASF = 0x9D; //只写,模拟输入选择 sfr ADC_CONTR = 0xBC; //带AD系列 sfr ADC_RES = 0xBD; //带AD系列 sfr ADC_RESL = 0xBE; //带AD系列 sfr AUXR = 0x8E; sfr AUXR2 = 0x8F; sfr P1M1 = 0x91; // sfr P1M0 = 0x92; // sfr P0M1 = 0x93; // sfr P0M0 = 0x94; // sfr P2M1 = 0x95; // sfr P2M0 = 0x96; // sfr P3M1 = 0xB1; // sfr P3M0 = 0xB2; // sfr P4M1 = 0xB3; // sfr P4M0 = 0xB4; // sfr P5M1 = 0xC9; // sfr P5M0 = 0xCA; // sfr P6M1 = 0xCB; // sfr P6M0 = 0xCC; // sfr P7M1 = 0xE1; sfr P7M0 = 0xE2; #define TOUCH_CHANNEL 8 //ADC通道数 #define ADC_90T (3<<5) //ADC时间 90T #define ADC_180T (2<<5) //ADC时间 180T #define ADC_360T (1<<5) //ADC时间 360T #define ADC_540T 0 //ADC时间 540T #define ADC_FLAG (1<<4) //软件清0 #define ADC_START (1<<3) //自动清0 sbit P_LED7 = P2^7; sbit P_LED6 = P2^6; sbit P_LED5 = P2^5; sbit P_LED4 = P2^4; sbit P_LED3 = P2^3; sbit P_LED2 = P2^2; sbit P_LED1 = P2^1; sbit P_LED0 = P2^0; u16 idata adc[TOUCH_CHANNEL]; //当前ADC值 u16 idata adc_prev[TOUCH_CHANNEL]; //上一个ADC值 u16 idata TouchZero[TOUCH_CHANNEL]; //0点ADC值 u8 idata TouchZeroCnt[TOUCH_CHANNEL]; //0点自动跟踪计数 u8 cnt_250ms; void delay_ms(u8 ms); void ADC_init(void); u16 Get_ADC10bitResult(u8 channel); void AutoZero(void); u8 check_adc(u8 index); void ShowLED(void); void main(void) { u8 i; P0M1 = 0; P0M0 = 0; //设置为准双向口 P1M1 = 0; P1M0 = 0; //设置为准双向口 P2M1 = 0; P2M0 = 0; //设置为准双向口 P3M1 = 0; P3M0 = 0; //设置为准双向口 P4M1 = 0; P4M0 = 0; //设置为准双向口 P5M1 = 0; P5M0 = 0; //设置为准双向口 P6M1 = 0; P6M0 = 0; //设置为准双向口 P7M1 = 0; P7M0 = 0; //设置为准双向口 delay_ms(50); ET0 = 0; //初始化Timer0输出一个300KHZ时钟 TR0 = 0; AUXR |= 0x80; //Timer0 set as 1T mode AUXR2 |= 0x01; //允许输出时钟 TMOD = 0; //Timer0 set as Timer, 16 bits Auto Reload. TH0 = (u8)(Timer0_Reload >> 8); TL0 = (u8)Timer0_Reload; TR0 = 1; ADC_init(); //ADC初始化 delay_ms(50); //延时50ms for(i=0; i adc_prev[i] = 1023; TouchZero[i] = 1023; TouchZeroCnt[i] = 0; } cnt_250ms = 0; while (1) { delay_ms(50); //每隔50ms处理一次按键 ShowLED(); if(++cnt_250ms >= 5) { cnt_250ms = 0; AutoZero(); //每隔250ms处理一次0点自动跟踪 } } } void delay_ms(u8 ms) { unsigned int i; do{ i = MAIN_Fosc / 13000; while(--i) ; }while(--ms); } void ADC_init(void) { P1ASF = 0xff; //8路ADC ADC_CONTR = 0x80; //允许ADC } u16 Get_ADC10bitResult(u8 channel) //channel = 0~7 { ADC_RES = 0; ADC_RESL = 0; ADC_CONTR = 0x80 | ADC_90T | ADC_START | channel; //触发ADC _nop_(); _nop_(); _nop_(); _nop_(); while((ADC_CONTR & ADC_FLAG) == 0) ; //等待ADC转换结束 ADC_CONTR = 0x80; //清除标志 return(((u16)ADC_RES << 2) | ((u16)ADC_RESL & 3)); //返回ADC结果 } void AutoZero(void) //250ms调用一次 这是使用相邻2个采样的差的绝对值之和来检测。 { u8 i; u16 j,k; for(i=0; i j = adc[i]; k = j - adc_prev[i]; //减前一个读数 F0 = 0; //按下 if(k & 0x8000) F0 = 1, k = 0 - k; //释放 求出两次采样的差值 if(k >= 20) //变化比较大 { TouchZeroCnt[i] = 0; //如果变化比较大,则清0计数器 if(F0) TouchZero[i] = j; //如果是释放,并且变化比较大,则直接替代 } else //变化比较小,则蠕动,自动0点跟踪 { if(++TouchZeroCnt[i] >= 20) //连续检测到小变化20次/4 = 5秒. { TouchZeroCnt[i] = 0; TouchZero[i] = adc_prev[i]; //变化缓慢的值作为0点 } } adc_prev[i] = j; //保存这一次的采样值 } } u8 check_adc(u8 index) //判断键按下或释放,有回差控制 { u16 delta; adc[index] = 1023 - Get_ADC10bitResult(index); //获取ADC值, 转成按下键, ADC值增加 if(adc[index] < TouchZero[index]) return 0; //比0点还小的值,则认为是键释放 delta = adc[index] - TouchZero[index]; if(delta >= 40) return 1; //键按下 if(delta <= 20) return 0; //键释放 return 2; //保持原状态 } void ShowLED(void) { u8 i; i = check_adc(0); if(i == 0) P_LED0 = 1; //指示灯灭 if(i == 1) P_LED0 = 0; //指示灯亮 i = check_adc(1); if(i == 0) P_LED1 = 1; //指示灯灭 if(i == 1) P_LED1 = 0; //指示灯亮 i = check_adc(2); if(i == 0) P_LED2 = 1; //指示灯灭 if(i == 1) P_LED2 = 0; //指示灯亮 i = check_adc(3); if(i == 0) P_LED3 = 1; //指示灯灭 if(i == 1) P_LED3 = 0; //指示灯亮 i = check_adc(4); if(i == 0) P_LED4 = 1; //指示灯灭 if(i == 1) P_LED4 = 0; //指示灯亮 i = check_adc(5); if(i == 0) P_LED5 = 1; //指示灯灭 if(i == 1) P_LED5 = 0; //指示灯亮 i = check_adc(6); if(i == 0) P_LED6 = 1; //指示灯灭 if(i == 1) P_LED6 = 0; //指示灯亮 i = check_adc(7); if(i == 0) P_LED7 = 1; //指示灯灭 if(i == 1) P_LED7 = 0; //指示灯亮 }