搜索
bottom↓
回复: 10

Capacitive sensing

[复制链接]

出0入0汤圆

发表于 2010-5-28 08:43:13 | 显示全部楼层 |阅读模式
I was experimenting using LEDs as photo detectors - very successful, by the way.

then I realized that the same principle applies to capacitive sensing. so after some quick changes, here is the code that utilizes capacitive sensing.

===========code=============
#include <htc.h>
#include <string.h>
#include "lcd_3wi.h"
#include "delay.h"

__CONFIG(MCLRDIS & WDTDIS & BORDIS & PWRTEN & INTIO);

#define LED_PIN                                (1<<0)                //led indicator
#define SEN_PORT                        PORTA                //leds on porta
#define SEN_ACQ                                (1<<4)                //acquisition pin
#define SEN_CHG                                (1<<5)                //charge up the capacitor
#define SEN_SET(bits)                SEN_PORT |= (bits)        //set bits
#define SEN_CLR(bits)                SEN_PORT &=~(bits)        //clear bits
#define SEN_FLP(bits)                SEN_PORT ^= (bits)        //flip bits
#define SEN_IN(bits)                TRISA |= (bits)                //bits as input
#define SEN_OUT(bits)                TRISA &=~(bits)                //bits as output
#define SEN_CHARGE(c, a)        SEN_IN(a); SEN_OUT(c); SEN_SET(c)                        //charge up the cap
#define SEN_DISCHARGE(c, a)        SEN_IN(a); SEN_OUT(c); SEN_CLR(c)                         //discharge the led
#define SEN_MAX_COUNT                0x8f                                //max cycle count for the led_detect() routine
#define SEN_PRESSED                        0x08                                //if count more SEN_PRESSED, consider the button pressed

unsigned char vRAM[17];                                //lcd buffer
const unsigned char str0[]="16F684CapSensing";
const unsigned char str1[]="t   =           ";
unsigned long t1_count=0;

void mcu_init(void ) {                                //reset the mcu
        ANSEL=0x00;                                                //all pins gpio
        CMCON0=0x07;                                        //analog comparators off
        IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4mhz
        SEN_CLR(LED_PIN);                                //clear led_pin
        SEN_OUT(LED_PIN);                                //set led_pin as output
}

void ultoa(char *s, unsigned long ul, unsigned char length) {        //convert unsigned long to a string, 3 dps
        unsigned char i;
       
        i=length;
        do {
//                if (i==(length-3)) s[i--]='.';
                s[i--]=ul % 10 + '0';
                ul = ul / 10;
        } while (ul);
}

unsigned char sen_detect(unsigned char sen_c, unsigned char sen_a) {        //return the cycle count
        unsigned char tmp;
        SEN_CHARGE(sen_c, sen_a); delay_ms(1);                        //charge up the cap
        SEN_DISCHARGE(sen_c, sen_a);                                        //discharge the cap
        tmp=0;
//        while ((SEN_PORT & sen_a) && (tmp < SEN_MAX_COUNT)) tmp++;                //wait for LED_K to fall
        while (SEN_PORT & sen_a) tmp++;                //wait for LED_K to fall
        return tmp;
//        return tmp>SEN_PRESSED;                                //return 1 if tmp>sen_pressed. otherwise 0
}

void
main(void)
{        unsigned char t1;
        unsigned char i=0;
        mcu_init();                                                //initialize the mcu
        lcd_init();                                                //initialize the lcd
        strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        while (1){
                if (sen_detect(SEN_CHG, SEN_ACQ) > SEN_PRESSED) SEN_FLP(LED_PIN);                 //if pressed, flip the led
                strcpy(vRAM, str1); ultoa(&vRAM[0], i++, 3); ultoa(&vRAM[2], t1, 13); lcd_display(LCD_Line1, vRAM);
//                LED_EMIT(LED_A, LED_K); delay_us(t1>>4);
//                simple_pwm(t1>>4, LED_A, LED_K);
                delay_ms(100);
                //TODO Auto-generated main function
        }
}
============end of code===============


(原文件名:16F684 Cap Sensing.PNG)

R1/C1 forms the basic cap sensing circuitry. the button and C2 simulate body capacitance: the button pressed = your finger on R1.

essentially, RA5 charges up C1 through R1, and then RA5 goes low to discharge C1. the program counts how long it takes C1 to be discharged.

with the body capacitance, it takes longer for C1//C2 to discharge. that allows the mcu to determine if the button has been pressed.

the same principle allows to pretty much any mcu.

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2010-5-28 10:30:24 | 显示全部楼层
谢谢楼主 millwood0。
触摸电容传感处理程序,原理介绍已经理解了。遗憾的是,我本人仅仅自学过汇编,没有学过C。
楼主提到的“LEDs as photo detectors”,好像曾经见过一个视频,不知是否属于同类或进一步发挥。期待楼主的介绍。

出0入0汤圆

 楼主| 发表于 2010-5-28 22:10:14 | 显示全部楼层
Yeah.

all the ideas are based on a paper by those nice folks at Mitsubishi (http://www.merl.com/papers/docs/TR2003-35.pdf)

Essentially, a LED, when reverse biased, behaves very much like a capacitor in parallel with a depleting current source, whose current drain is proportional to the amount of light on the LED: the higher the light, the larger the depleting current, and the sooner the initial voltage on the (LED) capacitor will be depleted.

so if you charge up a LED in reverse, and start to measure its voltage, it will gradually go down. so you put a loop on the mcu, incrementing a variable, exiting the loop when the voltage on the led is too low.

Basically, the same idea as the capacitive sensing idea before, :)

I will post the code later when I get a minute.

出0入0汤圆

 楼主| 发表于 2010-5-30 04:17:37 | 显示全部楼层
here is the code.

=========code==============
#include <htc.h>
#include <string.h>
#include "lcd_3wi.h"
#include "delay.h"

__CONFIG(MCLRDIS & WDTDIS & BORDIS & PWRTEN & INTIO);

#define LED_PORT                PORTA                //leds on porta
#define LED_A                        (1<<5)                //anode on pin0
#define LED_K                        (1<<4)                //cathode on pin2
#define LED_SET(bits)        LED_PORT |= (bits)        //set bits
#define LED_CLR(bits)        LED_PORT &=~(bits)        //clear bits
#define LED_FLP(bits)        LED_PORT ^= (bits)        //flip bits
#define LED_IN(bits)        TRISA |= (bits)                //bits as input
#define LED_OUT(bits)        TRISA &=~(bits)                //bits as output
#define LED_EMIT(a, k)        LED_OUT((a) | (k)), LED_SET(a), LED_CLR(k)        //forward bias the led
#define LED_CHARGE(a, k)        LED_OUT((a) | (k)), LED_CLR(a), LED_SET(k);                        //reverse charge up the led. led is off
#define LED_DISCHARGE(a, k)        LED_OUT(a), LED_CLR(a), LED_IN(k);                         //discharge the led
#define LED_MAX_COUNT        0xff                                //max cycle count for the led_detect() routine
#define LED_PRESSED                0x1f                                //if count more than LEd_PRESSED, consider the led has been pressed
#define KEY_DLY                        5                                        //key delay, 5ms
#define LED_BRIGHTNESS_BRIGHT        90                        //bright=90% dc
#define LED_BRIGHTNESS_DIM                1                        //dim=1% dc


unsigned char vRAM[17];                                //lcd buffer
const unsigned char str0[]="16F684 LEDDiode1";
const unsigned char str1[]="t   =           ";
const unsigned char key_pressed[]    ="Key     Pressed!";
const unsigned char key_not_pressed[]="Key NOT Pressed!";

unsigned long t1_count=0;

void mcu_init(void ) {                                //reset the mcu
        ANSEL=0x00;                                                //all pins gpio
        CMCON0=0x07;                                        //analog comparators off
        IRCF2=1, IRCF1=1, IRCF0=0;                //running at 4mhz
}

void ultoa(char *s, unsigned long ul, unsigned char length) {        //convert unsigned long to a string, 3 dps
        unsigned char i;
       
        i=length;
        do {
//                if (i==(length-3)) s[i--]='.';
                s[i--]=ul % 10 + '0';
                ul = ul / 10;
        } while (ul);
}

unsigned long led_detect(unsigned char led_a, unsigned char led_k) {        //return the cycle count
        unsigned long tmp;
        LED_CHARGE(led_a, led_k); delay_ms(1);                        //charge up the led
        LED_DISCHARGE(led_a, led_k);                                        //discharge the led
        tmp=0;
        while ((LED_PORT & led_k) && (tmp < LED_MAX_COUNT)) tmp++;                //wait for LED_K to fall
//        while (LED_PORT & led_k) tmp++;                //wait for LED_K to fall
//        return tmp;                                                        //return the cycle count
        return tmp>LED_PRESSED;                                //or if led ahs been pressed
}

void simple_pwm(unsigned char dc, unsigned char led_a,  unsigned char led_k) {//simple pwm. dc=0..99 percent
        unsigned char repeat, i;

        dc>>=4;                                        //dc's highest 4 bits

        for (repeat=0; repeat < LED_MAX_COUNT >> 4; repeat++) {
                LED_EMIT(led_a, led_k);                                                //turn on the led
                for (i=0, LED_EMIT(led_a, led_k); i<100; i++)
                        if (i==dc) {LED_CHARGE(led_a, led_k);}         //turn off the led;
        }
}

void
main(void)
{        unsigned long t1;
        unsigned char i=0;
        unsigned char key_flag=0;                //key not pressed initially
        mcu_init();                                                //initialize the mcu
        lcd_init();                                                //initialize the lcd
        strcpy(vRAM, str0); lcd_display(LCD_Line0, vRAM);
        while (1){
                if (led_detect(LED_A, LED_K)) {
                        key_flag ^=1;
                        delay_ms(KEY_DLY);}//flip key status
                        if (key_flag) {
                                strcpy(vRAM, key_pressed); lcd_display(LCD_Line1, vRAM);
                                simple_pwm(LED_BRIGHTNESS_BRIGHT, LED_A, LED_K);
                        }
                        else {
                                strcpy(vRAM, key_not_pressed); lcd_display(LCD_Line1, vRAM);
                                simple_pwm(LED_BRIGHTNESS_DIM, LED_A, LED_K);
                        }                       
//                LED_EMIT(LED_A, LED_K); delay_us(t1>>4);
//                simple_pwm(t1, LED_A, LED_K);
                //TODO Auto-generated main function
        }
}

=========end of code================

don't worry about the led stuff. you can comment it out.

when you touch the led, it will toggle between "bright" (90% duty cycle) and "dim" (1% duty cycle). the same principle.

出0入0汤圆

 楼主| 发表于 2010-5-30 04:20:47 | 显示全部楼层
here is the schematic.

C1(15pf) is there to simulate the junction capacitance. you don't need it in your actual circuit.

R2(10M) is there to help discharge the junction capacitance when it is very dark -- this detector has a very large range and can be extremely useful for low-lighting situation.

if you use a few of the leds, you can make this into a touch-sensitive sensor array and do a lot of interesting stuff.



(原文件名:16F684 LED Photodiode.PNG)


you see the similarity between this and the cap sensing code I posted earlier. They are roughly the same thing.

enjoy.

出0入0汤圆

发表于 2010-6-3 09:46:48 | 显示全部楼层
单纯用模拟电路是否能够构造出2楼说的效果,这是一个瞬态的过程,用MCU能够实现.我想搭一个电路做着玩(不用MCU)

出0入0汤圆

 楼主| 发表于 2010-6-4 21:09:01 | 显示全部楼层
"电压一会是220,一会是250,一会是180,一会是012V
我很头疼? "

I think it is possible.

1) you can use a capacitance meter to do that - it would be the simplest solution;

2) alternatively, you can use a square wave (555 timer for example), and apply it onto the led, in reverse bias. Then you can a nand gate to measure the time it takes for the led-capacitor to discharge. the output pulse from the nand gate would be proportional to the time it takes to discharge (or charge) the led.

出0入0汤圆

 楼主| 发表于 2010-6-4 21:18:32 | 显示全部楼层
here is a proof of concept.



(原文件名:cap sensing.PNG)


a clock signal comes in, through R1, to charge up a reverse-biased LED (C1//C2). so U1A(B)'s voltage goes up and down, gradually: higher capacitance means slower charge-up and down.

U1A(Y) goes high when one of its inputs, either the clock or U1A(B)'s voltage, goes below the threshold.

U1B takes the clock and U1A(Y) and do a nand, so its output is low when the cap is being discharged or charged, as you can see on the chart.

As a result, how low U1B(Y) stays reflects the capacitance of C1//C2: if you run U1B(Y) through a low-pass filter (R/C), the analog output voltage will reflect the capacitance of C1//C2.

when you shine a spotlight on the led, it will discharge faster, showing as smaller capacitance. when no light hits the led, it will discharge slower, showing larger capacitance.

This is essentially your capacitance meter.

the clock can be generate by a nand gate configured as a relaxation oscillator.

so all of this can be done with one hc132, :).

now, leds have very small equivalent capacitance (about 15 - 20pf). so you will need to run the clock at higher speed, like 1Khz or more. but the principle is the same.

出0入0汤圆

发表于 2010-6-5 09:57:55 | 显示全部楼层
简单的可变电容 鉴别图
和您以前的模拟LC表类似
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3911033&bbs_page_no=1&search_mode=3&search_text=millwood0&bbs_id=9999
多谢指教
millwood0 老大,能否更新一下你的邮件信息,有问题好发邮件向您请教

(原文件名:TM截图未命名.jpg)

出0入0汤圆

 楼主| 发表于 2010-6-6 02:55:58 | 显示全部楼层
yes, that's the same principle: generating a pulse whose width is related to the capacitor's charging / discharging.

出0入0汤圆

发表于 2011-11-8 22:38:21 | 显示全部楼层
Mark~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-21 00:00

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表