用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-17 00:35

嵌入式C语言位操作的移植与优化
引 言 单片机的应用越来越广泛,种类也越来越多。由于嵌入式C语言可读性强、移植性好,与汇编语言相比大大减轻了软件工程师的劳动强度,因而越来越多的单片机工程师开始使用C语言编程。但C语言的可移植性仅限于与硬件无关的子程序,而与具体硬件有关的子程序则无法移植。在单片机应用中,位操作(特别是对引脚的位操作)非常普遍,如EEPROM数据和IC卡数据的读写、字段式LCD显示等,很多带串目的集成电路都需要单片机用软件来做I/O口读写程序。如何让这些子程序既有很好的通用性,生成代码的效率又高,是很多软件工程师都在考虑的问题。这里介绍两种C语言位操作的移植方法。 1 用逻辑运算实现位操作 请看下面这个子程序: 这是通过单片机引
[单片机]
嵌入式<font color='red'>C语言</font>位操作的移植与优化
基于C语言在FPGA上实现DSP的解决方案
硬件设计者已经开始在高性能DSP的设计中采用FPGA技术,因为它可以提供比基于PC或者单片机的解决方法快上10-100倍的运算量。以前,对硬件设计不熟悉的软件开发者们很难发挥出FPGA的优势,而如今基于C语言的方法可以让软件开发者毫不费力的将FPGA的优势发挥得淋漓尽致。这些基于C语言的开发工具可以比基于HDL语言的硬件设计更节省设计时间,同时不需要太多的硬件知识。由于具有这些优势,FPGA技术不仅可使这些器件作为I/O器件的前端,FPGA还可实现大量的高带宽和运算密集型应用的实时处理。此外,FPGA还可很紧密地与板上存储器结合,并在一块电路板上集成多个器件。更好的是,FPGA电路板可通过新兴的串口通讯标准进行通讯,如RapidI
[嵌入式]
基于<font color='red'>C语言</font>在FPGA上实现DSP的解决方案
STM32中C语言的基础知识
C语言是单片机开发中的必备基础知识,本文列举了部分STM32学习中比较常见的一些C语言基础知识,希望能对大家有所帮助。 01位操作 下面我们先讲解几种位操作符,然后讲解位操作使用技巧。C语言支持以下六种位操作: (六种位操作) 下面,重点讲解一下位操作在单片机开发中的一些实用技巧。 1.1 在不改变其他位的值的状况下,对某几个位进行设值。 这个场景在单片机开发中经常使用,方法就是我们先对需要设置的位用&操作符进行清零操作,然后用 | 操作符设值。 比如,我要改变GPIOA的状态,可以先对寄存器的值进行&清零操作: 然后再与需要设置的值进行|或运算: 1.2 移位操作提高代码的可读性。 移位操
[单片机]
STM32中<font color='red'>C语言</font>的基础知识
51单片机C语言调用汇编子程序的简便方法
1、在汇编文件中,程序前边加上如下三句话就可以: PUBLIC _delay, _binrlc ;定义公用子程序名,这里定义了两个子程序(有下划线) LUOYUAN SEGMENT CODE ;程序段命名,LUOYUAN,叫啥名都可以 RSEG LUOYUAN 下边放子程序(程序名要下划线,其它标号不要下划线) ;汇编语言文件 PUBLIC _delay, _binrlc;定义子程序名 LUOYUAN SEGMENT CODE ;命名LUOYUAN的程序段 RSEG LUOYUAN _delay: MOV P1,#55H MOV R2,#30H DJNZ R2,$ RET
[单片机]
二叉堆的C语言实现
二叉堆的实现数据结构中如何使用,我任务主要是在操作系统中的任务优先级调度问题,当然也可以用于实现堆排序问题,比如找出数组中的第K个最小值问题,采用二叉堆能够快速的实现,今天我就采用C语言实现了一个简单的二叉堆操作,完成这些数据结构我并不知道能干什么,我就当自己在练习C语言的功底吧。逐步完成自己的代码,希望自己在知识的理解力上有一定的提高。 二叉堆是非常有特点的数据结构,可以采用简单的数组就能实现,当然链表的实现也是没有问题的,毕竟是一个二叉树问题,当然可以采用链表实现。采用数组实现时,可以找到两个特别明显的规律: 左儿子:L_Son = Parent * 2; 右儿子:R_Son = Parent * 2 + 1; 二叉
[单片机]
STM32下模拟I2C的C语言实现
近来主要在写一些STM32上的开发程序,由于STM32的固件库中,I2C模块实在是不好用,所以在采用了软件模拟的方法来实现。 具体的代码如下(在Keil下调试通过): #include stm32f10x_lib.h //条件编译 1:使用软件模拟I2C //#define PIN_SCL GPIO_Pin_6 //#define PIN_SDA GPIO_Pin_7 static __inline void TWI_SCL_0(void) { GPIOB- BRR=PIN_SCL; } static __inline void TWI_SCL_1(void) { GPIOB- BSRR=P
[单片机]
DS12887(时钟日历芯片) c语言驱动程序
****************DS12887 时钟日历芯片调试******************/ 管脚配置: MOT: 接地 CS: 接地 地址:0xFF00 AS: 接单片机 ALE R/W: 接 RW DS: 接 RD RESET: 接高 IRQ: 空 SQW: 空 */ #i nclude REG51.h #i nclude absacc.h /*************************/ #define TM_SEC XBYTE #define TM_MIN XBYTE #define TM_HOU XBYTE #define DAY XBYTE #define DATE XBYT
[单片机]
51单片机——数码管、按键、矩阵按键C语言入门编程
数码管: 数码管按段数可分为七段数码管和八段数码管,八段数码管多一个DP(小数点)二极管。也可分为共阳极数码管(低电平点亮)和共阴极数码管(高电平点亮)。本开发板上使用的是2个四位一体共阴极数码管。数码管静态显示是控制数码管的每一个引脚,输入一次电平之后可以一直显示直到再一次改变电平,静态显示会增加IO口的使用,结构复杂成本高,但是会减少占用CPU的时间。数码管动态显示通过位选—段选—清零(消影)来通过发光管余辉和人的视觉暂留是我们感觉出每一位同时显示。 通过74HC138译码器(C为高位B为次高位A为低位)输入高电平输出低电平进行位选,然后通过74HC245驱动数码管段选(a为低位,DP为高位)。 //共阴极数码管段
[单片机]
51单片机——数码管、按键、矩阵按键<font color='red'>C语言</font>入门编程

推荐帖子

EPSON TSP700 打印位置设置的问题
我在用EPSONTSP700的ESC\\POS指令编程时只要碰到打印位置设置的指令就出不来,不是打印出奇怪字符就是没效果,比如在页模式下打印区域的设置就老出不来,很是郁闷。请哪位做过的高手给我提示一二,最好能给个例子,不胜感激!!!!EPSONTSP700打印位置设置的问题是star的tsp700对,就是这个,好长时间了,问题就是解决不了,能指导一下吗?
lixin811013 嵌入式系统
【DSP】TMS320F28035 ADC例程(ePWM+中断)
#includeDSP28x_Project.hinterruptvoidadc_isr(void);Uint16ConversionCount;Uint16Voltage1;Uint16Voltage2;main(){InitSysCtrl();DINT;InitPieCtrl();IER=0x0000;IFR=0x0000;InitPieVectTable();EALLOW;PieVectTable.ADC
Aguilera DSP 与 ARM 处理器
【SC8905 EVM测评】+交作业啦
作业交的很勤快,果然我是一个好学生,哈哈哈,今天把SC8905EVM的作业交上来吧,不得不说SC8905EVM非常容易上手,这也看得出,南芯对客户的周到服务,在此深表感谢。社区和南芯留的作业如图所示:看这个作业属实非常简单,既然简单,那就上手去做吧。首先把官方提供的I2C工具接入到电脑之中,win10的话不会自动去安装驱动,需要去设备管理器中找到有问题的驱动,选择自动去更新和安装;安装完成的样子如上图所示。接下来打开软件,并且把设备都接好,5V电源给BAT端,该端当
yangjiaxu 国产芯片交流
请教: omap 138 中LCD如何横屏转竖屏
请教:omap138中LCD如何横屏转竖屏请教:omap138中LCD如何横屏转竖屏
denglin 嵌入式系统
兆易GD32307E-START开发板推荐
兆易GD32307E-START开发板搭载GD32ARMCortex-M4微控制器主流芯片GD32F307。也是刚刚举办过的兆易杯研究生电子设计竞赛的指定开发板之一。其中主芯片GD32F307主要特性 Cortex-M4内核@120MHz 支持软硬件DSP指令 闪存执行为零等待状态 内置256KB至3072KB​闪存 内置48KB至96KBSRAM EXMC接口支持外部SDRAM 高达5个UART
okhxyyo 国产芯片交流
gprs模块如何打电话??
嵌入式开发板2410的串口和wavecome的q2403a相连,手法短信已经没问题,现在想搞接打电话,不知从何下手,望大家指点.谢谢gprs模块如何打电话??这个是“非技术”啊?发错版块了吧。友情Up!
felixty 嵌入式系统
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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