Digital to Simulated Analog
‘Digital’, or more accurately, binary-state sensors/switches only report a simple ‘on’ or ‘off’ state – none of the analogue range of values that some sensors possess.
What if you want that simple binary state transition to begin and/or terminate a change in value gradually? We can devise a ‘sensor ramp’ mechanism that manages this increase/decrease of our desired ‘analogue’ value within a pre-set range.
An example might be using ‘digital’ sensors such as the PIR Motion Sensor, magnetic reed switches, or the basic pushbutton to gradually change the brightness of an LED.
Other examples might be from datasets in IoTa that broadcast binary states, such as car parking sensors or bike stations.
This simple algorithm is basically a counter that ramps up/down a variable over time. When the sensor is active (reports ‘on’) this variable slowly increases linearly. The opposite happens when the sensor is inactive (reports ‘off’). This algorithm is visually represented in this diagram below. What’s left is then up to you to make use of this variable:
graph TD;
style C fill:#ccbbff,stroke:#666,stroke-width:1px
style D fill:#ccbbff,stroke:#666,stroke-width:1px
style E fill:#aaccff,stroke:#666,stroke-width:2px
A{Is incoming value <br />TRUE/HIGH/1?} -- yes --> C[increase/decrease value of sensorRamp]
B{Is incoming value <br />FALSE/LOW/0?} -- yes --> C
C --> D[limit value of sensorRamp between RAMP_MIN and RAMP_MAX]
D --> E([update sensorRamp])
Code
The code is heavily commented below, so read it through and adapt into your own project. For simplicity, the code assumes a PIR sensor connected to an Arduino UNO.
Libraries Used
- None
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
SensorRamp: a way to simulate analogue output with digital sensors
This example code allows one to easily connect a DIGITAL sensor
that can be used to LINEARLY increment/decrement a variable gradually.
This is a general 'utility' script that requires tweaking to match
each project's needs.
In particular, look at RAMP_MIN, RAMP_MAX and RAMP_INCRE
Also, modify the #define tags to the pins / values accordingly to your project's wiring.
Check comments below for detailed explanation.
*/
/*
Please note that the code provided here is licensed under the MIT license.
The MIT License (MIT)
Copyright © 2016 Chuan Khoo
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#define SENSEPIN 3 // say you have a digital PIR sensor connected to D3
#define LEDPIN 9 // we'll use an LED connected on D9 (via a 330/220ohm resistor!) to visually observe the results of the ramp
#define RAMP_MIN 0 // the minimum value you want the ramp to drop down to
#define RAMP_MAX 800 // the maximum value you want the ramp to increase to
#define RAMP_INCRE 0.015 // how fast you want the ramp to set the speed of the ramp; fractions allowed! try a range of 0.015 to 2
int mySensorVal = 0; // placeholder that stores state of digital input
double sensorRamp = 0; // the current value of the ramp; change this if you want a non-zero initial value
int rampDir = 0; // an up/down direction modifier used in the code; don't modify this
/////////// SETUP function
void setup() {
Serial.begin(115200); // using this to debug the status of the sensorRamp value
pinMode(SENSEPIN, INPUT); // if you're using a pushbutton, use INPUT_PULLDOWN instead of INPUT
pinMode(LEDPIN, OUTPUT); // debug LED just to see what's going on with our ramp, remove this if you don't need it
}
/////////// LOOP function
void loop() {
mySensorVal = digitalRead(SENSEPIN); // read state of sensor into mySensorVal
if(mySensorVal) { // if you wish to detect a reverse state, change to !mySensorVal
rampDir = 1;
} else {
rampDir = -1;
}
updateRamp();
Serial.print(mySensorVal);
Serial.print(" : ");
Serial.println((int)sensorRamp);
// next, do whatever you need to do with the sensorRamp variable!
// e.g. driving a MOSFET gate to alter the speed of a DC motor / brightness of 12V analog LED strip:
// analogWrite(SOME_PWM_PIN, sensorRamp);
}
/////////// copy this entire updateRamp function into your own code
void updateRamp() {
sensorRamp += rampDir * RAMP_INCRE;
sensorRamp = constrain(sensorRamp, RAMP_MIN, RAMP_MAX); // make sure the ramp value is kept within RAMP_MIN and RAMP_MAX
int remap = map(sensorRamp, RAMP_MIN, RAMP_MAX, 0, 255);
analogWrite(LEDPIN, remap); // debug LED just to see what's going on with our ramp, comment this out if you don't need it
}