Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
sweetmalarkey
Published © GPL3+

Live Analog Sensor Graph

Graph live data from analog sensors.

IntermediateFull instructions provided1 hour1,198
Live Analog Sensor Graph

Things used in this project

Story

Read more

Schematics

Wiring an ADC and analog sensor to the Raspberry Pi

Code

XAML Markup

C#
Add 'LiveCharts.uwp' from Nuget Package Manager and Windows IoT Extensions for Markup for the UWP' from References.

Then add this markup to the MainPage.xaml file.
<Page
    x:Class="HacksterLiveChartsAnalogSensor.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HacksterLiveChartsAnalogSensor"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    xmlns:lvc="using:LiveCharts.Uwp"
    >

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" 
                Height="30" 
                Click="RunDataOnClick" 
                HorizontalAlignment="Stretch"
                >
            Start/Stop Data
        </Button>
        <lvc:CartesianChart Grid.Row="1">
            <lvc:CartesianChart.Series>
                <lvc:LineSeries Values="{Binding ChartValues}" 
                                PointGeometrySize="18" 
                                StrokeThickness="4" />
            </lvc:CartesianChart.Series>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis LabelFormatter="{Binding DateTimeFormatter}" 
                          MaxValue="{Binding AxisMax}" 
                          MinValue="{Binding AxisMin}"
                          DisableAnimations="True"
                          >
                    <lvc:Axis.Separator>
                        <lvc:Separator Step="{Binding AxisStep}"></lvc:Separator>
                    </lvc:Axis.Separator>
                </lvc:Axis>
            </lvc:CartesianChart.AxisX>
        </lvc:CartesianChart>
    </Grid>
</Page>

MeasureModel class

C#
Create a 'Models' folder and add a MeasureModel class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HacksterLiveChartsAnalogSensor.Models
{
    public class MeasureModel
    {
        public DateTime DateTime { get; set; }
        public double Value { get; set; }
    }
}

MCP3008 class

C#
to the same 'Models' add a class for the ADC
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//******
using Windows.Devices.Spi;
using Windows.Devices.Gpio;
using Windows.Devices.Enumeration;

namespace HacksterLiveChartsAnalogSensor.Models
{
    public class MCP3008
    {
        enum ADCChip
        {
            mcp3008, // 8 channel 10 bit
        }

        ADCChip whichADCChip = ADCChip.mcp3008;

        /*RaspBerry Pi2  Parameters*/
        private const string SPI_CONTROLLER_NAME = "SPI0";  /* For Raspberry Pi 2, use SPI0                             */
        private const Int32 SPI_CHIP_SELECT_LINE = 0;       /* Line 0 maps to physical pin number 24 on the Rpi2        */

        byte[] readBuffer = null;                           /* this is defined to hold the output data*/
        byte[] writeBuffer = null;                          /* we will hold the command to send to the chipbuild this in the constructor for the chip we are using */

        private SpiDevice SpiDisplay;

        // create a timer
        //private DispatcherTimer timer;

        int res;

        public MCP3008()
        {

            //timer = new DispatcherTimer();
            //timer.Interval = TimeSpan.FromMilliseconds(10);
            //timer.Tick += Timer_Tick;
            //timer.Start();

            whichADCChip = ADCChip.mcp3008;
            switch (whichADCChip)
            {

                case ADCChip.mcp3008:
                    {
                        readBuffer = new byte[3] { 0x00, 0x00, 0x00 };
                        writeBuffer = new byte[3] { 0x01, 0x80, 0x00 };
                    }
                    break;
            }

            //InitSPI();
        }
        public async Task InitSPI()
        {
            try
            {
                var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE);
                settings.ClockFrequency = 500000;// 10000000;
                settings.Mode = SpiMode.Mode0; //Mode3;
                var controller = await SpiController.GetDefaultAsync();
                SpiDisplay = controller.GetDevice(settings);
            }

            /* If initialization fails, display the exception and stop running */
            catch (Exception ex)
            {
                throw new Exception("SPI Initialization Failed", ex);
            }
        }
        //private void Timer_Tick(object sender, object e)
        //{
        //    DisplayTextBoxContents();
        //}
        public Task<int> DisplayTextBoxContents()
        {

            SpiDisplay.TransferFullDuplex(writeBuffer, readBuffer);
            res = convertToInt(readBuffer);
            //textPlaceHolder.Text = res.ToString();

            return res;

        }
        public int convertToInt(byte[] data)
        {
            int result = 0;
            switch (whichADCChip)
            {
                case ADCChip.mcp3008:
                    {
                        /*mcp3008 10 bit output*/
                        result = data[1] & 0x03;
                        result <<= 8;
                        result += data[2];
                    }
                    break;
            }

            return result;
        }

    }
}

MainPage.xaml.cs

C#
Finally add the code MainPage.xaml.cs file (I moved all the properties and fields to the top of the file for readability)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
//*******
//*****
using System.ComponentModel;
using LiveCharts;
using LiveCharts.Configurations;
using HacksterLiveChartsAnalogSensor.Models;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace HacksterLiveChartsAnalogSensor
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page, INotifyPropertyChanged
    {
        public Models.MCP3008 mCP3008;

        private double _axisMax;
        private double _axisMin;

        public ChartValues<MeasureModel> ChartValues { get; set; }
        public Func<double, string> DateTimeFormatter { get; set; }

        public double AxisStep { get; set; }

        public double AxisMax
        {
            get { return _axisMax; }
            set
            {
                _axisMax = value;
                OnPropertyChanged("AxisMax");
            }
        }
        public double AxisMin
        {
            get { return _axisMin; }
            set
            {
                _axisMin = value;
                OnPropertyChanged("AxisMin");
            }
        }

        public DispatcherTimer Timer { get; set; }
        public bool IsDataInjectionRunning { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public MainPage()
        {
            this.InitializeComponent();

            var mapper = Mappers.Xy<MeasureModel>()
                .X(model => model.DateTime.Ticks)
                .Y(model => model.Value);

            Charting.For<MeasureModel>(mapper);

            ChartValues = new ChartValues<MeasureModel>();

            DateTimeFormatter = value => new DateTime((long)(value)).ToString("mm:ss");

            AxisStep = TimeSpan.FromSeconds(2).Ticks;
            SetAxisLimits(DateTime.Now);

            Timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(10)
            };
            Timer.Tick += TimerOnTick;
            IsDataInjectionRunning = false;

            DataContext = this;
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            mCP3008 = new MCP3008();
            await mCP3008.InitSPI();
        }

        private void RunDataOnClick(object sender, RoutedEventArgs e)
        {
            if (IsDataInjectionRunning)
            {
                Timer.Stop();
                IsDataInjectionRunning = false;
            }
            else
            {
                Timer.Start();
                IsDataInjectionRunning = true;
            }
        }

        private async void TimerOnTick(object sender, object eventArgs)
        {
            var now = DateTime.Now;

            ChartValues.Add(new MeasureModel
            {
                DateTime = now,

                //Value = await _bme280.ReadTemperature()
                Value = await mCP3008.DisplayTextBoxContents()
            });

            SetAxisLimits(now);

            if (ChartValues.Count > 300) ChartValues.RemoveAt(0);
        }

        private void SetAxisLimits(DateTime now)
        {
            AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks;
            AxisMin = now.Ticks - TimeSpan.FromSeconds(30).Ticks;
        }

        public void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

Credits

sweetmalarkey
2 projects • 0 followers
Contact

Comments

Please log in or sign up to comment.