From 8cff7dc76f84e7b68454ffd3b8494e471a269b07 Mon Sep 17 00:00:00 2001 From: Arjen Baart Date: Tue, 2 Mar 2021 08:03:33 +0100 Subject: [PATCH 1/1] Initial revision --- Makefile.am | 1 + configure.ac | 45 ++++++++ doc/C-meter.svg | 291 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/input-divider.svg | 225 ++++++++++++++++++++++++++++++++++++++ doc/sensors.xml | 97 +++++++++++++++++ doc/single-slope.svg | 252 ++++++++++++++++++++++++++++++++++++++++++ doc/timing-diagram.svg | 206 ++++++++++++++++++++++++++++++++++ hardware/Cmeter.sch | 198 +++++++++++++++++++++++++++++++++ hardware/voltmeter.sch | 211 +++++++++++++++++++++++++++++++++++ src/Cmeter.cpp | 156 ++++++++++++++++++++++++++ src/Makefile.am | 8 ++ src/meters.cpp | 130 ++++++++++++++++++++++ src/pulsewidth.cpp | 124 +++++++++++++++++++++ src/tsic.cpp | 187 +++++++++++++++++++++++++++++++ src/voltmeter.cpp | 157 ++++++++++++++++++++++++++ 15 files changed, 2288 insertions(+) create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 doc/C-meter.svg create mode 100644 doc/input-divider.svg create mode 100644 doc/sensors.xml create mode 100644 doc/single-slope.svg create mode 100644 doc/timing-diagram.svg create mode 100644 hardware/Cmeter.sch create mode 100644 hardware/voltmeter.sch create mode 100644 src/Cmeter.cpp create mode 100644 src/Makefile.am create mode 100644 src/meters.cpp create mode 100644 src/pulsewidth.cpp create mode 100644 src/tsic.cpp create mode 100644 src/voltmeter.cpp diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3920780 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src doc diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c75a572 --- /dev/null +++ b/configure.ac @@ -0,0 +1,45 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([sensors], [0.1], [arjen@andromeda.nl]) +AM_INIT_AUTOMAKE([-Wall foreign]) +AC_CONFIG_SRCDIR([src/Cmeter.cpp]) +AC_CONFIG_HEADERS([config.h]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_CC + +# Check for wx-widgets + +AC_PATH_PROG(WX_CONFIG, wx-config, no) +if test $WX_CONFIG = "no" +then + echo "WX widgets is not installed" + exit 1 +fi + +WX_CXXFLAGS=`wx-config --cxxflags` +CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" +WX_LDFLAGS=`wx-config --libs` +LDFLAGS="$LDFLAGS $WX_LDFLAGS" + +#Checks for libraries. +AC_CHECK_LIB([pigpiod_if2], [pigpio_start]) +# FIXME: Replace `main' with a function in `-lrt': +AC_CHECK_LIB([rt], [main]) + +# Checks for header files. +AC_CHECK_HEADERS([unistd.h]) +AC_CHECK_HEADERS([wx/wx.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +AC_TYPE_UINT32_T + +# Checks for library functions. + +AC_CONFIG_FILES([Makefile + src/Makefile]) +AC_OUTPUT diff --git a/doc/C-meter.svg b/doc/C-meter.svg new file mode 100644 index 0000000..306ce7f --- /dev/null +++ b/doc/C-meter.svg @@ -0,0 +1,291 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cycle + Uref + Out + + + + + + + C1 + + diff --git a/doc/input-divider.svg b/doc/input-divider.svg new file mode 100644 index 0000000..d657837 --- /dev/null +++ b/doc/input-divider.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + R1 + R2 + R3 + Uo + Uin + Uc + + diff --git a/doc/sensors.xml b/doc/sensors.xml new file mode 100644 index 0000000..437345d --- /dev/null +++ b/doc/sensors.xml @@ -0,0 +1,97 @@ + + +
+ + + Raspberry Pi Sensors + Arjen Baart + February 18, 2021 + + + + + + Single slope voltmeter + + +The single slope voltmeter creates a ramp by charginf a capacitor with a contant current. +See also The Art of Electronics, page 416. +The figure below shows the concept: + + + + + +At rest, the capacitor C1 is shorted to ground by applying a positive voltage to the gate of the MOSFET. +The cycle starts when the gate voltage drops to 0 and capacitor C1 charges from the current source. +The voltage rises linearly and is compared to the input voltage. +When the voltage across C1 rises above the input voltage connected to the negative input of the comparator, +the comparator's open collector output is drawn to ground. +The cycle is shown in the timing diagram below: + + + + + +The time from releasing the MOSFET to the comparator's output going low is proportianal to the input volatge: + + + t = C / I * Uin + + + + +The measurable range of the input voltage is determined by the input voltage that can be handled by the comparator +and the maximum voltage for the current source. +For most comparators, the input voltage must be within 0.5 V to 1 V of the supply rails. +With a supply voltage of 5V, input voltages from 1 to 4V can be measured. +To measure input voltages from 0 to 30 V, an input devider must devide the input voltage by 10 and provide +an offset of 1 V: + + + + + + + + + + + (Uin - Uo) / R1 + (Uc - Uo) / R3 - Uo / R2 = 0 + + + Uo = (Uin * R2 * R3 + Uc * R1 * R2) / (R2 * R3 + R1 * R2 + R1 * R3) + + Uc = 5 V + R1 = 1.2 M + R2 = 150k + R3 = 560 k + + Uo = Uin * 0.086 + 0.97 + + + + + Capacitance meter + +When, instead of measuring Uin, the input voltage is fixed to Uref, the same +circuit can be used to measure the capacitance of C1, as shown below: + + + +
+
diff --git a/doc/single-slope.svg b/doc/single-slope.svg new file mode 100644 index 0000000..525f66b --- /dev/null +++ b/doc/single-slope.svg @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cycle + Uin + Out + + diff --git a/doc/timing-diagram.svg b/doc/timing-diagram.svg new file mode 100644 index 0000000..0725691 --- /dev/null +++ b/doc/timing-diagram.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + Cycle + U, C1 + Out + + + + Uin + + + + + t + + diff --git a/hardware/Cmeter.sch b/hardware/Cmeter.sch new file mode 100644 index 0000000..dfc531a --- /dev/null +++ b/hardware/Cmeter.sch @@ -0,0 +1,198 @@ +v 20130925 2 +C 40000 40000 0 0 0 title-B.sym +C 49800 46300 1 0 0 opamp-2.sym +{ +T 50600 47300 5 10 0 0 0 0 1 +device=OPAMP +T 50600 47100 5 10 1 1 0 0 1 +refdes=IC1 +T 50600 47500 5 10 0 0 0 0 1 +symversion=0.1 +T 50500 46500 5 10 1 1 0 0 1 +value=PM211 +} +C 46200 48500 1 180 0 pnp-2.sym +{ +T 45600 48100 5 10 0 0 180 0 1 +device=PNP_TRANSISTOR +T 45600 48000 5 10 1 1 180 0 1 +refdes=T3 +T 45100 47700 5 10 1 1 0 0 1 +value=BC559 +} +C 45800 48900 1 90 0 resistor-2.sym +{ +T 45450 49300 5 10 0 0 90 0 1 +device=RESISTOR +T 45500 49100 5 10 1 1 90 0 1 +refdes=R3 +T 45800 49200 5 10 1 1 0 0 1 +value=10k +} +C 46800 45600 1 90 0 resistor-2.sym +{ +T 46450 46000 5 10 0 0 90 0 1 +device=RESISTOR +T 46500 45800 5 10 1 1 90 0 1 +refdes=R5 +T 46900 45900 5 10 1 1 0 0 1 +value=33k +} +C 46800 48900 1 90 0 resistor-2.sym +{ +T 46450 49300 5 10 0 0 90 0 1 +device=RESISTOR +T 46500 49100 5 10 1 1 90 0 1 +refdes=R4 +T 46800 49200 5 10 1 1 0 0 1 +value=18k +} +N 45700 42600 45700 47500 4 +N 45700 48900 45700 48500 4 +N 46700 48900 46700 46500 4 +N 46200 48000 46700 48000 4 +C 40600 49700 1 0 0 terminal-1.sym +{ +T 40910 50450 5 10 0 0 0 0 1 +device=terminal +T 40910 50300 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 49750 5 10 1 1 0 6 1 +refdes=J2 +} +C 40600 43100 1 0 0 terminal-1.sym +{ +T 40910 43850 5 10 0 0 0 0 1 +device=terminal +T 40910 43700 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 43150 5 10 1 1 0 6 1 +refdes=J3 +} +C 40600 50200 1 0 0 terminal-1.sym +{ +T 40910 50950 5 10 0 0 0 0 1 +device=terminal +T 40910 50800 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 50250 5 10 1 1 0 6 1 +refdes=J1 +T 40600 50200 5 10 0 1 0 0 1 +value=3.3V +} +N 41500 49800 48600 49800 4 +N 41500 43200 49500 43200 4 +N 44700 43200 44700 45400 4 +N 46700 43200 46700 45600 4 +C 44200 45400 1 0 0 nmos-3.sym +{ +T 44800 45900 5 10 0 0 0 0 1 +device=NMOS_TRANSISTOR +T 44900 46000 5 10 1 1 0 0 1 +refdes=T2 +} +N 44700 46200 44700 47000 4 +N 44700 47000 45700 47000 4 +C 43100 44200 1 0 0 npn-2.sym +{ +T 43700 44700 5 10 0 0 0 0 1 +device=NPN_TRANSISTOR +T 43700 44700 5 10 1 1 0 0 1 +refdes=T1 +T 43700 44500 5 10 1 1 0 0 1 +value=BC549 +} +C 43700 46700 1 90 0 resistor-2.sym +{ +T 43350 47100 5 10 0 0 90 0 1 +device=RESISTOR +T 43400 46900 5 10 1 1 90 0 1 +refdes=R2 +T 43700 47000 5 10 1 1 0 0 1 +value=1k +} +N 43600 49800 43600 47600 4 +N 43600 46700 43600 45200 4 +N 43600 45600 44200 45600 4 +C 42000 44600 1 0 0 resistor-2.sym +{ +T 42400 44950 5 10 0 0 0 0 1 +device=RESISTOR +T 42200 44900 5 10 1 1 0 0 1 +refdes=R1 +T 42200 44400 5 10 1 1 0 0 1 +value=33k +} +N 42900 44700 43100 44700 4 +N 43600 44200 43600 43200 4 +T 50100 40700 9 10 1 0 0 0 1 +Single slope C meter +N 49800 47100 45700 47100 4 +C 51400 47900 1 90 0 resistor-2.sym +{ +T 51050 48300 5 10 0 0 90 0 1 +device=RESISTOR +T 51100 48100 5 10 1 1 90 0 1 +refdes=R6 +T 51400 48300 5 10 1 1 0 0 1 +value=10k +} +N 41500 50300 51300 50300 4 +N 51300 50300 51300 48800 4 +N 51300 42000 51300 47900 4 +N 50900 46800 51300 46800 4 +N 42000 44700 42000 42000 4 +C 48700 48500 1 90 0 resistor-2.sym +{ +T 48350 48900 5 10 0 0 90 0 1 +device=RESISTOR +T 48400 48700 5 10 1 1 90 0 1 +refdes=R6 +T 48700 48900 5 10 1 1 0 0 1 +value=12k +} +C 48700 45200 1 90 0 resistor-2.sym +{ +T 48350 45600 5 10 0 0 90 0 1 +device=RESISTOR +T 48400 45400 5 10 1 1 90 0 1 +refdes=R7 +T 48100 45200 5 10 1 1 0 0 1 +value=39k +} +N 48600 46500 49800 46500 4 +N 48600 46100 48600 48500 4 +N 48600 49400 48600 49800 4 +T 41800 41600 9 10 1 0 0 0 1 +Cycle +T 51000 41700 9 10 1 0 0 0 1 +Cmp Out +N 48600 45200 48600 43200 4 +C 45800 41700 1 90 0 terminal-1.sym +{ +T 45050 42010 5 10 0 0 90 0 1 +device=terminal +T 45200 42010 5 10 0 0 90 0 1 +footprint=CONNECTOR 1 1 +T 45750 41950 5 10 1 1 90 6 1 +refdes=J4 +} +C 46400 41700 1 90 0 terminal-1.sym +{ +T 45650 42010 5 10 0 0 90 0 1 +device=terminal +T 45800 42010 5 10 0 0 90 0 1 +footprint=CONNECTOR 1 1 +T 46350 41950 5 10 1 1 90 6 1 +refdes=J5 +} +N 46300 42600 46300 43200 4 +C 45600 40800 1 0 0 capacitor-1.sym +{ +T 45800 41500 5 10 0 0 0 0 1 +device=CAPACITOR +T 45800 41300 5 10 1 1 0 0 1 +refdes=C? +T 45800 41700 5 10 0 0 0 0 1 +symversion=0.1 +} diff --git a/hardware/voltmeter.sch b/hardware/voltmeter.sch new file mode 100644 index 0000000..c4ce272 --- /dev/null +++ b/hardware/voltmeter.sch @@ -0,0 +1,211 @@ +v 20130925 2 +C 40000 40000 0 0 0 title-B.sym +C 49800 46300 1 0 0 opamp-2.sym +{ +T 50600 47300 5 10 0 0 0 0 1 +device=OPAMP +T 50600 47100 5 10 1 1 0 0 1 +refdes=IC1 +T 50600 47500 5 10 0 0 0 0 1 +symversion=0.1 +T 50500 46500 5 10 1 1 0 0 1 +value=PM211 +} +C 46200 48500 1 180 0 pnp-2.sym +{ +T 45600 48100 5 10 0 0 180 0 1 +device=PNP_TRANSISTOR +T 45600 48000 5 10 1 1 180 0 1 +refdes=T3 +T 45100 47700 5 10 1 1 0 0 1 +value=BC559 +} +C 45800 48900 1 90 0 resistor-2.sym +{ +T 45450 49300 5 10 0 0 90 0 1 +device=RESISTOR +T 45500 49100 5 10 1 1 90 0 1 +refdes=R3 +T 45800 49200 5 10 1 1 0 0 1 +value=10k +} +C 46800 45600 1 90 0 resistor-2.sym +{ +T 46450 46000 5 10 0 0 90 0 1 +device=RESISTOR +T 46500 45800 5 10 1 1 90 0 1 +refdes=R5 +T 46900 45900 5 10 1 1 0 0 1 +value=33k +} +C 46800 48900 1 90 0 resistor-2.sym +{ +T 46450 49300 5 10 0 0 90 0 1 +device=RESISTOR +T 46500 49100 5 10 1 1 90 0 1 +refdes=R4 +T 46800 49200 5 10 1 1 0 0 1 +value=18k +} +C 45500 45600 1 270 0 capacitor-4.sym +{ +T 46600 45400 5 10 0 0 270 0 1 +device=POLARIZED_CAPACITOR +T 46000 45400 5 10 1 1 270 0 1 +refdes=C1 +T 46200 45400 5 10 0 0 270 0 1 +symversion=0.1 +T 45900 45000 5 10 1 1 0 0 1 +value=10uF +} +N 45700 47500 45700 45600 4 +N 45700 48900 45700 48500 4 +N 46700 48900 46700 46500 4 +N 46200 48000 46700 48000 4 +C 40600 49700 1 0 0 terminal-1.sym +{ +T 40910 50450 5 10 0 0 0 0 1 +device=terminal +T 40910 50300 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 49750 5 10 1 1 0 6 1 +refdes=J2 +} +C 40600 43100 1 0 0 terminal-1.sym +{ +T 40910 43850 5 10 0 0 0 0 1 +device=terminal +T 40910 43700 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 43150 5 10 1 1 0 6 1 +refdes=J3 +} +C 40600 50200 1 0 0 terminal-1.sym +{ +T 40910 50950 5 10 0 0 0 0 1 +device=terminal +T 40910 50800 5 10 0 0 0 0 1 +footprint=CONNECTOR 1 1 +T 40850 50250 5 10 1 1 0 6 1 +refdes=J1 +T 40600 50200 5 10 0 1 0 0 1 +value=3.3V +} +N 41500 49800 48600 49800 4 +N 41500 43200 46700 43200 4 +N 44700 43200 44700 45400 4 +N 46700 43200 46700 45600 4 +C 44200 45400 1 0 0 nmos-3.sym +{ +T 44800 45900 5 10 0 0 0 0 1 +device=NMOS_TRANSISTOR +T 44900 46000 5 10 1 1 0 0 1 +refdes=T2 +} +N 45700 43200 45700 44700 4 +N 44700 46200 44700 47000 4 +N 44700 47000 45700 47000 4 +C 43100 44200 1 0 0 npn-2.sym +{ +T 43700 44700 5 10 0 0 0 0 1 +device=NPN_TRANSISTOR +T 43700 44700 5 10 1 1 0 0 1 +refdes=T1 +T 43700 44500 5 10 1 1 0 0 1 +value=BC549 +} +C 43700 46700 1 90 0 resistor-2.sym +{ +T 43350 47100 5 10 0 0 90 0 1 +device=RESISTOR +T 43400 46900 5 10 1 1 90 0 1 +refdes=R2 +T 43700 47000 5 10 1 1 0 0 1 +value=1k +} +N 43600 49800 43600 47600 4 +N 43600 46700 43600 45200 4 +N 43600 45600 44200 45600 4 +C 42000 44600 1 0 0 resistor-2.sym +{ +T 42400 44950 5 10 0 0 0 0 1 +device=RESISTOR +T 42200 44900 5 10 1 1 0 0 1 +refdes=R1 +T 42200 44400 5 10 1 1 0 0 1 +value=33k +} +N 42900 44700 43100 44700 4 +N 43600 44200 43600 43200 4 +T 50100 40700 9 10 1 0 0 0 1 +Single slope volt meter +N 49800 47100 45700 47100 4 +N 49000 46500 49800 46500 4 +C 51400 47900 1 90 0 resistor-2.sym +{ +T 51050 48300 5 10 0 0 90 0 1 +device=RESISTOR +T 51100 48100 5 10 1 1 90 0 1 +refdes=R6 +T 51400 48300 5 10 1 1 0 0 1 +value=10k +} +N 41500 50300 51300 50300 4 +N 51300 50300 51300 48800 4 +N 51300 42000 51300 47900 4 +N 50900 46800 51300 46800 4 +N 42000 44700 42000 42000 4 +C 48600 46600 1 180 0 resistor-2.sym +{ +T 48200 46250 5 10 0 0 180 0 1 +device=RESISTOR +T 48400 46300 5 10 1 1 180 0 1 +refdes=R7 +T 47900 46000 5 10 1 1 0 0 1 +value=1.2M +} +C 48700 48500 1 90 0 resistor-2.sym +{ +T 48350 48900 5 10 0 0 90 0 1 +device=RESISTOR +T 48400 48700 5 10 1 1 90 0 1 +refdes=R6 +T 48700 48900 5 10 1 1 0 0 1 +value=560k +} +C 49100 45200 1 90 0 resistor-2.sym +{ +T 48750 45600 5 10 0 0 90 0 1 +device=RESISTOR +T 48800 45400 5 10 1 1 90 0 1 +refdes=R8 +T 48500 45200 5 10 1 1 0 0 1 +value=150k +} +C 49300 46100 1 270 0 capacitor-4.sym +{ +T 50400 45900 5 10 0 0 270 0 1 +device=POLARIZED_CAPACITOR +T 49800 45900 5 10 1 1 270 0 1 +refdes=C2 +T 50000 45900 5 10 0 0 270 0 1 +symversion=0.1 +T 49800 45400 5 10 1 1 0 0 1 +value=1uF +} +N 45700 43200 49500 43200 4 +N 49500 43200 49500 45200 4 +N 49000 45200 49000 43200 4 +N 49500 46100 49000 46100 4 +N 49000 46100 49000 46500 4 +N 49200 46500 48600 46500 4 +N 48600 46500 48600 48500 4 +N 47700 46500 47400 46500 4 +N 47400 46500 47400 42000 4 +N 48600 49400 48600 49800 4 +T 47200 41700 9 10 1 0 0 0 1 +Uin +T 41800 41600 9 10 1 0 0 0 1 +Cycle +T 51000 41700 9 10 1 0 0 0 1 +Cmp Out diff --git a/src/Cmeter.cpp b/src/Cmeter.cpp new file mode 100644 index 0000000..965a9aa --- /dev/null +++ b/src/Cmeter.cpp @@ -0,0 +1,156 @@ +#include +#include +#include + +#include +#include +#include + + +#define CYCLE_OUT 18 // The cycle output +#define CMP_IN 17 // The signal from the comparator +#define NR_SAMPLES 20 // Number of samples to avaerage out the jitter + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata); + +#define INPUT_OFFSET 0.97 +#define INPUT_DIVIDER 0.086 +#define SLOPE_FACTOR 38.7 // Current / Voltage ( 117uA / 3.0V) + +class DVM +{ + int pi; // Connection to pigpio daemon + unsigned cycle_gate; // The gate to run a measurement cycle + unsigned comparator; // The signal from the comparator + + + uint32_t last_tick; + uint32_t measure_start; + + uint32_t samples[NR_SAMPLES]; + int sample_index; + + float U; // The measured voltage + + +public: + + void input_event(unsigned gpio, unsigned level, uint32_t tick) + { + float measure_time; + + //printf("Input event: input %u = %u, %d\n", gpio, level, tick - last_tick); + + if (gpio == cycle_gate && level == 1) + { + measure_start = tick; + } + + if (gpio == comparator && level == 1) + { + samples[sample_index++] = tick - measure_start; + sample_index %= NR_SAMPLES; + + measure_time = (float)(tick - measure_start) / 1.0e6; + U = measure_time * 11.4 - INPUT_OFFSET; + U /= INPUT_DIVIDER; + + gpio_write(pi, cycle_gate, 0); + } + if (gpio == comparator && level == 0) + { + gpio_write(pi, cycle_gate, 1); + } + last_tick = tick; + } + + + DVM(int pi_connection, unsigned gate, unsigned cmp) + { + int open_return; + + pi = pi_connection; + cycle_gate = gate; + comparator = cmp; + + last_tick = 0; + sample_index = 0; + + + set_mode(pi, comparator, PI_INPUT); + set_mode(pi, cycle_gate, PI_OUTPUT); + set_pull_up_down(pi, comparator, PI_PUD_OFF); + + open_return = callback_ex(pi, cycle_gate, EITHER_EDGE, gpio_callback, this); + //fprintf(stderr, "Set callback returns %d.\n", open_return); + open_return = callback_ex(pi, comparator, EITHER_EDGE, gpio_callback, this); + //fprintf(stderr, "Set callback returns %d.\n", open_return); + gpio_write(pi, cycle_gate, 0); + sleep(1); + gpio_write(pi, cycle_gate, 1); + } + + float Voltage() + { + uint32_t sum = 0; + uint32_t average_time; + float measure_time; + + // To filter out the jitter, calculate the average measured time + + for (int i = 0; i < NR_SAMPLES; i++) + { + sum += samples[i]; + } + + average_time = (sum / NR_SAMPLES) >> 5 << 5; + std::cout << " Average time = " << average_time << "\n"; + measure_time = average_time / 1.0e6; + U = measure_time * SLOPE_FACTOR; + + return U; + } +}; + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata) +{ + DVM *sensor; + + sensor = (DVM *)userdata; + sensor->input_event(user_gpio, level, tick); +} + + +int main() +{ + int pi; + std::ofstream sensorfile; + + pi = pigpio_start(NULL, NULL); + if (pi < 0) + { + // pigpio initialisation failed. + fprintf(stderr, "GPIO initialization failed.\n"); + + } + else + { + // pigpio initialised okay. + DVM sensor(pi, CYCLE_OUT, CMP_IN); + + while (true) + { + sleep(1); + printf("%.3f\n", sensor.Voltage()); + fflush(stdout); + + sensorfile.open("sensor1"); + sensorfile << std::fixed << std::setprecision(3) << sensor.Voltage() << " uF\n"; + sensorfile.close(); + } + pigpio_stop(pi); + + } + +} + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..57e269b --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,8 @@ +bin_PROGRAMS = tsic pulsewidth voltmeter Cmeter meters + + +tsic_SOURCES = tsic.cpp +pulsewidth_SOURCES = pulsewidth.cpp +voltmeter_SOURCES = voltmeter.cpp +Cmeter_SOURCES = Cmeter.cpp +meters_SOURCES = meters.cpp diff --git a/src/meters.cpp b/src/meters.cpp new file mode 100644 index 0000000..868f5f0 --- /dev/null +++ b/src/meters.cpp @@ -0,0 +1,130 @@ +#include +#include + +class MyApp: public wxApp +{ +public: + virtual bool OnInit(); +}; + +class MyFrame: public wxFrame +{ +public: + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); +private: + void OnHello(wxCommandEvent& event); + void OnExit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + wxDECLARE_EVENT_TABLE(); +}; + +class SensorDisplay : public wxPanel +{ + int sensorvalue; + wxTimer *timer; + +public: + SensorDisplay(wxFrame *parent); + void OnPaint(wxPaintEvent& event); + void OnTimer(wxCommandEvent& event); +}; + +SensorDisplay::SensorDisplay(wxFrame *parent) + : wxPanel(parent, -1, wxPoint(-1, -1), wxSize(-1, -1), wxBORDER_SUNKEN) +{ + sensorvalue = 0; + wxColour background(wxT("LIGHT STEEL BLUE")); + + SetBackgroundColour(background); + + timer = new wxTimer(this, 1); + this->Connect(wxEVT_PAINT, wxPaintEventHandler(SensorDisplay::OnPaint)); + Connect(wxEVT_TIMER, wxCommandEventHandler(SensorDisplay::OnTimer)); + + timer->Start(500); +} + +void SensorDisplay::OnPaint(wxPaintEvent& event) +{ + wxString displayed_value; + + wxFont display_font(36, wxFONTFAMILY_MODERN,wxFONTSTYLE_NORMAL, + wxFONTWEIGHT_BOLD, false); + + sensorvalue++; + displayed_value.Printf(wxT("%04d"), sensorvalue); + + wxTextFile sensorfile(wxT("sensor1")); + sensorfile.Open(); + displayed_value = sensorfile.GetFirstLine(); + + wxPaintDC dc(this); + + dc.SetFont(display_font); + + dc.DrawText(displayed_value, 60, 80); +} + +void SensorDisplay::OnTimer(wxCommandEvent& event) +{ + sensorvalue += 10; + Refresh(); +} + +enum +{ + ID_Hello = 1 +}; + +wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(ID_Hello, MyFrame::OnHello) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) + EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) +wxEND_EVENT_TABLE() + +wxIMPLEMENT_APP(MyApp); + +bool MyApp::OnInit() +{ + MyFrame *frame = new MyFrame( "Sensors", wxPoint(50, 50), wxSize(450, 340) ); + frame->Show( true ); + return true; +} + +MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame(NULL, wxID_ANY, title, pos, size) +{ + wxMenu *menuFile = new wxMenu; + menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", + "Help string shown in status bar for this menu item"); + menuFile->AppendSeparator(); + menuFile->Append(wxID_EXIT); + wxMenu *menuHelp = new wxMenu; + menuHelp->Append(wxID_ABOUT); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append( menuFile, "&File" ); + menuBar->Append( menuHelp, "&Help" ); + SetMenuBar( menuBar ); + + SensorDisplay *display = new SensorDisplay(this); + + CreateStatusBar(); + SetStatusText( "Raspberry Pi sensors" ); +} + +void MyFrame::OnExit(wxCommandEvent& event) +{ + Close( true ); +} + +void MyFrame::OnAbout(wxCommandEvent& event) +{ + wxMessageBox( "Raspberry Pi sensor display version 1.0", + "About Sensors...", wxOK | wxICON_INFORMATION ); +} + +void MyFrame::OnHello(wxCommandEvent& event) +{ + wxLogMessage("Hello from sensors!"); +} + diff --git a/src/pulsewidth.cpp b/src/pulsewidth.cpp new file mode 100644 index 0000000..2856271 --- /dev/null +++ b/src/pulsewidth.cpp @@ -0,0 +1,124 @@ +#include +#include +#include + +#include +#include +#include + + +#define CMP_IN 22 // The signal from the comparator +#define NR_SAMPLES 20 + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata); + + +class DVM +{ + int pi; // Connection to pigpio daemon + unsigned comparator; // The signal from the comparator + + + uint32_t last_tick; + uint32_t measure_start; + + uint32_t samples[NR_SAMPLES]; + int sample_index; + +public: + + void input_event(unsigned gpio, unsigned level, uint32_t tick) + { + //printf("Input event: input %u = %u, %d\n", gpio, level, tick - last_tick); + + + if (gpio == comparator && level == 1) + { + measure_start = tick; + } + if (gpio == comparator && level == 0) + { + samples[sample_index] = tick - measure_start; + //printf(" Measured time = %d\n", tick - measure_start); + sample_index++; + if (sample_index == NR_SAMPLES) + { + uint32_t min = samples[0]; + uint32_t max = samples[0]; + uint32_t sum = 0; + + for (int i = 0; i < NR_SAMPLES; i++) + { + sum += samples[i]; + if (samples[i] > max) max = samples[i]; + if (samples[i] < min) min = samples[i]; + } + printf("Min = %d, Max = %d, Middle = %d, Avg = %d\n", min, max, (min + max) / 2, (sum / NR_SAMPLES) >> 5 << 5); + + sample_index = 0; + } + } + last_tick = tick; + } + + + DVM(int pi_connection, unsigned cmp) + { + int open_return; + + pi = pi_connection; + comparator = cmp; + + last_tick = 0; + sample_index = 0; + + + set_mode(pi, comparator, PI_INPUT); + set_pull_up_down(pi, comparator, PI_PUD_OFF); + set_glitch_filter(pi, comparator, 200); + + open_return = callback_ex(pi, comparator, EITHER_EDGE, gpio_callback, this); + fprintf(stderr, "Set callback returns %d.\n", open_return); + } + +}; + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata) +{ + DVM *sensor; + + sensor = (DVM *)userdata; + sensor->input_event(user_gpio, level, tick); +} + + +int main() +{ + int pi; + std::ofstream sensorfile; + + pi = pigpio_start(NULL, NULL); + if (pi < 0) + { + // pigpio initialisation failed. + fprintf(stderr, "GPIO initialization failed.\n"); + + } + else + { + // pigpio initialised okay. + DVM sensor(pi, CMP_IN); + + while (true) + { + sleep(1); + //printf("%.3f\r", sensor.Voltage()); + //fflush(stdout); + + } + pigpio_stop(pi); + + } + +} + diff --git a/src/tsic.cpp b/src/tsic.cpp new file mode 100644 index 0000000..cd269cb --- /dev/null +++ b/src/tsic.cpp @@ -0,0 +1,187 @@ +#include + +#include +#include +#include + +enum SerialState +{ + INITIAL, WAIT_START, START_BIT, AWAIT_BIT, INSIDE_BIT, PARITY_BIT, STOP_BIT + +}; + +#define TSIC_INPUT 4 // The sensor is connected to GPIO 4 + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata); + +class Tsic +{ + int pi; // Connection to pigpio daemon + unsigned gpio; // Input pin of the temparature sensor + + uint32_t last_high_tick; + uint32_t last_low_tick; + + uint32_t half_bit_time; + + SerialState serial_state; + + int bitcount; + unsigned char received_byte; + int byte_count; + unsigned char input_buffer[2]; + long temperature; // T * 100 + +public: + + void input_event(unsigned level, uint32_t tick) + { + + switch (serial_state) + { + case INITIAL: + if (level == 1) + { + last_high_tick = tick; + serial_state = WAIT_START; + } + break; + + case WAIT_START: + if (level == 0 && tick - last_high_tick > 3000) + { + last_low_tick = tick; + serial_state = START_BIT; + } + break; + + case START_BIT: // 2 + if (level == 1) + { + half_bit_time = tick - last_low_tick; + bitcount = 0; + received_byte = 0; + serial_state = AWAIT_BIT; + } + break; + + case AWAIT_BIT: // 3 + if (level == 0) + { + last_low_tick = tick; + serial_state = INSIDE_BIT; + } + break; + + case INSIDE_BIT: // 4 + if (level == 1) + { + unsigned bit = 0; + + if (tick - last_low_tick < half_bit_time) + { + bit = 1; + } + bitcount++; + if (bitcount < 9) + { + received_byte <<= 1; + received_byte |= bit; + serial_state = AWAIT_BIT; + } + else + { + input_buffer[byte_count++] = received_byte; + if (byte_count == 2) + { + unsigned int sensor_value = input_buffer[0] * 256 + input_buffer[1]; + temperature = sensor_value * 20000 / 2047 - 5000; + std::cout << " Temperature = " << temperature << "\n"; + byte_count = 0; + } + received_byte = 0; + serial_state = STOP_BIT; + } + } + break; + + case PARITY_BIT: // 5 + if (level == 1) + { + serial_state = STOP_BIT; + } + break; + case STOP_BIT: // 6 + if (level == 0) + { + serial_state = START_BIT; + last_low_tick = tick; + } + break; + } + } + + Tsic(int pi_connection, unsigned input) + { + pi = pi_connection; + gpio = input; + + last_high_tick = 0; + last_low_tick = 0; + + half_bit_time = 60; + + serial_state = INITIAL; + + bitcount = 0; + received_byte = 0; + byte_count = 0; + temperature = 0; // T * 100 + + set_mode(pi, gpio, PI_INPUT); + set_pull_up_down(pi, gpio, PI_PUD_OFF); + + int open_return = callback_ex(pi, gpio, EITHER_EDGE, gpio_callback, this); + fprintf(stderr, "Set callback returns %d.\n", open_return); + } + + long T() + { + return temperature; + } +}; + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata) +{ + Tsic *sensor; + + sensor = (Tsic *)userdata; + sensor->input_event(level, tick); +} + + +int main() +{ + int pi; + + pi = pigpio_start(NULL, NULL); + if (pi < 0) + { + // pigpio initialisation failed. + fprintf(stderr, "GPIO initialization failed.\n"); + + } + else + { + // pigpio initialised okay. + Tsic sensor(pi, TSIC_INPUT); + + + sleep(2); + std::cout << "The last temperature = " << sensor.T() / 100 << "." << sensor.T() % 100 << " Celcius.\n"; + pigpio_stop(pi); + + } + +} + diff --git a/src/voltmeter.cpp b/src/voltmeter.cpp new file mode 100644 index 0000000..cd33c0a --- /dev/null +++ b/src/voltmeter.cpp @@ -0,0 +1,157 @@ +#include +#include +#include + +#include +#include +#include + + +#define CYCLE_OUT 18 // The cycle output +#define CMP_IN 17 // The signal from the comparator +#define NR_SAMPLES 20 // Number of samples to avaerage out the jitter + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata); + +#define INPUT_OFFSET 0.97 +#define INPUT_DIVIDER 0.086 +#define SLOPE_FACTOR 11.4 // Current / Capacitance + +class DVM +{ + int pi; // Connection to pigpio daemon + unsigned cycle_gate; // The gate to run a measurement cycle + unsigned comparator; // The signal from the comparator + + + uint32_t last_tick; + uint32_t measure_start; + + uint32_t samples[NR_SAMPLES]; + int sample_index; + + float U; // The measured voltage + + +public: + + void input_event(unsigned gpio, unsigned level, uint32_t tick) + { + float measure_time; + + //printf("Input event: input %u = %u, %d\n", gpio, level, tick - last_tick); + + if (gpio == cycle_gate && level == 1) + { + measure_start = tick; + } + + if (gpio == comparator && level == 1) + { + samples[sample_index++] = tick - measure_start; + sample_index %= NR_SAMPLES; + + measure_time = (float)(tick - measure_start) / 1.0e6; + U = measure_time * 11.4 - INPUT_OFFSET; + U /= INPUT_DIVIDER; + + gpio_write(pi, cycle_gate, 0); + } + if (gpio == comparator && level == 0) + { + gpio_write(pi, cycle_gate, 1); + } + last_tick = tick; + } + + + DVM(int pi_connection, unsigned gate, unsigned cmp) + { + int open_return; + + pi = pi_connection; + cycle_gate = gate; + comparator = cmp; + + last_tick = 0; + sample_index = 0; + + + set_mode(pi, comparator, PI_INPUT); + set_mode(pi, cycle_gate, PI_OUTPUT); + set_pull_up_down(pi, comparator, PI_PUD_OFF); + + open_return = callback_ex(pi, cycle_gate, EITHER_EDGE, gpio_callback, this); + //fprintf(stderr, "Set callback returns %d.\n", open_return); + open_return = callback_ex(pi, comparator, EITHER_EDGE, gpio_callback, this); + //fprintf(stderr, "Set callback returns %d.\n", open_return); + gpio_write(pi, cycle_gate, 0); + sleep(1); + gpio_write(pi, cycle_gate, 1); + } + + float Voltage() + { + uint32_t sum = 0; + uint32_t average_time; + float measure_time; + + // To filter out the jitter, calculate the average measured time + + for (int i = 0; i < NR_SAMPLES; i++) + { + sum += samples[i]; + } + + average_time = (sum / NR_SAMPLES) >> 5 << 5; + std::cout << " Average time = " << average_time << "\n"; + measure_time = average_time / 1.0e6; + U = measure_time * SLOPE_FACTOR - INPUT_OFFSET; + U /= INPUT_DIVIDER; + + return U; + } +}; + +void gpio_callback(int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * userdata) +{ + DVM *sensor; + + sensor = (DVM *)userdata; + sensor->input_event(user_gpio, level, tick); +} + + +int main() +{ + int pi; + std::ofstream sensorfile; + + pi = pigpio_start(NULL, NULL); + if (pi < 0) + { + // pigpio initialisation failed. + fprintf(stderr, "GPIO initialization failed.\n"); + + } + else + { + // pigpio initialised okay. + DVM sensor(pi, CYCLE_OUT, CMP_IN); + + while (true) + { + sleep(1); + printf("%.3f\n", sensor.Voltage()); + fflush(stdout); + + sensorfile.open("sensor1"); + sensorfile << std::fixed << std::setprecision(1) << sensor.Voltage() << "\n"; + sensorfile.close(); + } + pigpio_stop(pi); + + } + +} + -- 2.11.0