I want to get data from the sensor(I used velostat). And this is my code.
Arduino Code
#define numRows 1
#define numCols 1
int rows_out = 13;
int cols_in = 12;
int Values = 0;
void setup() {
// set all rows and columns to INPUT (high impedance):
pinMode(rows_out, INPUT_PULLUP);
pinMode(cols_in, INPUT);
Serial.begin(9600);
}
void loop() {
pinMode(cols_in, OUTPUT); // set as OUTPUT
digitalWrite(cols_in, LOW); // set LOW
Values = analogRead(rows_out); // read INPUT
pinMode(cols_in, INPUT); // set back to INPUT!
// Print the incoming values of the grid:
Serial.println(Values);
delay(1000);
}
I made a sensor with velostat. It has two cable.
I connected one of them with an analog pin of arduino board. And the other one with GND and other analog pin. like this.
velostat cable 1 - analog pin 12
velostat cable 2 - analog pin 13 - GND
But when I upload this program, weird data is coming out on serial monitor.
Data displayed on serial monitor
4095
4095
4075
3283
3082
3056
2973
2941
2865
2685
2308
1859
1365
If anyone knows the reason, please help me. I guess it is because connection of cable has problem or I connected wrong pin, but i'm not sure.
The data could be fine, you most possibly skipped the calibration step.
A velostat measures pressure, but depending on the materials used to make the sensor, its PressureIn-VoltageOut characteristic may differ greatly. Furthermore, differences exist even in sensors with the same build, thus the need for calibration is vital in applications that require precision.
I would suggest you assume a linear characteristic for simplicity's sake, and do the following 3-step calibration:
Average out 10 values for when there's nothing pressing on the sensor. That'd be your zero reference. We'll reference it as X1.
Press with the average expected pressure on the velostat and average 10 measurements again. That'd be your 'ON' reference, and we'll reference it as X2. This ON value needs an arbitrary numeric equivalent. I chose 15.
In math, it'd look like:
aX1 + b = 0
aX2 + b = 15
Once you solve for a and b, your true values would be represented by: a*[measuerement]+b.
P.S.: Sorry for the horrendous math formatting, still not familiar how to integrate math nicely in markdown.
Later edit: Higher precision can be achieved by averaging across more measurements AND picking a larger arbitrary value for the second equation (to have more granularity).
Related
Thank you in advance. I am beginner in Lead acid batteries.
Actually I Am using solar energy to charge my 12v sealed lead acid battery. and the thing is I need continuous monitoring of my battery voltage. I used a voltage divider to do that.
Now my Question is, Can I connect voltage divider continuously to the battery?
And the calculated voltage is fluctuating, how to reduce this fluctuations?
Thank you.
Yes you can connect the battery continuously to the voltage divider. Make sure you use very big resistors. Current output = V/R . so if you want I<0.1mA you want 0.1mA < 12/R. This means you must use Resistors in the Mega Ohm range.
To reduce fluctuations you can average the voltage readings. A simple scaled average would work nicely.
V[0] = 0.4V[-1] + 0.3V[-2] + 0.2[V-3] + 0.1V[-4].
this will smooth out your readings.
Yes you can connect your voltage divider to one of Arduino's analog pins!
In fact, I've answered the same question last night in Arduino forum.
Have a look at it and don't hesitate to ask if you have further questions.
// number of analog samples to take per reading
#define NUM_SAMPLES 20
int sum = 0; // sum of samples taken
unsigned char sample_count = 0; // current sample number
float voltage = 0.0; // calculated voltage
void setup()
{
Serial.begin(9600);
}
void loop()
{
// take a number of analog samples and add them up
while (sample_count < NUM_SAMPLES) {
sum += analogRead(A2);
sample_count++;
delay(10);
}
// calculate the voltage
// use 5.0 for a 5.0V ADC reference voltage
// 5.015V is the calibrated reference voltage
voltage = ((float)sum / (float)NUM_SAMPLES * 5.0) / 1024.0;
// send voltage for display on Serial Monitor
// voltage multiplied by 11 when using voltage divider that
// divides by 11. 11.132 is the calibrated voltage divide
// value
Serial.print(voltage * 11.002);
Serial.println (" V");
sample_count = 0;
sum = 0;
}
in setup() a serial communication is being initialized. so that the output can be displayed in serial monitor.
in loop()
n reading of the analog pin is taken and the sum is stored.
then the voltage is calculated and the results is reported back to the user.
since we are in void loop the process will be repeated till power is disconnected from the Arduino board.
I found this useful site for my project. Have a look at it, If are interested. It's a "solar charge controller". They used best coding techniques to "calculate 12v battery" and solar panel voltage.
Thank you.
http://www.instructables.com/id/ARDUINO-SOLAR-CHARGE-CONTROLLER-Version-20/?ALLSTEPS
I am using arduino Uno to read voltage from A0 pin with simple 1/3 resister divider (5v applies to a voltage divider, and A0 gets 1/3 of 5v). There is a relay connected to D1 pin.
(My eventual goal is to measure 15v, that's why using voltage divider to diagnose the problem)
I noticed that when relay is on, the A0 read is higher than it should be. I am not sure what's the cause, and like to understand it.
Description about the circuit:
A0: analog pin used to measure voltage.
D1: a digital pin used to control a relay.
Resistor divider: R1 = 2k, R2 = 1k. R1 connects to 5v (arudino Uno 5v output). A0 is connected to R2, therefore, A0 should get 1/3 of 5v, which is 1.67v.
Few measurements to diagnose the problem:
Vmesaure_all: a manual voltage measure on R1 + R2.
Vmeasure_r1: a manual voltage measure on R2 only, which is input voltage of A0.
Vcode_r1_A0: arduino A0 analog read.
A)Relay is off:
Vmeasure_r1=1.67v (1.67 *3 = 5.01)
Vmesaure_all=5.03v
Vcode_r1_A0=339 (339 * 3 = 1017)
All above makes sense.
B) Relay is on:
Vmeasure_r1=1.63v (1.63 * 3 = 4.89v. OK. Makes sense as it is almost same as Vmesaure_all)
Vmesaure_all=4.91v (Relay is a load, it makes voltage drop on if measuring voltage of R1+ R2. I think it is expected)
Vcode_r1_A0=345 (why higher than 339, which is relay off A0 read???)
I could not explain this. If use this value to calculate voltage on R1 + R2, you will get higher voltage (the voltage to be measured), compared with relay off.
I would expect Vcode_r1_A0 to be < 339.
I did few experiments, andgot consistent behavior described above. Why?
Yes, the numbers can make sense. The analog to digital converter (ADC) by itself is not an absolute voltmeter. ADC's have a reference voltage and are calculating the digital value relative to that reference voltage. The Arduino provides you choice of reference voltage via the function analogReference()
The default behavior is that analog reference is the supply voltage pin, which is nominally 5.0 V. But that leads to your problem:
If Vcc changes while the analog input stays the same, the digital value changes.
If Vcc drops, the digital value will increase.
In other words, an ADC is only as accurate as its reference voltage.
The ATmega chips include a voltage reference that will not vary with Vcc. If you set the INTERNAL reference, then full scale 1024 digital is now 1.1 V.
analogReference(INTERNAL);
x = analogRead(A0);
// now x = 1024 is A0 = 1.1 V
Using this code, the digital value will be more accurate and not sensitive to Vcc. The tradeoff is that the full scale range is greatly reduced to only 1.1 V. To accommodate that reduced range, you need to add a voltage divider. Because you already intend to do that, you should use the internal reference and adjust the resistor values of your divider.
But, you are dropping Vcc by 0.1 V! Do you notice the chip is hot or a burning smell? Confirm that the current drawn by the relay coil is within the rating of the pin. Commonly, people use a transistor or driver chip (for example ULN2003) to power a relay load. Also beware that connecting inductive loads like relays and motors straight to digital pins tends to destroy those pins because of the flyback voltage when you turn off the coil.
We are simulating an oven. The potentiometer sets the desired temp and the sensor reads the current temperature of a little copper plate that is "the oven."
Both the temp sensor are connected to their own analog input pin on my arduino uno. Individually, I have gotten values for both the potentiometer and the temp sensor that make sense (I am monitoring the values on the serial window). However, when I adjust the potentiometer it significantly alters the sensor reading.
For example:
The potentiometer is at its 0 position, and the sensor is in the room temperature air. The serial shows TempSensor = 22 C, TSet = 0 C. This is normal.
Then when I turn the pot up: TempSensor= 40 C, TSet=55 C. -But the temperature sensor is still in the room temp air! So the pot value, TSet, goes up like it should, but also affects the sensor reading even though the temperature hasn't really changed.
Any advice would be greatly appreciated. Thanks!
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A3);
float tsens = map(sensorValue, 0, 1023, 0, 500);
int sensorValue2 = analogRead(A1);
float tset = map(sensorValue2, 0, 1023, 0, 70);
Serial.println(tsens);
Serial.println(tset);
}
I've recently bumped into a similar problem and my searches suggest that inserting a delay between the reads can help. On this question, I found this answer and this answer particularly helpful.
The idea is that you need to let some time pass after making a reading, then make another reading after the ADC has stabilized. Here's a function I have been using:
int safeAnalogRead(int pin)
{
int x = analogRead(pin); // make an initial reading to set up the ADC
delay(10); // let the ADC stabilize
x = analogRead(pin); // toss the first reading and take one we will keep
delay(10); // delay again to be friendly to future readings
return x;
}
I'm still having trouble getting an accurate reading of several potentiometers connected to the analog pins configured as a voltage dividers between vcc and ground, but at least now the values are stable.
BTW, it could be argued that since you have a delay after the first reading, it isn't necessary to have the second delay. This might matter if you call safeAnalogRead() twice in quick succession on two different pins.
You most likely have a ungrounded or miswired grounding on your temperature sensor. The pin configurations on the analog pins in Arduinos are layed out very close to each other such that floating voltages will move up or down when nearby pins have an applied voltage. If your ground connection (or power, though if it's correct at the beginning it's probably ground) for the sensor is disconnected or fixed to a high impedance line the analog voltages will move all over the place as other normally minuscule voltage sources will dominate the signal pathing. It probably fluctuates heavily if you put your finger near the A3 pin as well.
Is it noise or a bad value? I did a little test routine that looks at a pin and checks it against previous max and min values. I printed it to the serial monitor whenever a new boundary value showed up. If the wrong value is stable, check the circuit. If its noisey around a valid value, a digital low pass filter works pretty well. Take 34 readings of the pot. Find the highest and lowest values and discard those. Then take the average of the remaining 32 readings. I saw a 90% improvement in my setup (40 count error down to 3). 36 readings with 2 high and 2 low discarded would probably improve things further. If you have the time, you can do a double pass filter. Do this same process 34 times, then throw away the high and low and average it again. All together this is 34 x 34 readings, so noise should go away, but you are taking a long time to get a sample and a pot change will take awhile to get detected. To help with the time, I read the pot every pass through the main loop and save each value in a circular buffer. When I need to read a pot, I look at the historical 33 readings along with a 34th new one.
I have run into this issue before when reading multiple analog sensors in rapid succession. One possible cause(and the one I experienced) is the fact that the arduino only has 1 ADC and it charges a capacitor to take that reading. That capacitor can remain charged between readings thus skewing them.
Introducing a delay could potentially help with this as another user has pointed out, however the cleanest solution I was able to come up with was to "Reset" and discharge the ADC capacitor by taking an analog read of a third pin that is connected directly to ground.
int sensorValue;
int sensorValue2;
float tsens;
float tset;
int resetADC;
void setup()
{
Serial.begin(9600);
pinMode(A0,input);
pinMode(A1,input);
pinMode(A3,input);
}
void loop()
{
resetADC = analogRead(A0);
sensorValue = analogRead(A3);
tsens = map(sensorValue, 0, 1023, 0, 500);
resetADC = analogRead(A0);
sensorValue2 = analogRead(A1);
tset = map(sensorValue2, 0, 1023, 0, 70);
Serial.println(tsens);
Serial.println(tset);
}
I'm new to microcontrollers and I need help reading voltages and printing them in the serial monitor. I have done this using a potentiometer, but I was wondering if I could do the same with just voltages. Below is the code that I used when I read the potentiometer values:
I have tried reading voltages but when I input a voltage smaller than between 3-5V in pin A0 I get 0s in the serial monitor
int potPin = 0; // select the input pin
int val = 0; // variable to store the value coming from the function generator
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
val = analogRead(potPin); // read the value from the function generator
Serial.println(val);
delay(1000); //Sampling rate for the signal
}
as Udo Klein said, this looks like a hardware issue. try setting up your circuit like this: http://imgur.com/PYbeqLq
note that the grounds are shared between the function generator and the arduino - this is important for ensuring that voltages are measured correctly. remember that voltage is actually a difference in electric potential, so you need a common reference point to measure from.
To answer your question, yes you can read voltages from another piece of hardware.
As gearbot tells you it is important to keep a common ground between the arduino and the other piece of hardware.
Also be carefull, the arduino can only measure voltages between 0 and 5 Volts. Don't try to measure higher voltages without adjusting the circuitry as you might destroy your arduino board.
If you're unsure measure the voltages before attaching to the arduino with a multimeter.
The Uno has 6 analog inputs, labeled A0 through A5, each of which provide 10 bits of resolution (i.e. 1024 different values). By default they measure from ground to 5 volts, though is it possible to change the upper end of their range using the AREF pin and the analogReference() function.
edit:
I didn't see the added comment at the bottom of your post. This indicates indeed a hardware problem (probably in your circuitry)
To be sure the arduino does the right thing, measure the voltage with your multimeter between pin A0 and GND while your hardware is attached and working. You should be able to read the correct voltage there.
I suspect it will give the same values as the Arduino.
Then trace back your circuitry with your multimeter (keeping GND attached) to find where something is going wrong.
Try scaling your 0 to 5 or 1-5v input
using map function.
int setValue = map(ana1Value, 0, 1023, 0, 100);
could be a help for you.
the analogue input voltage is the scaled 0-100 then you can work with that
I've just hooked up a electret microphone to an Arduino, and I'd like to sample between the ranges of 1 kHz and 4 kHz.
I understand this is limited to the machine code and the ADC, so I'm trying to keep the sketch simple.
Is it possible to sample between these frequencies with the sketch below?
const int analogPin = 0;
int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
int mn = 1024;
int mx = 0;
for (int i = 0; i < 5; ++i) {
int val = analogRead(analogPin);
mn = min(mn, val);
mx = max(mx, val);
}
if (mx-mn >= 50) {
digitalWrite(ledPin, HIGH);
}
else {
digitalWrite(ledPin, LOW);
}
}
Arduino is a prototyping platform consisting of a number of hardware boards plus a software abstraction layer. For a question like this, it is useful to consider the capabilities of the underlying hardware, as these provide the ultimate limits. I'll assume you are using Arduino Uno/Nano, the story is different for Due.
According to the datasheet, each ADC reading (beyond the first one) takes 13 ADC clock cycles. ADC clock (different from the MCU) clock is derived by dividing the system clock by some factor, at least 2. So at 16Mhz board this amounts to 0.6 million samples per second. So far so good. However, that's not the end of the story, you still need to read the data. If you use interrupts, even if you do something very simple, experience suggests that you will lose about 100 clock to interrupt processing. Now you are down to 126K samples/second. But this is a theoretical maximum.
The datasheet states that for maximum accuracy for the ADC requires 50kHz - 200kHz ADC clock. In the Arduino code (in wiring.c), a division factor of 128 is chosen:
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
This means that each conversion takes 128*13 = 1764 clocks, which yields a theoretical maximum of 10K samples per second. It is a little bit worse than that given that the readAnalog() function does something beyond just starting the ADC conversion and waiting for it to finish, but it shouldn't be too much worse. This doesn't involve your code of course: any processing you do on the results of readAnalog() will make it more difficult to capture more samples. But yes, to capture at 4Khz you will need to make sure that you code spends less than 1.5k clock cycles/sample, which should be doable. Note that if you are doing five readings like you are doing in the code you posted, the maximum capture rate will be 2kHz if your code does very little.
As far as how to capture the data, you need to make deal with the fact that microphones without amplification will not give you 0-5V readings that you might expect if you are using analogRead(). In fact, microphone output voltages swing from positive to negative, however, the negative voltages will not be picked up by the ADC, and show up as just zeros, unless you give your microphone a voltage offset.
I am not exactly sure what your code that compares minimum amplitude to maximum amplitude is supposed to be doing. Are you wanting to digitize the audio? In this case you need to save all the amplitude readings collected from analogRead(), and then you can run FFTs on them on another computer: Arduino is most likely not going to be fast enough to do frequency analysis on the data.
I have heard, or rather remember reading, that the ADC could handle up to 10k-samples per second, so it should be OK up to 5 kHz. However, I have not tried this nor do I have a link to back it up at the moment.
Just try and see.
Now I know some of the Arduino library functions are slow, notably the DigitalRead/Write that has overhead of hundreds of cycles. Most of this is the sanity checking that allows people to just perform DigitalRead/Write without thinking much about setting everything up.
However, to squeeze out the maximum performance you could look into writing your own AnalogRead that is optimized for your use case.
At least some links on the subject:
Pin I/O performance (JeeLabs)
C++ Template method for faster access (JeeLabs)
I happen to have just tried this using an Arduino Uno and similar code to yours and I've been able to sample an average of 8000 times a second. That is the Nyquist frequency for 4 kHz so you're good but not much margin for error.