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

发布者:RainbowDreamer最新更新时间:2023-10-08 来源: zhihu关键字:C语言  主时钟 手机看文章 扫描二维码
随时随地手机看文章

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

}


关键字:C语言  主时钟 引用地址:用C语言写一个电容感应触摸键程序

上一篇:用AT89C51单片机显示倒计时程序
下一篇:用汇编语言做一个看门狗测试

推荐阅读最新更新时间:2024-11-10 10:22

LCD1602显示C语言
//**********定义与声明******************* #include p IC .h #define uchar unsigned char #define uint unsigned int #define E RE2 #define RS RB4 uchar i,num,byte,ys; uchar const table = Shan qing gong ; //为什么2009前面要空开两个才能显示后空开1个儿呢?这个定义要小心!一定要用uchar const,不要丢了uchar,也不要用code uchar const table1 = tong xin 06-2 ; //4第二数组
[单片机]
单片机C语言电子时钟加日历显示编程
一、 任务和要求 设计制作一个电子表并且能够显示日历,用LED数码管直接显示,并且能够通过按键调整时间、年月日,功能为按第一个键被调整的相应调整区域开始闪烁,第二个键加一,第三个减一,第四个确认,最后一个在时分秒和年月日中间相互切换。 二、方案论证 我们在这里选用了C8051F单片机,它是完全集成的混合信号系统级芯片(SoC),具有与8051兼容的高速CIP-51内核,与MCS-51指令集完全兼容,片内集成了数据采集和控制系统中常用的模拟、数字外设及其他功能部件;内置FLASH程序存储器、内部RAM,大部分器件内部还有位于外部数据存储器空间的RAM,即XRAM。C8051F单片机具有片内调试电路,通过4脚的JTAG接口可以进行非侵
[单片机]
单片机<font color='red'>C语言</font>电子时钟加日历显示编程
C语言的数组、字符串等一些知识总结
1、字符串:位于双引号中的字符序列,以 结束,所占字节比实际多一个。 2、字符常量可以赋给字符变量,字符串常量不可以赋给字符串变量。C语言中用字符数组来存放字符串。 3、字符数组:memset(a, ,10);用来给数组清0的。需要加头文件#include。 注意:定义数组时,应确保数组长度比字符串长度至少多1,未被使用的元素自动初始化为0。 4、 代表ASCII码为0的字符(NUL)。为 空操作符 ,用它作为字符串结束标志不会产生附加的操 作或增加有效字符,只起一个供辨别的标志。 5、字符数组的输入输出的两种方法: (1)逐个字符输入输出(%c);(输出字符不包含 ) (2)整个字符串
[单片机]
单片机C语言教程第二课-初步认识51芯片
上一课我们的第一个项目完成了,可能有懂C语言的朋友会说, 这和PC机上的C语言没有多大的区别呀 。的确没有太大的区别,C语言只是一种程序语言的统称,针对不同的处理器相关的C语言都会有一些细节的改变。编写PC机的C程序时,如要对硬件编程你就必须对硬件要有一定的认识,51单片机编程就更是如此,因它的开发应用是不可与硬件脱节的,所以我们先要来初步认识一下51苾片的结构和引脚功能。MSC51架构的芯片种类很多,具体特点和功能不尽相同(在以后编写的附录中会加入常用的一些51芯片的资料列表),在此后的教程中就以Atmel公司的AT89C51和AT89C2051为中心对象来进行学习,两者是AT89系列的典型代表,在爱好者中使用相当的多,应用资料
[单片机]
单片机<font color='red'>C语言</font>教程第二课-初步认识51芯片
AVR单片机从左到右LED流水灯C语言程序
AVR单片机第一个实验,从左到右的LED流水灯C语言程序,编程环境是WinAVR,8MHZ晶振。 #include avr/io.h //相关库 #include util/delay.h typedef unsigned int uint; typedef unsigned char uchar; uchar const tab ={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; void main(void)//主函数 { PORTB=0xff;//PB口输出为高电平 DDRB=0xff;//高PB口为输出 uchar a;//定义变量 while(1)//无限
[单片机]
单片机C语言程序设计:用定时器设计的门铃
/* 名称:用定时器设计的门铃 说明:按下按键时蜂鸣器发出叮咚的门铃声。 */ #include reg51.h #define uchar unsigned char #define uint unsigned int sbit Key=P1^7; sbit DoorBell=P3^0; uint p=0; //主程序 void main() { DoorBell=0; TMOD=0x00; //T0 方式 0 TH0=(8192-700)/32; //700us 定时 TL0=(8192-700)%32; IE=0x82; while(1) { if(Key==0) //按下按键启动定时
[单片机]
单片机<font color='red'>C语言</font>程序设计:用定时器设计的门铃
基于51的EEPROM C语言程序
#include reg52.h //单片机51头文件,存放着单片机的寄存器 #include intrins.h #define uchar unsigned char #define uint unsigned int uchar code tab = 0123456789 ; sbit SID=P2^0; //数据信号 sbit SCLK=P2^1; //时钟信号 uint tcnt; //定时中断次数 bit write=0; //写24C08的标志; sbit scl=P3^7; //24c08 SCL sbit sda=P3^6; //24c08 SDA uchar a,
[单片机]
Proteus仿真51单片机C语言程序实例-开关控制报警器
简介:51单片机C语言程序实例-开关控制报警器(用K1开关控制报警器,程序控制P1.0输出两种不同频率的声音,模拟很逼真的报警效果)。
[单片机]
Proteus仿真51单片机<font color='red'>C语言</font>程序实例-开关控制报警器

推荐帖子

【讨论】JTAG能够只接5根线就用吗?请求回答!!!
【讨论】JTAG能够只接5根线就用吗?请求回答!!!是。还应该共地TDO/TDI,TDI,TMS,TCK,REST这五根吗?再加地Reset可以不接,外接个复位按钮,我一直这样用。tocool430:真的吗?我可一直用TDO/TDI,TDI,TMS,TCK,REST.外加共地线,,请问rest在JTAG中骑什么作用呢??只要工作正常都一样的,TI的隔离JTAG就只用了这5根连线。这个得到了认可吗?我的意思是定义了函数putchar后,就可以直接在程序里使用Print
hhyyzzcool 微控制器 MCU
你最省钱的设计,赢LPC1114开发板!(已颁奖)
感谢chenzhufly贡献了一块LPC1114开发板,由于他老人家感冒在身,所以由我越权来发这个板子。板子只有一块,感兴趣的朋友估计不止一个,所以想了个比较有意思的话题,希望大家多多参与。话题:谈谈你做过的最省钱的设计?——越省钱越好参与方式:跟帖结束日期:06月30日7月1日的时候,我们将确定获得LPC1114板子的人选。板子图赏(这是上次做活动的图,LPC1114就是其中一个,故图片仅供参考)lyzhangxia
soso NXP MCU
【FireBeetle 2 ESP32 C6开发板】8、使用触屏 + espnow控制led灯
###前言lvgl已经出到9.x版本了,github上的lv_port_esp32还是7.x版本,由于我自己有Linux和esp32两种设备的开发需求,esp32的RAM和Flash也不算小,我打算直接使用9.1版本的lvgl,然后使用lvgl_esp32_drivers仓库,仓库地址是https://github.com/lvgl/lvgl_esp32_drivers.git####远程点灯前面我们已经实现了微雪板子的lvgl按钮和触屏案例,现在使用espnow来实现远程点灯,效果
walker2048 RF/无线
关于GPRS模块的拨号连接问题
用windows的拨号连接,可以接通网络,上网也没有问题。拨号设置的是*99***2#如果用AT命令ATD*99***2#,如何连接GPRS网络?AT+CGDCONT=1,IP,CMNETOKATD*99***2#CONNECT~?}#9}}&}}*}}}\'}}(}}%}&~?}#~?}#~?}#~?}#~?}#~?}#~?}#~?}#~?}#NOCARRIER不知道这是什么原因,请问还需要别的什么吗?关于GPRS模块的拨号连接问题对了,
yes2250 嵌入式系统
在WINCE60里面把CELLCORE组件加进了NK,怎么测试这块是不是可以正常工作?有没简单的测试AP可用?怎么测试RIL组件绑定了物理通信的串口?
在WINCE60里面把CELLCORE组件加进了NK,怎么测试这块是不是可以正常工作?有没简单的测试AP可用?怎么测试RIL组件绑定了物理通信的串口?在WINCE60里面把CELLCORE组件加进了NK,怎么测试这块是不是可以正常工作?有没简单的测试AP可用?怎么测试RIL组件绑定了物理通信的串口?想用VS2005写个简单的AP来测试RIL功能,执行RIL_Initialize()函数老是不成功,错误码又显示调用成功了,搞不懂啊。还要调整什么地方???Ril.lib库的问题,找一个旧一点
ali50m WindowsCE
[STM32H7R/S]测评 ⑥使用CUBE AI移植模型至开发板运行
在开始自己训练模型并运行到开发板上前,我得先尝试一下把一个现成的模型移植到STM32开发板上,先积累经验。训练好的模型是无法直接在STM32上运行的,我浅薄的理解就是STM32只是一个单片机,他的硬件能力和软件架构无法直接运行AI模型,那么就需要一个工具,把这些复杂的东西转换成C语言的代码,这样STM32单片机就可以运行AI模型里,CUBEAI就是ST为各位开发者准备好的工具。一.安装CUBEAICUBEAI是CUBEMX中的一个软件包,
不爱胡萝卜的仓鼠 stm32/stm8
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved