Ejemplo n.º 1
0
        /// <summary>
        /// Try to gets the current distance, , usual range from 2 cm to 400 cm
        /// </summary>
        /// <param name="result">Length</param>
        /// <returns>True if success</returns>
        public bool TryGetDistance(out Length result)
        {
            // Time when we give up on looping and declare that reading failed
            // 100ms was chosen because max measurement time for this sensor is around 24ms for 400cm
            // additionally we need to account 60ms max delay.
            // Rounding this up to a 100 in case of a context switch.
            long hangTicks = DateTime.Now.Ticks + 100 * TimeSpan.TicksPerMillisecond;

            _timer.Reset();

            // Measurements should be 60ms apart, in order to prevent trigger signal mixing with echo signal
            // ref https://components101.com/sites/default/files/component_datasheet/HCSR04%20Datasheet.pdf
            while (DateTime.Now.Ticks - _lastMeasurment < 60 * TimeSpan.TicksPerMillisecond)
            {
                Thread.Sleep(TimeSpan.FromTicks(DateTime.Now.Ticks - _lastMeasurment));
            }

            _lastMeasurment = DateTime.Now.Ticks;

            // Trigger input for 10uS to start ranging
            _controller.Write(_trigger, PinValue.High);
            DelayHelper.DelayMicroseconds(10, true);
            _controller.Write(_trigger, PinValue.Low);

            // Wait until the echo pin is HIGH (that marks the beginning of the pulse length we want to measure)
            while (_controller.Read(_echo) == PinValue.Low)
            {
                if (DateTime.Now.Ticks - hangTicks > 0)
                {
                    result = default;
                    return(false);
                }
            }

            _timer.Start();

            // Wait until the pin is LOW again, (that marks the end of the pulse we are measuring)
            while (_controller.Read(_echo) == PinValue.High)
            {
                if (DateTime.Now.Ticks - hangTicks > 0)
                {
                    result = default;
                    return(false);
                }
            }

            _timer.Stop();

            // distance = (time / 2) × velocity of sound (34300 cm/s)
            result = Length.FromCentimeters((_timer.Elapsed.TotalMilliseconds / 2.0) * 34.3);

            if (result.Value > 400)
            {
                // result is more than sensor supports
                // something went wrong
                result = default;
                return(false);
            }

            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// The CCS811 sensor constructor
        /// </summary>
        /// <param name="i2cDevice">A valid I2C device</param>
        /// <param name="gpioController">An optional controller, either the default one will be used, either none will be created if any pin is used</param>
        /// <param name="pinWake">An awake pin, it is optional, this pin can be set to the ground if the sensor is always on</param>
        /// <param name="pinInterruption">An interruption pin when a measurement is ready, best use when you specify a threshold</param>
        /// <param name="pinReset">An optional hard reset pin</param>
        /// <param name="shouldDispose">Should the GPIO controller be disposed at the end</param>
        public Ccs811Sensor(I2cDevice i2cDevice, GpioController?gpioController = null, int pinWake = -1, int pinInterruption = -1, int pinReset = -1, bool shouldDispose = true)
        {
            _i2cDevice       = i2cDevice;
            _pinWake         = pinWake;
            _pinInterruption = pinInterruption;
            _pinReset        = pinReset;
            _shouldDispose   = shouldDispose;
            // We need a GPIO controller only if we are using any of the pin
            if ((_pinInterruption >= 0) || (_pinReset >= 0) || (_pinWake >= 0))
            {
                _shouldDispose = _shouldDispose || gpioController == null;
                _controller    = gpioController ?? new GpioController();
            }

            if (_controller is object)
            {
                _controller.OpenPin(_pinWake, PinMode.Output);
                _controller.Write(_pinWake, PinValue.High);
            }

            if (_controller is object && _pinReset >= 0)
            {
                _controller.OpenPin(_pinReset, PinMode.Output);
                _controller.Write(_pinReset, PinValue.Low);
                // Delays from documentation CCS811-Datasheet.pdf page 8
                // 15 micro second
                DelayHelper.DelayMicroseconds(15, true);
                _controller.Write(_pinReset, PinValue.High);
                // Need to wait at least 2 milliseconds before executing anything I2C
                Thread.Sleep(2);
            }

            // Initialization flow page 29
            // https://www.sciosense.com/wp-content/uploads/2020/01/CCS811-Application-Note-Programming-and-interfacing-guide.pdf
            // do a soft reset
            Span <byte> toReset = stackalloc byte[4]
            {
                0x11,
                0xE5,
                0x72,
                0x8A
            };

            WriteRegister(Register.SW_RESET, toReset);
            // Wait 2 milliseconds as per documentation
            Thread.Sleep(2);
            if (HardwareIdentification != 0x81)
            {
                throw new IOException($"CCS811 does not have a valid ID: {HardwareIdentification}. ID must be 0x81.");
            }

            if ((HardwareVersion & 0xF0) != 0x10)
            {
                throw new IOException($"CCS811 does not have a valid version: {HardwareVersion}, should be 0x1X where any X is valid.");
            }

            // Read status
            if (!Status.HasFlag(Status.APP_VALID))
            {
                throw new IOException($"CCS811 has no application firmware loaded.");
            }

            // Switch to app mode and wait 1 millisecond according to doc
            WriteRegister(Register.APP_START);
            Thread.Sleep(1);

            if (!Status.HasFlag(Status.FW_MODE))
            {
                throw new IOException($"CCS811 is not in application mode.");
            }

            // Set interrupt if the interruption pin is valid
            if (_controller is object && _pinInterruption >= 0)
            {
                _controller.OpenPin(_pinInterruption, PinMode.Input);
                byte mode = 0b0000_1000;
                WriteRegister(Register.MEAS_MODE, mode);
                _controller.RegisterCallbackForPinValueChangedEvent(_pinInterruption, PinEventTypes.Falling, InterruptReady);
                _running = true;
                // Start a new thread to monitor the events
                new Thread(() =>
                {
                    _isRunning = true;
                    while (_running)
                    {
                        var res = _controller.WaitForEvent(_pinInterruption, PinEventTypes.Falling, new TimeSpan(0, 0, 0, 0, 50));
                        if ((!res.TimedOut) && (res.EventTypes != PinEventTypes.None))
                        {
                            InterruptReady(_controller, new PinValueChangedEventArgs(res.EventTypes, _pinInterruption));
                            // We know we won't get any new measurement in next 250 milliseconds at least
                            // Waiting to make sure the sensor will have time to remove the interrupt pin
                            Thread.Sleep(50);
                        }
                    }

                    _isRunning = false;
                }).Start();
            }
        }
Ejemplo n.º 3
0
            private void Initialize()
            {
                // Prep the pins
                _controller.OpenPin(_rsPin, PinMode.Output);

                if (_rwPin != -1)
                {
                    _controller.OpenPin(_rwPin, PinMode.Output);

                    // Set to write. Once we enable reading have reading pull high and reset
                    // after reading to give maximum performance to write (i.e. assume that
                    // the pin is low when writing).
                    _controller.Write(_rwPin, PinValue.Low);
                }

                if (_backlight != -1)
                {
                    _controller.OpenPin(_backlight, PinMode.Output);
                    if (_backlightBrightness > 0)
                    {
                        // Turn on the backlight
                        _controller.Write(_backlight, PinValue.High);
                    }
                }

                _controller.OpenPin(_enablePin, PinMode.Output);

                for (int i = 0; i < _dataPins.Length; ++i)
                {
                    _controller.OpenPin(_dataPins[i], PinMode.Output);
                }

                // The HD44780 self-initializes when power is turned on to the following settings:
                //
                //  - 8 bit, 1 line, 5x7 font
                //  - Display, cursor, and blink off
                //  - Increment with no shift
                //
                // It is possible that the initialization will fail if the power is not provided
                // within specific tolerances. As such, we'll always perform the software based
                // initialization as described on pages 45/46 of the HD44780 data sheet. We give
                // a little extra time to the required waits as described.
                if (_dataPins.Length == 8)
                {
                    // Init to 8 bit mode (this is the default, but other drivers
                    // may set the controller to 4 bit mode, so reset to be safe.)
                    DelayHelper.DelayMilliseconds(50, allowThreadYield: true);
                    WriteBits(0b0011_0000, 8);
                    DelayHelper.DelayMilliseconds(5, allowThreadYield: true);
                    WriteBits(0b0011_0000, 8);
                    DelayHelper.DelayMicroseconds(100, allowThreadYield: true);
                    WriteBits(0b0011_0000, 8);
                }
                else
                {
                    // Init to 4 bit mode, setting _rspin to low as we're writing 4 bits directly.
                    // (Send writes the whole byte in two 4bit/nybble chunks)
                    _controller.Write(_rsPin, PinValue.Low);
                    DelayHelper.DelayMilliseconds(50, allowThreadYield: true);
                    WriteBits(0b0011, 4);
                    DelayHelper.DelayMilliseconds(5, allowThreadYield: true);
                    WriteBits(0b0011, 4);
                    DelayHelper.DelayMicroseconds(100, allowThreadYield: true);
                    WriteBits(0b0011, 4);
                    WriteBits(0b0010, 4);
                }

                // The busy flag can NOT be checked until this point.
            }
Ejemplo n.º 4
0
        /// <summary>
        /// Read through One-Wire
        /// </summary>
        internal virtual void ReadThroughOneWire()
        {
            byte readVal = 0;
            uint count;

            // keep data line HIGH
            _controller.SetPinMode(_pin, PinMode.Output);
            _controller.Write(_pin, PinValue.High);
            DelayHelper.DelayMilliseconds(20, true);

            // send trigger signal
            _controller.Write(_pin, PinValue.Low);
            // wait at least 18 milliseconds
            // here wait for 18 milliseconds will cause sensor initialization to fail
            DelayHelper.DelayMilliseconds(20, true);

            // pull up data line
            _controller.Write(_pin, PinValue.High);
            // wait 20 - 40 microseconds
            DelayHelper.DelayMicroseconds(30, true);

            _controller.SetPinMode(_pin, PinMode.InputPullUp);

            // DHT corresponding signal - LOW - about 80 microseconds
            count = _loopCount;
            while (_controller.Read(_pin) == PinValue.Low)
            {
                if (count-- == 0)
                {
                    IsLastReadSuccessful = false;
                    return;
                }
            }

            // HIGH - about 80 microseconds
            count = _loopCount;
            while (_controller.Read(_pin) == PinValue.High)
            {
                if (count-- == 0)
                {
                    IsLastReadSuccessful = false;
                    return;
                }
            }

            // the read data contains 40 bits
            for (int i = 0; i < 40; i++)
            {
                // beginning signal per bit, about 50 microseconds
                count = _loopCount;
                while (_controller.Read(_pin) == PinValue.Low)
                {
                    if (count-- == 0)
                    {
                        IsLastReadSuccessful = false;
                        return;
                    }
                }

                // 26 - 28 microseconds represent 0
                // 70 microseconds represent 1
                _stopwatch.Restart();
                count = _loopCount;
                while (_controller.Read(_pin) == PinValue.High)
                {
                    if (count-- == 0)
                    {
                        IsLastReadSuccessful = false;
                        return;
                    }
                }

                _stopwatch.Stop();

                // bit to byte
                // less than 40 microseconds can be considered as 0, not necessarily less than 28 microseconds
                // here take 30 microseconds
                readVal <<= 1;
                if (!(_stopwatch.ElapsedTicks * 1000000F / Stopwatch.Frequency <= 30))
                {
                    readVal |= 1;
                }

                if (((i + 1) % 8) == 0)
                {
                    _readBuff[i / 8] = readVal;
                }
            }

            _lastMeasurement = Environment.TickCount;

            if ((_readBuff[4] == ((_readBuff[0] + _readBuff[1] + _readBuff[2] + _readBuff[3]) & 0xFF)))
            {
                IsLastReadSuccessful = (_readBuff[0] != 0) || (_readBuff[2] != 0);
            }
            else
            {
                IsLastReadSuccessful = false;
            }
        }