티스토리 뷰

반응형

이전 글에서 gpio 핀을 이용하여 LED 의 high/low 값을 write 해서 깜빡깜빡하는 것을 확인해 보았는데, 실제로 Windows 10 IoT core가 올라간 RaspberryPI와 외부 디바이스가 연결할 수 있는 방법은 gpio 핀을 이용하는 것 말고도 다양하다. 오늘은 외부 things 인 sensor나 actuator를 연결하는 방법들 중 GPIO, I2C, SPI 통신에 대해 간략히 소개하고 그중 하나인 I2C 를 이용해서 Accelerometer인 가속도 센서를 제어해보도록 하겠다.

# GPIO/I2C/SPI

흔히 말하는 외부 디바이스와 통신 방식은 WIFI/BT/ZIGBEE 같은 Network Protocol 표준 방식들을 생각하겠지만, System resource를 이용한 sensor와 actuator와의 통신 방식이다. LED 도 외부 디바이스이 개념으로 생각할 수 있는데, 이렇게 LED에 Signal을 주었던 통로가 gpio 핀이다.

1. GPIO

 - GPIO는 General Purpose IO의 뜻으로 하나의 하드웨어 핀이 입력도 되고 출력도 될 수 있다. 기본적으로 RaspberryPI 도 GPIO 핀을 여러개 가지고 있기 때문에 간단한 방식의 제어가 필요한 곳에 활용할 수 있다. 

<시나리오>

방안이 어두어지면 자동으로 스탠드 전등이 켜진다.


위와 같은 시나리오로 구성하고자 할때, 전등의 스위치를 On/Off로 제어 하듯이 전등의 스위치와 GPIO 핀 하나를 연결해 놓아서 조도의 센서 값에 따라 GPIO의 Value를 High 또는 Low를 주면 조도에 따라서 자동으로 꺼졋다가 켜졋다가 하는 식의 IoT 시나리오를 구현할 수 있게 된다. GPIO는 앞으로 설명할 System Resource를 사용하는 통신방식 중 가장 쉬운 방법이니 자세한 내용은 별도로 찾아봐도 좋을 것 같다.

2. I2C

-  I2C는 Inter Intergrated Circuit 으로 두 가닥의 선을 이용함으로 TWI(Two Wire Interface)라고도 불린다. I2C 버스는 양방향 오픈 드레인 선인 SCL(Serial Clock) 과 SDA(Serial Data)로 이루어져 있으며, Master-Slave 형태로 동작한다. 속도면에서는 다른 방식에 비해서 현저하게 느리지만 하드웨어적으로 간단한 구성과 대화형 Protocol을 만들 수 있고 하나의 버스에 많은 수의 노드를 연결 할 수 있다는 큰 장점이 있다. SCL은 통신의 동기를 위한 클럭 선, SDA는 데이터 선이기에 I2C는 반이중 (Half duplex) 통신만 가능하다. 이번 글에서도 RaspberryPI에 I2C 를 이용해서 센서값을 읽는 App을 만들어 볼 예정이다.

3. SPI

SPI는 Serial Peripheral Interface로 완전한 전이중(Full Duplex) 통신이다. 전송되는 비트에 대한 완전한 프로토콜의 유연성을 가지고있고(16bit), 전송기가 필요없으며 매우 단순한 하드웨어 인터페이스 처리가 가능하다. 전이중 통신을 하기위해 4개의 PIN이 사용되는데 아래와 같다.

Serial Name

Alternative Names 

설명 

SCLK 

SCK, CLK

Serial Clock

MOSI

SDI, DI, SI

Master Output Slave Input

MISO

SDO, DO, SO

Slave Output Master Input

SS

nCS, CS, nSS, STE, CE

Slave Select, Chip Enable

4개의 핀을 보니 SCK 클럭에 따라서 마스터에서 슬레이브로 한비트를 전송하고 슬레이브에서도 마스터로 한비트를 전송한다. 근데 SPI는 3-Wire Mode가 있고 4-Wire Mode가 있는데 이게 뭘까? 4-Wire Mode는 앞서 설명한 내용과 같고 3-Wire Mode의 경우에는 Slave 장치에서 SS핀에 항상 받을 준비를 하라고 SS핀을 GND에 묶어 높은 형태이다. 센서마다 스펙이 다르기때문에 어떤 경우는 3-Wire Mode만 지원할 수도 있으니 잘 확인할 필요가 있다.

# 가속도 센서 - MMA7455

오늘 Test 해볼 센서는 가속도 틸트 센서인 MMA7455 이다.

<Datasheet 참조>

https://www.parallax.com/sites/default/files/downloads/28526-MMA7455-3-Axis-Accelerometer-Documentation-v1.1.pdf

Datasheet를 보면 8개의 Pin으로 구성되어 있고, x,y,z 축의 값을 읽을 수 있으며, I2C와 SPI 통신을 이용할 수 있다고 되어 있다. 앞서 I2C의 연결방법에서 봤듯이 VC, GND를 제외하고 SCL, SDA 만 연결하면 되므로 센서로 보면 DATA 핀과 CLK 핀을 연결하면 된다. 이제 본격적으로 진행하기에 앞서, 한가지 드는 의문이 있는데 센서의 이름이 Accelerometer 즉 가속도 센서다. 보통 핸드폰에 기능처럼 들고있는 방향성의 변화에 따라 변화되는 값을 읽어들이는 센서가 Gyro 센서로 알고 있고 가속도 센서는 이동하는 속도가 어떠한지 알아내는 센서이지 않나 생각되었는데 실제 가속도 센서와 자이로 센서의 차이는 다음과 같다.

1. 가속도 센서는 특정 지점에서 특점 지점으로 이동하는 벡터(Vector)형태의 인지밖에 할 수 없다.

2. 자이로 센서는 x, y, z축의 변화를 추적하여 말그대로 폰의 회전을 감지할 수 있다.

3. 가속도 센서는 실제로 골프게임과 같은 것을 구현할 때 골프채를 곡선으로 휘두르는 것을 인지할 수가 없다.

4. 마찬가지로 가속도 센서는 트위스트와 같은 꽈배기 형태의 움직임을 인지할 수 없다.

5. 자이로 센서는 폰의 회전률을 정확하게 알아낼 수 있다.

정리하면 가속도 센서는 직선방향의 움직임을, 자이로 센서는 곡선(회전)을 인식할 수 있는데 MMA7455와 같은 가속도 센서는 동적 힘을 감지하여 가속도 커지면 큰 충격을 받는다고 할 수 있다.

조금이나마 두 센서의 차이를 이해했으리라 생각하고 실제 값을 얻어보면서 어떤 형태로 값이 변하는지 알아보도록 하자. 그 전에 하나더 확인할 게 있다면 I2C로 연결하는 방법은 쉬운데 실제 어떻게 읽는지가 궁금하다. MMA7455로 검색해보면 이미 아두이노로 이 센서의 라이브러리를 제공해서 쉽게 센서값을 읽을 수 있게 해놨다. 다만, Windows 10 IoT Core 기반에서 하기위해선 실제 어떻게 값을 읽는지 Research가 필요하다.

# 알아야 할 것들

- The 10 bit values of the accelerometer are 10-bit signed integers. Some code is needed to convert them into normal signed integers of 16-bits.

- Soldering this chip can be very hard. There are however many easy to use modules with this accelermeter. Some modules have a voltage regulator to make 3.3V for the Accelerometer.

- The MMA7455 has internal offset registers. But the actual offset of the accelerometer changes if those offset registers are used.

- The chip is temperature compensated. There is even a temperature register, but reading that register returns always a zero.

- The MMA7455 is able to generate an interrupt for a certain level or pulse. But only one mode can be used at one time("Measurement" or "Level Detection" or "Pulse Detection")

제일 처음에 10bit의 값으로 센서를 읽을 수 있다고 나와있는데, x, y, z 값이 각각 2 byte로 이루어져서 MSB, LSB를 연산해서 뽑아내야 한다. 다만 간편하게 8 bit로도 읽을수도 있는데 빠르고 쉬운 반면 10 bit다 더 정확하다고 한다.

다음은 datasheet의 주요 register 값이다.

#define MMA7455_XOUTL 0x00      // Read only, Output Value X LSB
#define MMA7455_XOUTH 0x01      // Read only, Output Value X MSB
#define MMA7455_YOUTL 0x02      // Read only, Output Value Y LSB
#define MMA7455_YOUTH 0x03      // Read only, Output Value Y MSB
#define MMA7455_ZOUTL 0x04      // Read only, Output Value Z LSB
#define MMA7455_ZOUTH 0x05      // Read only, Output Value Z MSB
#define MMA7455_XOUT8 0x06      // Read only, Output Value X 8 bits
#define MMA7455_YOUT8 0x07      // Read only, Output Value Y 8 bits
#define MMA7455_ZOUT8 0x08      // Read only, Output Value Z 8 bits
#define MMA7455_STATUS 0x09     // Read only, Status Register
#define MMA7455_DETSRC 0x0A     // Read only, Detection Source Register
#define MMA7455_TOUT 0x0B       // Temperature Output Value (Optional)
#define MMA7455_RESERVED1 0x0C  // Reserved
#define MMA7455_I2CAD 0x0D      // Read/Write, I2C Device Address
#define MMA7455_USRINF 0x0E     // Read only, User Information (Optional)
#define MMA7455_WHOAMI 0x0F     // Read only, "Who am I" value (Optional)
#define MMA7455_XOFFL 0x10      // Read/Write, Offset Drift X LSB
#define MMA7455_XOFFH 0x11      // Read/Write, Offset Drift X MSB
#define MMA7455_YOFFL 0x12      // Read/Write, Offset Drift Y LSB
#define MMA7455_YOFFH 0x13      // Read/Write, Offset Drift Y MSB
#define MMA7455_ZOFFL 0x14      // Read/Write, Offset Drift Z LSB
#define MMA7455_ZOFFH 0x15      // Read/Write, Offset Drift Z MSB
#define MMA7455_MCTL 0x16       // Read/Write, Mode Control Register 
#define MMA7455_INTRST 0x17     // Read/Write, Interrupt Latch Reset
#define MMA7455_CTL1 0x18       // Read/Write, Control 1 Register
#define MMA7455_CTL2 0x19       // Read/Write, Control 2 Register
#define MMA7455_LDTH 0x1A       // Read/Write, Level Detection Threshold Limit Value
#define MMA7455_PDTH 0x1B       // Read/Write, Pulse Detection Threshold Limit Value
#define MMA7455_PD 0x1C         // Read/Write, Pulse Duration Value
#define MMA7455_LT 0x1D         // Read/Write, Latency Time Value (between pulses)
#define MMA7455_TW 0x1E         // Read/Write, Time Window for Second Pulse Value
#define MMA7455_RESERVED2 0x1F  // Reserved

#define MMA7455_I2C_ADDRESS 0x1D

수 많은 레지스터를 보니 벌써부터 머리가 복잡해 온다. 어떻게 읽고 계산해야할까? Datasheet로 보니 output에 대한 설명이 나와있다. 번역에 대한 오해를 없애기 위해 원문 그대로를 우선 읽어보자.

<Measured Acceleration Output Values>

The MMA7455L converts a detected acceleration into a number which can easily be read by an external microcontroller. The number it generates depends on the sensitivity of the device which can be ±2g, ±4g, or ±8g. One g represents the acceleration due to the earth's gravity: 1g ≒ 9.8 ㎨ or 1g ≒ 32.2ft/s2. Of course this value varies depending on the object's latitude and distance from sea level. From a sensory standpoint, there is no detectable difference between forces observed under the influence of acceleration and forces observed under the influence of gravity. Using units of g's is simply a convenient way of relating the magnitude of a measured acceleration to the familiar force of gravity.

The full measurement range is divided up into a number of counts which is determined by the number of bits specified for the datal 8-bit data has 256 counts, and 10-bit data has 1,024 counts. The value of one count, or least significant bit(LSB) of data, can be determined as follows;

One LSB = ( Full g - range ) / Number of counts

So for a sensitivity range of ±2g(full range = 4g) in 8-bit mode(256 counts), the value of one LSB would be approximately;

One LSB = 4g / 256 counts ≒ 0.016 g/count

위와 같이 datasheet에 나와있는데 읽어보니 더욱 복잡하다. 다만 x, y, z 값이 속도의 변화량이라는 거라는것만 알고 진행하자.

우선 하드웨어를 구성하고 Windows 10 IoT Core 사이트에서 제공하는 I2C Accelerometer 예제 프로젝트를 이용하기로 한다.

<Sample project>

https://developer.microsoft.com/ko-kr/windows/iot/samples/i2caccelerometer

제공되는 샘플은 ADXL345라는 가속도 센서를 I2C 방식으로 제어하는 것인데, 센서 스펙만 다를 뿐, 하드웨어 구성 및 기본적인 것은 같기 때문에 시도해볼 만 하다.

준비할 것은 MMA7455 가속도 센서와, 브레드 보드, 라즈베리파이, 그리고 센서와 라즈베리를 이어줄 커넥터들이다. 라즈베리의 핀 맵은 이전에 다뤘기에 간략히 연결해야하는 포인트만 다시 말하면 3.3V의 VC, GND 그리고 SCL, SDA 핀에 해당되는 곳이다.

No 

RaspberryPI

MMA7455 

VC(PIN 1)

VC 

GND(PIN 6)

GND 

SCL(PIN 5)

CLK 

SDA(PIN 3) 

DATA 


위 표에서와 같이 연결하면 다음과 같이 된다. 굳이 브레드 보드를 사용할 필요 없어서 다이렉트로 센서와 연결했다.

하드웨어 구성은 다 됬고, I2C를 이용해 센서 값을 읽어볼때 필요한코드를 살펴보도록 하자.

# I2C로 가속도 센서의 값을 읽어보는 application

- 필요한 Library

using Windows.UI.Xaml.Controls;

using Windows.Devices.I2c;

using Windows.Devices.Enumeration;

using System.Diagnostics;

using System.Threading;

using System;


- 센서 init 코드

namespace I2C_MMA7455

{

struct Acceleration

{

        public double X;

        public double Y;

        public double Z;

};

public sealed partial class Mainpage : Page

{

private const byte ACCEL_I2C_ADDR = 0x1D; 

private const byte MMA7455_MCTL = 0x16;

private const byte MMA7455_MCTL_MEASURE = 0x01;

private const byte MMA7455_XOUTL = 0x00;

private I2cDevice MMA7455;

private Timer periodicTimer;

public MainPage()

{

this.InitializeComponent();

InitMMA7455();

}

private async void InitMMA7455()

{

byte[] WriteBuf_DataFormat = new byte[] { MMA7455_MCTL, MMA7455_MCTL_MEASURE };

try

{

string aqs = I2cDevice.GetDeviceSelector();

var dis = await DeviceInformation.FindAllAsync(aqs);

var settings = new I2cConnectionSettings(ACCEL_I2C_ADDR);

settings.BusSpeed = I2cBusSpeed.StandardMode;

MMA7455 = await I2cDevice.FromIdAsync(dis[0].Id, settings);

}

catch (Exception error)

{

Text_Status.Text = "Failed to communicate with device: " + error.Message;

return;

}


byte[] writeMode = new byte[] { MMA7455_MCTL, MMA7455_MCTL_MEASURE };

try

{

MMA7455.Write(writeMode);

}

      catch (Exception error)

      {

          Text_Status.Text = "Failed to communicate with device: " + error.Message;

          return;

      }

periodicTimer = new Timer(this.TimerCallback, null, 0, 100); //100ms 단위로 읽는다.

}

}

}

init 코드를 보면 setting 시에 address를 세팅하는게 되는데 MMA7455의 경우 0x1D로 차음 세팅해주어야 I2C 로 데이터를 읽을 수 있게 된다. 앞서 설명했듯이 MMA7455 센서는 I2C와 SPI 두가지 통신 방법으로 data를 읽어 갈수 가 있기 때문이며, I2C Bus의 Speed 즉, Frequency의 경우 FastMode로 설정했다. 아래는 각 라인별 자세항 사항이다.

- I2cDevice.GetDeviceSelector( ); RaspberryPi의 I2C 컨트롤러에 관한 정보(AQS:Advanced Query Syntax) 를 얻는다.

- DeviceInformation.FindAllSync(aqs) : 앞에서 얻은 AQS 문자열에 일치하는 DeviceInformation 객체를 열거한다.

- I2cConnectionSettings( ); I2C 장치(센서)의 연결 설정으로 장치 주소와 속도를 지정한다.

- I2cDevice.FromIdAsync( ); 앞의 연결 설정을 사용하여 I2C 컨틀롤러의 I2C 장치(센서) 객체를 얻는다.

타이머 코드

타이머 콜백이 발생하면 센서에 기록되어 있는 데이터를 읽는다.

  private void TimerCallback(object state)

        {

            string xText, yText, zText;

            string statusText;

            

/* Read and format accelerometer data */

            try

            {

                Acceleration accel = ReadI2CAccel();

                xText = String.Format("X Axis: {0:F3}G", accel.X);

                yText = String.Format("Y Axis: {0:F3}G", accel.Y);

                zText = String.Format("Z Axis: {0:F3}G", accel.Z);

                statusText = "Status: Running";

            }

            catch (Exception ex)

            {

                xText = "X Axis: Error";

                yText = "Y Axis: Error";

                zText = "Z Axis: Error";

                statusText = "Failed to read from Accelerometer: " + ex.Message;

            }

            

            /* UI updates must be invoked on the UI thread */

            var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>

            {

                Text_X_Axis.Text = xText;

                Text_Y_Axis.Text = yText;

                Text_Z_Axis.Text = zText;

                Text_Status.Text = statusText;

            });

        }

레지스터에 따라 X, Y, Z 에 대한 데이터를 읽어서 실제 값으로 변환해야 하는데 센서의 Mode Table을 선택할때 아래 모드 중 우선 Measurement를 선택해야한다.

D1(MODE[1]) - Mode Select     

D0(MODE[0]) - Mode Select

00 - Standby

01 - Measurement                                 

10 - Level Detection

11 - Pulse Detection

나는8bit 8g 모드로 읽어보록할 것이기에 읽기전에 register를 8bit/8g로 세팅하고 mode를 Measurement로 세팅했다. 그리고 1바이트 읽은 값을 변환해준다.

- Data 변환 코드

  private Acceleration ReadI2CAccel()

        {

            const int ACCEL_RES = 1024;        

            const int ACCEL_DYN_RANGE_G = 8;    

            const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G;  /* Ratio of raw int values to G units                          */


            byte[] RegAddrBuf = new byte[] { ACCEL_REG_X }; /* Register address we want to read from   */                                   

            byte[] ReadBuf = new byte[3];

            /* 

             * Read from the accelerometer 

             * We call WriteRead() so we first write the address of the X-Axis I2C register, then read all 3 axes

             */

            I2CAccel.WriteRead(RegAddrBuf, ReadBuf);

            short AccelerationRawX = ReadBuf[0];

            short AccelerationRawY = ReadBuf[1];

            short AccelerationRawZ = ReadBuf[2];

            /* Convert raw values to G's */

            Acceleration accel;

            accel.X = (double)AccelerationRawX / UNITS_PER_G;

            accel.Y = (double)AccelerationRawY / UNITS_PER_G;

            accel.Z = (double)AccelerationRawZ / UNITS_PER_G;


            return accel;

        }

MSB 2 비트와 LSB 8 비트를 이용하기 때문에 MSB를 8 비트를 왼쪽으로 이동시키고 LSB 8비트를 or 연산 해주어 x, y, z 값을 구한다음 UI로 출력을 해준다. 출력시에는 UI에 String으로 출력하도록 UI를 구성하자.

- UI Xaml 코드

<Page

    x:Class="MMA7455.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="using:MMA7455"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d">


    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <TextBlock x:Name="Title" HorizontalAlignment="Center" Margin="0,230,0,0" TextWrapping="Wrap" Text="MMA7455 Accelerometer Data" VerticalAlignment="Top" Height="67" Width="640" FontSize="40" TextAlignment="Center"/>

        <TextBlock x:Name="Text_X_Axis" HorizontalAlignment="Center" Margin="0,290,0,0" TextWrapping="Wrap" Text="X Axis: Not Initialized" VerticalAlignment="Top" Width="312" FontSize="26.667" Foreground="#FFC71818" TextAlignment="Center"/>

        <TextBlock x:Name="Text_Y_Axis" HorizontalAlignment="Center" Margin="0,330,0,0" TextWrapping="Wrap" Text="Y Axis: Not Initialized" VerticalAlignment="Top" Width="312" FontSize="26.667" Foreground="#FF14D125" TextAlignment="Center"/>

        <TextBlock x:Name="Text_Z_Axis" HorizontalAlignment="Center" Margin="0,370,0,0" TextWrapping="Wrap" Text="Z Axis: Not Initialized" VerticalAlignment="Top" Width="312" FontSize="26.667" Foreground="#FF1352C1" TextAlignment="Center"/>

        <TextBlock x:Name="Text_Status" HorizontalAlignment="Center" Margin="10,410,10,0" TextWrapping="Wrap" Text="Status: Initializing ..." VerticalAlignment="Top" Width="1346" FontSize="32" TextAlignment="Center"/>

    </Grid>

</Page>

C# 코드에서 x, y, z 값을 구해서 Text_X_Axis, Text_Y_Axis, Text_Z_Axis 이름을 갖는 TextBlock에 update 되도록 한다.

이제 직접 작성한 Application을 RaspberryPI에 실행해보자.


X, Y, Z 의 움직임에 따라 값이 변하는 모습을 볼 수 있는데, Calibration 이 필요하고 offset 값을 세팅해야할 필요도 있다. 다만 가속도 센서를 이해하고, I2C 통신을 이해해서 이에 맞는 Windows 10 IoT core의 UI를 가진 application을 작성해 보았다. 전체 C#코드는 아래와 같다. 

<전체 코드>

using Windows.UI.Xaml.Controls;

using Windows.Devices.I2c;

using Windows.Devices.Enumeration;

using System.Diagnostics;

using System.Threading;

using System;

namespace MMA7455

{

    /// <summary>

    /// 자체적으로 사용하거나 프레임 내에서 탐색할 수 있는 빈 페이지입니다.

    /// </summary>

    /// 

    struct Acceleration

    {

        public double x;

        public double y;

        public double z;

    };

    public sealed partial class MainPage : Page

    {

        private I2cDevice MMA7455;

        private Timer periodicTimer;

        private const byte ACCEL_I2C_ADDR = 0x1D;

        private const byte MMA7455_MCTL = 0x16;

        private const byte MMA7455_MCTL_MEASURE = 0x01;

        private const byte MMA7455_XOUTL = 0x00;

        public MainPage()

        {

            this.InitializeComponent();

            Unloaded += MainPage_Unloaded;

            InitMMA7455();

        }

        private void MainPage_Unloaded(object sender, object args)

        {

            /* Cleanup */

            MMA7455.Dispose();

        }

        private async void InitMMA7455()

        {

            try

            {

                string aqs = I2cDevice.GetDeviceSelector();

                var dis = await DeviceInformation.FindAllAsync(aqs);

                var settings = new I2cConnectionSettings(ACCEL_I2C_ADDR);

                settings.BusSpeed = I2cBusSpeed.StandardMode;

                MMA7455 = await I2cDevice.FromIdAsync(dis[0].Id, settings);

            }

            catch (Exception error)

            {

                Text_Status.Text = "Failed to communicate with device: " + error.Message;

                return;

            }

            // Setting for mode and bit

            // 00(8g), 01(mode)

            byte[] writeMode = new byte[] { MMA7455_MCTL, MMA7455_MCTL_MEASURE };

            try

            {

                MMA7455.Write(writeMode);

            }

            catch (Exception error)

            {

                Text_Status.Text = "Failed to communicate with device: " + error.Message;

                return;

            }

            periodicTimer = new Timer(this.TimerCallback, null, 0, 100);

        }

       private void TimerCallback(object state)

        {

            string xText, yText, zText;

            string statusText;

            

/* Read and format accelerometer data */

            try

            {

                Acceleration accel = ReadI2CAccel();

                xText = String.Format("X Axis: {0:F3}G", accel.X);

                yText = String.Format("Y Axis: {0:F3}G", accel.Y);

                zText = String.Format("Z Axis: {0:F3}G", accel.Z);

                statusText = "Status: Running";

            }

            catch (Exception ex)

            {

                xText = "X Axis: Error";

                yText = "Y Axis: Error";

                zText = "Z Axis: Error";

                statusText = "Failed to read from Accelerometer: " + ex.Message;

             

            /* UI updates must be invoked on the UI thread */

            var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>

            {

                Text_X_Axis.Text = xText;

                Text_Y_Axis.Text = yText;

                Text_Z_Axis.Text = zText;

                Text_Status.Text = statusText;

            });

        }

        private Acceleration ReadI2CAccel()

        {

            const int ACCEL_RES = 1024;                           

            const int ACCEL_DYN_RANGE_G = 8;    

            const int UNITS_PER_G = ACCEL_RES / ACCEL_DYN_RANGE_G;  /* Ratio of raw int values to G units  */


            byte[] RegAddrBuf = new byte[] { ACCEL_REG_X }; /* Register address we want to read from   */                                   

            byte[] ReadBuf = new byte[3];

            /* 

             * Read from the accelerometer 

             * We call WriteRead() so we first write the address of the X-Axis I2C register, then read all 3 axes

             */

            I2CAccel.WriteRead(RegAddrBuf, ReadBuf)

            short AccelerationRawX = ReadBuf[0];

            short AccelerationRawY = ReadBuf[1];

            short AccelerationRawZ = ReadBuf[2];

            /* Convert raw values to G's */

            Acceleration accel;

            accel.X = (double)AccelerationRawX / UNITS_PER_G;

            accel.Y = (double)AccelerationRawY / UNITS_PER_G;

            accel.Z = (double)AccelerationRawZ / UNITS_PER_G;

            return accel;

        }

    }

}

길었던 글 작성이 끝났다. 이번 기회를 통해 조금더 IoT Application을 구현하는데 어떻게 해야하는지 프로그램 동작 구조를 읽히는데 도움이 되었던 것 같다. 이 글을 읽는 분들 모두 좀더 쉽게 접근할 수 있기를 바란다. 

반응형
댓글