#include <cstdio> #include <cstdint> #include <cmath> /* Examples for dealing with ADCs & DACs, including how to work with voltages and how to adjust readings to account for offset and gain errors. */ /* Examples for converting between code points and voltage. Code points are the integer readings from an ADC or the integer output register for a DAC. For example, if you have a 10-bit DAC, then the code points are from 0 to 1023. */ #define RESOLUTION_8_BIT 256 #define RESOLUTION_10_BIT 1024 #define RESOLUTION_12_BIT 4096 #define RESOLUTION_14_BIT 16384 #define RESOLUTION_16_BIT 65536 /* Convert a code point to a voltage. This is useful for ADCs - if you know the range of the ADC's measurements you can use this to determine which voltage an analogRead() result corresponds to. */ float code_points_to_volts(uint32_t code_point, uint32_t resolution = RESOLUTION_12_BIT, float min_voltage = 0.0f, float max_voltage = 3.3f) { float voltage_range = max_voltage - min_voltage; float normalized_value = (float)(code_point) / (float)(resolution - 1); return min_voltage + (voltage_range * normalized_value); } /* Convert a voltage to a code point. This is useful for DACs - if you want to output a specific voltage, then you can use this to determine which code point to pass to analogWrite() */ uint32_t volts_to_code_points(float volts, uint32_t resolution = RESOLUTION_12_BIT, float min_voltage = 0.0f, float max_voltage = 3.3f) { float voltage_range = max_voltage - min_voltage; float normalized_value = (volts - min_voltage) / voltage_range; uint32_t code_points = ceil(normalized_value * (resolution - 1)); } /* Demonstration of the conversion functions */ void demonstrate_coversions() { printf("\nConversion demonstration:\n\n"); printf("Code points -> Volts:\n"); float volts = code_points_to_volts(2048); printf("2048 : 4096 :: %0.2f V : 3.3 V\n", volts); volts = code_points_to_volts(256, RESOLUTION_10_BIT, 1.0f, 2.0f); printf("256 : 1024 :: %0.2f V : 1.0 V to 2.0 V\n", volts); printf("Volts -> Code points:\n"); uint32_t code_points = volts_to_code_points(1.65f); printf("%u : 4096 :: 1.65 V : 3.3 V\n", code_points); code_points = volts_to_code_points(1.25f, RESOLUTION_10_BIT, 1.0f, 2.0f); printf("%u : 1024 :: 1.25 V : 1.0 V to 2.0 V\n", code_points); } /* Helpers for determining and correcting gain and offset errors. */ /* Determines the gain and offset error using two measurements. For example, if you were using this for a DAC, you would pick two output voltages to measure - one near the bottom of the range, one near the top. Use the volts_to_code_points() function to set the DAC output's value. Measure the *actual* voltage for both of the expected values. You would use those values here to get the gain and offset errors. */ void calculate_gain_and_offset_error(float low_measured, float high_measured, float low_expected, float high_expected, float& gain_error, float& offset_error) { gain_error = (high_measured - low_measured) / (high_expected - low_expected); offset_error = (low_measured * (1.0f / gain_error)) - low_expected; } /* Use the gain and offset error to correct a value. */ float apply_error_correction(float value, float gain_error, float offset_error) { return (value * (1.0f / gain_error)) - offset_error; } /* Demonstration of the conversion error functions. */ void demonstrate_error_correction() { printf("\nGain & offset error demonstration:\n\n"); float low_expected = 1.0; float high_expected = 3.0; printf("Expected values: %0.2f and %0.2f\n\n", low_expected, high_expected); /* Measurements are the same as expected, there should be no errors measured. */ float low_measured = 1.0; float high_measured = 3.0; float gain_error; float offset_error; calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Actual values: %0.2f and %0.2f: gain error: %0.4f, offset error: %0.2f\n", low_measured, high_measured, gain_error, offset_error); /* The high-side measurment is more than it should be, which indicates that the gain error is above one. */ high_measured = 3.5; calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Actual values: %0.2f and %0.2f: gain error: %0.4f, offset error: %0.2f\n", low_measured, high_measured, gain_error, offset_error); /* The high-side measurment is less than it should be, which indicates that the gain error is below one. */ high_measured = 2.5; calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Actual values: %0.2f and %0.2f: gain error: %0.4f, offset error: %0.2f\n", low_measured, high_measured, gain_error, offset_error); /* Both readings are slightly more than they should be (by the same amount) which indicates there is a positive offset error, but no gain error. */ low_measured = 2; high_measured = 4; calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Actual values: %0.2f and %0.2f: gain error: %0.4f, offset error: %0.2f\n", low_measured, high_measured, gain_error, offset_error); /* Both readings are slightly less than they should be (by the same amount) which indicates there is a negative offset error, but no gain error. */ low_measured = 0; high_measured = 2; calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Actual values: %0.2f and %0.2f: gain error: %0.4f, offset error: %0.2f\n", low_measured, high_measured, gain_error, offset_error); printf("\nError correction demonstration:\n\n"); printf("Expected values: 1.0 and 3.0\n"); low_measured = 1.1; high_measured = 2.95; printf("Actual values: %0.2f and %0.2f\n", low_measured, high_measured); calculate_gain_and_offset_error( low_measured, high_measured, low_expected, high_expected, gain_error, offset_error); printf("Gain error: %0.4f, offset error: %0.2f\n\n", gain_error, offset_error); for(float v = low_expected; v <= high_expected; v += 0.1) { printf("Unadjusted: %0.2f, adjusted: %0.2f\n", v, apply_error_correction(v, gain_error, offset_error)); } } /* This main function is just here to demonstrate these functions, you wouldn't include this in your Arduino sketch. */ int main() { demonstrate_coversions(); demonstrate_error_correction(); return 0; }
Write, Run & Share C++ code online using OneCompiler's C++ online compiler for free. It's one of the robust, feature-rich online compilers for C++ language, running on the latest version 17. Getting started with the OneCompiler's C++ compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C++
and start coding!
OneCompiler's C++ online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cout << "Enter name:";
getline (cin, name);
cout << "Hello " << name;
return 0;
}
C++ is a widely used middle-level programming language.
When ever you want to perform a set of operations based on a condition If-Else is used.
if(conditional-expression) {
//code
}
else {
//code
}
You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.
Switch is an alternative to If-Else-If ladder.
switch(conditional-expression){
case value1:
// code
break; // optional
case value2:
// code
break; // optional
......
default:
code to be executed when all the above cases are not matched;
}
For loop is used to iterate a set of statements based on a condition.
for(Initialization; Condition; Increment/decrement){
//code
}
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while (condition) {
// code
}
Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.
do {
// code
} while (condition);
Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity. Function gets run only when it is called.
return_type function_name(parameters);
function_name (parameters)
return_type function_name(parameters) {
// code
}