But not exactly. In those tables above they show MUX5:0 as a nice contiguous 6 bits, but the reality is they’re not. MUX4:0 are the bottom 5 bits of ADMUX while MUX5 lives in bit 3 of ADCSRB. Here’s how the Arduino analogRead() handles it…
#if defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
#if defined(ADMUX)
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = (analog_reference << 4) | (pin & 0x07);
#else
ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif
#endif
I’ve got to repeat, the library was written for the '328P. You must expect to have to make changes when you port it to a different processor, even when it’s part of the same family.
@Robert.Wall Thank you for your continued work on this library. You have contributed greatly to all of us interested in power consumption and made it extremely easy to load and measure quickly. This is a great solution, and my topic is not a bug, fault, or a bump in your roadmap. I’m the one at fault here by hijacking the support thread for your well commented library. Thank you again for all of this.
@dBC Thank you for spoon feeding me. I see exactly why you wanted me to look at the analogread code. Your knowledge and attachments will get me over the goal line.
I wasn’t criticising you for porting the library, but pointing out that there might well be other areas where you need to look very carefully at the differences between the two processors.
E.g., the recently added API call to use the 1.1 V reference might well need changing, and I see the '2560 also has a 2.56 V reference, which the '328P doesn’t have - so there’s no provision to switch to it - but which in some circumstances you might want to use.
I don’t have access to a '2560, so even if I did put forward changes, I couldn’t verify them.
@dBC Thank you for your help. I added these lines and everything is working correctly now.
@Line 920
//****Begin New Block for ADC A8 and above**********
#if defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((ADC_Sequence[next] >> 3) & 0x01) << MUX5);
#endif
//****End New Block for reading ADC A8 and above**********
//*********Modified existing line below to add "& 0x07" to handle A8 and above
ADMUX = ADCRef + (ADC_Sequence[next] *& 0x07*) ; // set up the next-but-one conversion
I recently used the EmonLibCM library in a project and during debugging I noticed what looks to me like an error in the maths.
In EmonLibCM_Init() we have
double phase_shift = (phaseCal_CT[i] / 360.0 + ADC_Sequence[i+1] *
(double)ADCDuration * cycles_per_second/MICROSPERSEC) * two_pi; // Total phase shift in radians
If phaseCal_CT[i] is in degrees and the intention is to convert to radians then given there are 2pi radians in 360 degrees, then shouldn’t this calculation be :
double phase_shift = (phaseCal_CT[i] * two_pi / 360.0 + ADC_Sequence[i+1] *
(double)ADCDuration * cycles_per_second/MICROSPERSEC) * two_pi; // Total phase shift in radians
The same calculation occurs in EmonLibCM_ReCalibrate_IChannel()
Apologies if I have this completely wrong. It is a long time since I did my GCE maths.
Exactly. With a modern compiler that can optimise effectively it’s more important to position terms for human readability than perceived machine optimisation. And multiplication by a constant factor like 2π usually comes at the front of an expression in mathematics.
If you wish to change your version locally, feel free to do so. I don’t feel inclined to issue a revised version just because Mr Howorth doesn’t like the order of operations.
I have finally started my energy monitor renewal project and I am completing the PCB.
I recently discovered that the EmonLibCM library is also available, I’m starting to study it: really congratulations to all those who worked on it.
This library would be perfect for my log operations: with my current software I measure every 0.5 seconds with standard Emonlib and then send the average data to EmonCMS every minute, calculating the average of the various parameters in this period.
Setting EmonLibCM_datalog_period(60) I would get just what I need.
In addition, the library already integrates the measurement from the temperature sensors: perfect!
My Arduino, however, also performs the task of signaling with a buzzer that I placed in the kitchen, if the (absorbed power - produced power) exceeds an adjustable threshold. This function is very useful when starting appliances in conditions that would lead to interruption of the power supply of the whole house.
I suppose it is not possible to access “instantaneous” measurement data or with another period shorter than the log period, for other types of functions (I think of those who want to implement load control-priority systems).
What could I do? Reduce the log period to what I need and then calculate the average of the quantities to send to EmonCMS as before?
That is correct - the “instantaneous” data does not exist in a form that is usable, because in order to be able to monitor continuously, much of the calculation that was done on each sample pair (in emonLib - the old discrete sample version) is now done when reporting the average values.
That is the real problem - OEM was never intended for control, only monitoring.
You could set the reporting period to 0.5 s. You can use the ½ second power values to actuate your buzzer. Then you need to send every 120th set of energy values to emonCMS. If you want power averaged over that period, you can do that in emonCMS or you can save the old energy value in the sketch and subtract it from the new value. That would be very easy to do.
You are likely to have problems with temperature measurements - the library commands the sensor to start “converting” the temperature at a time it calculates, based on the resolution you ask for, so that the reading will be ready when the power calculations are done. (This is so that, reporting every 1 minute, the temperatures are only 1 second old when they are reported.) It would be possible, but very hard, to command the start in the previous datalogging period and read the temperature in the next, but even then, data transfer from the sensor is very slow (it takes about 16ms per sensor) and that might cause more problems. It is not something I have looked into.
thanks for the answer, probably for the sampling time it would take me 2-3 seconds to command the buzzer (even now I managed a delay in exceeding the threshold), for the temperatures I go on studying the library
I’m slowly moving forward with my project (it’s not easy with a baby girl).
I made a slight modification to the V2.0.4 library, which I wanted to share, if @Robert.Wall deems it useful (and above all correct) he could integrate it in a future release.
For those who need quite fast clocks in electrical parameter measurements, but not for temperature measurements, I added a property:
temperatureSamplingRatio (default = 1)
to be considered as a multiplier of the “datalog_period”: if this property is not changed, the measurement clock will be the same as the electrical parameters (datalog_period_in_seconds) and the library behavior will be standard, otherwise the temperature data will be available every (datalog_period_in_seconds * temperatureSamplingRatio).
For example by setting datalog_period_in_seconds = 0.5 and temperatureSamplingRatio = 120, the temperatures from the sensors will be read every minute.
I then added the EmonLibCM_setTemperatureSamplingRatio(int) property-setter
and the return value of EmonLibCM_Ready() will no longer be a boolean, but a bitmask indicating the type of data available (only electrical or even temperatures).
I also removed the inclusion of the Wire and SPI libraries, as they don’t seem to be used in the library.
I’ve done some testing and everything seems to work, I haven’t tried in acPresent==false mode.
with clock less than 0.2 seconds the temperature measurement would not be possible, the library returns BAD_TEMPERATURE
with clock lower than a second the resolution is forced to the minimum (9 bit)
if I just need a temperature recording every minute, but I need to measure the electrical parameters every 0.5 seconds (see my example above) doesn’t seem like a good idea to invoke a temperature conversion on all sensors 120 times per minutes where 119 are done for nothing
a question for my curiosity: in my Arduino project, as written in some previous posts, I command a buzzer to signal that power exceeds a settable threshold
the command is done using the tone() statement:
tone(BuzzerPin, 2500);
I noticed that, compared to the use of the discrete EmonLib library, with the CM the tone emitted by the buzzer is different, a lower frequency: this behavior derives from the use of interrupts?