I'm developing a project with Arduino, which includes measuring frequency (an output from humidity sensor), and also managing RGB light. I use PWM at pins 9,10,11 for R,G,B channels.
When my sketch starts, everything's ok. But a few seconds later, after FreqCounter is called, PWM output on pins 9,10,11 changes - from the color of the backlight I guess that its duty cycle increases(the colours shift to more intense ones, i.e. orange->red etc), but this is only a guess.
Here are parts of code that are responsible for this:
void updateHumidity(boolean force){
if(!force){ //if not forced to update
if (blOn || millis()-lastHumScan<HM_TIMEOUT) return; //do not do it while backlight is on or too often
}
FreqCounter::f_comp= 8; // Set compensation to 12
FreqCounter::start(1000); // Start counting with gatetime of 1000ms
while (FreqCounter::f_ready == 0) // wait until counter ready
freq=FreqCounter::f_freq; // read result
lastHumScan = millis();
lcd.setCursor(8,1);lcd.print(freq);
}
void backLight(){
if(bldTick==0 || (millis()-bldTick<BL_TIMEOUT)){
analogWrite(9,r);
analogWrite(10,g);
analogWrite(11,b);
blOn=true;
} else {
analogWrite(9,0);
analogWrite(10,0);
analogWrite(11,0);
blOn=false;
}
}
I use Arduino Uno.
The frequency range is about 5-10 kHz, and most often I get 7.5 kHz.
Could you please help me with this? Is there way to return PWM outputs to normal after freq.measurement? Both true colours and frequency measurement are very important to my project.
Or should I use another pins, not controlled by Timer1?
What does the signal from the humidity sensor look like? Depending on the frequency being measured you might be able to measure the pulse times in software. The pulseIn() function will give you the length of a pulse in microseconds. Just because the sensor outputs a frequency in cycles per second doesn't mean that you have to count the number of pulses per second. A single half-cycle might be enough to tell you the value.
For example, if the signal is a square wave and you measure a high pulse of 152 microseconds the full wave time (high and low) would be twice that (304 microseconds or 0.000304 seconds). Take the inverse to get cycles per second: 1000000UL/304UL = 3289 cycles per second.
If if isn't a square wave then measure a hight pulse and a low pulse to get the total wavelength.
Yes, it's a square wave.
I've dediced to use pulseIn() at last. The problem is that it does not provide accurate results: for a frequency of 7430 Hz it shows something like 7920 on HIGH, and 7168 on LOW. (Despite I collect 1024 samples and use average as a reading).
However, LOW seems more stable, so I remembered my Metrology lectures, collected a large number of readings from both pulseIn and FreqCounter, and it defined some regions with linear corrections (for instance, if f is in [7100;7200] I add 260 to pulseIn value etc...)
This resulted in ~3% accuracy (average about -0,4% humidity), but together with sensor 3% this produces accuracy of about 6% (humidity)
So the problem is solved - in a part for sensor readings (although they are not as accurate as I wish).
See here: tushev.org // Simon Tushev However, I'm still wondering, if there's a way to undo changes that FreqCounter does to PWM's?
I ran into this as well. On an Uno I am not able to get PWM to work even on pin 11 with FreqCounter running. I too am wondering if there is some way to add a call to FreqCounter to return the interrupt control to what it was but I suspect not.
In the meantime I wrote a software PWM that runs at about 1000hz -
// "heat" is PWM duty cycle, range 0-255
for (i1=0; i1<2000; i1++) { // 2000 * 0.00102 s = ~2 seconds of heating
digitalWrite(heatPin,HIGH);
delayMicroseconds(heat4);
digitalWrite(heatPin,LOW);
delayMicroseconds(1020-heat4);
}
That might work for some cases. I'm measuring a pulse frequency that varies between 4 kHz and 5 mHz, and I need 1 hZ accuracy. Using the Arduino as a frequency counter works perfectly. The pulse itself isn't regular enough to use as a timebase.
Atmega 8, for instance, is $3 only. You can program it to measure frequency, and read data from it via I2C, as I did. And it requires just a couple of elements to make it running: 16MHz crystal, two 22pF capacitors and several wires. Just program the bootloader (optiboot for mega8 works fine), and you can upload sketches simply by inserting it to Arduino Uno.