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.
Related
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.
The function of the program I am writing is to stream incoming analog data from a sensor to a program on my computer across the USB port. For a little fun, I've decided to add a button to the program that will turn on/off a lamp. The lamp will be connected to a relay, which is connected to the arduino. I know how to go about programming it, but I want to know if this will interrupt the sensor data transfer?
I will get the current state of the light (HIGH(1) or LOW(0)) from the arduino when the button is pressed, then write to the arduino (HIGH(1) or LOW(0)) depending on the current state. I have a 5 second delay between each loop of the arduino program, for reasons related to the sensor output; however, I think I'm going to have to change this so that when the button is pressed, it is not missed by the arduino loop, or is that not possible?
I thought I read somewhere that you can't transmit/receive streaming data on the same serial line...in which case, I will need the Mega.
You have to remember and think of the Arduino as a single threaded device. While it is doing anything it is not able to do anything else. Period! In regard to the serial port however, the buffer will still accept incoming data on RX, however if an overflow situation occurs whilst blocked, management is impossible.
See the following taken directly from the Arduino reference
Certain things do go on while the delay() function is controlling the Atmega chip however, because the delay function does not disable interrupts. Serial communication that appears at the RX pin is recorded, PWM (analogWrite) values and pin states are maintained, and interrupts will work as they should. Reference
Now in saying that when you are setting the delay to 5 seconds between loops ( delay(5000) ) you are essentially blocking it from doing anything else almost full stop.
The Arduino framework exposes a a counter ( millis() ) that basically runs from the moment of boot for roughly 50 days in increments of one (1) millisecond. See Arduino - millis()
In your application you would define (remember) what loop you were due to run & when the said loop had finished so to not allow the other loop to run until the millis() counter was a defined amount more than your count. (Remember to define the count as a long)
Then what you do is move your loops out into separate functions that will only execute if the if statement return true...
for example...
long interval = 5000; // Define interval outside of the main loop
long previousCount = 0; // Used to store milli count when finished
int loopPosition = 1;
void loop()
{
if ((long)millis() - previousCount >= 5000 )
// This if statement will only return true every 5 seconds (5000ms)
{
if (loopPosition == 1)
{
function_One();
previousCount = millis(); // Redefine previousCount to now
loopPosition++; // Increment loop position
}
else if (loopPosition == 2)
{
function_Two();
previousCount = millis();
loopPosition--; // Decrement loop position
}
}
// Do Anything Here You Want
// - While ever the if statement above returns false
// the loop will move to this without hesitation so
// you can do things like monitor a pin low / high scenario.
}
void function_One()
{
// Do Your First Loop
}
void function_Two()
{
// Do Your Second Loop
}
The above will stop any delay you are using from blocking awesomeness, and to more of a point, almost make delay obsolete if implemented correctly under the right scenarios.
In regard to your serial data comment, like i said at the top of this article, the Arduino can only do one thing at a time. Transmitting and receiving at exactly the same time is impossible even with the Mega. In saying that a board like the 'Uno' for example is only capable of one serial interface, where as the 'Mega' is capable of four.
Best of luck....
NB- For a beginner reading this, the following tutorial / example covers what i have above in fairly simple terms and is a great building block for further awesomeness! Arduino - Blink Without Delay
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.
I am building a hard drive POV clock. (google it, they are pretty cool)
I am working on the code for it, right now all i want to do is get the hang of making it do simple patterns with the RGB leds. I am wondering if anyone has any ideas on how to do something simple like make a red line rotate around the platter.
right now what i have is an interrupt that triggers a function.
int gLED = 8; // pins for RGB led strip
int rLED = 9;
int bLED = 10;
attachInterrupt(0, ledPattern, FALLING);
void ledPattern(){
digitalWrite(gLED, HIGH); // This will make a stable image of slice of the
delayMicroseconds(500); // platter, but it does not move.
digitalWrite(gLED, LOW);
}
That is the main part of the code (obviously I cut some stuff out that arduino requires)
What I am trying to figure out is how can make that slice rotate around the platter.
Eventually I will make the pattern more interesting by adding in other colors.
Any Ideas?
Try adding a delay at the start of ledPattern before turning the LEDs on, and increasing that delay each time the interrupt is called. To display a line at a particular angle, you will need to measure the time between subsequent interrupts (the time taken for one whole revolution of the LEDs) and make all the delays in the ledPattern routine proportional to this time.
Be aware that, if too much delay is added, the ledPattern routine won't have returned by the time the next interrupt is called; you might need to mitigate this, or at least work out exactly what the arduino environment is doing in this situation.
I have tried measuring the analog pin value using the provided standard sketch in the Arduino IDE. However even when there is no connection to the pin, it prints out random values. Is there anything that has to be taken care of?
I have a FSR sensor connected from 5V+ to analog pin 0
No connection giving you random value is completely expected. The pin is floating, and may or may not have a charge on it at any time, giving random values.
Attach the analog input to ground - it should return a number approaching zero (within the accuracy and noise of the ADC).
You have to use "Pull-up" or "Pull-down" resistor. Read here about this circuit: http://www.ladyada.net/learn/arduino/lesson5.html
Providing a path of higher resistance to ground ensures that when that portion of the circuit is open, the static electricity remaining in the portion connected to the pin gets grounded. It also splits the voltage between both paths to allow you to properly throttle the voltage to the pin.
The same problem arise to me ,
What you have to do is change the" Serial.begin(9600);"
To "Serial.beigin(115200);
Now it is showing exact zeroes without any input source.