Introduction

We continue our path on the development and prototyping with the board RaspberryPi2. In the previous article found at this link, our goal was to control the switching of an LED. In recent days, among other things, and the new release of Windows 10 IoT, namely 10.0.10586.0, which has brought with it several new features that we will see in later articles in this. Our goal now and that as the title, to manage an analog sensor. Unlike a digital, analog sensor it said very briefly, is taken as one example of temperature, provides a constant voltage value in time, according to the temperature value which is detected by the sensor itself. Another example, a potentiometer, a resistance variable type, which according to how we act on it through his knob, will vary its value in ohms and therefore also varies the value of the output voltage. Until version 10.0.10240.0 to which we refer, there and the opportunity to connect analog sensors on the GPIO pin as missing inputs and PWM outputs (which stands for power with modulation), so we have to resort to so-called Converter ADC (Analog to Digital converter), namely an electronic circuit capable of converting an analog signal into a binary value expressed in bytes.
Hardware required
After this brief introduction, we move to the next step. For the realization of our circuit, we need the following hardware material:
A brief mention on the chip MCP3008
The datasheet you found at this link, it is an analog/digital converter powered at a voltage of 5 v DC max, 10-bit resolution. The following are the main features.
We can observe that the type of communication with the raspberry occurs through SPI protocol. Here's the pin.
The pin MCP3008
Figure 1: The pin MCP3008
Starting from pin 1 to pin 8, we have Channels form CH0 to CH7, where we will connect the output of / Analog sensors. Each channel as we shall see must be configured by following the manufacturer's instructions as per the attached datasheet. The pins 16-15 are connected to the positive pins 14-9 to zero volts (or Ground of the Raspberry Pi2). The pins on pins 13-12-11-10 on bus SPI0 or SPI1 Raspberry Pi2.
Electrical / electronic circuit
The following is the final circuit of our project, undertaken with Fritzing, excellent software for the creation of patterns electrical/electronic.
The electronic circuit
Figure 2: The electronic circuit
Not to be confused in the electrical connections, see below how to connect the GPIO with the MCP 3008. Observing figure 1, we see that between the pins 1 and 16 we have a sign of recognition, by turning the component by 90 ° counterclockwise, pin 1 will be the one at the bottom left, pin 8 is the one on the bottom right, the top right 9 and 16 in the upper left.
These are connections chip MCP3008 with the card Raspberry Pi2.
Temperature Sensor TMP36
Pinout Sensor TMP36
Figure 3: Pinout Sensor TMP36
It is an analog temperature sensor, which supplies a voltage value of 10mV for degree directly proportional to the temperature value which is detected. It has a reading range that goes from -40 to 125 ° C. Here's how to connect it. Looking at the picture above, we see that it has three pins, the first on the left (1) connect me to the voltage of 3.3 v DC, the center pin (2) as shown on the input CH0 of the MPC3008, the pin right (3) on GND.
Create the test project with Visual Studio 2015
Once the hardware part, the materials needed for the components and their characteristics, and now time to focus on the software side. We will use Visual Studio 2015. If you have not been carried out and, besides Visual Studio 2015 and Windows 10 (at least the Professional version), you must download and install the SDK for the development of Windows 10 that find this link. After installation finishes, we start Visual Studio 2015 and create using the File, New Project application using the blank template app (Windows Universal) as shown and call the project "AnalogTemperature".
New screen project
Figure 4: New screen project
Confirm with the OK button. A project created to develop within the IoT, we need the necessary libraries. In exploring solutions position the cursor to the "References", right-click select "Add Reference” and the subsequent screens to the "Extensions" select Windows IoT extensions for the UWP as visible in the next picture.
Management screen references
Figure 5: Management screen references
In terms of extensions, we have everything you need. We now need to create a couple of classes that will serve for the management of the sensor TMP36 and MCP 3008.
Creating Classes MCP3008 and TMP36
In exploring solutions, we place the cursor on the project name, right-click and choose "Insert" and right after "Class" and we call the MCP3008 as a chip. In the same way, we create a class called TMP36. Within the class, MCP3008 insert the following code,
  1. using System;
  2. using Windows.Devices.Enumeration;
  3. using Windows.Devices.Spi;
  4. using Windows.UI.Popups;
  5. namespace AnalogTemperature
  6. {
  7. public class MCP3008
  8. {
  9. SpiDevice _device;
  10. TMP36 _TMP36 = new TMP36();
  11. string _CHOICECHANNEL;
  12. const double _MAXVALUE = 1023.0;
  13. const int _MINVALUE = 0;
  14. const int _RESOLUTIONBITS = 10;
  15. const int _SHIFTBYTE = 8;
  16. byte[] _CH0 = new byte[]
  17. {
  18. 1,
  19. 0x80,
  20. 0
  21. };
  22. byte[] _CH1 = new byte[]
  23. {
  24. 1,
  25. 0x90,
  26. 0
  27. };
  28. byte[] _CH2 = new byte[]
  29. {
  30. 1,
  31. 0xA0,
  32. 0
  33. };
  34. byte[] _CH3 = new byte[]
  35. {
  36. 1,
  37. 0xB0,
  38. 0
  39. };
  40. byte[] _CH4 = new byte[]
  41. {
  42. 1,
  43. 0xC0,
  44. 0
  45. };
  46. byte[] _CH5 = new byte[]
  47. {
  48. 1,
  49. 0xD0,
  50. 0
  51. };
  52. byte[] _CH6 = new byte[]
  53. {
  54. 1,
  55. 0xE0,
  56. 0
  57. };
  58. byte[] _CH7 = new byte[]
  59. {
  60. 1,
  61. 0xF0,
  62. 0
  63. };
  64. byte[] _DATARECEIVED = new byte[]
  65. {
  66. 0,
  67. 0,
  68. 0
  69. };
  70. public async void InitializeMCP3008(SerialComunication serialcomunication, Channel channel, SpiComunication spicomunication, SpiMode mode)
  71. {
  72. var spiconnectionsettings = new SpiConnectionSettings((int) Spicomunication);
  73. spiconnectionsettings.ClockFrequency = _TMP36.CLOCK_SIGNAL;
  74. spiconnectionsettings.Mode = mode;
  75. string spiDevice = SpiDevice.GetDeviceSelector(Spicomunication.ToString());
  76. var deviceInformation = await DeviceInformation.FindAllAsync(SpiDevice);
  77. if (DeviceInformation != null && DeviceInformation.Count > 0)
  78. {
  79. _device = await SpiDevice.FromIdAsync(DeviceInformation[0].id, spiconnectionsettings);
  80. _CHOICECHANNEL = Channel.ToString();
  81. }
  82. else
  83. {
  84. var dialog = new MessageDialog("Device Not Found");
  85. await dialog.ShowAsync();
  86. return;
  87. }
  88. }
  89. public double ReturnResult()
  90. {
  91. switch (_CHOICECHANNEL)
  92. {
  93. case "CH0":
  94. _DEVICE.TransferFullDuplex(_CH0, _DATARECEIVED);
  95. break;
  96. case "CH1":
  97. _DEVICE.TransferFullDuplex(_CH1, _DATARECEIVED);
  98. break;
  99. case "CH2":
  100. _DEVICE.TransferFullDuplex(_CH2, _DATARECEIVED);
  101. break;
  102. case "CH3":
  103. _DEVICE.TransferFullDuplex(_CH3, _DATARECEIVED);
  104. break;
  105. case "CH4":
  106. _DEVICE.TransferFullDuplex(_CH4, _DATARECEIVED);
  107. break;
  108. case "CH5":
  109. _DEVICE.TransferFullDuplex(_CH5, _DATARECEIVED);
  110. break;
  111. case "CH6":
  112. _DEVICE.TransferFullDuplex(_CH6, _DATARECEIVED);
  113. break;
  114. case "CH7":
  115. _DEVICE.TransferFullDuplex(_CH7, _DATARECEIVED);
  116. break;
  117. }
  118. var result = ((_DATARECEIVED[1] & 0x03) << _SHIFTBYTE) + _DATARECEIVED[2];
  119. var mVolt = result * (_TMP36.VOLTAGE / _MAXVALUE);
  120. var tempCelsius = mVolt / _RESOLUTIONBITS;
  121. return tempCelsius;
  122. }
  123. }
  124. public enum SerialComunication
  125. {
  126. SINGLE_ENDED,
  127. DIFFERENTIAL
  128. }
  129. public enum Channel
  130. {
  131. CH0,
  132. CH1,
  133. CH2,
  134. CH3,
  135. CH4,
  136. CH5,
  137. CH6,
  138. CH7
  139. }
  140. public enum SpiComunication
  141. {
  142. SPI0,
  143. SPI1
  144. }
  145. }
Let's analyze the code above. They have defined variables at the class level. The first is nothing but the base class for testing and managing device connected to / and SPI ports of GPIO.
  1. SpiDevice _device;
Here we define a new object type TMP36 that we will see later.
  1. TMP36 _TMP36 = new TMP36();
The variables that follow, are all features of the integrated circuit MCP3008, starting from _MAXVALUE, which will be the maximum value in a 10-bit resolution as features found in the datasheet. _MINVALUE is the minimum value, _RESOLUTIONBITS and the maximum resolution of the MCP3008, _SHIFTBYTE representing the movement of 8 bits that must be performed once acquired the values that are returned from the DOUT pin of the MCP3008. The variables from _CH0 to _CH7 represent the eight channels available where you can connect an analog component, we will use in this example the _CH0. The variable _CHOICECHANNEL, will serve to store and what channel was used and pass the byte with the correct configuration, we will see it in the method ReturnResult (). Remains _DATARECEIVED, the byte that contains the end of the bit information to be processed and displayed to the user as the detected temperature.
  1. string _CHOICECHANNEL;
  2. const double _MAXVALUE = 1023.0;
  3. const int _MINVALUE = 0;
  4. const int _RESOLUTIONBITS = 10;
  5. const int _SHIFTBYTE = 8;
  6. byte[] _CH0 = new byte[] {1, 0x80, 0};
  7. byte[] _CH1 = new byte[] {1, 0x90, 0};
  8. byte[] _CH2 = new byte[] {1, 0xA0, 0};
  9. byte[] _CH3 = new byte[] {1, 0xB0, 0};
  10. byte[] _CH4 = new byte[] {1, 0xC0, 0};
  11. byte[] _CH5 = new byte[] {1, 0xD0, 0};
  12. byte[] _CH6 = new byte[] {1, 0xE0, 0};
  13. byte[] _CH7 = new byte[] {1, 0xF0, 0}
  14. byte[] _DATARECEIVED = new byte[] {0, 0, 0};
The method InitializeMCP3008, requires certain parameters, the first and the type of management data read from the channels of MCP3008, that we can set to "single-ended" or "Differential" as required in the datasheet, the channel on which connect the sensor in our TMP36 case of CH0, which we use on the SPI port GPIO, then the mode of communication on the SPI bus.
  1. /// <Param name = "serialcomunication">Define type comunication</ Param>
  2. /// <Param name = "channel">Define number of channel MCP3008</ Param>
  3. /// <Param name = "spicomunication">Define spicomunication channel</ Param>
  4. /// <Param name = "fashions">Define spi mode</ Param>
  5. public async void InitializeMCP3008(SerialComunication serialcomunication, Channel channel, SpiComunication spicomunication, SpiMode mode)
  6. {
  7. //It is defined as an instance of the class SpiConnectionSettings, passing an integer argument that defines which SPI bus is used,
  8. //for we will be 0.
  9. var spiconnectionsettings = new SpiConnectionSettings((int) Spicomunication);
  10. //Then we set the clock frequency and mode. We note to set the clock rate we use a class property TMP36.
  11. spiconnectionsettings.ClockFrequency = _TMP36.CLOCK_SIGNAL;
  12. spiconnectionsettings.Mode = mode;
  13. //Subsequently, with the class and method SpiDevice GetDeviceSelector, we get all the SPI bus on the card Raspberry Pi2.
  14. string spiDevice = SpiDevice.GetDeviceSelector(Spicomunication.ToString());
  15. //This section with the class DeviceInformation, we retrieve all the necessary information on / the SPI bus.
  16. var deviceInformation = await DeviceInformation.FindAllAsync(SpiDevice);
  17. //If the parameter deviceInformation not null, and greater than zero, we can define which SPI bus use, open the channel of communicat ion that we have set for us will be how SPI0 said, passing the method FromIdAsync Id bus and configuration.
  18. if(DeviceInformation! = null && DeviceInformation.Count > 0)
  19. {
  20. _device = await SpiDevice.FromIdAsync(DeviceInformation[0].id, spiconnectionsettings);
  21. _CHOICECHANNEL = Channel.ToString();
  22. }
  23. Else
  24. //If there has been no SPI warn the user with a MessageDialog.
  25. {
  26. var dialog = new MessageDialog("Device Not Found");
  27. await dialog.ShowAsync();
  28. return;
  29. }
  30. }
In this method, according to the channel that we decided to use, always it will be called the method TransferFullDuplex, who will send the settings on each channel selected on the SPI bus, and the second parameter byte where you will store the converted data from the signal analog to digital that we then process in a timely manner. Finally, we will have a result which will be our final temperature value.
  1. public double ReturnResult ()
  2. {
  3. switch (_CHOICECHANNEL)
  4. {
  5. case "CH0":
  6. _DEVICE.TransferFullDuplex (_CH0, _DATARECEIVED);
  7. break;
  8. case "CH1":
  9. _DEVICE.TransferFullDuplex (_CH1, _DATARECEIVED);
  10. break;
  11. case "CH2":
  12. _DEVICE.TransferFullDuplex (_CH2, _DATARECEIVED);
  13. break;
  14. case "CH3":
  15. _DEVICE.TransferFullDuplex (_CH3, _DATARECEIVED);
  16. break;
  17. case "CH4":
  18. _DEVICE.TransferFullDuplex (_CH4, _DATARECEIVED);
  19. break;
  20. case "CH5":
  21. _DEVICE.TransferFullDuplex (_CH5, _DATARECEIVED);
  22. break;
  23. case "CH6":
  24. _DEVICE.TransferFullDuplex (_CH6, _DATARECEIVED);
  25. break;
  26. case "CH7":
  27. _DEVICE.TransferFullDuplex (_CH7, _DATARECEIVED);
  28. break;
  29. }
  30. var result = ((_DATARECEIVED [1] & 0x03) << _SHIFTBYTE) + _DATARECEIVED [2];
  31. var mVolt = result * (_TMP36.VOLTAGE / _MAXVALUE);
  32. var tempCelsius = mVolt / _RESOLUTIONBITS;
  33. return tempCelsius;
  34. }
  35. }
_DATARECEIVED, is a byte array, we serve the first two left bits of the second element, while the first, _DATARECEIVED [0] we ignore it because there will be no value. Then we go to add up _DATARECEIVED [1] with _DATARECEIVED [2]. The subsequent calculations do nothing but obtain the value of temperature, _TMP36.VOLTAGE to note, that we will see later. I also added three enumerations that will be used when the MainPage define the code to implement the method InitializeMCP3008, are the type of communication channel used and what bus SPI intend to send and receive data.
  1. public enum SerialComunication
  2. {
  3. SINGLE_ENDED,
  4. DIFFERENTIAL
  5. }
  6. public enum Channel
  7. {
  8. CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7
  9. }
  10. public enum SpiComunication
  11. {
  12. SPI0,
  13. SPI1
  14. }
This and the need for the class MCP3008. Now for the class TMP36, after you create it, insert the following code.
  1. namespace AnalogTemperature
  2. {
  3. public class TMP36
  4. {
  5. const int _CLOCKSIGNAL = 1650000;
  6. const double _VOLTAGE = 2000;
  7. public int CLOCK_SIGNAL
  8. {
  9. get
  10. {
  11. return _CLOCKSIGNAL;
  12. }
  13. }
  14. public double VOLTAGE
  15. {
  16. get
  17. {
  18. return _VOLTAGE;
  19. }
  20. }
  21. }
  22. }
Simply, the parameters that are defined are the clock frequency, and the maximum voltage that can dispense the sensor at maximum output, the TMP36 to 125 ° c, delivers a voltage of about 2 vdc.
Creation of the graphical interface and code in MainPage class
Now is time to define the necessary classes, let's see how to implement it in Class MainPage. In exploring solutions, double click with the mouse on MainPage.xaml, entered in the code define our user interface, by entering the following XAML.
  1. <Page
  2. x:Class= "AnalogTemperature.MainPage"
  3. xmlns= "Http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x= "Http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local= "Using: AnalogTemperature"
  6. xmlns:d= "Http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc= "Http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. mc:Ignorable= "D">
  9. <Grid Background= "{ThemeResource ApplicationPageBackgroundThemeBrush} ">
  10. <Grid.RowDefinitions>
  11. <RowDefinition Height= "Auto" />
  12. <RowDefinition Height= "Auto" />
  13. </Grid.RowDefinitions>
  14. <Grid.ColumnDefinitions>
  15. <ColumnDefinition Width= "Auto" />
  16. <ColumnDefinition Width= "Auto" />
  17. <ColumnDefinition Width= "Auto" />
  18. </Grid.ColumnDefinitions>
  19. <TextBlock Grid.Row= "0" Grid.ColumnSpan= "3" x:Name= "TxtHeader" FontSize= "50" Text= "TMP 36 MCP AND SAMPLE 3008" />
  20. <TextBlock Grid.Column= "0" Grid.Row= "1" x:Name= "TxtReadingTemp" FontSize= "30" Margin= "15,0,0,0" Text= "Temperature value is:" />
  21. <TextBlock Grid.Column= "1" Grid.Row= "1" x:Name= "TxtReading" FontSize= "30" Margin= "15,0,0,0" />
  22. <TextBlock Grid.Column= "2" Grid.Row= "1" x:Name= "TxtCelsius" FontSize= "30" Margin= "15,0,0,0" Text= "C" />
  23. </Grid>
  24. </Page>
In itself it is very simple, but enough to display the temperature value returned by the method ReturnResult () class MCP3008 that is our goal. With F7 key, enter in the code C #, entering the underside.
  1. using System;
  2. using Windows.UI.Xaml;
  3. using Windows.UI.Xaml.Controls;
  4. using Windows.Devices.Spi;
  5. // The item template for the blank page is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x410
  6. namespace AnalogTemperature
  7. {
  8. /// <Summary>
  9. /// Blank page that can be used independently or explored within a frame.
  10. /// </ Summary>
  11. public sealed partial class MainPage : Page
  12. {
  13. DispatcherTimer _timer = new DispatcherTimer();
  14. MCP3008 _mcp3008 = new MCP3008();
  15. public MainPage ()
  16. {
  17. InitializeComponent ();
  18. _mcp3008.InitializeMCP3008 (SerialComunication.SINGLE_ENDED, Channel.CH0, SpiComunication.SPI0,SpiMode.Mode0);
  19. _timer.Interval = new TimeSpan(0, 0, 5);
  20. _timer.Start ();
  21. _timer.Tick + = _timer_Tick;
  22. }
  23. private void _timer_Tick (object sender, object is)
  24. {
  25. txtReading.Text = Math.round (_mcp3008.ReturnResult ()). ToString ();
  26. }
  27. }
  28. }
Analyzing the previous C # code, we initialize a timer.
  1. DispatcherTimer _timer = new DispatcherTimer();
We define an object of type MCP3008.
  1. MCP3008 _mcp3008 = new MCP3008();
We InitializeMCP3008 implement the method, passing the necessary parameters.
  1. _mcp3008.InitializeMCP3008 (SerialComunication.SINGLE_ENDED, Channel.CH0, SpiComunication.SPI0,SpiMode.Mode0);
We set the timers Interval property with a value of type TimeSpan 5 seconds, we start with the Start () method and finally we manage its Tick event.
  1. _timer.Interval = new TimeSpan(0, 0, 5);
  2. _timer.Start ();
  3. _timer.Tick + = _timer_Tick;
Inside the event Tick, let's highlight the Text property of the TextBox txtReading, showing the temperature value by calling the ReturnResult (), but before we round the value with the static class Math and Round () method to remove decimal too.
  1. private void _timer_Tick (object sender, object is)
  2. {
  3. txtReading.Text = Math.round (_mcp3008.ReturnResult ()). ToString ();
  4. }
Test the application
After the piece of code, before running the test application, there are a few things to see. The first being that we are developing on Raspberry Pi2, and to set the ARM compilation mode, you can invoke it from the pull-down menu as in the following figure,
The main menu of Visual Studio 2015
Figure 6: The main menu of Visual Studio 2015
In reference to the previous image, you will notice that is on the run as "Remote computer". This is because we want to run the application on the card Raspberry Pi2. Select this mode, and go to the next screen to select the device and the IP address of the Raspberry Pi2 clearing authentication or you can change these settings by selecting the project, right-click, select "Properties" and immediately after "Debug", we will be led by the following screen.
Section debugging in the project properties
Figure 7: Section debugging in the project properties
After this activity, we can run the Debugging. The F5 key, and if everything was done correctly, that's what the monitor will display,
The sample application running on Windows 10
Figure 8: The sample application running on Windows 10 and Raspberry Pi2 IoT.

Conclusion

In this article, we saw an introduction on what are the sensors Analog, and what an ADC because the card RaspberryPi2 need this component to make use of sensors and instruments with an analog signal. In future articles, we'll explore further using other components and see how to adapt different types of sensors and analog instruments on the ADC and Raspberry.