Skip to content

Instantly share code, notes, and snippets.

@Andrei-Pozolotin
Last active July 27, 2020 16:10
Show Gist options
  • Save Andrei-Pozolotin/e7bf413e2438863a04c2497258662bec to your computer and use it in GitHub Desktop.
Save Andrei-Pozolotin/e7bf413e2438863a04c2497258662bec to your computer and use it in GitHub Desktop.
Z-probe-on-smd-resistors-2512 / better code / https://github.com/IvDm/Z-probe-on-smd-resistors-2512/issues/7
//
// https://github.com/bogde/HX711
//
// sensor setup:
// * 5V supply (from nano)
// * 128 gain (library config)
// * +-20 mV input range (derived from gain)
// * int32_t output range (library convention)
// * 80 Hz (12.5 ms) sample rate (jumper on board)
//
#include <Arduino.h>
#include "avg.h"
#include "log.h"
#include "time.h"
#include <HX711.h>
// host communication
const long SERIAL_RATE = 1000000;
// sensor/nano connection
const int SENSOR_PIN_DATA = 2; // sensor to nano
const int SENSOR_PIN_SCLK = 3; // nano to sensor
// sensor-dependent experimental value constant
// threshold sensor change values for on/off event detection
const int32_t MICRO_VOLT = 100000; // based on hx711 supply/gain
const int32_t DELTA_ACTIVE = 2 * MICRO_VOLT;
const int32_t DELTA_PASSIVE = 1 * MICRO_VOLT;
// sensor instance
HX711 sensor;
// signal smoothing
// 1 tick is HX711 ADC conversion period of 12.5 ms
MovingAverage moving_fast(2); // 2^2=4 ticks, 50 ms signal detection window
MovingAverage moving_slow(14); // 2^14=16384 ticks, 200 sec drifting context window
// trigger state
bool has_trigger = false; // is touch event detected
int32_t trigger_slow = 0; // trigger level for recovery
// track event duration
uint32_t time_active = 0; // touch event start time, millis
uint32_t time_passive = 0; // touch event finish time, millis
// nano output signal
void process_output(int level) {
digitalWrite(LED_BUILTIN, level);
}
// detect touch events
void process_trigger() {
const int32_t fast = moving_fast.average();
const int32_t slow = moving_slow.average();
const int32_t delta = fast - slow;
if (delta > 0) { // react only on proper direction
if (has_trigger) {
if (delta < DELTA_PASSIVE) { // detect turn off
has_trigger = false; // remember state
moving_slow.setup(trigger_slow); // recover to event start
process_output (LOW); // issue turn off
time_passive = millis(); // report event finish
}
} else {
if (delta > DELTA_ACTIVE) { // detect turn on
has_trigger = true; // remember state
trigger_slow = slow; // remember till event finish
process_output (HIGH); // issue turn on
time_active = millis(); // report event start
}
}
}
}
// report for debug, only after touch detection
void loopReport() {
if (time_active != 0 && time_passive != 0) {
const uint32_t time_delta = time_passive - time_active;
time_active = 0;
time_passive = 0;
const int32_t fast = moving_fast.average();
const int32_t slow = moving_slow.average();
Serial.print(" fast=");
Serial.print(fast);
Serial.print(" slow=");
Serial.print(slow);
Serial.print(" time=");
Serial.print(time_delta);
Serial.println();
}
}
//
void setupSensor() {
sensor.begin(SENSOR_PIN_DATA, SENSOR_PIN_SCLK, 128);
}
//
void setupAverage() {
const int32_t value = sensor.read();
trigger_slow = value;
moving_fast.setup(value);
moving_slow.setup(value);
}
void loopSensor() {
const int32_t value = sensor.read();
moving_fast.update(value);
moving_slow.update(value);
process_trigger();
}
//
void setupSerial(String stamp) {
Serial.begin(SERIAL_RATE);
log_println();
log_println("version=" + stamp);
delay(1000);
}
//
void setupOutput() {
digitalWrite(LED_BUILTIN, LOW);
pinMode(LED_BUILTIN, OUTPUT);
}
// the setup function runs once
void setup() {
String stamp;
time_stamp(stamp);
setupSerial(stamp);
setupSensor();
setupAverage();
setupOutput();
}
// the loop function runs forever
void loop() {
loopSensor();
loopReport();
}
// average caculator
#include <Arduino.h>
#include "avg.h"
MovingAverage::MovingAverage(int16_t rate) {
decay_rate = rate;
}
void MovingAverage::setup(int32_t value) {
average_value = value;
average_total = (int64_t) value << decay_rate;
}
void MovingAverage::update(int32_t value) {
average_total += value;
average_total -= average_value;
average_value = average_total >> decay_rate;
}
int32_t MovingAverage::average() {
return average_value;
}
// average caclulator
#pragma once
class MovingAverage {
public:
// create with decay rate
MovingAverage(int16_t rate);
// provide initial average
void setup(int32_t value);
// apply sensor measurement
void update(int32_t value);
// report moving average
int32_t average();
protected:
// exponential attenuation
int16_t decay_rate = 0;
// current moving average
int32_t average_value = 0;
// moving average integral
int64_t average_total = 0;
};
// logger settings
#pragma once
void log_print(char text[]) {
Serial.print(text);
}
void log_print(const __FlashStringHelper* text) {
Serial.print(text);
}
void log_println(char text[]) {
Serial.println(text);
}
void log_println(String text) {
Serial.println(text);
}
void log_println(const __FlashStringHelper* text) {
Serial.println(text);
}
void log_println() {
Serial.println();
}
void log_print_bar() {
Serial.print(F("| "));
}
// time support
#pragma once
#include <stdio.h>
#include <Time.h>
// https://stackoverflow.com/questions/1765014/convert-string-from-date-into-a-time-t
time_t time_parse(char const *date, char const *time) {
int year;
char month[5];
tmElements_t tm;
static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; // TODO PSTR
sscanf_P(date, PSTR("%s %hhd %d"), month, &tm.Day, &year);
sscanf_P(time, PSTR("%2hhd %*c %2hhd %*c %2hhd"), &tm.Hour, &tm.Minute,
&tm.Second);
tm.Year = year - 2000;
tm.Month = (strstr(month_names, month) - month_names) / 3 + 1; // TODO PSTR
return makeTime(tm);
}
// https://stackoverflow.com/questions/3053999/c-convert-time-t-to-string-with-format-yyyy-mm-dd-hhmmss
void time_stamp(String &value) {
tmElements_t tm;
time_t time = time_parse(__DATE__, __TIME__);
breakTime(time, tm);
char text[32];
sprintf_P(text, PSTR("%02u%02u%02u-%02u%02u%02u"), tm.Year, tm.Month,
tm.Day, tm.Hour, tm.Minute, tm.Second);
value += text;
}
@lehuuloc-0104
Copy link

Hi,
Is this firmware better than the original? And are the IO connectors the same as the original PCB shared? Looking forward to your support.
Thank you.

@Andrei-Pozolotin
Copy link
Author

this firmware better

yes, "better", only runs on nano, not attiny85
https://en.wikipedia.org/wiki/Arduino_Nano

why "better" is described here:
IvDm/Z-probe-on-smd-resistors-2512#7

IO connectors the same

no, connection is for nano

// sensor/nano connection
const int SENSOR_PIN_DATA = 2;  // sensor to nano
const int SENSOR_PIN_SCLK = 3;  // nano to sensor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment