Skip to content

Commit 7f65d0c

Browse files
committed
0.2.1 X9C10X
1 parent f24d899 commit 7f65d0c

File tree

10 files changed

+289
-42
lines changed

10 files changed

+289
-42
lines changed

libraries/X9C10X/README.md

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ Arduino Library for X9C10X series digital potentiometer.
1313

1414
## Description
1515

16-
This **experimental** library provides a X9C base class, a X9C10X class and
17-
four derived classes for specific digital potentiometer.
16+
This **experimental** library provides
17+
- a minimal X9C base class,
18+
- an elaborated X9C10X class and
19+
- four derived classes for specific digital potentiometer.
1820

1921
| class | resistance | tested | notes |
2022
|:------:|:----------:|:-------:|:-------------|
@@ -29,22 +31,25 @@ four derived classes for specific digital potentiometer.
2931
_Note: Ω Ohm sign = ALT-234_
3032

3133
The X9C10X object keeps track of the position of the potentiometer,
32-
but the user should set it with **setPosition(pos, true);**
34+
but the user should set it with **setPosition(position, true);**
3335
Otherwise the library and device will probably not be in sync.
3436

35-
Since 0.2.0 the library has a minimal X9C class. See below.
37+
Since 0.2.1 the library also supports **restoreInternalPosition(position)**
38+
to set the internal position with the value from the latest **store()** call.
39+
See the examples.
3640

3741

3842
### Multiple devices
3943

4044
Multiple devices can be controlled by assigning them an unique selectPin (CS).
4145
This behaviour is similar to the SPI select pin.
4246

43-
It should be possible to share the U/D and INC lines (not tested) when controlling multiple X9C devices.
47+
It should be possible to share the U/D and INC lines (not tested) when controlling
48+
multiple X9C devices.
4449

4550
Note: one should select one device at a time.
4651
Sharing a CS pin or sending pulses to multiple devices at the same time will
47-
cause the library and devices get oout of sync.
52+
cause the library and devices get out of sync.
4853

4954

5055
### PINOUT
@@ -79,13 +84,14 @@ quality can become an issue. (not investigated further)
7984

8085
## Interface
8186

87+
```cpp
88+
#include "X9C10X.h"
89+
```
8290

8391
## X9C base class
8492

8593
This is the most minimalistic base class.
86-
It does not provide position information but that is sometimes enough.
87-
88-
Use **\#include "X9C10X.h"**
94+
It does not provide position information but sometimes that is just enough.
8995

9096
- **X9C()** Constructor.
9197
- **void begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin)**
@@ -95,45 +101,61 @@ Note: **begin()** has a hard coded 500uS delay so the device can wake up.
95101
- **void decr()** moves one position down (if possible).
96102
- **void store()** stores the current position in NV-RAM to be used at the next restart.
97103
Does not return a value as the position cannot be read from the device.
98-
So the user should keep track of the position if needed.
104+
So the user must keep track of the position if needed.
99105

100106

101107
## X9C10X base class
102108

103-
This class is derived from the X9C class but adds position, Ohm and type information.
104-
105-
Use **\#include "X9C10X.h"**
109+
This class is derived from the X9C class and adds position, Ohm and type information.
106110

107111
- **X9C10X(uint32_t Ohm = 10000)** Constructor, default initializes the resistance to 10000 Ω.
108112
To calibrate one can fill in any other (measured) value e.g. 9950 Ω.
109113
This can be useful e.g. if one sets a fixed resistor parallel over the X9C one.
110114
- **void begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin)**
111115
sets the INC, UD and CS pins used by the device.
112116
Note: **begin()** has a hard coded 500uS delay so the device can wake up.
113-
- **void setPosition(uint8_t position, bool forced = false)** sets the wiper
117+
- **uint8_t setPosition(uint8_t position, bool forced = false)** sets the wiper
114118
to a position between 0 and 99.
115119
The movement is relative to the current (internal) position.
116120
If forced is set to true, the wiper will be moved to the closest "end" position
117121
and from there moved to the requested position.
118-
The internal position is replaced by the new position.
122+
The internal position is replaced by the new position.
123+
If the new position > 99 the new position is truncated to 99.
124+
Returns new position 0 .. 99.
119125
- **uint8_t getPosition()** returns the current (internal) position. 0..99
120126
- **bool incr()** moves one position up (if possible).
121127
Returns true if moved and false if already at end position
122128
according to internal position math.
123129
- **bool decr()** moves one position down (if possible).
124130
Returns true if moved and false if already at begin position
125131
according to internal position math.
126-
- **uint8_t store()** stores the current position in the NVRAM of the device,
127-
and returns the current position so it can later be used as position parameter for **setPosition()**.
128-
Warning: use with care (not tested).
129-
Note: **store()** blocks for 20 milliseconds.
132+
- **uint8_t store()** stores the current position in the NVRAM of the device.
133+
Returns the current position so it can later be used as position parameter
134+
for **setPosition()** or **restoreInternalPosition()**.
135+
- Warning: use with care (not tested).
136+
- Note: **store()** blocks for 20 milliseconds.
137+
- **uint8_t restoreInternalPosition(uint8_t position)** hard overwrite of the current
138+
(internal) position to initialize the library with the value returned by **store()**.
139+
The potentiometer will not be moved() in this process, and the user is responsible
140+
to provide the right value.
141+
Returns new position 0 .. 99.
142+
This function allows users e.g. to save the position returned by **store()** in EEPROM
143+
to initialize the library with this EEPROM value after a reboot.
144+
- Warning: use with care (not tested).
130145

131146
Note: **begin()** changed in 0.2.0 as the implicit parameter position
132147
was removed for the explicit function call to **setPosition()**.
133148
If **setPosition()** is not called, the device uses the last stored
134149
value as position. Unfortunately the position cannot be read from the device.
135150
This will result in a mismatch between the internal position and the
136-
external one.
151+
external one.
152+
153+
Since 0.2.1 the function **uint8_t restoreInternalPosition(uint8_t position)**
154+
gives some means to solve this, see examples.
155+
Be aware that if a system resets and the position has been changed since last
156+
**store()** the restore and therefore the library will not be in sync with the device.
157+
To create a fool proof system additional hardware is needed, see Concept read position below.
158+
137159

138160

139161
#### Ohm
@@ -165,7 +187,7 @@ These classes have the same interface as the X9C10X base class.
165187
The only difference is that the type is set to a non zero value.
166188

167189

168-
#### Performance
190+
## Performance
169191

170192
The table below is tested on a (relative slow) Arduino UNO 16 MHz with IDE 1.18.19.
171193
Other processors might give similar or faster times. See performance example.
@@ -191,6 +213,8 @@ X9C10X_LIB_VERSION: 0.1.2
191213

192214
Time per step is 780 / 99 = ~8 us per step on an UNO.
193215

216+
Note: no performance improvements since 0.1.2
217+
194218

195219
## Operation
196220

@@ -206,9 +230,30 @@ A voltage of **3V3** would be **setPosition(66)**.
206230
Note: check datasheet for the range of the max voltage and current allowed.
207231

208232

233+
#### Concept read position
234+
235+
If you need to make a robust system with X9C devices you can solder two devices "in parallel".
236+
One to control whatever you need to control, and the other to create a feedback loop through analogRead().
237+
Lets name them feedback device and control device.
238+
The two devices should share the select, direction and pulse pins in hardware.
239+
This way they will get the exact same pulses and signals and would therefore be in the exact same position
240+
after initialization.
241+
242+
The feedback device would be a voltage divider, splitting 5 Volts in 100 level.
243+
To read these levels you need at least an 8 bit ADC or better.
244+
This setup would allow you to read the position in the control device 100% of the time.
245+
246+
The price is at least twice as high in terms of hardware, the performance will be less at some times
247+
and the code will be slightly more complex
248+
249+
It might be possible to measure the voltage of the wiper of the control device.
250+
However that might not always be easy or possible, due to voltage used, etc.
251+
252+
209253
## Future
210254

211255
- update documentation
256+
- concept of **read()** => put 2 X9C parallel and read one with analogRead().
212257
- test different platforms
213258
- add error codes ?
214259
- add examples
@@ -225,5 +270,5 @@ Note: check datasheet for the range of the max voltage and current allowed.
225270
- **getOhm()** ==> **getValue()**
226271
- **getMaxOhm()** ==> **getMaxValue()**
227272
- think milliVolt, ohm, lux, speed, etc.
228-
User can do this too with **getPosition() * factor**
273+
User can do this too with **getPosition() \* factor**
229274

libraries/X9C10X/X9C10X.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// FILE: X9C10X.cpp
33
// AUTHOR: Rob Tillaart
4-
// VERSION: 0.2.0
4+
// VERSION: 0.2.1
55
// PURPOSE: Arduino Library for X9C10X series digital potentiometer.
66
// URL: https://github.com/RobTillaart/X9C10X
77
//
@@ -15,12 +15,18 @@
1515
// 0.2.0 2022-07-09 fix #7 incorrect signal during initialize
1616
// remove position parameter from begin()
1717
// to make setting position more explicit.
18-
// update readme
18+
// update readme.md
1919
// add uint8_t Ohm2Position()
20+
// 0.2.1 2022-07-23 fix #9 add restoreInternalPosition(pos)
21+
// change return type setPosition() to indicate truncation
22+
// update readme.md and comments
23+
// update build-CI tests
24+
2025

2126

2227
#include "X9C10X.h"
2328

29+
2430
// minimum pulse width CLOCK = ? us (datasheet);
2531
// digitalWrite takes enough time on UNO / AVR so clock_delay == 0
2632
// Note that if clock pulses are long enough the data pulses are too.
@@ -33,6 +39,8 @@
3339
#define X9C10X_UP HIGH
3440
#define X9C10X_DOWN LOW
3541

42+
#define X9C10X_MAXPOT 99
43+
3644

3745
/////////////////////////////////////////////////////////
3846
//
@@ -122,8 +130,6 @@ void X9C::_move(uint8_t direction, uint8_t steps)
122130

123131

124132

125-
126-
127133
/////////////////////////////////////////////////////////
128134
//
129135
// X9C10X BASE CLASS
@@ -134,14 +140,14 @@ X9C10X::X9C10X(uint32_t maxOhm) : X9C()
134140
}
135141

136142

137-
void X9C10X::setPosition(uint8_t position, bool forced)
143+
uint8_t X9C10X::setPosition(uint8_t position, bool forced)
138144
{
139-
if (position > 99) position = 99;
140-
// reference 0.1.0
141-
// while (position > _position) incr();
142-
// while (position < _position) decr();
145+
if (position > 99)
146+
{
147+
position = 99;
148+
}
143149

144-
// force to nearest end position first to minimize steps.
150+
// force to nearest end position first to minimize number of steps.
145151
if (forced)
146152
{
147153
if (position < 50)
@@ -165,6 +171,7 @@ void X9C10X::setPosition(uint8_t position, bool forced)
165171
}
166172

167173
_position = position;
174+
return _position;
168175
}
169176

170177

@@ -193,6 +200,17 @@ uint8_t X9C10X::store()
193200
}
194201

195202

203+
uint8_t X9C10X::restoreInternalPosition(uint8_t position)
204+
{
205+
if (position > 99)
206+
{
207+
position = 99;
208+
}
209+
_position = position;
210+
return _position;
211+
}
212+
213+
196214
// rounding needed!
197215
uint32_t X9C10X::getOhm()
198216
{

libraries/X9C10X/X9C10X.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
//
33
// FILE: X9C10X.h
44
// AUTHOR: Rob Tillaart
5-
// VERSION: 0.2.0
5+
// VERSION: 0.2.1
66
// PURPOSE: Arduino Library for X9C10X series digital potentiometer.
77
// URL: https://github.com/RobTillaart/X9C10X
88

99

1010
#include "Arduino.h"
1111

12-
#define X9C10X_LIB_VERSION (F("0.2.0"))
12+
#define X9C10X_LIB_VERSION (F("0.2.1"))
1313

1414

1515
/////////////////////////////////////////////////////////
@@ -25,6 +25,7 @@ class X9C
2525
void begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin);
2626

2727
// step size 1.
28+
// return false if end of range reached.
2829
bool incr();
2930
bool decr();
3031

@@ -51,18 +52,27 @@ class X9C10X : public X9C
5152
X9C10X(uint32_t maxOhm = 10000);
5253

5354
// position = 0..99
55+
// values > 99 are truncated.
5456
// forced = true will ignore the cached position
55-
// takes up to 150 steps as one cannot read the position from device.
57+
// takes up to 150 steps as one cannot read the position from device.
5658
// forced = default false as that is safer and backwards compatible.
57-
void setPosition(uint8_t position, bool forced = false);
59+
// returns new position 0..99
60+
uint8_t setPosition(uint8_t position, bool forced = false);
5861
uint8_t getPosition() { return _position; };
5962

6063
// step size 1.
64+
// return false if end of range reached.
6165
bool incr();
6266
bool decr();
6367

6468
// use with care
69+
// returns new position 0..99
6570
uint8_t store();
71+
// note: restoreInternalPosition() is not available in X9C base class.
72+
// position = 0..99
73+
// values > 99 are truncated.
74+
// returns new position 0..99
75+
uint8_t restoreInternalPosition(uint8_t position);
6676

6777
// current resistance in ohm.
6878
uint32_t getOhm();

libraries/X9C10X/examples/X9C10X_performance/X9C10X_performance.ino

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ void setup()
153153
Serial.print("10 x decr():\t");
154154
Serial.println(stop - start);
155155
delay(100);
156+
157+
Serial.println("\ndone...");
156158
}
157159

158160

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
compile:
2+
# Choosing to run compilation tests on 2 different Arduino platforms
3+
platforms:
4+
- uno
5+
# - due
6+
# - zero
7+
# - leonardo
8+
# - m4
9+
# - esp32
10+
# - esp8266
11+
- mega2560
12+
13+
libraries:
14+
- "printHelpers"

0 commit comments

Comments
 (0)