“什么码头?” 或者我们使用Xamarin(Android)上的移动应用程序通过蓝牙控制控制器

在上一篇文章中,我答应过谈如何使用UART将CANNY 3 tiny连接到蓝牙。而且由于您在这些五月的假期中不会真正散散步,因此决定度过一段有益的时光,并且仍然信守诺言。但是仅仅将控制器连接到蓝牙适配器HC-06,对于Habr来说太容易了。

因此,我们不仅会连接所有内容,还将使用C#和Xamarin为电路编写一个原始的Android应用程序。

如果您喜欢我喜欢的“限位开关”和簧片开关的监控,欢迎您的到来。



这就是我们今天要谈论的内容:

第一部分:简介
第二部分:连接CANNY 3 tiny的电路和程序
第三部分:我们在Xamarin上为Android编写了一个应用程序
第四部分:结论

第一部分:简介


我先从好的代码开始,除了在C#中插入程序代码外,这一次,本文将相对较小,因为我们已较早地研究了使用控制器的基本技术。为了不再重复,这里列出了一些文章,在这些文章中,我们已经研究了使用CANNY控制器的基本方法:

  1. “一,二,三-烧圣诞树!” 或我第一次看到CANNY 3微型控制器 -在本文中,我们分析了控制器的含义,以及在CannyLab开发环境中工作的基础知识。
  2. “目的地有很多伪装……”,或者我们使用CANNY 3 tiny和光敏电阻自动控制灯 -在本文中,我们研究了使用USB虚拟COM端口,将传感器连接到ADC以及在控制器输出端使用高频PWM的方法。
  3. « ...» (CANNY Arduino) Raspberry PI — UART, .

在准备本文时,我使用了以下硬件:CANNY 3微型控制器,HC-06蓝牙适配器,限位开关(Trema模块),簧片开关,旧有线耳机,面包板,电线,鳄鱼。

我们将构建一个系统,该系统使用移动应用程序监视两个传感器的状态,并在必要时可以手动发出警报。

本文将介绍的所有内容都是出于教育和示范目的而发明的。我只是想展示一些与控制器一起使用的技巧,以及一次购买的铁片,以某种方式计算出它们的价值。

尽管要解决的问题的性质与现实相去甚远,但我们可以想象,我们正在隔室的滑动门后面制造一个监视系统。当它开始移动时,簧片开关将起作用,并且在路径的尽头它将向拖车发出信号。例如,如果我们需要引起注意,以使门关闭,我们将通过扬声器发出“吱吱”的信号。是的,我没有扬声器,但是有旧耳机。



好吧,和往常一样,一个音符。我强烈不建议将本文中的材料用作最终的真理。我本人第一次做很多事情,当然可以做得更好。


第二部分:连接CANNY 3 tiny的电路和程序


首先,为了不冒犯他人的版权,我从论坛上借来了东西,但我自己通过将它们连接到HC-06 想法来适应他们的想法,方法是通过``串行蓝牙终端''应用程序控制它并在开发图表时使用一些技巧你的任务。

接线图如下:



限位开关和簧片开关连接到6号和5号控制器的端子,耳机连接到4号端子(具有RF PWM),UART RX是1号端子,UART TX是2号端子,3号端子。它用于提供“ + 5V”,输出“-”-与“地”进行通信。

这是组装时的样子:



我在CannyLab 1.42版中为CANNY 3开发了图表(程序),也许在其他版本的开发环境中以及与其他控制器一起使用时,有必要对图表进行更改。

这是发生的事情:



与控制器设置和通过UART发送消息相关模块在上一篇文章中已分解

让我们更详细地研究剩下的两个。

接收UART消息 ”块负责打开警笛(耳机)。原则上,需要解析通过UART接收消息的示例。

首先,我们检查接收到的数据是否在UART中,如果存在,则将其发送到D触发器输入“ E”,在这种情况下,触发器将复制“ D”输入中的值,然后将其写入通过UART接收的消息中的前两个字符。我不想使所有事情复杂化,因此我们将进一步使用一个简单的方案。我们假设UART会收到从00到99的任何数字,我们会将其从符号形式转换为数字形式(我建议阅读转换器模块的工作方式;我有一个小的“插头”)。此外,前沿检测器的输入上的任何值> 0“都将导致一个信号,该信号在RF PWM模式下运行5秒钟将输出5导通。

您可以使用RF PWM的填充时间在设置中播放,耳机中的声音将取决于此。

让我们继续前进“消息的形成乍一看它的实现似乎很不寻常。这是因为我并没有真正弄清楚如何使用串行蓝牙终端程序以及Xamarin中的相同蓝牙协议。

我会向前走一点,说我还没有学会如何在智能手机上接收从控制器发送的消息。如果上一篇文章中的有线UART一切都显而易见,那么实际上是使用蓝牙,而不是发送的消息,只能读取其一部分,并且违反了传输命令的含义。

我认为最简单的解决方案是传输单个号码,这样可以保证到达接收方而不会造成损失。

在我们的案例中,我们监视磁簧开关和限位开关的离散状态。也就是说,我们只有4种可能的组合:簧片开关和限位开关关闭,仅一个打开,两个都打开。

由于簧片开关和限位开关会给出离散信号(0/1),因此您需要以某种方式区分它们。为此,我们将簧片信号的值乘以2.现在事实证明,信号的总和将为我们提供从0到3的值。

现在我们将分析一个非显而易见的选项,将其加上50事实是CannyLab向UART发送了两个字符,即03,而不是3,但是正如我所说,存在丢失某些信息的风险。例如,从值01开始,智能手机上的程序只能读取第一个“ 0”,这已经是一个错误。

可能会感到困惑并转换数据,例如用一些字母或空格替换寄存器的“ D1”字符,但我决定简化一下。我将值01转换为51(02转换为52,依此类推)。这五个不带信号,我在智能手机的程序级别将其剪切掉了。因此,我们始终保证保留消息的有用部分。

我们将程序加载到控制器中,单击“运行”,如果一切按计划进行,则HC-06将定期闪烁红色LED。

接下来,我们将智能手机与适配器配对。现在,您可以在“串行蓝牙终端”应用程序或任何其他具有类似功能的应用程序中检查性能。

写下蓝牙适配器的地址,这将在下一章中对我们很有用。



如您所见,根据传感器的状态,数据来了,如果您发送“ 11”,则在耳机中会听到讨厌的尖叫声。我们可以在这里停止,但让我们来概述一个原始应用程序。

可以从GitHub 下载用于控制器的程序和用于智能手机的程序的源代码。

我想指出的是,您不必在CANNY控制器上专门在硬件中实现所有功能,您可以为Arduino或其他喜欢的控制器编写程序。最初,我本人还计划为Arduino写草图的另一个版本,但是由于我几乎杀死了所有的五月假期,所以我再也没有能力连接CANNY和智能手机应用程序。

第三部分:编写Xamarin Android应用程序


坦率地说,我知道Xamarin并不是移动开发最受欢迎的解决方案。也许您已经有一个问题:“我为什么选择它?”。我想用Psoya Korolenko同名歌曲中的话回答他:



老实说,没有客观原因。就在几年前,我学习了C#的基础知识,每个人都想看看Xamarin是什么。而现在,由于“自我孤立”,人们终于可以动手了。

好吧,让我再次提醒您。这是我第一次见到Xamarin,这是我的第一个Android应用程序。不要盲目复制我的曲线代码,如果突然之间您可以找到更漂亮的解决方案,请使用它。

在开发程序时,我依赖于此材料这篇文章并没有特别的嚼劲,甚至是西班牙语,所以我仍然觉得可以与您分享我在该主题上的变化。

我在Visual Studio 2019社区版中构建了该程序。

首先,如图所示,创建一个新的空Android项目(Xamarin)。



我仅对三个文件进行了更改,它们可以在GitHub上完全查看,在这里我们将仅分析重要的部分:

AndroidManifest.xml

2权限已添加到标准模板中:

  <uses-permission android:name="android.permission.BLUETOOTH"/>
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

activity_main.xml
默认容器(RelativeLayout)已被删除。相反,添加LinearLayout容器仅仅是因为它更简单。在此容器中,所有元素都垂直对齐,并在屏幕的整个宽度上延伸。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/linearLayout1">
    <TextView
        android:text="Reed switch status - undefined"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/rSwitch"
        android:textSize="12pt" />
    <TextView
        android:text="End sensor status - undefined"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/EndSensor"
        android:textSize="12pt" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/startSiren"
        android:text="Send signal to siren" />
    <Switch
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/bltSwitch"
        android:checked="false"
        android:showText="true"
        android:text="Connect bluetooth" />
    <TextView
        android:text="status"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/status" />
</LinearLayout>

任何稍微熟悉HTML布局或XML的人都可以轻松理解用户界面的结构。我们有三个只读文本字段(TextView),一个开关(Switch),基本上像一个复选框一样工作,还有一个普通按钮(Button)。可以通过从构造函数中拖放元素来将元素放置在窗体上,也可以在属性窗口或代码中将元素设置为更方便的ID,文本存根和其他参数。

剩下要描述程序的逻辑。

MainActivity.cs

下面,在扰流板下方,整个代码是为了方便起见

完整的MainActivity.cs代码
// based on http://alejandroruizvarela.blogspot.com/2014/01/bluetooth-arduino-xamarinandroid.html
// for this article https://habr.com/ru/post/500454/


// based on http://alejandroruizvarela.blogspot.com/2014/01/bluetooth-arduino-xamarinandroid.html
// for this article https://habr.com/ru/post/500454/


using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
using System.Linq;
using System;
using System.IO;
using Java.Util;
using Android.Bluetooth;
using System.Threading.Tasks;

namespace _6.Canny_Xanarin_Bluetooth_Android
{
    [Activity(Label = "Control Canny 3 tiny via bluetooth", Theme = "@style/AppTheme", MainLauncher = true)]
    public class MainActivity : AppCompatActivity
    {

        Button startSiren;
        TextView rSwitch;
        TextView EndSensor;
        Switch bltSwitch;
        TextView status;
        private Java.Lang.String dataToSend;
        private BluetoothAdapter mBluetoothAdapter = null;
        private BluetoothSocket btSocket = null;
        private Stream outStream = null;
        // don't forget change addres to your device:
        private static string address = "98:D3:91:F9:6C:F6";
        // MY_UUID can be saved as is
        private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
        private Stream inStream = null;


        protected override void OnCreate(Bundle savedInstanceState)
        {

            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            startSiren = FindViewById<Button>(Resource.Id.startSiren);
            rSwitch = FindViewById<TextView>(Resource.Id.rSwitch);
            EndSensor = FindViewById<TextView>(Resource.Id.EndSensor);
            status = FindViewById<TextView>(Resource.Id.status);
            bltSwitch = FindViewById<Switch>(Resource.Id.bltSwitch);


            startSiren.Click += startSiren_ClickOnButtonClicked;
            bltSwitch.CheckedChange += bltSwitch_HandleCheckedChange;
            CheckBt();
        }

        private void CheckBt()
        {
            mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;

            if (!mBluetoothAdapter.Enable())
            {
                Toast.MakeText(this, "Bluetooth Off",
                    ToastLength.Short).Show();
            }

            if (mBluetoothAdapter == null)
            {
                Toast.MakeText(this,
                    "Bluetooth does not exist or is busy", ToastLength.Short)
                    .Show();
            }
        }

        void startSiren_ClickOnButtonClicked(object sender, EventArgs e)
        {
            if (bltSwitch.Checked)
            {
                try
                {
                    dataToSend = new Java.Lang.String("11");
                    writeData(dataToSend);
                    System.Console.WriteLine("Send signal to siren");
                }
                catch (System.Exception execept)
                {
                    System.Console.WriteLine("Error when send data" + execept.Message);
                }

            }
            else status.Text = "bluetooth not connected";
        }
        void bltSwitch_HandleCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
        {
            if (e.IsChecked)
            {
                Connect();
            }
            else
            {
                status.Text = "bluetooth not connected";
                if (btSocket.IsConnected)
                {
                    try
                    {
                        btSocket.Close();
                        System.Console.WriteLine("Connection closed");
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        public void Connect()
        {
            BluetoothDevice device = mBluetoothAdapter.GetRemoteDevice(address);
            System.Console.WriteLine("Connection in progress" + device);
            mBluetoothAdapter.CancelDiscovery();
            try
            {
                btSocket = device.CreateRfcommSocketToServiceRecord(MY_UUID);
                btSocket.Connect();
                System.Console.WriteLine("Correct Connection");
                status.Text = "Correct Connection to bluetooth";
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                try
                {
                    btSocket.Close();
                    System.Console.WriteLine("Connection closed");
                }
                catch (System.Exception)
                {
                    System.Console.WriteLine("Impossible to connect");
                    status.Text = "Impossible to connect";
                }
                System.Console.WriteLine("Socket Created");
  
            }
            beginListenForData();

        }

        public void beginListenForData()
        {
            try
            {
                inStream = btSocket.InputStream;
            }
            catch (System.IO.IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            Task.Factory.StartNew(() => {
                byte[] buffer = new byte[1024];
                int bytes;
                
                while (true)
                {

                    try
                    {
                        bytes = inStream.Read(buffer, 0, 1024);
                        System.Console.WriteLine("bytes " + bytes.ToString());
                        if (bytes > 0)
                        {
                            
                            RunOnUiThread(() => {
                                string valor = System.Text.Encoding.ASCII.GetString(buffer).Replace("5",String.Empty);
                                // transform string for deleate all symbols except 1-4(command from canny).
                                string command = new string(valor.Where(char.IsDigit).ToArray());

                                if (command.Length > 0)
                                {
                                     status.Text="data successfully readed";
                                    System.Console.WriteLine("command  " + command);
                                    switch (Int32.Parse(command))
                                    {
                                        case 0:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 1:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                            break;
                                        case 2:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 3:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                        break;
                                    }
                                }
                            });
                        }
                    }
                    catch (Java.IO.IOException)
                    {
                        RunOnUiThread(() => {
                            EndSensor.Text = "End sensor status - undefined";
                            rSwitch.Text = "Reed switch status - undefined ";
                        });
                        break;
                    }
                }
            });
        }

        private void writeData(Java.Lang.String data)
        {
            try
            {
                outStream = btSocket.OutputStream;
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with OutputStream when write to Serial port" + e.Message);
            }

            Java.Lang.String message = data;

            byte[] msgBuffer = message.GetBytes();

            try
            {
                outStream.Write(msgBuffer, 0, msgBuffer.Length);
                System.Console.WriteLine("Message sent");
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with  when write message to Serial port" + e.Message);
                status.Text = "Error with  when write message to Serial port";
            }
        }


    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
 }


现在分为几部分。

具有名称空间,类声明等连接的块 我会想念。


我们创建变量,稍后将使用它们绑定用户界面元素:

   Button startSiren;
   TextView rSwitch;
   TextView EndSensor;
   Switch bltSwitch;
   TextView status;

接下来是我所依赖的示例中的代码。某些方法的操作所必需的变量(字段)。

  private Java.Lang.String dataToSend;
        private BluetoothAdapter mBluetoothAdapter = null;
        private BluetoothSocket btSocket = null;
        private Stream outStream = null;
        // don't forget change addres to your device:
        private static string address = "98:D3:91:F9:6C:F6";
        // MY_UUID can be saved as is
        private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
        private Stream inStream = null;

对于我们来说,在此处将HC-06模块的地址驱动到地址字段中非常重要。

由于这是我第一次使用智能手机进行开发,包括使用Xamarin,因此我决定不对其进行复杂化处理,因此设备地址(如原始示例中所示)是固定的。如果需要,您可以看一下本文,似乎已经实现了对可用蓝牙设备的搜索。

继续。


        protected override void OnCreate(Bundle savedInstanceState)
        {

            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            startSiren = FindViewById<Button>(Resource.Id.startSiren);
            rSwitch = FindViewById<TextView>(Resource.Id.rSwitch);
            EndSensor = FindViewById<TextView>(Resource.Id.EndSensor);
            status = FindViewById<TextView>(Resource.Id.status);
            bltSwitch = FindViewById<Switch>(Resource.Id.bltSwitch);


            startSiren.Click += startSiren_ClickOnButtonClicked;
            bltSwitch.CheckedChange += bltSwitch_HandleCheckedChange;
            CheckBt();
        }

此方法是自动创建的,我们的任务是将其中的UI对象与该类的字段相关联,并附加处理程序以响应事件(startSiren.Click bltSwitch.CheckedChange)。

通过蓝牙检查连接:


        private void CheckBt()
        {
            mBluetoothAdapter = BluetoothAdapter.DefaultAdapter;

            if (!mBluetoothAdapter.Enable())
            {
                Toast.MakeText(this, "Bluetooth Off",
                    ToastLength.Short).Show();
            }

            if (mBluetoothAdapter == null)
            {
                Toast.MakeText(this,
                    "Bluetooth does not exist or is busy", ToastLength.Short)
                    .Show();
            }
        }

打开警笛。本质上只是将字符“ 11”发送给控制器:


   void startSiren_ClickOnButtonClicked(object sender, EventArgs e)
        {
            if (bltSwitch.Checked)
            {
                try
                {
                    dataToSend = new Java.Lang.String("11");
                    writeData(dataToSend);
                    System.Console.WriteLine("Send signal to siren");
                }
                catch (System.Exception execept)
                {
                    System.Console.WriteLine("Error when send data" + execept.Message);
                }

            }
            else status.Text = "bluetooth not connected";
        }

检查开关的状态(如果向右移动,则表明它已打开):

   void bltSwitch_HandleCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
        {
            if (e.IsChecked)
            {
                Connect();
            }
            else
            {
                if (btSocket.IsConnected)
                {
                    try
                    {
                        btSocket.Close();
                        System.Console.WriteLine("Connection closed");
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

当您打开电源时,我们将开始与蓝牙的连接。

连接本身的实现:

   public void Connect()
        {
            BluetoothDevice device = mBluetoothAdapter.GetRemoteDevice(address);
            System.Console.WriteLine("Connection in progress" + device);
            mBluetoothAdapter.CancelDiscovery();
            try
            {
                btSocket = device.CreateRfcommSocketToServiceRecord(MY_UUID);
                btSocket.Connect();
                System.Console.WriteLine("Correct Connection");
                status.Text = "Correct Connection to bluetooth";
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
                try
                {
                    btSocket.Close();
                    System.Console.WriteLine("Connection closed");
                }
                catch (System.Exception)
                {
                    System.Console.WriteLine("Impossible to connect");
                    status.Text = "Impossible to connect";
                }
                System.Console.WriteLine("Socket Created");
  
            }
            beginListenForData();

        }

这是最重要的方法之一-直接读取数据:


    public void beginListenForData()
        {
            try
            {
                inStream = btSocket.InputStream;
            }
            catch (System.IO.IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            Task.Factory.StartNew(() => {
                byte[] buffer = new byte[1024];
                int bytes;
                
                while (true)
                {

                    try
                    {
                        bytes = inStream.Read(buffer, 0, 1024);
                        System.Console.WriteLine("bytes " + bytes.ToString());
                        if (bytes > 0)
                        {
                            
                            RunOnUiThread(() => {
                                string valor = System.Text.Encoding.ASCII.GetString(buffer).Replace("5",String.Empty);
                                // transform string for deleate all symbols except 1-4(command from canny).
                                string command = new string(valor.Where(char.IsDigit).ToArray());

                                if (command.Length > 0)
                                {
                                     status.Text="data successfully readed";
                                    System.Console.WriteLine("command  " + command);
                                    switch (Int32.Parse(command))
                                    {
                                        case 0:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 1:
                                            rSwitch.Text = "reed switch - disconnected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                            break;
                                        case 2:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - not pressed ";
                                            break;
                                        case 3:
                                            rSwitch.Text = "reed switch - connected ";
                                            EndSensor.Text = "end sensor - pressed ";
                                        break;
                                    }
                                }
                            });
                        }
                    }
                    catch (Java.IO.IOException)
                    {
                        RunOnUiThread(() => {
                            EndSensor.Text = "End sensor status - undefined";
                            rSwitch.Text = "Reed switch status - undefined ";
                        });
                        break;
                    }
                }
            });
        }

据我所知,我在示例中留下了该方法的许多元素,首先,它与数据流建立了连接,如果缓冲区中有一些内容与读取的数据一起被读取,则将其读取到变量中valor而且,正如我所承诺的,我们只需删除数字“ 5”。

接下来,我们从读取的消息中删除除数字以外的所有字符string command = new string(valor.Where(char.IsDigit).ToArray());

,然后,一切变得简单,这取决于所收到的数字,从而在UI中显示此状态。

我没有从根本上更改这两种方法:

  private void writeData(Java.Lang.String data)
        {
            try
            {
                outStream = btSocket.OutputStream;
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with OutputStream when write to Serial port" + e.Message);
            }

            Java.Lang.String message = data;

            byte[] msgBuffer = message.GetBytes();

            try
            {
                outStream.Write(msgBuffer, 0, msgBuffer.Length);
                System.Console.WriteLine("Message sent");
            }
            catch (System.Exception e)
            {
                System.Console.WriteLine("Error with  when write message to Serial port" + e.Message);
                status.Text = "Error with  when write message to Serial port";
            }
        }


    public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
 }

据我了解,此代码块实现了消息的发送和事件处理程序,以扩大访问蓝牙的权限。

好了,剩下的就是建立用于调试应用程序的智能手机连接 奇怪的是,但是它可以工作:





第四部分:结论


该程序的工作方式如下:



这是我在Android上为智能手机开发应用程序的第一次经验。

我想指出的是,旧计算机上的VS 2019和Xamarin的运行速度非常慢。

在项目的第一次组装中,我真的设法吃了这些柔软的法式面包卷和喝茶。而且,坦白地说,应用程序本身很痛苦,打开/关闭开关不能很方便地工作,但是另一方面,鉴于我对.NET的基本开发技术只有一点点熟悉,而且我根本不是程序员,所以我什至可以无需完成单个教程或单个课程,就可以在一天内概述您的第一个应用程序。因此,用于创建基本应用程序的进入阈值非常低。

据我了解,CANNY控制器可用于汽车(尤其是家用汽车)的调试,因此很有可能具有某种“功能”并为其编写智能手机应用程序。要记住的主要事情是,当通过车辆的车载网络供电时,控制器的输出也将具有与输入相同的电压(例如12V而不是5V)。不要忘记保护蓝牙适配器,以免其意外失效。

这篇文章对我来说非常费力,我希望一切都没有白费,您会喜欢的。

All Articles