Get Adobe Flash player
FacebookTwitterGoogle+
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

In the late-1800s, Nikola Tesla pioneered the generation, transmission, and use of alternating current (AC) electricity, which can be transmitted over much greater distances than direct current. Tesla's inventions used electricity to bring indoor lighting to our homes and to power industrial machines.
 

Help us stay online:

small donate

IMG 0003This is 100% functional and checked complete project for usage of CSM capacitive sensing module on PIC16F707 microcontroller. For better understanding code provided I recommend you to read Complete guide trough mTouch capacitive sensing by using CSM module inside Microchip PIC16F707 microcontroller first. Code has many comments that make it easy to understand. Complete source code and project files can be downloaded from direct link at the bottom of this page.

 

 

Functions are divided into several .c and .h files for easier understanding. These files are:

"DAC.c", "main.c", "mTouch.c", "TMR1.c", "TMR3.c", "UART.c", "DAC.h", "mTouch.h", "TMR1.h", "TMR3.h" and "UART.c"

In "*.h" files are located definitions of constants and predefined function parameters for easier calls of the functions. Now we will list and say few words about most important functions that are used to work with CSM module.

 

void init_CPSA (char State, char ABchannel, char Current, char CSchannel) is used to configure work of CPSA CSM module. It has few parameters for easy module configurability.

State – turns CSM CPSA module on or off

It accepts parameters predefined in "mTouch.h"

#define ON 1
#define OFF 0

ABchannel- this should choose if CPSA or CPSB is used but at the moment it has no function since this part of the code is not yet written.

Current- Configures which current is used. It also accept parameters predefined in "mTouch.h" These parameters are:

#define OFF 0
#define NOISEDETECTION 1
#define uA0d1 2
#define uA1d2 3
#define uA9 4
#define uA18 5
#define uA30 6
#define uA100 7

CSchannel - choose which channel we are measuring. It accepts values 0-15

Here is complete code of this function:

void init_CPSA (char State, char ABchannel, char Current, char CSchannel)
{
CPSAON=State;
//CPSxON: Capacitive Sensing Module Enable bit
//1 = Capacitive sensing module is enabled
//0 = Capacitive sensing module is disabled
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
switch (Current)
{
case OFF:
CPSARM=0;
CPSARNG0=0;
CPSARNG1=0;
break;
case NOISEDETECTION:
CPSARM=1;
CPSARNG0=0;
CPSARNG1=0;
break;
case uA0d1:
CPSARM=0;
CPSARNG0=1;
CPSARNG1=0;
break;
case uA1d2:
CPSARM=0;
CPSARNG0=0;
CPSARNG1=1;
break;
case uA9:
CPSARM=1;
CPSARNG0=1;
CPSARNG1=0;
break;
case uA18:
CPSARM=0;
CPSARNG0=1;
CPSARNG1=1;
break;
case uA30:
CPSARM=1;
CPSARNG0=0;
CPSARNG1=1;
break;
case uA100:
CPSARM=1;
CPSARNG0=1;
CPSARNG1=1;
break;
default:
CPSARM=0;
CPSARNG0=0;
CPSARNG1=0;
}
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
//CPSxRM: Capacitive Sensing Reference Mode bit
//1 = Capacitive sensing module is in high range. DAC and FVR provide oscillator voltage references.
//0 = Capacitive sensing module is in low range. Internal oscillator voltage references are used.
//If CPSxRM = 0 (low range):
//11 = Oscillator is in high range: Charge/discharge current is nominally 18 µA.
//10 = Oscillator is in medium range. Charge/discharge current is nominally 1.2 µA.
//01 = Oscillator is in low range. Charge/discharge current is nominally 0.1 µA.
//00 = Oscillator is off.
//If CPSxRM = 1 (high range):
//11 = Oscillator is in high range: Charge/discharge current is nominally 100 µA.
//10 = Oscillator is in medium range. Charge/discharge current is nominally 30 µA.
//01 = Oscillator is in low range. Charge/discharge current is nominally 9 µA.
//00 =Oscillator is on; Noise Detection mode; No charge/discharge current is supplied.
if (CSchannel<16)
CPSACON1=CSchannel;
else
CPSACON1=0;
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
//CPSxCH<3:0>: Capacitive Sensing Channel Select bits
//If CPSxON = 0:
//These bits are ignored. No channel is selected.
//If CPSxON = 1:
//0000 = channel 0, (CPSx0)
//0001 = channel 1, (CPSx1)
//0010 = channel 2, (CPSx2)
//0011 = channel 3, (CPSx3)
//0100 = channel 4, (CPSx4)
//0101 = channel 5, (CPSx5)
//0110 = channel 6, (CPSx6)
//0111 = channel 7, (CPSx7)
//1000 = channel 8, (CPSx8)
//1001 = channel 9, (CPSx9)
//1010 = channel 10, (CPSx10)
//1011 = channel 11, (CPSx11)
//1100 = channel 12, (CPSx12)
//1101 = channel 13, (CPSx13)
//1110 = channel 14, (CPSx14)
//1111 = channel 15, (CPSx15)
//timer 1 clock input is mTouch module output (this can be done in timer1 initialization)
TMRCS0=1;
TMRCS1=1;
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
//SetDAT(DACvalue);//should be set separately
//det DAC value that will be used as negative voltage limit
//for change of current sources of CS module. Positive reference will be FVR
//applicable only in high range currents 9uA, 30uA and 100uA
}

Function "init_timer1()" initialize Timer1 to work count oscillation number of CSM oscillator whose frequency depends on read capacitance.

Its code is provided below:

void init_timer1(void)
{
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
TMRCS0=1;
TMRCS1=1;
//TMRxCS<1:0>: Timerx Clock Source Select bits
//11 =Timerx clock source is Capacitive Sensing Oscillator (CPSxOSC)
//10 =Timerx clock source is pin or oscillator:
//If T1OSCEN = 0:
//External clock from TxCKI pin (on the rising edge)
//If T1OSCEN = 1:
//Crystal oscillator on T1OSI/T1OSO pins
//01 =Timerx clock source is system clock (FOSC)
//00 =Timerx clock source is instruction clock (FOSC/4)
T1CKPS0=0;
T1CKPS1=0;
//TxCKPS<1:0>: Timerx Input Clock Prescale Select bits
//11 = 1:8 Prescale value
//10 = 1:4 Prescale value
//01 = 1:2 Prescale value
//00 = 1:1 Prescale value
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
T1OSCEN=0;
//bit 3 T1OSCEN: LP Oscillator Enable Control bit(1)
//1 = Dedicated Timer1/3 oscillator circuit enabled
//0 = Dedicated Timer1/3 oscillator circuit disabled
T1SYNC=1;
//bit 2 TxSYNC: Timerx External Clock Input Synchronization Control bit
//If TMRxCS<1:0> = 1X
//1 = Do not synchronize external clock input
//0 = Synchronize external clock input with system clock (FOSC)
//If TMRxCS<1:0> = 0X
//This bit is ignored. Timerx uses the internal clock when TMR1CS<1:0> = 0X.
TMR1ON=1;
//TMRxON: Timerx on bit
//1 = Enables Timerx
//0 = Stops Timerx
//Clears Timerx gate flip-flop
TMR1GE=0;
//TMRxGE: Timerx Gate Enable bit
///If TMRxON = 0:
//This bit is ignored.
//If TMRxON = 1:
//1 = Timerx counting is controlled by the Timerx gate function
//0 = Timerx counts regardless of Timerx gate function
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
TMR1ON=1;
//• TMRxON bit of the TxCON register turns ON/OFF TMR1 module operation
TMR1IE=1;
//• TMRxIE bit of the PIEx register enables TMR1 interrupt
PEIE=1;
//• PEIE bit of the INTCON register enables peripherals to have interrupts
GIE=1;
//• GIE bit of the INTCON register enables global microcontroller interrupts
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
}

Timer3 is used in standard time measuring mode so we will not discuss it here further.

When used in HIGH current range CSM oscillator uses voltage references from FVR and DAC so we have to configure them too. This is done with functions:

SetFVR(ON,X4,OFF);

DAC_init(ON,POSITIVE_PIN,ENABLE,FVR,20);

With accepting parameters defined in "DAC.h"

#define ON 1
#define OFF 0
#define NEGATIVE_PIN 0
#define POSITIVE_PIN 1
#define ENABLE 1
#define DISABLE 0
#define VDD 0
#define VREF 1
#define FVR 2
#define OFF 0
#define X1 1
#define X2 2
#define X4 4

Source of these functions is provided below:

//this function sets DAC output value when it is already configured
void SetDAC(char DACvalue)
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
{
if (DACvalue<32)
DACCON1=DACvalue;
else
DACCON1=31;
}
void DAC_init(char State, char ReferencePin, char DacOutEnable, char RefSource, char DAC_val)
{
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
DACEN=State;
//DACEN: Digital-to-Analog Converter Enable bit
//0 = Digital-to-Analog Converter is disabled
//1 = Digital-to-Analog Converter is enabled
DACLPS=ReferencePin;
//DACLPS: DAC Low-Power Voltage State Select bit
//0 = VDAC = DAC negative reference source selected
//1 = VDAC = DAC positive reference source selected
DACOE=DacOutEnable;
//DACOE: DAC Voltage Output Enable bit
//0 = DAC voltage level is output on the DACOUT pin
//1 = DAC voltage level is disconnected from the DACOUT pin
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
switch (RefSource)
{
case VDD:
DACPSS1=0;
DACPSS0=0;
break;
case VREF:
DACPSS1=0;
DACPSS0=1;
break;
case FVR:
DACPSS1=1;
DACPSS0=0;
SetFVR(ON,X4,OFF);
break;
default:
DACPSS1=0;
DACPSS0=0;
}
//DACPSS<1:0>: DAC Positive Source Select bits
//00 = VDD
//01 = VREF
//10 = FVR Buffer 2 output
//11 = Reserved, do not use
SetDAC(DAC_val); //function is used to set DAC output value
TRISA2=0;
//making dac pin as output pin
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
ANSC2=0;
}
//this function sets FIXED VOLTAGE REFERENCE used by DAC
void SetFVR(char State, char DACreference,char ADCreference)
{
FVREN=State;
//FVREN: Fixed Voltage Reference Enable bit
//0 = Fixed Voltage Reference is disabled
//1 = Fixed Voltage Reference is enabled
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
switch (DACreference)
{
case OFF:
CDAFVR1=0;
CDAFVR0=0;
break;
case X1:
CDAFVR1=0;
CDAFVR0=1;
break;
case X2:
CDAFVR1=1;
CDAFVR0=0;
break;
case X4:
CDAFVR1=1;
CDAFVR0=1;
break;
default:
CDAFVR1=0;
CDAFVR0=0;
}
//CDAFVR<1:0>: Cap Sense and D/A Converter Fixed Voltage Reference Selection bit(2)
//00 = CSM and D/A Converter Fixed Voltage Reference Peripheral output is off.
//01 = CSM and D/A Converter Fixed Voltage Reference Peripheral output is 1x (1.024V)
//10 = CSM and D/A Converter Fixed Voltage Reference Peripheral output is 2x (2.048V)
//11 = CSM and D/A Converter Fixed Voltage Reference Peripheral output is 4x (4.096V)
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
switch (ADCreference)
{
case OFF:
ADFVR1=0;
ADFVR0=0;
break;
case X1:
ADFVR1=0;
ADFVR0=1;
break;
case X2:
ADFVR1=1;
ADFVR0=0;
break;
case X4:
ADFVR1=1;
ADFVR0=1;
break;
default:
ADFVR1=0;
ADFVR0=0;
}
//ADFVR<1:0>: A/D Converter Fixed Voltage Reference Selection bit(2)
//00 = A/D Converter Fixed Voltage Reference Peripheral output is off.
//01 = A/D Converter Fixed Voltage Reference Peripheral output is 1x (1.024V)
//10 = A/D Converter Fixed Voltage Reference Peripheral output is 2x (2.048V)
//11 = A/D Converter Fixed Voltage Reference Peripheral output is 4x (4.096V)
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
while(!FVRRDY);
//FVRRDY: Fixed Voltage Reference Ready Flag bit
//0 = Fixed Voltage Reference output is not active or stable
//1 = Fixed Voltage Reference output is ready for use
//FVRRDY is always '1' on PIC16F707 devices
//examples and more detailed explanation at complete projects section of www.Electronics-Base.com
}

"Main.c" is very simple. It uses TMR1 to count readout from CSM oscillator while using TMR3 to produce fixed time base as previously explained in Complete guide trough mTouch capacitive sensing by using CSM module inside Microchip PIC16F707 microcontroller article.

Serial port is used to write results to UART and receive command for CPSA CSM module configuration.

Complete code is listed below:

#include
#include
#include
#include
#include "UART.h"
#include "DAC.h"
#include "mTouch.h"
#include "TMR1.h"
#include"TMR3.h"
__CONFIG(WDTE_OFF&PWRTE_ON&CP_OFF&FOSC_HS_OSC&BOREN_OFF); //707 HS
unsigned char mTouchOverflow;
unsigned char MeasuringPeriodSET;
unsigned char MeasuringPeriod;
unsigned char SendingPeriodSET;
unsigned char SendingPeriod;
unsigned char mTouchOF_counter;
unsigned char DataReadyForSend;
unsigned long mTouch_counterSum;
unsigned char command_received;
unsigned int mTouch_counter;
unsigned int temp;
///////////////////////////////////////////////////////////////////////////////////////////////////////
// USART Receiver buffer
#define RX_BUFFER_SIZE 80
char rx_buffer[RX_BUFFER_SIZE];
#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif
// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;
///////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char getch(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
GIE=0;
--rx_counter;
GIE=1;
return data;
}
void interrupt isr(void)
{
/* isr code goes here */
if (TMR1IF)
{
mTouchOverflow++;
TMR1IF=0;
}
if (TMR3IF)
{
TMR3IF=0;
TMR3=47103;
//clock is 7372800Hz
//and timer source is Fosc/4 = 1843200 Hz
//if we want interrupt to ocure every 10ms timer should count up to 18432 every time
//timer is initiated to make interrupt on overflow meaning it should start from
//65535 (count on whicn it will make interrupt) - 18432 = 47103
MeasuringPeriod++;
if (MeasuringPeriod==MeasuringPeriodSET)
{
mTouch_counter=TMR1;
mTouchOF_counter=mTouchOverflow;
TMR1=0;
mTouchOverflow=0;
MeasuringPeriod=0;
}
SendingPeriod++;
if (SendingPeriod==SendingPeriodSET)
{
SendingPeriod=0;
DataReadyForSend=1;
}
}
if(RCIF)
{
RCIF=0;
char status,data;
data=RCREG;
if (FERR||OERR)
{
CREN=0;
CREN=1;
}
else
{
if (data==13)
command_received=1;//enables parsing only if something is received
rx_buffer[rx_wr_index]=data;
if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
if (++rx_counter == RX_BUFFER_SIZE)
{
rx_counter=0;
rx_buffer_overflow=1;
}
}
}
}
void SetMeasurementInterval(unsigned char MeasureInterval)
{
MeasuringPeriodSET=MeasureInterval;
}
void SetSendingInterval(unsigned char SendingInterval)
{
SendingPeriodSET=SendingInterval;
}
void main(void)
{
unsigned int i1;
unsigned int delay1,delay2;
TRISD=0xff;
TRISB=0xff;
TRISA=0xff;
TRISB5=0;
serial_setup();
init_CPSA(ON, A, uA100,0);
init_timer1();
init_timer3();
SetFVR(ON,X4,OFF);
DAC_init(ON,POSITIVE_PIN,ENABLE,FVR,20);
SetDAC(20);
GIE=1;
MeasuringPeriodSET=100;
SendingPeriodSET=100;
while(1)
{
if(DataReadyForSend==1)
{
DataReadyForSend=0;
mTouch_counterSum=(unsigned long) mTouchOF_counter*65535+(unsigned long) mTouch_counter;
printf("mTouch count is: %u counts and %u overflows. total counts are %ld \n ", mTouch_counter, mTouchOF_counter,mTouch_counterSum);
putch(13);
}
if (command_received) //code executes only if conmmand ending with enter is received
{
//command format detailed specification is available and www.electronics-base.com
//rx_buffer[4] is ON/OFF 0-1
//rx_buffer[8] is curent 0-7
//rx_buffer[10] is channel 0-15
//rx_buffer[12] is DACreferencevalue 0-31
//rx_buffer[14] is measurement interval x10ms
//rx_buffer[16] is sending interval x10ms
putch(13);
printf("command received is ON/OFF %d ,Current selected is %d ,Channel %d ,DACrefValue %d ,Measurement interval %d0ms, Sending interval %d0 ms", rx_buffer[4], rx_buffer[8], rx_buffer[10], rx_buffer[12], rx_buffer[14], rx_buffer[16]);
SetSendingInterval(rx_buffer[16]);
SetMeasurementInterval(rx_buffer[14]);
init_CPSA(rx_buffer[4], A, rx_buffer[8],rx_buffer[10]);
SetDAC(rx_buffer[12]);
putch(13);
putch(13);
command_received=0;
for(unsigned char i=0;i<rx_buffer_size-1;i++)< p="">
rx_buffer[i]=0;
rx_counter=0;
rx_buffer_overflow=0;
rx_wr_index=0;
}
}
}

As you can see if TMR1 makes overflow before data are read it is remembered in mTouchOF_counter varable while current state of TMR1 is remembered in mTouch_counter variable.

Command that is received from UART via com port terminal - development tool has predefined format:

CPS "X1",A, "X2","X3","X4","X5","X6"

C P S A , - these are ASCII characters

X1-X6 - these are single bytes in binary format meaning its values 0,1,2 are not ASCII '0','1','2' values but decimal numbers 0,1,2

Now we will explain their meaning

X1 – ON/OFF has values

0- OFF
1- ON

X2 – CSM oscillator current has value 0-7

#define OFF 0
#define NOISEDETECTION 1
#define uA0d1 2
#define uA1d2 3
#define uA9 4
#define uA18 5
#define uA30 6
#define uA100 7

X3 – is channel selection byte and has values 0-15 for corresponding channel to be connected to CSM CPSA

X4 - is DAC reference value 0-31 that is used as Ref- voltage for CSM oscillator in HIGH RANGE if currents ONLY.

X5 - is measurement interval measured in x10ms. Defines how long measurement is preformed. It defines how many interrupts created by TMR3 microcontroller will waith before he get measurement results from TMR1. Range is 0-255

X6 - is sending interval measured in x10ms to define how many interrupts of TMR3 microcontroller will wait before data is send to UART. This was convenient thing to implement so you can change measurement interval independently of sending interval. Still you must choose measuring interval shorter or equal than sending interval. X5<=X6. Range is 0-255

Complete source code and project can be downloaded free from >>>>this link<<<<

 

Above provided code can be seen in action on video below.

 

I predefined commands on com port terminal - development tool inside macros M1-M12 Macros save file can be downloaded here.

On video1 you can see frequency is changing as we bring finger close to pad that is being read. When we remove oscilloscope probe that has input capacitance of 15pF we can see frequency increment and bigger relative change when we approach with finger.

This is compromise that you must make when designing Touch pad hardware. If you have bigger neutral capacity of the pad you will get more stable readout but relative change of finger press will be much smaller while if pad capacity is smaller it can be unstable but you will get better detection of finger approaching pad.

On second video you can see is that when we change current used by CSM frequency is changing. With note that first selected current is from LOW RANGE and has different referent voltages. It is using internal reference and for second and third selected current FVR and DAC output reference are used.

Third change is caused by increasing Ref- voltage in CSM oscillator by setting higher DAC output

 

After that it is presented that you can change measurement interval . You can see as we decrease measurement interval, number of measured counts from CSM oscillator also decreases.

 

On last video you can see sending interval being changed on command

 

Again link to download complete project with source files

 

Currently we are making small software for PC to use presented code. It will have GUI and time graph and commands for changing each of the parameters described above. I hope you like it, feel free to make comment.

 

Team of Electronics-Base.com