用C语言写一个电容感应触摸键程序

2023-01-13  

使用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; //指示灯亮

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。