/*********************************************************************************************************************
A direct reading ohm meter, values extracted from the 24 resistors serie
Raphal Ollier (France)
V1.1 - Software upgrades
V1.2 - Add servo to lock resistor during measure, and switch to control it
V1.3 - Switch and servo implemented
v1.4 - Misc. Soft. Improvements
v1.5 - Timed closing and end contact implemented
Largely inspired (and partly copied) from the work of Federico Vivaldi : Sorting resistors the lazy way
https://create.arduino.cc/projecthub/federico-vivaldi/sorting-resistors-the-lazy-way-ceb557?ref=platform&ref_id=424_trending___&offset=7
*********************************************************************************************************************/
// External libraries
#include <Servo.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Constantes
#define BatDispWidth 20 // Display battery width
#define BatDispHeight 7 // Display battery height
#define BatDispPosX 105 // Display battery position
#define BatDispPosY 0
#define ServoCmd 9 // Data output for PWM
#define SwitchInput 8 // Data input for switch
#define ServoEnd 10 // Data input for end contact
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define ServoOpen 120 // 180 max. quasiment 1 par unit
#define ServoClosed 0
int ServoVal = ServoOpen / 2; // variable for servo pos
int SwCount = 3; // counter init for switch debounce
int VCount = SwCount; // counter variable for switch debounce
int ActiveKey = 1; // variable key active
boolean Opened = true; // variable for door state
// Srie de rsistances par 24
int SerieVal[] = {10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30,
33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82, 91, 100
};
int DelayConv = 10; // time allocated to A/D conversion
int MeasuresNbr = 10; // number of conversions and divider
int MinRaw = 300; // original value 350
int MaxRaw = 820; // original value 800
int R1 = 100; // Base resistors
int R2 = 1000;
int R3 = 10000;
long R4 = 100000;
long R5 = 1000000;
long Rn; // Base resistor used for conversion
int D2 = 2; // Data Bus
int D3 = 3;
int D4 = 4;
int D5 = 5;
int D6 = 6;
int ValBrut = 0;
int StrLength = 0; //chain length
String ValueStr = "000" ;
String SuffixStr = " Mo";
float Raw = 0; // Raw read value
float Ru = 0; // Unknown resistor value
int AnalogRead = A0; // Analog port for reading
Servo Trappe;
void setup() {
// ****************** Adafruit address test routine **************************
Serial.begin(9600);
// Serial.println (display.begin(SSD1306_SWITCHCAPVCC, 0x3C));
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// ****************** Draw rectangles at the beginning of the program *********
Rectangles();
Trappe.attach(ServoCmd);
GoOpen();
delay(1000); // Time for servo to arrive
pinMode(SwitchInput, INPUT);
pinMode(ServoEnd, INPUT);
}
// ****************** Main loop ***********************************************
void loop() {
ActiveKey = digitalRead(SwitchInput);
if (ActiveKey == 0) { // key on
if (VCount == 1) {
if (Opened == true) { // test if opened
GoClose();
VCount--;
} else {
GoOpen();
VCount--;
}
} else { // VCount<>1
if (VCount != 0) { // VCount<>0
VCount--;
}
}
} else {
VCount = SwCount; // reinit counter
}
pinMode(D2, OUTPUT); // original setup, REF 1M
pinMode(D3, INPUT);
pinMode(D4, INPUT);
pinMode(D5, INPUT);
pinMode(D6, INPUT);
digitalWrite(D2, HIGH);
Reading_analog_in();
Rn = R5;
if (Raw < MinRaw || Raw > MaxRaw) { // REF 100k
digitalWrite(D2, LOW);
pinMode(D2, INPUT);
pinMode(D3, OUTPUT);
digitalWrite(D3, HIGH);
Reading_analog_in();
Rn = R4;
if (Raw < MinRaw || Raw > MaxRaw) { // REF 10k
digitalWrite(D3, LOW);
pinMode(D3, INPUT);
pinMode(D4, OUTPUT);
digitalWrite(D4, HIGH);
Reading_analog_in();
Rn = R3;
if (Raw < MinRaw || Raw > MaxRaw) { // REF 1k
digitalWrite(D4, LOW);
pinMode(D4, INPUT);
pinMode(D5, OUTPUT);
digitalWrite(D5, HIGH);
Reading_analog_in();
Rn = R2;
if (Raw < MinRaw || Raw > MaxRaw) { // REF 100 impossible to decrease
digitalWrite(D5, LOW);
pinMode(D5, INPUT);
pinMode(D6, OUTPUT);
digitalWrite(D6, HIGH);
Reading_analog_in();
Rn = R1;
}
}
}
}
if (Raw > 1020) { // Raw value out of window
Ru = 11000000; // to display ">10 Mo"
} else {
Ru = ((Raw * Rn) / (1024 - Raw)); // Calculation for resistor to find but lower than 10Mo
}
// ****************** Display assignments & calculation ***********************
// NEEDS IMPROVEMENTS !!
StrLength = String(Ru, 0).length();
if (StrLength > 7) {
ValueStr = ">10";
SuffixStr = " Mo";
} else {
if (StrLength > 6) {
/* ValueStr = "<10"; // not used, only to debug
SuffixStr = " Mo";*/
Ru = Ru / 100000;
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut] / 10);
SuffixStr = " Mo";
if (ValBrut == 24 ) {
ValueStr = ("10");
SuffixStr = " Mo";
}
} else {
if (StrLength > 5) {
Ru = Ru / 10000;
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut]);
SuffixStr = "0 ko";
if (ValBrut == 24) {
ValueStr = ("1");
SuffixStr = " Mo";
}
} else {
if (StrLength > 4) {
Ru = Ru / 1000;
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut]);
SuffixStr = " ko";
} else {
if (StrLength > 3) {
Ru = Ru / 100;
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut]).substring(0, 1) + "." + String(SerieVal[ValBrut]).substring(1, 2);
SuffixStr = " ko";
} else {
if (StrLength > 2) {
Ru = (Ru / 10);
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut]);
SuffixStr = "0 ohm";
if (ValBrut == 24) {
ValueStr = ("1");
SuffixStr = " ko";
}
} else {
Plusproche(); // call to comparison routine
ValueStr = String(SerieVal[ValBrut]);
if (ValBrut == -1) {
ValueStr = ("< 10");
}
SuffixStr = " ohm";
}
}
}
}
}
}
DisplayOled(); // call display routine
// impression(); // call to debug infos
}
void Plusproche() {
for (int i = 0; i < 25; i++) { // scan into the 24 normalized values
int SerieDifference = (Ru - SerieVal[i]); // dif between R and normalized
if (SerieDifference == 0) { // exact norm value
ValBrut = i;
break;
}
if (SerieDifference < 0) { // next norm value
int old = (Ru - SerieVal[i - 1]);
if (old - abs( SerieDifference) < 0) { // test n with n-1
ValBrut = (i - 1);
} else {
ValBrut = (i);
}
break;
}
}
}
void GoClose() {
ServoVal = (ServoOpen / 2); // semi fermeture de la trappe
while (digitalRead(ServoEnd) && (ServoVal > ServoClosed)) {
ServoVal--;
Trappe.write (ServoVal);
Serial.println(ServoVal);
delay(10);
}
Trappe.write (ServoVal-5);
Serial.println(ServoVal);
Opened = false;
}
void GoOpen() {
Trappe.write (ServoOpen); // ouverture de la trappe
Opened = true;
}
void Reading_analog_in () {
delay(DelayConv); // delay for conversion
Raw = 0; // init Raw ValueStr
for (int x = 0; x < MeasuresNbr; x++) {
Raw += analogRead(AnalogRead);
}
Raw = Raw / MeasuresNbr; // average value
}
void DisplayOled() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.print("S24");
// *************** display battery status **************
display.setCursor(60, 0);
display.print("Battery ");
display.drawRect(BatDispPosX, BatDispPosY, BatDispWidth, BatDispHeight, WHITE);
display.fillRect(BatDispPosX, BatDispPosY, BatDispWidth * 0.5, BatDispHeight, WHITE); // battery at 50%
// *************** display resistor value **************
display.setCursor(0, 12);
display.setTextSize(3);
display.print(ValueStr);
display.print(SuffixStr);
display.display(); // needed to reinit drawings
}
void Rectangles() { // routine which draws in and out rectangles, purely cosmetic !
display.clearDisplay();
for (int i = 0; i < 16; i++) {
display.drawRect(i, i, (SCREEN_WIDTH - 1) - 2 * i, (SCREEN_HEIGHT - 1) - 2 * i, WHITE);
display.display();
delay(100);
display.drawRect(i, i, (SCREEN_WIDTH - 1) - 2 * i, (SCREEN_HEIGHT - 1) - 2 * i, BLACK);
}
for (int i = 15; i > 0; i--) {
display.drawRect(i, i, (SCREEN_WIDTH - 1) - 2 * i, (SCREEN_HEIGHT - 1) - 2 * i, WHITE);
display.display();
delay(100);
display.drawRect(i, i, (SCREEN_WIDTH - 1) - 2 * i, (SCREEN_HEIGHT - 1) - 2 * i, BLACK);
}
}
void impression() { // routine to print debug values, not necessary
Serial.print("Raw : ");
Serial.println(Raw);
Serial.print("Rn : ");
Serial.println(Rn);
Serial.print("ValBrut : ");
Serial.println(ValBrut);
Serial.print("Ru aprs = ");
Serial.println(Ru);
Serial.print ("Valeur et Suffixe : ");
Serial.print(ValueStr);
Serial.println(SuffixStr);
Serial.println (StrLength);
Serial.println (" ");
}
Comments