I have a gas sensor that I am trying to read. I have connected the sensor to the analog input of ESP-S2 TFT Feather. When I change the analog to digital and read the measured voltage, the measured voltage is very very high. I figured out the resolution of this board is 13 bit. But, the measured voltage is still very high.
int analogInPin = A2;
void readco() {
// read the analog in value:
sensorValue = 0;
const int res = 8191; //resolution = 13-bit and 2^13 - 1 = 8191
sensorValue = analogRead(analogInPin) + sensorValue;
iaq_data.co_0=(float) sensorValue*3.3/res;
From the ESP32-S2 docs found here,
Resolution of ESP32-S2 ADC raw results under Single Read mode is 12-bit
Are you sure your resolution is 13 bit?
Also, you seem to be adding sensorValue to itself every time. You initialise it to 0 every time so it should not matter but I would remove that.
This code should work:
int 12_bit_resolution = 4095; // 2^12 4096 - 1
input_voltage = analogRead(analogInPin) * (3.3 / 12_bit_resolution);
Related
i'm doing wireless sensor node using (esp32, DHT11, soil moisture and nrf24l01) and i want to add an battery to supply those sensors, also need to measure battery voltage.
For the battery, voltage always change to cant use as a Vcc reference, so i find there is an internal reference voltage.
Could anyone done with this give me some instruction.
Thank you
i'm gonna use LIFEPO4 3.3v normaly (3.6v at max) or 18650 3.7v/4.2v max
According to docs:
The default ADC full-scale voltage is 1.1V. To read higher voltages
(up to the pin maximum voltage, usually 3.3V) requires setting >0dB
signal attenuation for that ADC channel.
So set it to zero for 1.1v; next, you can read the voltage (in a loop for better accuracy) and then convert it to a valid voltage and find the percentage of battery level.
In the below example, the function would return the percentage of battery level. Remember to edit battery_max and battery_min based on your battery voltage levels. I assumed that you connect the battery to ADC1 channel 0 (GPIO 36).
Also, I recommend you create a resistor divider circuit to reduce the voltage level. If your input power supply drops down, the Arduino will feed directly from Analog input, which is undesirable. Remember that your voltage level should not exceed above 3.9v.
#include <driver/adc.h>
float battery_read()
{
//read battery voltage per %
long sum = 0; // sum of samples taken
float voltage = 0.0; // calculated voltage
float output = 0.0; //output value
const float battery_max = 3.6; //maximum voltage of battery
const float battery_min = 3.3; //minimum voltage of battery before shutdown
float R1 = 100000.0; // resistance of R1 (100K)
float R2 = 10000.0; // resistance of R2 (10K)
for (int i = 0; i < 500; i++)
{
sum += adc1_get_voltage(ADC1_CHANNEL_0);
delayMicroseconds(1000);
}
// calculate the voltage
voltage = sum / (float)500;
voltage = (voltage * 1.1) / 4096.0; //for internal 1.1v reference
// use if added divider circuit
// voltage = voltage / (R2/(R1+R2));
//round value by two precision
voltage = roundf(voltage * 100) / 100;
Serial.print("voltage: ");
Serial.println(voltage, 2);
output = ((voltage - battery_min) / (battery_max - battery_min)) * 100;
if (output < 100)
return output;
else
return 100.0f;
}
void setup()
{
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db); //set reference voltage to internal
Serial.begin(9600);
}
void loop()
{
Serial.print("Battery Level: ");
Serial.println(battery_read(), 2);
delay(1000);
}
If you add a divider circuit, you need to change battery_min and battery_max according to the new output of the divider circuit.
I'm using Arduino Micro to read from 5 flex sensors and display the corresponding angles to the Serial monitor. I am currently having quite some problems with the oscillating values I am getting from the analogRead(). It doesn't seem to matter whether the pin is connected to a flex sensor or just grounded - the output is oscillating a lot.
Originally everything was being read and outputted just fine but I wanted to have an exact 100Hz sampling frequency and tried to play a bit with Timer Interrupts. And that's when this oscillating behaviour started. I reversed to my original code, which just uses some delay(), and simplified to only read from two pins, but cannot seem to shake off the oscillations.
I think I may have messed up something about ADC when trying to implement Interrupts, but I don't know how to check it or fix it. Please, help me figure out how to fix this!
This is the raw output of analogRead. The drop in values occurs when I bend the flex sensor
And this is the resulting calculated angle. Also oscillating.
Here is my code minimal working example:
int fin;
const int input[5] = {A0,A1,A2,A3,A4}; // the analog pins
int flex[5]; // analog signal read
float flexV;
float flexR[5]; // resistance on the 47k resistor
int angle[5]; // joint angles
const float VCC = 4.98; // Measured voltage of Arduino 5V line
// Measured resistance of the 47k resistors R1-R5
const float R[5] = {45900.0,45900.0,45900.0,45900.0,45900.0};
// Calibration values of resistance measured during straight phase and 90 deg bend phase
const float R_STRAIGHT[5] = {37651.0,37651.0,37651.0,37651.0,37651.0};
const float R_BEND[5] = {71783.0,71783.0,71783.0,71783.0,71783.0};
void setup() {
}
void loop() {
for(fin = 0; fin <= 4; fin++) {
flex[fin] = analogRead(input[fin]);
flexV = flex[fin]*VCC/1023.0;
flexR[fin] = R[fin] * (VCC/flexV - 1.0);
angle[fin] = map(flexR[fin],R_STRAIGHT[fin],R_BEND[fin],0,90.0);
delay(1);
}
Serial.print(angle[0]);
Serial.print(" ");
Serial.print(angle[1]);
Serial.print(" ");
Serial.print(angle[2]);
Serial.print(" ");
Serial.print(angle[3]);
Serial.print(" ");
Serial.print(angle[4]);
Serial.print(" ");
Serial.println(millis());
delay(6);
}
ok, analogReads normally do have a little oscillation, its normal! they are measuring voltage values and depending on the sensor you are using they will oscillate, same idea of measuring voltage using a multi meter. if you want to learn a bit more about this, ADC's conversor is a good way to start.
What you need to do in order to prevent those oscillations is to develop a filter. this could be done on hardware or software. Obviously the software is the easiest way to go.
My tip for you would be to a average filter! it's a simple concept, you will get X readings at the same time of that sensors (values would go up and down on variation) and you would get the avarage value out of it.
Here is a simple example using your code:
int fin;
const int input[5] = {A0,A1,A2,A3,A4}; // the analog pins
int flex[5]; // analog signal read
float flexV;
float flexR[5]; // resistance on the 47k resistor
float average; //Variable to store the sum of measurements
int nSamples = 4; //Number of reading you are going to use
int angle[5]; // joint angles
const float VCC = 4.98; // Measured voltage of Arduino 5V line
// Measured resistance of the 47k resistors R1-R5
const float R[5] = {45900.0,45900.0,45900.0,45900.0,45900.0};
// Calibration values of resistance measured during straight phase and 90 deg bend phase
const float R_STRAIGHT[5] = {37651.0,37651.0,37651.0,37651.0,37651.0};
const float R_BEND[5] = {71783.0,71783.0,71783.0,71783.0,71783.0};
void setup() {
}
void loop() {
for(fin = 0; fin <= 4; fin++) {
/* A new for here to make readings and store them on the average variable */
for(int x = 0; x <= nSamples; x++){
flex[fin] = analogRead(input[fin]);
average = average + flex[fin];
}
/*Do de avarage and clear the value on this variable*/
flex[fin] = average/nSamples;
avarage = 0;
flexV = flex[fin]*VCC/1023.0;
flexR[fin] = R[fin] * (VCC/flexV - 1.0);
angle[fin] = map(flexR[fin],R_STRAIGHT[fin],R_BEND[fin],0,90.0);
delay(1);
}
Serial.print(angle[0]);
Serial.print(" ");
Serial.print(angle[1]);
Serial.print(" ");
Serial.print(angle[2]);
Serial.print(" ");
Serial.print(angle[3]);
Serial.print(" ");
Serial.print(angle[4]);
Serial.print(" ");
Serial.println(millis());
delay(6);
}
The idea here is simple, to smooth the values by doing this average, leading to more consistent values. Obviously, Higher number of samples improve the results.
It's simple math, if you are getting 4 values like: 45, 50, 55, 50, your average would be 50 (45+50+55+50 = 200/nSamples = 50)
I'm new here so, if I make any mistake, sorry. Well, I'm working with Arduino (Mega2560) to construct an Ammeter and found out a little problem... Arduino Mega measures voltage from 0 to 5V, and the AnalogPins return a 10-bit value according with the reading (that is, 1 bit represents 5/(2^10)=4mV (approximately)). But, in the case of ammeter, I need to use a resistor with small resistance so that my circuit don't get changes. So my objective is read the voltage drop and from V = R.I, calculate the current. But, as the voltage drop is such as slowly, the pin can't read any value.
Eg.: there is a current flowing from 2mA in the region that I would like to measure. With a resistance of 0.3 ohms (the lower value I found here) , would be: V = 2m . 0.3 = 0.6mV.
As I said, the lower posssible value of reading in analogPins is 4mV.
Thus, how to improve my precision of reading? For example, instead of 1023 represents only 5V, the same value represents around of 30 or 40mV...
0 - 0 V
1023 - 30/40 mV
You can use 1.1V internal voltage reference, or some more precise external one (This can be archieved by analogReference). BTW with such a small currents it would be more convenient to use bigger resistor.
Or, forget about limited functionality of analogRead and do it directly. For example 2.56V reference, differential input with 10x or 200x gain (but you'll get range -512 to 511 -> 2.56/512).
In below example, voltage_meter reads 500 samples in about 1 millisecond and returns the average. I set the reference to 1.1v for better precision.
int battery_pin = A3;
float voltage_meter()
{
//read battery voltage per %
long sum = 0; // sum of samples taken
float voltage = 0.0; // calculated voltage
float output = 0.0; //output value
for (int i = 0; i < 500; i++)
{
sum += analogRead(battery_pin);
delayMicroseconds(1000);
}
// calculate the voltage
voltage = sum / (float)500;
// voltage = (voltage * 5.0) / 1023.0; //for default reference voltage
voltage = (voltage * 1.1) / 1023.0; //for internal 1.1v reference
//round value by two precision
voltage = roundf(voltage * 100) / 100;
return voltage;
}
void setup()
{
analogReference(INTERNAL); //set reference voltage to internal
Serial.begin(9600);
}
void loop()
{
Serial.print("Voltage Level: ");
Serial.print(voltage_meter(), 4);
Serial.println(" V");
delay(1000);
}
On ATmega based boards (UNO, Nano, Mini, Mega), it takes about 100 microseconds (0.0001 s) to read an analog input, so the maximum reading rate is about 10,000 times a second.
100 Microsecond and no 1000 how the example
i want made speed detection "device" using with Arduino and two ultrasonic hc-sr04 like this link. but I want to make it with ultrasonic instead by LDR.
from that link. how lasers and ldr work, like this
The resistors are used as pull-down resistors and I wired the sensors and put them in a case, to avoid them detecting surrounding light. For each case, a hole was drilled so that the laser beam can light the sensor while the ambient light does not affect the sensor.
The working principle is easy: an object that passes by will "cut" the laser beams, this means the LDR sensor will detect this sudden drop of light intensity. First I defined a threshold value under which the sensor is considered triggered, once the value is under threshold for the first sensor then Arduino waits for the second one to be triggered. During this waiting time it counts the elapsed time between the two events. When the second beam is interrupted, the timer stops and now is just simple math. The distance between the 2 sensors is known, the time between the two events is known, and speed can be computed as speed = distance/time.
Below the Arduino code:
/*
by Claudiu Cristian
*/
unsigned long time1;
int photocellPin_1 = 0; // 1st sensor is connected to a0
int photocellReading_1; // the analog reading from the analog port
int photocellPin_2 = 1; // 2nd sensor is connected to a1
int photocellReading_2; // the analog reading from the analog port
int threshold = 700; //value below sensors are trigerd
float Speed; // declaration of Speed variable
float timing;
unsigned long int calcTimeout = 0; // initialisation of timeout variable
void setup(void) {
// We'll send debugging information via the Serial monitor
Serial.begin(9600);
}
void loop(void) {
photocellReading_1 = analogRead(photocellPin_1); //read out values for sensor 1
photocellReading_2 = analogRead(photocellPin_2); //read out values for sensor 2
// if reading of first sensor is smaller than threshold starts time count and moves to calculation function
if (photocellReading_1 < threshold) {
time1 = millis();
startCalculation();
}
}
// calculation function
void startCalculation() {
calcTimeout = millis(); // asign time to timeout variable
//we wait for trigger of sensor 2 to start calculation - otherwise timeout
while (!(photocellReading_2 < threshold)) {
photocellReading_2 = analogRead(photocellPin_2);
if (millis() - calcTimeout > 5000) return;
}
timing = ((float) millis() - (float) time1) / 1000.0; //computes time in seconds
Speed = 0.115 / timing; //speed in m/s given a separation distance of 11.5 cm
delay(100);
Serial.print(Speed);
Serial.print("\n");
}
how to implement the code with ultrasonic HC-SR04 sensors?
the coding is problem for me. hopefully someone can help me...... :(
Please excuse my poor English !
There are already lots of examples on the internet, so if all you want to do is copy, google arduino sr04
But if you want to know how to do it...
The sr04 has 4 pins, vin, gnd, trigger, and echo.
Connect vin and ground to +5 and gnd
Connect trigger to a digital output pin
Connect echo to a digital input pin
Trigger by going low for 2 microseconds (us) and then high for 10 us then low again
Then get the results with a pulseIn from the echo pin
Read the data sheet for more information
I am creating my first Arduino program on the UNO r3. I have played with the Arduino Uno before just with petty example programs, etc. I am using two analog inputs to sense distance using 2 laser sensors with 0-5vdc scaling. These two inputs are 0-5vdc and I have ensured common grounding throughout. The two sensors are named left and right and are input to A0 and A1 respectively. I also have a differential POT which uses a 10K ohm POT wiper voltage as an input on A2. The theory of the program is to take the absolute value of the difference in input voltages between the left and right lasers then determine if the result is greater than or equal to the voltage on pin A2 from the POT wiper. Based on the resulting math, turn on or off a relay interposed to pin D13 via a transistor driver circuit.
The PROBLEM: I cannot achieve accurate changes in voltage on the scale (0-1023) on pins A0, A1, or A2. I have utilized the serial monitor to diagnose this problem. Not sure what the problem is, any help would be great. Also, I cannot achieve a 0 value on any of the above analog pins, even the POT wiper!!!
Here's my code:
const int lf_dist = A0; //names A0
const int rt_dist = A1; //names A1
const int differential = A2; //names A2
const int relay = 13; // select the pin for the relay coil
unsigned int left = 0; // variable to store the value coming from the left sensor
unsigned int right = 0; // variable to store the value coming from the right sensor
unsigned int diff = 0; // variable to store the value coming from the differential POT for maximum distance differential
unsigned int offset = 0; // variable that stores the value between the two laser sensors
void setup() {
Serial.begin(9600);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(relay, OUTPUT); // declare the relay pin as an OUTPUT:
analogReference(DEFAULT);
}
void loop()
{
unsigned int left = 0; // variable to store the value coming from the left sensor
unsigned int right = 0; // variable to store the value coming from the right sensor
unsigned int diff = 0; // variable to store the value coming from the differential POT for maximum distance differential
unsigned int offset = 0; // variable that stores the value between the two laser sensors
left = analogRead(A0); // read the value from the left laser
delay(5);
right = analogRead(A1); // read the value from the right sensor
delay(5);
diff = analogRead(A2); // read the value from the differential POT
delay(5);
offset = abs(left - right);
if(offset >= diff) // does math to check if left and right distances are greater than the value clocked in by the differential POT
{
digitalWrite(relay, LOW); // turns off the relay, opens the stop circuit, and turns on the yellow light
}
else
{
digitalWrite(relay, HIGH); // turns on the relay if all is good, and that keeps the machine running
}
Serial.print("\n left = " );
Serial.print(left);
Serial.print("\n right = " );
Serial.print(right);
Serial.print("\n differential = " );
Serial.print(diff);
delay(1000);
}
afaict, this should really be due to the floating pins surrounding the measuring pins, having erratic values, hence perturbating your measures. You should look at your values using arduinoscope, which will show you the interfering effects of the other floating pins on your measuring pins.
The easy workaround for this is to ground all analogical input pins you're not using, and put as much space as you can between both your inputs, so they don't interfere with each other.
I realize this thread is somewhat old not, but perhaps this will help someone. If you power the Arduino with only 5V, as you say you did with a regulator, you will get very erratic behavior, particularly from the analog pins. This is because you will start to brown out the internal voltage regulators that provide the AREF, 3.3, and 5.0 outputs. I've tested this for a robotics project I'm working on, and right around 6.5 volts, everything begins to go wrong. I suppose if you always provided 5.0 input voltage you could compensate for this effect, but in my case I used a LiPo battery that could range from 8.4 volts down to 6.0 volts, and everything goes crazy at 6.5 volts.
The minimum current that arduino sinks in during the sampling from potentiometer should not disturb the actual open input volts at the wiper.
Initialize the pins in pull up mode to avoid garbage values or 'floating' pins or use your own pull down/up resistors at the pins :)