与众不同 windows phone (18) - Device(设备)之加速度传感器, 数字罗盘传感器

[索引页]
[源码下载]


与众不同 windows phone (18) - Device(设备)之加速度传感器, 数字罗盘传感器



作者:webabcd


介绍
与众不同 windows phone 7.5 (sdk 7.1) 之设备

  • 加速度传感器(加速度计)
  • 数字罗盘(磁力计)



示例
1、演示如何使用加速度传感器
AccelerometerDemo.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Device.AccelerometerDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">
            
            <TextBlock Name="lblAccelerometerSupported" />
            <Button Name="btnStart" Content="打开加速度传感器" Click="btnStart_Click" />
            <Button Name="btnStop" Content="关闭加速度传感器" Click="btnStop_Click" />
            <TextBlock Name="lblAccelerometerStatus" />
            <TextBlock Name="lblTimeBetweenUpdates" />
            <TextBlock Name="lblMsg" />
            
        </StackPanel>
    </Grid>

</phone:PhoneApplicationPage>

AccelerometerDemo.xaml.cs

/*
 * 演示如何使用加速度传感器
 * 
 * Accelerometer - 用于访问设备中的加速度计
 *     IsSupported - 设备是否支持加速度传感器
 *     IsDataValid - 是否可从加速度传感器中获取到有效数据
 *     CurrentValue - 加速度传感器当前的数据,AccelerometerReading 类型
 *     TimeBetweenUpdates - 触发 CurrentValueChanged 事件的时间间隔,如果设置的值小于 Accelerometer 允许的最小值,则此属性的值将被设置为 Accelerometer 允许的最小值
 *     State - 加速度计的当前的状态(Microsoft.Devices.Sensors.SensorState 枚举)
 *         NotSupported - 设备不支持加速度传感器
 *         Ready - 加速度传感器已准备好,并且正在解析数据
 *         Initializing - 加速度传感器正在初始化
 *         NoData - 加速度传感器无法获取数据
 *         NoPermissions - 无权限调用加速度传感器
 *         Disabled - 加速度传感器被禁用
 *     Start() - 打开加速度计
 *     Stop() - 关闭加速度计
 *     CurrentValueChanged - 加速度传感器获取到的数据发生改变时所触发的事件,属性 TimeBetweenUpdates 的值决定触发此事件的时间间隔
 *     
 * AccelerometerReading - 加速度传感器数据
 *     Acceleration - 详细数据,Vector3 类型的值
 *     DateTimeOffset - 从加速度传感器中获取到数据的时间点
 *     
 * 
 * 
 * 关于从加速度传感器中获取到的 Vector3 类型的值中 X Y Z 的解释如下
 * 手机坐标系:以手机位置为参照,假设手机垂直水平面放(竖着放),屏幕对着你,那么
 * 1、左右是 X 轴,右侧为正方向,左侧为负方向
 * 2、上下是 Y 轴,上侧为正方向,下侧为负方向
 * 3、里外是 Z 轴,靠近你为正方向,远离你为负方向
 * 以上可以用相对于手机位置的右手坐标系来理解
 * X Y Z 的值为中心点到地平面方向的线与各个对应轴线正方向的夹角的余弦值
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace Demo.Device
{
    public partial class AccelerometerDemo : PhoneApplicationPage
    {
        private Accelerometer _accelerometer;

        public AccelerometerDemo()
        {
            InitializeComponent();

            // 判断设备是否支持加速度传感器
            if (Accelerometer.IsSupported)
            {
                lblAccelerometerStatus.Text = "此设备支持加速度传感器";
            }
            else
            {
                lblAccelerometerStatus.Text = "此设备不支持加速度传感器";
                
                btnStart.IsEnabled = false;
                btnStop.IsEnabled = false;
            }
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (_accelerometer == null)
            {
                // 实例化 Accelerometer,注册相关事件
                _accelerometer = new Accelerometer();
                _accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1);
                _accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(_accelerometer_CurrentValueChanged);

                lblTimeBetweenUpdates.Text = "TimeBetweenUpdates 设置为 1 毫秒,实际为 " + _accelerometer.TimeBetweenUpdates.TotalMilliseconds.ToString() + " 毫秒";
            }

            try
            {
                // 打开加速度传感器
                _accelerometer.Start();
                lblAccelerometerStatus.Text = "加速度传感器已打开";
            }
            catch (Exception ex)
            {
                lblAccelerometerStatus.Text = "加速度传感器已打开失败";
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            if (_accelerometer != null)
            {
                // 关闭加速度传感器
                _accelerometer.Stop();
                lblAccelerometerStatus.Text = "加速度传感器已关闭";
            }
        }

        void _accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            // 注:此方法是在后台线程运行的,所以需要更新 UI 的话注意要调用 UI 线程
            Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
        }
        
        // 更新 UI
        private void UpdateUI(AccelerometerReading accelerometerReading)
        {
            Vector3 acceleration = accelerometerReading.Acceleration;

            // 输出 X Y Z 的值
            lblMsg.Text = "acceleration.X: " + acceleration.X.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "acceleration.Y: " + acceleration.Y.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "acceleration.Z: " + acceleration.Z.ToString("0.0");
        }
    }
}


2、演示如何使用数字罗盘传感器
CompassDemo.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.Device.CompassDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">

            <TextBlock Name="lblCompassSupported" />
            <Button Name="btnStart" Content="打开数字罗盘" Click="btnStart_Click" />
            <Button Name="btnStop" Content="关闭数字罗盘" Click="btnStop_Click" />
            <TextBlock Name="lblCompassStatus" />
            <TextBlock Name="lblTimeBetweenUpdates" />
            <TextBlock Name="lblOrientation" />
            <TextBlock Name="lblMsg" />

        </StackPanel>

        <Grid x:Name="gridCalibration" Visibility="Collapsed" Background="Black" Opacity="1">
            <StackPanel>
                <Image Source="CompassCalibrate.png" HorizontalAlignment="Center"/>
                <TextBlock TextWrapping="Wrap" TextAlignment="Center">
                    设备需要校准。校准方法:如图所示,对手机做“8字”旋转,直至完成校准(即 HeadingAccuracy 小于等于 10)
                </TextBlock>
                <Button Name="btnKnown" Content="知道了" Click="btnKnown_Click" />
            </StackPanel>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

CompassDemo.xaml.cs

/*
 * 演示如何使用数字罗盘传感器
 * 
 * Compass - 用于访问设备中的磁力计
 *     IsSupported - 设备是否支持数字罗盘
 *     IsDataValid - 是否可从数字罗盘中获取到有效数据
 *     CurrentValue - 数字罗盘当前的数据,CompassReading 类型
 *     TimeBetweenUpdates - 触发 CurrentValueChanged 事件的时间间隔,如果设置的值小于 Compass 允许的最小值,则此属性的值将被设置为 Compass 允许的最小值
 *     Start() - 打开磁力计
 *     Stop() - 关闭磁力计
 *     CurrentValueChanged - 数字罗盘传感器获取到的数据发生改变时所触发的事件,属性 TimeBetweenUpdates 的值决定触发此事件的时间间隔
 *     Calibrate - 当系统检测到数字罗盘需要校准时所触发的事件
 *     
 * CompassReading - 数字罗盘传感器数据
 *     HeadingAccuracy - 数字罗盘的精度,其绝对值如果大于 10 则需要校准
 *     TrueHeading - 与地理北极的顺时针方向的偏角(单位:角度),经测试可用
 *     MagneticHeading - 与地磁北极的顺时针方向的偏角(单位:角度),经测试理解不了
 *     MagnetometerReading - 磁力计的原始数据(单位:微特斯拉),经测试理解不了
 *     DateTimeOffset - 从数字罗盘传感器中获取到数据的时间点
 *     
 * 
 * 
 * 手机坐标系:以手机位置为参照,假设手机垂直水平面放(竖着放),屏幕对着你,那么
 * 1、左右是 X 轴,右侧为正方向,左侧为负方向
 * 2、上下是 Y 轴,上侧为正方向,下侧为负方向
 * 3、里外是 Z 轴,靠近你为正方向,远离你为负方向
 * 以上可以用相对于手机位置的右手坐标系来理解
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using System.Windows.Threading;

namespace Demo.Device
{
    public partial class CompassDemo : PhoneApplicationPage
    {
        private Compass _compass;
        private Accelerometer _accelerometer;

        public CompassDemo()
        {
            InitializeComponent();

            // 判断设备是否支持数字罗盘
            if (Compass.IsSupported)
            {
                lblCompassSupported.Text = "此设备支持数字罗盘";
            }
            else
            {
                lblCompassSupported.Text = "此设备不支持数字罗盘";

                btnStart.IsEnabled = false;
                btnStop.IsEnabled = false;
            }
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (_compass == null)
            {
                // 实例化 Compass,注册相关事件
                _compass = new Compass();
                _compass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(1);
                _compass.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<CompassReading>>(_compass_CurrentValueChanged);
                _compass.Calibrate += new EventHandler<CalibrationEventArgs>(_compass_Calibrate);

                lblTimeBetweenUpdates.Text = "TimeBetweenUpdates 设置为 1 毫秒,实际为 " + _compass.TimeBetweenUpdates.TotalMilliseconds.ToString() + " 毫秒";

                // 实例化 Accelerometer,注册相关事件,用于判断手机是横放状态还是竖放状态
                _accelerometer = new Accelerometer();
                _accelerometer.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerReading>>(_accelerometer_CurrentValueChanged);
            }

            try
            {
                // 打开数字罗盘
                _compass.Start();
                lblCompassStatus.Text = "数字罗盘已打开";

                _accelerometer.Start();
            }
            catch (Exception ex)
            {
                lblCompassStatus.Text = "数字罗盘打开失败";
                MessageBox.Show(ex.ToString());
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            if (_compass != null && _compass.IsDataValid)
            {
                // 关闭数字罗盘
                _compass.Stop();
                _accelerometer.Stop();

                lblCompassStatus.Text = "数字罗盘已关闭";
            }
        }

        void _compass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
        {
            // 注:此方法是在后台线程运行的,所以需要更新 UI 的话注意要调用 UI 线程
            Dispatcher.BeginInvoke(() => UpdateUI(e.SensorReading));
        }

        // 更新 UI
        private void UpdateUI(CompassReading compassReading)
        {
            // 显示从数字罗盘中获取到的各个参数
            lblMsg.Text = "magneticHeading: " + compassReading.MagneticHeading.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "trueHeading: " + compassReading.TrueHeading.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "headingAccuracy: " + Math.Abs(compassReading.HeadingAccuracy).ToString("0.0");
            lblMsg.Text += Environment.NewLine;

            Vector3 magnetometerReading = compassReading.MagnetometerReading;

            lblMsg.Text += "magnetometerReading.X: " + magnetometerReading.X.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "magnetometerReading.Y: " + magnetometerReading.Y.ToString("0.0");
            lblMsg.Text += Environment.NewLine;
            lblMsg.Text += "magnetometerReading.Z: " + magnetometerReading.Z.ToString("0.0");
        }

        void _compass_Calibrate(object sender, CalibrationEventArgs e)
        {
            // 注:此方法是在后台线程运行的,所以需要更新 UI 的话注意要调用 UI 线程

            // 显示“提示页”,用于提示用户设备需要校准
            Dispatcher.BeginInvoke(() => { gridCalibration.Visibility = Visibility.Visible; });
        }

        private void btnKnown_Click(object sender, RoutedEventArgs e)
        {
            // 隐藏“提示页”
            gridCalibration.Visibility = System.Windows.Visibility.Collapsed;
        }

        // 判断手机是竖放还是横放
        void _accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
        {
            Vector3 v = e.SensorReading.Acceleration;

            bool isCompassUsingNegativeZAxis = false;

            if (Math.Abs(v.Z) < Math.Cos(Math.PI / 4) && (v.Y < Math.Sin(7 * Math.PI / 4)))
            {
                isCompassUsingNegativeZAxis = true;
            }

            Dispatcher.BeginInvoke(() => { lblOrientation.Text = (isCompassUsingNegativeZAxis) ? "手机竖放" : "手机横放"; });
        }
    }
}



OK
[源码下载]

posted @ 2012-08-02 08:32  webabcd  阅读(3078)  评论(4编辑  收藏  举报