與眾不同 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
[源碼下載]