Hi everyone. I'm working on a project which measures the aggregated power consumption (other parameters like reactive power and harmonics too) of the house and then using these parameters and some neural network algorithms (back propagation classifiers etc), perform appliances classification and individual load monitoring. I'm now at the first stage in which I'm getting signals in from the arduino and I am able to pipe them over to the PC via USB/Serial. To do a quick validation on whether the samples make sense, I fire up putty and the sample values are received in the form of " ...". In other words, each sample value which is sent from the Arduino is delimited with a space. I then copy all values in the putty window and paste them into MATLAB to produce a plot.
The problem that I'm facing is that the ADC sampling rate doesn't tally with the sampling rate calculated from sampling points collected at the PC. For example, the sampling rate is set such that the ADC clock is 125kHz (using a prescaler of 128). In this case, the maximum sampling rate should be (125kHz/13 = 9615.4 samples/s) since the conversion takes 13 ADC clock cycles from the start of the conversion. However, when taking the number of samples in one AC voltage cycle (1/(50Hz) = 0.02s) and dividing it with the period of the AC waveform to obtain the sampling rate, it doesn't match with the sampling rate configured at the ADC. The calculated one is slower.
I should mentioned that I need a strict sampling rate because I would be including current harmonics as one component of the feature vector used as an appliance signature.
Here's the code that is running on the 328P:
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int sensorValue = 0;
int sensorPin = A0;
volatile unsigned char badc0;
volatile unsigned char badc1;
//volatile unsigned short channel;
void setup() {
Serial.begin(1000000); // Setup serial connection with baud rate of 1000000 baud/s
// Initialize the ADC and enable interrupts
// I bit in the SREG is already enabled in wiring.c's init()
// Disable ADC before enabling ADC interrupts.
cbi(ADCSRA,ADEN);
sbi(ADCSRA,ADIE); // Enable interrupt for ADC.
cbi(ADCSRA,ADIF); // Clear the interrupts flag for ADC.
sbi(ADMUX,REFS0); // VCC Reference
cbi(ADMUX,REFS1);
// Convert voltage of channel 0 first.
cbi(ADMUX,MUX0);
cbi(ADMUX,MUX1);
cbi(ADMUX,MUX2);
cbi(ADMUX,MUX3);
// Set registers for free running mode.
sbi(ADCSRA,ADATE);
// No need to set register ADCSRB for the trigger source because it is by default all zero and uses ADIF as the trigger source.
// Enable ADC.
sbi(ADCSRA,ADEN);
// Start the conversion.
sbi(ADCSRA,ADSC);
}
void loop() {
//sensorValue = analogRead(sensorPin);
//Serial.print(sensorValue);
//Serial.print(" ");
//delayMicroseconds(50);
}
ISR(ADC_vect) {
badc0 = ADCL;
badc1 = ADCH;
Serial.print((badc1 << 8) + badc0);
Serial.print(" ");
}
I started off using the basic analogRead(). The problem exist and I thought the reason is because analogRead() uses polling to check if conversion is completed. So I moved on to using interrupts and configure the ADC for free-running mode but to no avail. I did a little debugging and I thought the problem is related to using Serial.print() in the ISR. For instance, when execution moves inside the ISR, interrupt is disabled as the I-flag in SREG is cleared by the hardware. And in this context, if Serial.print() takes some time to return and the next conversion is completed, the new conversion value will not be printed. Overall, the effect is some samples are missed and not being sent over the serial connection. Does this make sense? Do you think this is the problem?
Where can I find the implementation(source) of Serial.print()?
Thanks in advance. I really appreciate any suggestions on what went wrong.