This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Capacitance meter

Other Parts Discussed in Thread: MSP430G2131

Hi all,

I would like to create a capacitance meter with my MSP430G2 (launchpad) using CCS v6. I found this article on the Arduino pages:

http://arduino.cc/en/pmwiki.php?n=Tutorial/CapacitanceMeter

It sound like a really simple approach, But I did some more research and I found people telling to use a comparator.

What is the best approach when high accuracy is not that important and (low) power is important?

Im still a beginner, so sorry for stupid questions in advance!

Thanks!

  • If you go to the TIDesigns page: http://www.ti.com/tidesigns and search for “Capacitive” or “Capacitive Touch” download one (or more) of the projects and study the documentation.

  • Thanks for your reply. I've found some nice samples. 

    But it looks like a lot is based (or applied) for (human) touch. I just want to measure capacitance in a very plain and simple way. Measure capacitance of (wet) soil.

    I found the following article and i've created it on my MSP430. 

    http://wordpress.codewrite.co.uk/pic/2014/01/21/cap-meter-with-arduino-uno/

    ...And it looks like, its working! :)

    My question basically was/is; (1) is this a good approach? Do I need a timer? (2) Can I directly connect such capacitor on my MSP430 pin (max 2mA)?

  • I hope you get the right documents how are describing the several ways to measure a capacitance.

    The “Capacitive Touch” is in principle the same as your Arduino project. The “Capacitive Touch” measures the capacitance of the PCB dielectric –which changes when an object (finger) nears the PCB- mostly with the RC method. The Arduino project creates a voltage divider.

    The accuracy of the measurements depends on the accuracy of the used reference.

     

    The Arduino way is a possible way, only the used voltage needs to be in the range of your MSP (3.3V) then you also will not reach the maximum allowed current of your port pin.

  • Hi,

    Thanks for your reply. I'm still struggling with my capacitance meter (for weeks now! :) ). Maybe someone could help me out.

    I have the following setup, read ADC10 on P1.1 after setting P1.4 high.

    [P1.4] ------------>|| CT

    [P1.1] <------------|| 20pF ------------ GND

     

    I would like to measure CT using the following formula: "(adcValue * 20.0f) / (1023 - adcValue)".

    But my readings doesn't make any sense! I tried with 100pf, 50pf, 10pf. But the readings are stuck around 950 raw value with sometimes random peaks.

    ADC10 Init code:

    ADC10CTL1 = INCH_1;
    ADC10CTL0 = ADC10ON + ADC10IE;
    ADC10AE0 |= PinCapacitance;

    ADC10 read code:

    ADC10CTL0 &= ~ENC;
    while (ADC10CTL1 & BUSY) {  }
    int adcValue = ADC10MEM;
    ADC10CTL0 |= ENC + ADC10SC;

    Any ideas? Thanks!

  • This is roughly the equivalent of your measurement;

    Your Read code looks a little bit strange to me. You disable conversion, wait, read ADC result and start conversion. I think the order should be: enable and start conversion, wait till ready, read ADC result and disable conversion.

  • Hi Leo,

    Thanks for your quick reply.

    Yes, the scheme looks like something I work with. The only thing is; I set P1.4 to HIGH, and Cref is only connected to ground. I'm using a "msp430g2131"

    P1.4 --------> || CT --------[P1.1]--------|| Cref -----------GND

    Oops, you are right about the code. I was moving code lines/part to find the issue. It looks like it didn't make any (visual) difference.

    For instance when I remove CT (and P1.4 becomes floating) I get almost the same ADC reading, around 920. How is that possible? Is it not sensitive enough?

    Do you have a code sample? Any suggestions?

    ...or is there any better approach?

    Thanks a lot.

  • As already told there are at least two ways to measure the capacitance: the CC and RC way. The Arduino links show’s you both ways. I’ve not much experience with them but I think both way’s must be possible, but each with their own difficulties.
    Now you are on the CC way and for now I would stay here.

    I gave you the schematic equivalent of your way to give you an idea what you are doing and to realize that the ADC already contains a capacitor and also resistors which you have to include in your measurement result. Also when using a breadboard realize this has a very high capacitance and low resistance.
    All these capacitances and resistances are unknown and need to be explored experimental.
    It looks like the resistance of the ADC is not related to ground but somewhere between Vcc and ground which results in a default reading of ~920 when all capacitors are charged.

    What I’m not seeing in your setup is how do you discharge all the capacitors prior to start a high pulse and start the measurement.

    Measuring this low capacitances you need also to discharge the ADC capacitor, which requires you to use a second analogue port (let’s say P1.2) in parallel connected to the ADC input port/channel (P1.1).

    The software should like this;
    Setup:
    • Setup ADC as you already have (including channel)
    • AE on for port P1.1

    Prepare measuring:
    • P1.4 Output Low
    • P1.2 Output Low
    • P1.2 disable AE (AE=0)
    • Wait, let’s say 1mS to discharge

    Start measuring, everything immediately after each other:
    • Enable and Start ADC conversion (sampling)
    • P1.2 AE on (AE=1)
    • P1.4 Output High
    • Wait for ADC ready
    • Read ADC result

    To protect your MCU port pins when changing CT, I would end with:
    • P1.4 Output Low
    • P1.2 Output Low
    • P1.2 disable AE (AE=0)
    But anyhow be aware that your capacitors are not charged with high voltages prior to connect. Also you can add a small, 100-1,000 Ohm, resistor in series to your port pins when using this small capacitors.
  • Hoi!

    Thanks again for your detailed reply and your time. I really appreciate your help.

    I tried to create the setup you suggested. See image!

    I use the following ports:

    • P1.1 for Measurement
    • P1.2 for Discharge (adc)
    • P1.4 for Charge

    This code for ADC setup:

    ADC10CTL1 = INCH_1;             // A1
    ADC10CTL0 = ADC10ON + ADC10IE;	// ADC10 On + Interrupt
    ADC10AE0 |= PinCapacitance;     // P1.1 ADC10 option select

    The following code for reading (in a while(1)-loop):

    // 1) Prepare for measure (discharge)
    P1DIR &= ~PinCapacitance;
    P1OUT &= ~PinDischarge;		// Make Discharge pin low
    P1OUT &= ~PinCharge;		// Make Charge pin low
    ADC10AE0 &= ~PinDischarge;	// Disable AE
    sleep(10000);
    
    // 2) Measure
    ADC10CTL0 |= ENC + ADC10SC;	// Enable ADC
    ADC10AE0 |= PinDischarge;	// Enable AE
    P1OUT |= PinCharge;		// Make Charge pin high
    while (ADC10CTL1 & BUSY) { }    // Wait for ADC
    adcValue = ADC10MEM;		// Read results
    ADC10CTL0 &= ~ENC;		// Disable conversion
    
    // 3) Clean
    P1OUT &= ~PinCharge;		// Make Charge pin low
    P1OUT &= ~PinDischarge;		// Make Discharge pin low
    ADC10AE0 &= ~PinDischarge;	// Disable AE

    The results:

    CT = *nothing*, CRef = 20pF, ADC = 916
    CT = 10pF, CRef = 20pF, ADC = 921
    CT = 20pF, CRef = 20pF, ADC = 928
    CT = 40pF, CRef = 20pF, ADC = 935
    CT = 100pF, CRef = 20pF, ADC = 955
    CT = 1nF, CRef = 20pF, ADC = 1020

    CT = 100pF, CRef = 10pF, ADC = 954
    CT = 40pF, CRef = 100pF, ADC = 961

    My questions:

    1) First of all, did I miss something in my setup or code?

    2) How I can stretch the values more? From 0..1023 (instead of 916..1021)?

    3) Is it possible to create a function out of these readings?

    4) Touching the CT capacitor doen't make any (visible) difference in the readings. Is that because of the limited reading-range?

    4) I'm measuring the ADC value in the CCS debugger (after measurement), does it influence the outcome?

    5) Currently i'm working with ceramic disc capacitors. 

    Thanks!!

  • One quick note for now.

    You are enable ADC interrupts but doesn’t have an ISR for it, this can lead to a crash. Remove the ‘ADC10IE’.

    You have a changing reading according to the changed capacitor values, that already an improvement. But, agree, the readings are too high.
    For the CT=40p & Cref=100p it should be about 258.

    Do a test: Leave the Charge/Discharge ports low (P1.2 & P1.4) and start a ADC conversion.
    The result must be ‘0’. If not you probably have a analogue ground problem. Check if your analogue ground (to Cref) is not shared with the Vss wire but directly connected (closest) to the MCU Vss pin.
  • Quick reply;

    I've not pasted all my code, but I have an interrupt:

    #pragma vector = ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
      __bic_SR_register_on_exit(CPUOFF);
    }

    I'll try that test; i'll keep ya posted!

  • I looks like when I keep P1.2 & P1.4 LOW the adc-value is also 915 and not the expected zero!

    The Cref is directly connected to the GND (pin14) of my MSP430.

    So, maybe there was (already) something not correctly configured. Any ideas?
  • Analyzing your measurement values it looks like you have enabled the internal Pull-Up on P1.1 or P1.2!

  • Didn’t see your last post.
    This is weird, and can’t have to do with a pull-up, however the value fits with it.
    What voltage do you measure at the ADC pin?
  • Pull-up looks like disabled: P1REN = 0x00

    According to my multi-meter it's around 3.55V (USB powered launchpad)

    Just to make sure: When I directly connect my P1.1 to GND it read the expected ~0, and when connected to VCC it reads ~1023.

    So, I have the feeling it's some stupid setting I can't find! :)

    My GPIO setup:
    P1DIR = 0xFF;
    P1OUT = 0;
    P2DIR = 0xFF;
    P2OUT = 0;

    P1DIR &= ~PinCapacitance;
    P1DIR |= PinCharge;
    P1DIR &= ~PinDischarge;

    P1OUT &= ~PinCapacitance;
    P1OUT &= ~PinCharge;
    P1OUT &= ~PinDischarge;

  • Can you post your whole code, so it’s difficult for me to see what could be wrong.
  • Hehe, yes I can imagine. My current code looks like this:

    #include <msp430.h> 
    
    //Defines
    #define PinLedGreen 	BIT6				// 1.6
    #define PinLedRed 		BIT0				// 1.0
    #define PinCapacitance	BIT1				// 1.1
    #define PinDischarge		BIT2 				// 1.2
    #define PinCharge 		BIT4 				// 1.4
    
    int adcValue = 0;
    
    int main(void)
    {
             // Initialize
    	 WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
    	 P1DIR = 0xFF;                             // All P1.x outputs
    	 P1OUT = 0;                                	// All P1.x reset
    	 P2DIR = 0xFF;                             // All P2.x outputs
    	 P2OUT = 0;                                	// All P2.x reset
    
    	 //Gpio's
    	 P1DIR |= PinLedGreen + PinLedRed; 	// Output
    	 P1DIR &= ~PinCapacitance;
    	 P1DIR |= PinCharge;
    	 P1DIR &= ~PinDischarge;
    
    	 P1OUT &= ~PinLedGreen;
    	 P1OUT &= ~PinCapacitance;
    	 P1OUT &= ~PinLedRed;
    	 P1OUT &= ~PinCharge;
    	 P1OUT &= ~PinDischarge;
    
    	 //Analog
    	 ADC10CTL1 = INCH_1;               	                // A1
    	 ADC10CTL0 = ADC10ON + ADC10IE;		// ADC10 On + Interrupt
    	 ADC10AE0 |= PinCapacitance;                      // P1.1 ADC10 option select
    
        while (1)
        {
        	P1OUT &= ~PinLedRed;
        	P1OUT &= ~PinLedGreen;
    
        	// 1) Prepare for measure (discharge)
        	P1OUT &= ~PinDischarge;						// Make Discharge pin low
        	P1OUT &= ~PinCharge;						// Make Charge pin low
        	ADC10AE0 &= ~PinDischarge;					// Disable AE
        	__delay_cycles(100000);
        	// 2) Measure
        	ADC10CTL0 |= ENC + ADC10SC;					// Enable ADC
        	ADC10AE0 |= PinDischarge;					// Enable AE
        	P1OUT |= PinCharge;							// Make Charge pin high
        	P1OUT |= PinDischarge;						// Make Discharge pin high
    	while (ADC10CTL1 & BUSY) { }    			// Wait for ADC
    	adcValue = ADC10MEM;						// Read results
    	ADC10CTL0 &= ~ENC;							// Disable conversion
    
        	// 3) Clean
          	P1OUT &= ~PinCharge;		// Make Charge pin low
          	P1OUT &= ~PinDischarge;		// Make Discharge pin low
          	ADC10AE0 &= ~PinDischarge;	// Disable AE
    
    	// 4) Result
    	if (adcValue < 975) //I Measured the ADC value here!
    	{
    	P1OUT |= PinLedRed;
    	}
    	else
    	{
    	P1OUT |= PinLedGreen;
    	}
    	__delay_cycles(1000000);
        }
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////////
    #pragma vector = ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    
    }
    
    
    #pragma vector=TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    {
    
    }
    

  • There are a few unnecessary lines but for now they don’t harm.
    You are probably using the G2-Launchpad. Then remove the jumpers TxD & RxD, and try again.
  • I removed the 2 jumpers (TxD and RxD).

    What happens?! I get rather random values around 20..180 for (CT=100pF, Cref=20pF). I don't get it (yet)?

    Yes, some unnecessary lines, I have to clean it (getting a messy here).
  • Ok, but now you have solved the base of the problem.

    You are using very low capacitors, the influence of the wiring and also now your finger/hand will be big.

    First now try to get a stable reading/software with lager capacitors, let’s say a Cref from 1n till 100n, to reduce the influence of the pin and ADC capacitance.

    Maybe extending the ADC sample time can help.
    Or the order of the lines under ‘Measure’, maybe start conversion after setting the port’s.
  • Cool! You are a hero! I should buy you a beer! ;)

    btw: how did the TxD/RxD jumpers help me here? What did they block?


    I'm going to play around with this (difference caps sizes / times). Thanks a lot!

  • KiwiFreaK said:
    I should buy you a beer!

    Sounds good! When you have a good local beer, put it already in fridge for the case I’m maybe in the near.

    Port 1.1 (RxD) and 1.2 (TxD) are, via jumpers, connected to the emulator chip to provide UART serial connection via USB.

    When you have finished your software with calculation to a Capacitance value, you could post here the final result as a “MSP430 Capacitance Meter project”.

    You need to calibrate the system. If you use 100p capacitors for each CT and Cref you should read 512, but it will be lower. The difference is the wire, port and ADC capacitance, this you can calculate now and name it for example Csystem. From each capacitance calculation you have to deduct this value.

    Measuring these low capacitor values it’s possible that your AC line power have some influence. This you can compensate by measuring multiple times within your AC cycle time (50Hz=20mS, 60Hz=16.667mS) and average the value.

**Attention** This is a public forum