Jump to content
Sign in to follow this  
maelli01

micropower microvoltmeter with MSP430FR4133 and MCP3422 ADC

Recommended Posts

Weekend-project:

Autoranging microvoltmeter based on the MSP430FR4133 launchpad.

ADC used: MIcrochip MCP3422, an 18bit, 3.75 sample/second Sigma Delta with 2 differential inputs. I2C interface

This nice little chip contains a programmable amplifier (x2,x4,x8) and a not-too-bad internal reference of 2.048V.

Max input range is +/-2.048V, resolution (8x amplified) is 2uV.

 

Hand-etched a single layer PCB which goes on top of Launchpad.

 

 

post-37272-0-47232300-1487772319_thumb.jpg

Type K cable in hot water: 2.93mV, 73Kelvin temp difference to ambient

 

 

post-37272-0-03080400-1487772415_thumb.jpg

compare with my Fluke 289, 0.06% (datasheet says 0.05% typical, 0.35% max)

Not too shabby for a chip that costs 3 bucks.

 

 

post-37272-0-60423900-1487772489_thumb.jpg

Current consumption: on average <40uA, the whole setup would run 5000hours from a CR2032

The ADC does 1 sample/second and sleeps the rest of the time, the MSP430 does what it likes the most: sleep in LPM3

 

 

Code is not a big deal, quick hack based on the FR4133 examples, for the LCD and for the I2C interface 

//microvolt meter with MCP3422 and MSP430FR413
//******************************************************************************
#include <msp430.h> 
#define LCDMEMW ((int*)LCDMEM)

#define pos1 4                                               // Digit A1 - L4
#define pos2 6                                               // Digit A2 - L6
#define pos3 8                                               // Digit A3 - L8
#define pos4 10                                              // Digit A4 - L10
#define pos5 2                                               // Digit A5 - L2
#define pos6 18                                              // Digit A6 - L18

const char digit[10] ={
    0xFC,                                                    // "0"
    0x60,                                                    // "1"
    0xDB,                                                    // "2"
    0xF3,                                                    // "3"
    0x67,                                                    // "4"
    0xB7,                                                    // "5"
    0xBF,                                                    // "6"
    0xE0,                                                    // "7"
    0xFF,                                                    // "8"
    0xF7                                                     // "9"
};

volatile long voltage;
unsigned long dvoltage;
unsigned char TXByteCtr;
unsigned char TXData;
unsigned char newgain,gain;

void Clear_LCD(){
	int i;
	for(i=5;i;i--) LCDMEMW[i]=0;
	LCDMEMW[9]=0;
}

int main( void )
{
    WDTCTL = WDTPW | WDTHOLD;                               // Stop watchdog timer

    P1OUT = 0x00;P2OUT = 0x00;P3OUT = 0x00;P4OUT = 0x00;
    P5OUT = 0x00;P6OUT = 0x00;P7OUT = 0x00;P8OUT = 0x00;

    P1DIR = 0xFF;P2DIR = 0xFF;P3DIR = 0xFF;P4DIR = 0xFF;
    P5DIR = 0xFF;P6DIR = 0xFF;P7DIR = 0xFF;P8DIR = 0xFF;

    P5SEL0 |= BIT2 | BIT3;                   // I2C pins

    // Configure XT1 oscillator
    P4SEL0 |= BIT1 | BIT2;                              // P4.2~P4.1: crystal pins
    do  {
        CSCTL7 &= ~(XT1OFFG | DCOFFG);                  // Clear XT1 and DCO fault flag
        SFRIFG1 &= ~OFIFG;
    }
    while (SFRIFG1 & OFIFG);                           // Test oscillator fault flag

    // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    CSCTL4 = SELMS__DCOCLKDIV + SELA__XT1CLK;  			// MCLK=SMCLK=DCO; ACLK=XT1

    // Configure RTC
    RTCCTL |= RTCSS__XT1CLK | RTCIE;                    // Initialize RTC to use XT1 and enable RTC interrupt
    RTCMOD = 16384;                                     // Set RTC modulo to 16384 to trigger interrupt twice a second

    // Configure LCD pins
    SYSCFG2 |= LCDPCTL;                                 // R13/R23/R33/LCDCAP0/LCDCAP1 pins selected

    LCDPCTL0 = 0xFFFF;
    LCDPCTL1 = 0x07FF;
    LCDPCTL2 = 0x00F0;                                  // L0~L26 & L36~L39 pins selected

    LCDCTL0 = LCDSSEL_0 | LCDDIV_7;                     // flcd ref freq is xtclk

    // LCD Operation - Mode 3, internal 3.08v, charge pump 256Hz
    LCDVCTL = LCDCPEN | LCDREFEN | VLCD_5 | (LCDCPFSEL0 | LCDCPFSEL1 | LCDCPFSEL2 | LCDCPFSEL3);

    LCDMEMCTL |= LCDCLRM;                               // Clear LCD memory

    LCDCSSEL0 = 0x000F;                                 // Configure COMs and SEGs
    LCDCSSEL1 = 0x0000;                                 // L0, L1, L2, L3: COM pins
    LCDCSSEL2 = 0x0000;

    LCDM0 = 0x21;                                       // L0 = COM0, L1 = COM1
    LCDM1 = 0x84;                                       // L2 = COM2, L3 = COM3

    LCDCTL0 |= LCD4MUX | LCDON;                         // Turn on LCD, 4-mux selected (LCD4MUX also includes LCDSON)

    Clear_LCD();

    // Configure USCI_B0 for I2C mode
    UCB0CTLW0 |= UCSWRST;                   		// Software reset enabled
    UCB0CTLW0 |= UCMODE_3 | UCMST | UCSYNC; 		// I2C mode, Master mode, sync
    UCB0CTLW1 |= UCASTP_2;                  		// Automatic stop generated
                                              	  	// after UCB0TBCNT is reached
    UCB0BRW = 0x0008;                         		// baudrate = SMCLK / 8

    UCB0I2CSA = 0x0068;                     		// Slave address
    UCB0CTL1 &= ~UCSWRST;
    UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE | UCTXIE0;



    while(1){
   // 	P1OUT |= BIT0;
    	TXByteCtr = 1;                              // Load TX byte counter
    	TXData = 0x8C+gain;
    	while (UCB0CTLW0 & UCTXSTP);                // Ensure stop condition got sent
    	UCB0CTLW0 |= UCTR | UCTXSTT;                // I2C TX, start condition
   // 	P1OUT &= ~BIT0;
    	__bis_SR_register(LPM3_bits | GIE);         // timer will wake me up

  //  	P1OUT |= BIT0;
        UCB0TBCNT = 0x0003;                     	// 3 bytes to be received
    	voltage=0;
    	UCB0CTLW0 &= ~UCTR;
        while (UCB0CTL1 & UCTXSTP);         		// Ensure stop condition got sent
        UCB0CTL1 |= UCTXSTT;                		// I2C start condition
        __bis_SR_register(LPM3_bits | GIE);			// I2C irq will wake me up

        voltage<<=8;					// shift to left corner to do the sign correctly
        voltage/=32;				        // calibration is done here: 2048 in an ideal world
        if ((voltage<400000)&&(voltage>(-400000))){     // autoranging, downshift
        	if (newgain<3) newgain++;
        }
        if ((voltage>1000000)||(voltage<-1000000)){     // autoranging, upshift
        	if (newgain) newgain--;
        }
        voltage>>=gain;
        gain=newgain;
        if ((voltage<500000)&&(voltage>-500000)){
        	voltage*=10;							//low range
        	LCDMEM[11]&=~1;							//adjust decimal point
        	LCDMEM[9]|=1;
        }
        else{									//high range
        	LCDMEM[9]&=~1;							//adjust decimal point
        	LCDMEM[11]|=1;
        }
        voltage*=25;
        voltage/=128;

        if (voltage<0)	 {dvoltage=-voltage; LCDMEM[5]|=4 ;}	//negative
        else		 {dvoltage= voltage; LCDMEM[5]&=~4;}	//positive

      	LCDMEM[pos1] = digit[(dvoltage / 100000)%10];
       	LCDMEM[pos2] = digit[(dvoltage / 10000)%10];
   	LCDMEM[pos3] = digit[(dvoltage / 1000)%10];
        LCDMEM[pos4] = digit[(dvoltage / 100)%10];
   	LCDMEM[pos5] = digit[(dvoltage / 10)%10];
   	LCDMEM[pos6] = digit[dvoltage % 10];
   //	P1OUT &= ~BIT0;
   	__bis_SR_register(LPM3_bits | GIE);         // timer will wake me up
    }
}



#pragma vector = RTC_VECTOR
__interrupt void RTC_ISR(void){
    switch(__even_in_range(RTCIV, RTCIV_RTCIF)){
        case  RTCIV_NONE:   break;          // No interrupt
        case  RTCIV_RTCIF:                  // RTC Overflow
       __bic_SR_register_on_exit(LPM3_bits);
            				break;
        default: 			break;
    }
}

#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void){
  switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)){
    case USCI_NONE:          break;         // Vector 0: No interrupts
    case USCI_I2C_UCALIFG:   break;         // Vector 2: ALIFG
    case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
        UCB0CTL1 |= UCTXSTT;                  // I2C start condition
      	  	  	  	  	  	 break;
    case USCI_I2C_UCSTTIFG:  break;         // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG:  break;         // Vector 8: STPIFG
    case USCI_I2C_UCRXIFG3:  break;         // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3:  break;         // Vector 14: TXIFG3
    case USCI_I2C_UCRXIFG2:  break;         // Vector 16: RXIFG2
    case USCI_I2C_UCTXIFG2:  break;         // Vector 18: TXIFG2
    case USCI_I2C_UCRXIFG1:  break;         // Vector 20: RXIFG1
    case USCI_I2C_UCTXIFG1:  break;         // Vector 22: TXIFG1
    case USCI_I2C_UCRXIFG0:                 // Vector 24: RXIFG0
        voltage=(voltage<<8)+UCB0RXBUF;
      	  	  	  	  	     break;
    case USCI_I2C_UCTXIFG0:		    // Vector 26: TXIFG0
        if (TXByteCtr){                     // Check TX byte counter
            UCB0TXBUF = TXData; // Load TX buffer
            TXByteCtr--;                    // Decrement TX byte counter
        }
        else{
            UCB0CTLW0 |= UCTXSTP;           // I2C stop condition
            UCB0IFG &= ~UCTXIFG;            // Clear USCI_B0 TX int flag
        }
        					 break;
    case USCI_I2C_UCBCNTIFG:                // Vector 28: BCNTIFG
        __bic_SR_register_on_exit(LPM3_bits);
        					 break;
    case USCI_I2C_UCCLTOIFG: break;         // Vector 30: clock low timeout
    case USCI_I2C_UCBIT9IFG: break;         // Vector 32: 9th bit
    default: break;
  }
}

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...