I have a sketch which illuminates an LED and uses PWM to fade it out. It works properly on an Arduino Uno, but on an ATtiny85 (via the HLT core) the LED switches off before it's fully faded. I was wondering if anyone can speculate as to why the fade behaves differently on the Attiny85.
Strangely, I also have the exact same problem with the sketch runnning on an Uno, but only when 'Serial.print' is running.
/*
The purpose of this sketch is to immediately illuminate LEDs when it detects sound over a
certain threshold. The LEDs will stay on for a fixed time, then fade out. The cycle will start any time a
sound peak is detected.
5/17/11 - The sketch functions as intended.
*/
// User set variables
const int micPin = 4 ; // Input into analog pin (from a mic through an op-amp.)
const int ledPin = 1 ; // Output to LEDs via a resistor.
const int thresholdPin= 3 ; // Input to set threshold via a potentiometer.
int threshold = 120 ; // Sound level at (or above) which LEDs are illuminated.
const int onTime = 1000 ; // The LEDs will stay at maximum for at least this long.
const int fadeTime = 2550 ; // The LEDs will take this long to fade out.
const int fadeInterval= 30 ; // Time interval between LED brightness increments.
const int fadeAmount = 3 ; // Amount by which to fade, each loop cycle.
// Automatically set variables
int soundLevel = 0 ; // Current sound level.
unsigned long lightStart = 0 ; // Time the LEDs are lit.
unsigned long fadeStart = 0 ; // Time at which to start fading the LEDs.
unsigned long fadeEnd = 0 ; // Time at which to finish fading the LEDs.
unsigned long timeThen = 0 ; // Time reference for fading
unsigned long timeNow = 0 ; // Time reference for fading
int fadeLight ; // LED brightness int for fading.
//mapping
int sensorValue = 0;
int mappedValue;
//smoothing
int sensorVal = 0;
int smoothedVal = 0;
int samples = 10;
void setup()
{
pinMode(micPin, INPUT) ; // Set mic pin as an input.
pinMode(ledPin, OUTPUT) ; // Set led pin as an output.
pinMode(thresholdPin, INPUT) ; // Set threshold pin as an input
}
void loop()
{
// soundLevel = analogRead(micPin); // Read the sound level, store it in an int.
// mapping
sensorValue = analogRead(thresholdPin);
mappedValue = map(sensorValue, 0, 1023, 0, 400);
threshold = (mappedValue);
//smoothing
sensorVal = analogRead(micPin);
smoothedVal = smoothedVal + ((sensorVal - smoothedVal)/samples);
// Sound peak
if (smoothedVal >= threshold) // If the sound level is equal to or greater than the threshold.
{
analogWrite(ledPin, 255); // Set the LED output to maximum brightness.
lightStart = millis(); // Store the time in an int.
timeThen = millis();
fadeStart = lightStart + onTime; // Store the time at which to start fading the LEDs.
fadeEnd = fadeStart + fadeTime; // Store the time at which to finish fading the LEDs.
fadeLight = 255; // Reset the fade brightness int.
}
// Start to fade
if (millis() >= fadeStart && millis() <= fadeEnd) // If the time the LEDs are supposed to be at max for has elapsed.
{
timeNow = millis() - timeThen; // Store in an int, the difference in time between the current time and the time the previous cycle ended.
if (timeNow >= fadeInterval) // Check that the amount of time specified by 'fadeInterval' has elapsed (to give a smooth fade).
{
fadeLight = fadeLight - fadeAmount;// Reduce the LED brightness int by an amount specified by 'fadeAmount')
timeNow = millis(); // Reset timeNow to the current time.
timeThen = millis(); // Reset timeThen to the current time.
}
analogWrite(ledPin, fadeLight); // Set the LED brightness to the amount now specified by the 'fadeLight' int.
}
// End fade
if (millis() > fadeEnd) // If the time the LEDs are supposed to lit for has elasped.
{
analogWrite(ledPin, 0); // Turn the LEDs off.
fadeLight = 0; // Reset the 'fadeLight' int.
}
}
Ok, a few things have shown up.
For one, there is no analog input #4, so analogRead(4) returns 0, or at least not a reasonable value (for me, at least!).
Moving the mic pin to 3 and the threshhold to 2 fixed that issue.
I think what you're running into is that your fading and your ending the fade are two separate processes, fadeEnd can show up while you're still above 0 fade. I would change the end state so that it waits for the current brightness to be <= 4 (seeing as you're going in steps of 3), and then stop the fade loop based on that, rather than on time.
Finally had some time to pick this back up again. Your Tiny Core has done the trick! It now fades out nice and smoothly, and for the most part my sketch seems to run properly. I guess all cores are not created equal. A massive thanks for providing your Tiny Core! Would your core also allow me to program the SOIC version of the ATtiny85, using the same method as the DIP version?
Bobnova:
Ok, a few things have shown up.
For one, there is no analog input #4, so analogRead(4) returns 0, or at least not a reasonable value (for me, at least!).
Moving the mic pin to 3 and the threshhold to 2 fixed that issue.
So you were getting no usable readings until you changed the pins? The pin arrangement in my code works for me, with the threshold pot to physical pin 2, micPin input from the amp to physical pin 3, and the output ledPin to physical pin 6.
Bobnova:
I think what you're running into is that your fading and your ending the fade are two separate processes, fadeEnd can show up while you're still above 0 fade. I would change the end state so that it waits for the current brightness to be <= 4 (seeing as you're going in steps of 3), and then stop the fade loop based on that, rather than on time.
That certainly sounds like a more robust method! Although using the Tiny Core seems to have eliminated the problem, resulting in consistently smooth fades.
The issue now seems to be that when the LED is lit, it causes noise which the MCU sees as another sound peak, keeping the LED on indefinitely. Funnily, when I attach a loudspeaker to be able to hear what's going on, the noise isn't loud enough to re-trigger the LEDs on, so this suggests the right hardware can solve it. But is there an obvious way to reduce/eliminate noise from the LED and/or preventing it from affecting the rest of the circuit? I'll have a go at de-coupling, but I don't know if this is the right idea...
Given that an LED doesn't produce audio noise (well, it can once if you drive it hard enough :P) you're almost certainly seeing electrical noise.
Do you have 10-100uF and 0.1uF caps on the VCC line right next to the MCU?
I don't know if op-amps need such things as well, never used an op-amp.
Bobnova:
Given that an LED doesn't produce audio noise (well, it can once if you drive it hard enough :P) you're almost certainly seeing electrical noise.
Do you have 10-100uF and 0.1uF caps on the VCC line right next to the MCU?
I don't know if op-amps need such things as well, never used an op-amp.
Yeah, electrical noise is what I meant! I'm listening to it via a little speaker I pulled out of an old mobile phone. After having a more careful listen, the loud noise only occurs during the fading phase. When the LED is lit and not fading, there's a very quiet noise which doesn't seem to be causing any trouble, but is audible.
I've tried a 10uF and 0.1uF together, both as close as possible to the MCU, with no effect. There's also a 0.1uF cap on the op-amp. When you say a 10-100uF cap, will any cap between those two values do, or should I experiment across the whole range?
At this point it seems like a hardware problem, but other than power de-coupling I don't know anything about this!
Bobnova:
I did my testing with a piezo speaker.
As a microphone? Connected directly to the MCU?
You're right, I now have my sketch running on a SOIC ATtiny85! It's quite amazing how small it is...
In my sketch, is the analog-to-digital converter used simply for analogRead, or is there more to it than that?
AnalogRead is the only thing the ADC can be used for, without smoothing on it you can get some interesting spikes (which may be triggering your issues, who knows).
I did indeed test with a piezo speaker acting as a microphone, it works pretty well though I'm sure a microphone+opamp is a lot more sensitive.
I would try a couple of things, the first being to beef up the decoupling.
The second being to take a few samples and average them together. Something like replacing
sensorVal = 0;
for (byte x = 0 ; x < 100 ; x++){
sensorValue +=analogRead(analogRead(micPin);
delayMicroseconds(20);
}
smoothedValue = sensorVal / 100;
That'll take 100 readings of the pin ~20microseconds apart and average them together, it may or may not work better than what you have (I don't really understand how yours works, so I may well be trying to replace it with something cruder), but it's worth a shot IMO. It does waste ~2 ms with delay, but that shouldn't mess anything up in your program.
This is how I've been doing my smoothing, it seems to work fairly well for me even in electrically noisy environments.
EDIT:
Alternatively you could take the road less traveled and experiment with decoupling caps on the op-amp and/or analog pin inputs. You'd need a mighty small one on the op-amp signal input I expect, otherwise it'd wipe out the entire microphone output. Depending on how strong the op-amp output is you may be able to use a fairly juicy cap on the ADC input.
Personally I suspect that the op-amp end of things is where the noise is getting in.
Sorry about the delay in replying! I haven't had much time for this project recently, but I tried reducing the gain of the op-amp which has in turn reduced the noise to a usable level. I don't see this as a very robust solution though, so my next step will be to try out your ideas. I think I'll start with your way of smoothing, since that'll be quicker than experimenting with different de-coupling caps.
It helps to use ADC Noise Reduction .... In my sketch, is the analog-to-digital converter used simply for analogRead, or is there more to it than that?
Yes. ADC Noise Reduction is a sleep mode. There are examples in the forum.