Arduino: Using analogRead() on Photoresistor to read LED with PWM - arduino

I have been working on a project with Arduino and have come across something that I find fascinating/confusing. So, I had to test something before constructing this project. I built a simple circuit that consists of just an LED and photoresistor. What I had to test was whether the photoresistor was capable of determining the brightness of an LED that was being dimmed through PWM. My initial expectation was that this would not work (the photoresistor would either read 1023 or 0 because PWM is achieved digitally). To my surprise, the photoresistor was able to accurately read the brightness of the LED (accurately to an extent -- this is simply based off of comparing the apparent brightness of the PWM LED with an LED placed in series with a certain resistor)! This is exactly what I wanted, but I am just curious as to why this works. I am not sure if my original doubt was due to a misunderstanding of photoresistors or PWM. Any help would be much appreciated. Thank you!
Here is the code I am running (I am not using the analogWrite() function because the project I am working on requires me to have a certain level of control over the PWM):
const int LED_PIN = 9;
const int PHOTO_PIN = 0;
//These values have been altered and tested
const int HIGH_TIME = 250;
const int LOW_TIME = 2750;
void setup()
{
pinMode(LED_PIN, OUTPUT);
pinMode(PHOTO_PIN, INPUT);
Serial.begin(9600);
}
void loop()
{
digitalWrite(LED_PIN, HIGH);
delayMicroseconds(HIGH_TIME);
digitalWrite(LED_PIN, LOW);
delayMicroseconds(LOW_TIME);
Serial.println(analogRead(PHOTO_PIN));
}

A "photoresistor" is a variable resistor. That is the simplest way to say it.
Just imagine your potentiometer, you can control its resistance by turning the little knob and then analogRead it. The photoresistor on the other side, changes it resistance depending on the light intensity. Because of that, the resistance will go up and down depending on your LED.
For "HOW" it actually works, see here.
Now, there are a couple of factors to consider:
1 - The ambient light of your room.
2 - The distance between your LED
So hope I helped you learn a little more about photoresistors!

The response time of the photo resistor is much slower than the PWM frequencies you are using. So it averages the on and off times of the LED and gives a resistance proportional to the average light. If you were using a photodiode with a fast response time, it would be able to "see" the LED go on and off.
I suggest that you don't try to write to the Serial port every time through the loop since it will quickly fall behind at 9600 baud. Perhaps write every 500 times through the loop.

Related

Designing a basic RGB LED blinking circuit

The circuit:
Trying to get this just to blink, but can't figure out how.
void setup() {
pinMode(3, OUTPUT);
}
void loop() {
digitalWrite(3, HIGH);
delay(250);
digitalWrite(3 , LOW);
delay(250);
}
Pretty much the stock Arduino code, but I don't know why it won't work with multiple LEDs.
EDIT: The LEDs aren't blown out, because they all still work one at a time.
The problem isn't in your code.
A single standard red LED drops about 1.8 V, and with the proper resistor an Arduino pin can drive such a LED at the right current.
Three LEDs (especially with a blue one among them) in series need more voltage than the Arduino pin can deliver (5 V), so they won't light up. Maybe two LEDs with a recalculated resistor will just about work.
Try leaving out the blue LED; it has the highest voltage drop (about 3 to 3.3 V), so adding one other LED will already go too close to, or beyond, 5 V, and the LEDs won't light up.
You could put the LEDs in parallel, each with their own properly calculated resistor, but the total current you pull in that configuration may exceed the maximum current allowed per Arduino pin (this depends on the Arduino used: about 20 mA for most Arduinos, but only 7 mA for SAMD21-based Arduinos).

Arduino servo without library

As education exercise on sending digital signals, I'm trying to code the pulse train for a servo without using the servo.h library.
The servo is a 9g micro servo. Hardware is correct, as many examples using servo.h work fine.
I have the following code. The problem is that the servo jerks around for 3 seconds rather than moving and holding still.
void loop() {
movePulse_1000();
delay(3000);
}
void movePulse_1000(){
Serial.print("Start movePulse_1000()\t\t");
for (int pulseCounter=0; pulseCounter<=150; pulseCounter++){
digitalWrite(pinServo,LOW);
delay(20); // between pulses
digitalWrite(pinServo,HIGH);
delayMicroseconds(1000);
}
Serial.println("End movePulse_1000()");
}
Using an analog servo, the average pulse width must be 1.5ms apart, and the duty cycle changes based on the desired position. To keep the servo where you want it, you must constantly refresh the servo data. This isn't a super simple task and that servo library is quite optimized. There's few reason not to use it.
It creates hardware timers and uses them to refresh the servos. This allows your regular code to appear to continue regularly even though it's being interrupted by the servo library to service the servos. Duty cycle, pwm frequency, and refresh rates all come into play. You'll have to look at the data sheet of the servo you are using to get the full details. But its not as simple you think and those delay/delaymicros functions you're using aren't always precise enough. That's why you would use times and overflow interrupts. Though most servos aren't too picky and you can get away with a ton of slop.
The library servo.h constantly sends pulses which means servo growling = battery consumption.
I changed your function to only rotate the servo without a timer from 0 to 180 degrees.
del = (7 * x) +500; - for my servo-pulse 500 to 1260us (calculated, not measured)
void movePulse(int x){
int del=(7*x)+500;
for (int pulseCounter=0; pulseCounter<=50; pulseCounter++){
digitalWrite(pinServo,HIGH);
delayMicroseconds(del);
digitalWrite(pinServo,LOW);
delay(20); // between pulses
}
}

How can I change the frequency and amplitude at the same time?

For example, if I need to set the frequency of 100 Hertz, I used the tone function to set the frequency using PWM. Now I need to vary the amplitude between 0 - 5 Volts using PWM. Is it possible to use tone and analogWrite together to fix frequency i.e 100 Hertz and analogWrite to change the amplitude?
Let me know if there is any another alternative because I tried the above commands tone and analog write on the same pin , it is not working.
You cannot do that using the tone function. Look into https://en.wikipedia.org/wiki/Pulse-width_modulation to get an idea of how a "Frequency" is generated using PWM. This image might be helpful:
If you really need to have different voltages, you will either need to add external components on the output pin (a simple voltage divider at least) or you generate the signal using solely analogWrite. Be aware that in the latter case timing issues may arise depending on the complexity of your code.
You can
use analogWrite and throw away the tone function, mimicing the behavior of the tone function;
use an external circuit.
The code that can suit the first solution is
#define TONE_PERIOD 10 /* Period in milliseconds */
unsigned long lastPulseStart;
byte volume;
void setup()
{
volume = ...;
lastPulseChange = millis();
}
void loop()
{
if (lastPulseStart - millis() < TONE_PERIOD/2)
analogWrite(pin, volume);
else if (lastPulseStart - millis() < TONE_PERIOD)
analogWrite(pin, 0);
else
lastPulseStart += TONE_PERIOD;
}
For the second solution you can use two pins, then use something to mix the outputs. For instance
an AND port (tone goes to an input, analogWrite to the other; the and port should be before the filter);
a buffer with enable input (tone goes to the enable, analogWrite to the line; this can be either before or after the filter);
if you are using an amplifier and it has an enable pin, use it (of course tone goes to the enable, analogWrite to the line);
an external ADC (in this case you will use the tone as the voltage reference, the volume should be passed as value for the ADC);
if you have attached a speaker directly to the output, you can send the analogWrite output to the speaker and put an NMOS on the other pin of the speaker, driven by the tone output.
If you need some schematics just ask..
Edit
Have you considered an digital potentiometer? After reading its description, it pretty much matches you need.
[...] controlling the volume on your stereo [...]
It functions quite like a normal potentiometer and I think it should work for you.
Original post
The answer is no, because tone will output pulses at a set frequency, but then analogWrite will ask the pin to output something else. The microcontroller might get "confused" and will probably not do what do you want it to do.
An more mechanical way to get over this problem is to use an potentiometer. It is pretty much a variable resistor that will change its resistance depending on the position of its knob. Why does this work is that no pulses are involved and the only thing you do is to lower the strengh of the signal while not modifying it.

necessity to give delay to adc

I was trying to send analog signals from arduino to the computer by the serial port.For getting the maximum samples of my input analog signals,I put my baudrate to the maximum limit.The code is as given
void setup()
{
Serial.begin(115200);
}
void loop()
{
int a=analogRead(A0);
Serial.println(a);
delay(1);
}
This program works well for my signals with very low frequency.but at higher frequency signals,there is still arising a problem of aliasing.I tried decreasing the delay.i got more samples When i did this but some of my digital values that I got could not be used,that is,some of the wrong digital values were like 353?12 and so on.Is it manda to give minimum delay of 1 ms to the ADC??Or is there any way that i can Increase my samplestory
You are running into an issue with the default prescaler setting in arduino. The default setup will only get less than 10 samples per millisecond.
You can certainly get faster reads from your ADC if you want to play with some of the underlying settings:
www.microsmart.co.za/technical/2014/03/01/advanced-arduino-adc/
has a good write up on the subject. They got it running at 50 samples per millisecond with some tweaking.
The other option is to get an ADC chip which will run faster for you. Search sparkfun for "mcp3002". No tweaking of your arduino required since it uses spi input.

Small air blower (12V DC motor) only buzzing

I'm trying to get my DC Brushless fan (an air blower like this one: https://iprototype.nl/products/components/overige/blower-squirrel-cage ) working.
This is my set-up: (note that the DC motor in the image is my fan)
And this is my code (nothing fancy):
int motorPin = 9;
void setup() {
Serial.begin(9600);
pinMode(motorPin, OUTPUT);
}
void loop() {
for(int i=0; i < 255; i++) {
analogWrite(motorPin, i);
Serial.println(analogRead(motorPin));
delay(5);
}
}
The only thing my air blower is doing is BUZZING. A little "peeeeep" coming out of it, so there is a connection but it doesn't seem to work for some reason.
My battery i'm using is a normal Duracell 9V battery and when I hold the cables of my air blower against the + and - of my battery it works pretty well, so the voltage should be enough.
Would anyone know a solution for this?
First off I would be careful posting this here. There are a TON of trolls that will push you off Stack Overflow because this is an Engineering question.
That said:
First thing I noticed that is wrong.
You are using analogWrite(motorPin, i); but you clearly have it plugged into the digital pins on the Arduino. The pins that are marked A0-A5 are your analog pins.
What you want to use is digitalWrite(pin,value)
Arduino Documentation
Second, have you tested this with a multimeter?
I would be concerned with how much current is actually getting to your blower and if it's enough to run it. This really depends on how it is wired. I would suggest using an H-Bridge for anything motor related. You can find them REALLY cheap on sparkfun. I use one from adafruit. You can see an example of it working and how it's wired at http://anthonyrussell.info/postpage.php?name=65 If you could attach an actual photo of your setup that might be a little more useful

Resources