Other Parts Discussed in Thread: MSP430I2041
Tool/software: Code Composer Studio
Hello everyone, I'm trying to translate the Arduino Emon code library into the MSP430. Basically the code calculates the RMS voltage, RMS current, active power, reactive power and the power factor.
To simulate a signal from the ZMPT101b voltage sensor, I am using a signal generator with a 60 Hz sinusoid, as shown in the figure below:
This is my code:
#include <msp430g2553.h> #include <stdlib.h> //Use for rand() function #include <stdio.h> #include <string.h> #include <stdbool.h> #include <math.h> #define ADC_BITS 10 #define ADC_COUNTS (1<<ADC_BITS) const int TIPO_TC = 0; //0-> 0-5 A; 1-> 0-10 A;2-> 0-20A void ADC_Config_Sequence_Channel_Mode(void); void Clock_Config(void); void GPIO_Config(void); void UART_Config(void); float offsetV = ADC_COUNTS >> 1; float filteredV = 0; float sqV = 0; float sumV = 0; float Vrms = 0; float offsetI = ADC_COUNTS >> 1; float filteredI = 0; float sqI = 0; float sumI = 0; float Irms = 0; float phaseShiftedV = 0; float phaseShiftedI = 0; float instP = 0; float sumP = 0; float realPower = 0; float apparentPower = 0; float powerFactor = 0; //----------------------CALIBRATION------------------- float VCAL = 681.5;//681.5; //631 float ICAL = 7.6;//7.6; //2.925 float PHASECAL = 0.783;//0.783; //1.9 //---------------------------------------------------- int lastVCross; int checkVCross; int SupplyVoltage = 3300; float ruido = 0;//0.15;// 0.05; unsigned int contador_1 = 0; unsigned int contador_2 = 0; unsigned int crossCount = 0; //Used to measure number of times threshold is crossed. unsigned int numberOfSamples = 0; //This is now incremented unsigned int startV; int crossings = 500; int timeout = 1000; float lastFilteredI; float lastFilteredV; unsigned int sampleV; unsigned int sampleI; float V_RATIO; float I_RATIO; V_RATIO = (float) VCAL * ((SupplyVoltage / 1000.0) / (ADC_COUNTS)); I_RATIO = (float) ICAL * ((SupplyVoltage / 1000.0) / (ADC_COUNTS)); unsigned int read_samples[2]; int STATE = 0; int TXByte = 0; int main(void) { Clock_Config(); GPIO_Config(); UART_Config(); ADC_Config_Sequence_Channel_Mode(); __bis_SR_register(GIE); while(1) { //------------------------------------------------------------------------------------------------------------------------- // STATE = 0 Read de start voltage by interrupt. //------------------------------------------------------------------------------------------------------------------------- if (STATE == 0) { ADC10DTC1 = 0x01; ADC10CTL0 |= ENC + ADC10SC; STATE = 1; } //------------------------------------------------------------------------------------------------------------------------- // STATE = 2 Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve. //------------------------------------------------------------------------------------------------------------------------- if (STATE == 2) { if ((startV > (ADC_COUNTS * 0.45)) && (startV < (ADC_COUNTS * 0.55))) { contador_2 = 0; STATE = 3; } else if (contador_1 > timeout) { contador_2 = 0; STATE = 3; } else STATE = 0; } //------------------------------------------------------------------------------------------------------------------------- // STATE = 3 Main measurement loop //------------------------------------------------------------------------------------------------------------------------- if (STATE == 3) { if ((crossCount < crossings) && (contador_2 < timeout)) { numberOfSamples++; // Count number of times looped. lastFilteredV = filteredV; // Used for delay/phase compensation //----------------------------------------------------------------------------- //STATE = 4 Read in raw voltage and current samples by interrupt //----------------------------------------------------------------------------- ADC10DTC1 = 0x02; ADC10CTL0 |= ENC + ADC10SC; STATE = 4; } else { //------------------------------------------------------------------------------------------------------------------------- // Post loop calculations //------------------------------------------------------------------------------------------------------------------------- //Calculation of the root of the mean of the voltage and current squared (rms) //Calibration coefficients applied. Vrms = (float) V_RATIO *sqrtf( sumV / numberOfSamples); Irms = (float) I_RATIO *sqrtf( sumI / numberOfSamples); realPower = (float) V_RATIO * I_RATIO * (sumP / numberOfSamples); apparentPower = (float) Vrms * Irms; powerFactor = (float) realPower / apparentPower; sumV = 0; sumI = 0; sumP = 0; contador_1 = 0; contador_2 = 0; STATE = 0; //Return to STATE = 0. Starts new calculations crossCount = 0; numberOfSamples = 0; } } if (STATE == 5) { //----------------------------------------------------------------------------- // STATE = 5 Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset, // then subtract this - signal is now centred on 0 counts. //----------------------------------------------------------------------------- offsetV = offsetV + ((sampleV - offsetV) / 1024); filteredV = sampleV - offsetV; offsetI = offsetI + ((sampleI - offsetI) / 1024); filteredI = sampleI - offsetI; //----------------------------------------------------------------------------- // Root-mean-square method voltage and current //----------------------------------------------------------------------------- sqV = (float) filteredV * filteredV; //1) square voltage values sumV += sqV; //2) sum sqI = (float) filteredI * filteredI; //1) square current values sumI += sqI; //2) sum //----------------------------------------------------------------------------- // Phase calibration //----------------------------------------------------------------------------- phaseShiftedV = (float) lastFilteredV + PHASECAL * (filteredV - lastFilteredV); //----------------------------------------------------------------------------- // Instantaneous power calc //----------------------------------------------------------------------------- instP = (float) phaseShiftedV * filteredI; //Instantaneous Power sumP += instP; //Sum //----------------------------------------------------------------------------- // Find the number of times the voltage has crossed the initial voltage // - every 2 crosses we will have sampled 1 wavelength // - so this method allows us to sample an integer number of half wavelengths which increases accuracy //----------------------------------------------------------------------------- lastVCross = checkVCross; if (sampleV > startV) checkVCross = 1; else checkVCross = 0; if (numberOfSamples == 1) lastVCross = checkVCross; if (lastVCross != checkVCross) crossCount++; contador_2++; STATE = 3; //Return to STATE = 3. } } } #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { if (STATE == 1) { startV = read_samples[0]; //read raw start voltage STATE = 2; contador_1++; } else if (STATE == 4) { sampleV = read_samples[0]; //read raw votage sample sampleI = read_samples[1]; //read raw current sample STATE = 5; IE2 |= UCA0TXIE; } ADC10SA = &read_samples[0]; } #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (IFG2 & UCA0TXIFG) { if (TXByte == 0) UCA0TXBUF = (int)Vrms; if (TXByte == 1) UCA0TXBUF = (int)Irms; TXByte++; if (TXByte == 2) { TXByte = 0; IE2 &= ~UCA0TXIE; } } } void Clock_Config(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT if (CALBC1_16MHZ==0xFF) // If calibration constant erased while(1); // do not load, trap CPU!! DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_16MHZ; // Set DCO DCOCTL = CALDCO_16MHZ; } void ADC_Config_Sequence_Channel_Mode(void) { ADC10CTL1 = INCH_5 + CONSEQ_1 + ADC10SSEL_3; ADC10CTL0 = ADC10SHT_0 + MSC + REFON + ADC10ON + ADC10IE; ADC10DTC1 = 0x02; ADC10AE0 |= BIT4 + BIT5; ADC10SA = &read_samples[0]; } void GPIO_Config(void) { P1DIR |= BIT1 + BIT2; P1DIR &= ~(BIT4+BIT5); P1OUT |= BIT1 + BIT2; } void UART_Config(void) { P1SEL |= BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD P1SEL2 |= BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSWRST; UCA0CTL0 |= UCMODE_0; UCA0CTL1 = UCSSEL_2 + UCSWRST; // UCSSEL_2 = SMCLK; UCSWRST = Reset UCA0BR0 = 104; // 16MHz 9600 UCA0BR1 = 0; // 16MHz 9600 UCA0MCTL |= UCBRF2 + UCBRF1 + UCOS16; // Modulation UCBRSx = 0, UCBRFx = 3, UCOS16 = 1 UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** IE2 |= UCA0RXIE; }
But when I start the code, the data sent by the UART is random. And when I simply change the ADC10SHT from ADC10SHT_3 to ADC10SHT_0, the MSP does not send anything else to the UART.
Could someone help me understand where the error is? The code for arduino is in this link: https://community.openenergymonitor.org/t/emon-arduino-program-code/7049