微控指南针(1)西电通院微控上位机(安卓)指南 2024版本 ...

打印 上一主题 下一主题

主题 1023|帖子 1023|积分 3069

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 1.前言:

        本文章写于 2024通院微控竣事阶段。首先微控这个课吧,很耗费经历,对于很多组来说都是一道坎,尤其是头一次接触的上位机(安卓)部门。其次,这门课程的分工很重要,肯定要找到适合自己的三个队友,你永久不知道会分到什么样的队友,希望你不要酿成一个组里干所有活的夫役。
        由于本人在微控期间涉及了除了MCU和L610的所有部门(因为这两个有大佬队友来),以是本人想以一个初学者的角度,写一篇速通微控指南,大概会涵盖很多方面(如果我不懒的话),接下来,我先写下上位机部门的指南。由于本篇只是提供一个学习路线与debug的经历,不足之处,往大家包涵。
        对我而言,上位机部门更像是做裁缝,除了GUI别的部门真就东拼西凑,没整出来啥实际的东西,大多数时间都在写bug和debug(bushi,以是选择上位机分工,各位要有点心理预备,很多组末了都会因为上位机通宵,各位加油!
2.前期预备:

1.设备:

        通院接纳的设备为friendly arm公司Smart4418SDK,个人认为设备主要有以下几点重要须知:

  • 注意启动方式:设备主要有两种启动方式,SD卡启动和内存启动,详情可以看老师在学在西电课程章节中上传的视频。很多时候不肯定是设备坏了,大概是误触了相干开关。
  • 注意关机方式:肯定要先长按关机再拨开关,末了拔电源线。由于设备年久失修,这样是最好的包管设备不烂在手里的方式(bushi。具体演示也可以看老师在学在西电课程章节中上传的视频。
  • 注意打开USB调试和检查数据线:首先是打开USB调试,这个闲言少叙,大家能上这个专业多少都了解,不会的也可以去看老师发的视频。最重要的是检查发的数据线是否可用,因为很多数据线都是学长自己配的,原装数据线十不存一(不要问我怎么知道的)。以是有时候无法连接并不是你的问题,或许换一根数据线就好了。
  • 注意UART口的选择,这里建议选择UART3,最适合接线,其余的或多或少都有问题。
 2.软件:

        软件分以下几个部门来说:

  • Java环境配置:这个在数电课程大作业里做运算单元时应该都配过了,没配过的可以参考这篇文章:
    Java环境配置
  • Android studio版本的选择:以下Android studio简称AS。这里我建议选择2019版本,因为更加稳固,而且本文章的所有代码也是在2019版本上编写的,且AS的工程移植性极差,故建议使用2019版本。
    为了方便同砚,我将如何下载和安装最新版AS的文章和2019版本的安装包都附录如下:
    AS下载与安装
    2019版AS下载
    此外,AS的具体使用可以参考这篇文章:
    AS根本使用
  • 国内镜像源:在初次使用AS大概导入信你的工程文件时候,肯定会面临gradle下载慢的问题,解决这个问题可以点击如下链接:
    gradle镜像源替换
  • 众所周知,AS是一款很难卸载的软件,每次需要更换版本都十分困难,这里我将引用一篇文章来为大家先容AS的卸载:
    彻底卸载AS
 3.adb的安装与使用:

        在初期GUI制作阶段,大概通过AS里自带的步调就可以将软件下载到上位机中。但是,我们在后期需要调用串口时,需要经过签名生成apk文件,然后将apk文件安装进上位机中,如此你所编写的软件才能顺遂的打开串口进行与MCU的通信。
        固然可以通过VIVO手机助手进行链接和下载(蓝厂就是最diao的!!!),但我还是更推荐adb安装,更快,效率更高,同时还有肯定的调试功能。
        这里我也是引用一篇教程,通俗易懂。至于VIVO手机助手,大家可以查阅学长的视频讲授。
adb的安装及使用详解
3.GUI的界面制作:

1.GUI界面的计划:

        在大约第五周的时候,老师会让你们交一份GUI的计划稿。这个以后是要跟着后续功能的,以是说建议慎重一点,跟组员讨论敲定后再计划。
         在计划GUI时,有两种计划方式,一种类似于制作PPT,就用office和WPS就可以完成,因为这玩意原来也不高端,就是一层皮。还有一种方式就是使用Figma这款计划软件,他好就幸亏免费且有汉化社区,而且可以适配平板,还可以实现跳转,可以帮你理清前期逻辑,这玩意学习成本比较低,我就不在此赘述了,有爱好的同砚可以在B站上看up的课程,但是自学效率更快,具体链接如下:
Figma教程
2.GUI的制作

        这个没什么可以说的,也是看b站的速成课,同时学在西电中老师也放了一些指南。纯前端边边的东西,学习成本不高,一周左右速通差不多。具体课程附录如下:
GUI零基础
(ps:这个老师讲的挺不错的)

3.注意事项:


  • 肯定肯定不要拖动组件!!! 这样很轻易造成你的GUI下载下来一团乱麻。
  • 肯定要记着在Mainfest文件中定义页面优先级,不然很轻易下载一堆进来。
4.通信部门: 

        最大的boss来啦!不外不怕,咱们庖丁解牛,懂得代码用处天然做起来得心应手。
 1.硬件包的导入:

        这部门时第一步的预备部门,需要引入对应的驱动,这里呢老师们在学在西电的文件里有具体的解说,我就不外多赘述了,对应的文件也在学在西电的资料中,同砚们可以自行查阅。
2.串口助手: 

        在第一次进行数据链联调时,我们往往都是先使用上位机的串口助手来进行的,这个串口助手的工程我会附录在文章末了,具体使用不用我说大家应该都会,接下来我们将会对串口助手的java代码进行一个详解。

  • 包和导入:这些导入语句引入了Android开发所需的各种类和接口,以及用于硬件控制的FriendlyARM库。
    1. package com.example.sang.testserial; // 定义包名
    2. import android.app.Activity; // 导入Activity类
    3. import android.content.res.Configuration; // 导入Configuration类
    4. import android.os.Bundle; // 导入Bundle类
    5. import android.view.View; // 导入View类
    6. import android.view.View.OnClickListener; // 导入OnClickListener接口
    7. import android.widget.Button; // 导入Button类
    8. import android.widget.EditText; // 导入EditText类
    9. import android.widget.ScrollView; // 导入ScrollView类
    10. import android.widget.TextView; // 导入TextView类
    11. import android.util.Log; // 导入Log类
    12. import android.text.Html; // 导入Html类
    13. import android.widget.Toast; // 导入Toast类
    14. import java.util.Timer; // 导入Timer类
    15. import java.util.TimerTask; // 导入TimerTask类
    16. import com.friendlyarm.FriendlyThings.HardwareControler; // 导入HardwareControler类
    17. import com.friendlyarm.FriendlyThings.BoardType; // 导入BoardType类
    18. import android.os.Handler; // 导入Handler类
    19. import android.os.Message; // 导入Message类
    20. import android.content.Context; // 导入Context类
    21. import android.content.Intent; // 导入Intent类
    复制代码
  •  主类定义与成员变量定义:这些变量用于存储UI组件、串口配置和数据缓冲区等信息。
    1. public class MainActivity extends Activity implements OnClickListener { // 定义MainActivity类,继承Activity并实现OnClickListener接口
    2.     private static final String TAG = "SerialPort"; // 定义日志标签
    3.     private TextView fromTextView = null; // 定义TextView变量
    4.     private EditText toEditor = null; // 定义EditText变量
    5.     private final int MAXLINES = 200; // 定义最大行数
    6.     private StringBuilder remoteData = new StringBuilder(256 * MAXLINES); // 定义StringBuilder用于存储接收到的数据
    7.     // NanoPC-T4 UART4
    8.     private String devName = "/dev/ttyAMA3"; // 定义串口设备名
    9.     private int speed = 115200; // 定义串口波特率
    10.     private int dataBits = 8; // 定义数据位
    11.     private int stopBits = 1; // 定义停止位
    12.     private int devfd = -1; // 定义设备文件描述符
    复制代码
  •  onDestory:在活动销毁时,取消定时器并关闭串口。
    1.     @Override
    2.     public void onDestroy() { // 重写onDestroy方法
    3.         timer.cancel(); // 取消定时器
    4.         if (devfd != -1) { // 如果设备文件描述符有效
    5.             HardwareControler.close(devfd); // 关闭串口
    6.             devfd = -1; // 重置设备文件描述符
    7.         }
    8.         super.onDestroy(); // 调用父类的onDestroy方法
    9.     }
    复制代码
  • onCreat:在活动创建时,根据设备的方向加载不同的布局文件,初始化UI组件,并实验打开串口。如果串口打开成功,启动定时器定期检查数据。
    1.     @Override
    2.     public void onCreate(Bundle savedInstanceState) { // 重写onCreate方法
    3.         super.onCreate(savedInstanceState); // 调用父类的onCreate方法
    4.         if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { // 如果设备处于横屏模式
    5.             setContentView(R.layout.serialport_dataprocessview_landscape); // 设置横屏布局
    6.         } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { // 如果设备处于竖屏模式
    7.             setContentView(R.layout.serialport_dataprocessview); // 设置竖屏布局
    8.         }
    9.         String winTitle = devName + "," + speed + "," + dataBits + "," + stopBits; // 构建窗口标题
    10.         setTitle(winTitle); // 设置窗口标题
    11.         ((Button)findViewById(R.id.sendButton)).setOnClickListener(this); // 设置发送按钮的点击监听器
    12.         fromTextView = (TextView)findViewById(R.id.fromTextView); // 获取TextView组件
    13.         toEditor = (EditText)findViewById(R.id.toEditor); // 获取EditText组件
    14.         /* no focus when begin */
    15.         toEditor.clearFocus(); // 清除焦点
    16.         toEditor.setFocusable(false); // 设置不可获得焦点
    17.         toEditor.setFocusableInTouchMode(true); // 设置在触摸模式下可获得焦点
    18.         devfd = HardwareControler.openSerialPort(devName, speed, dataBits, stopBits); // 打开串口
    19.         if (devfd >= 0) { // 如果串口打开成功
    20.             timer.schedule(task, 0, 500); // 启动定时器,每500毫秒执行一次任务
    21.         } else { // 如果串口打开失败
    22.             devfd = -1; // 重置设备文件描述符
    23.             fromTextView.append("Fail to open " + devName + "!"); // 显示错误信息
    24.         }
    25.     }
    复制代码
  • 定时器和处理器(吸收部门):定时器每500毫秒发送一次消息给处理器,处理器检查串口是否有数据可读,如果有则读取数据并更新UI。
    1.     private final int BUFSIZE = 512; // 定义缓冲区大小
    2.     private byte[] buf = new byte[BUFSIZE]; // 定义缓冲区
    3.     private Timer timer = new Timer(); // 定义定时器
    4.     private Handler handler = new Handler() { // 定义处理器
    5.         public void handleMessage(Message msg) { // 重写handleMessage方法
    6.             switch (msg.what) { // 根据消息类型进行处理
    7.                 case 1: // 如果消息类型为1
    8.                     if (HardwareControler.select(devfd, 0, 0) == 1) { // 检查串口是否有数据可读
    9.                         int retSize = HardwareControler.read(devfd, buf, BUFSIZE); // 读取串口数据
    10.                         if (retSize > 0) { // 如果读取到数据
    11.                             String str = new String(buf, 0, retSize); // 将数据转换为字符串
    12.                             remoteData.append(str); // 将数据追加到remoteData中
    13.                             if (fromTextView.getLineCount() > MAXLINES) { // 如果TextView中的行数超过最大行数
    14.                                 int nLineCount = fromTextView.getLineCount(); // 获取当前行数
    15.                                 int i = 0; // 定义计数器
    16.                                 for (i = 0; i < remoteData.length(); i++) { // 遍历remoteData
    17.                                     if (remoteData.charAt(i) == '\n') { // 如果遇到换行符
    18.                                         nLineCount--; // 行数减一
    19.                                         if (nLineCount <= MAXLINES) { // 如果行数小于等于最大行数
    20.                                             break; // 退出循环
    21.                                         }
    22.                                     }
    23.                                 }
    24.                                 remoteData.delete(0, i); // 删除多余的行
    25.                                 fromTextView.setText(remoteData.toString()); // 更新TextView内容
    26.                             } else { // 如果行数未超过最大行数
    27.                                 fromTextView.append(str); // 追加数据到TextView
    28.                             }
    29.                             ((ScrollView)findViewById(R.id.scroolView)).fullScroll(View.FOCUS_DOWN); // 滚动到最底部
    30.                         }
    31.                     }
    32.                     break;
    33.             }
    34.             super.handleMessage(msg); // 调用父类的handleMessage方法
    35.         }
    36.     };
    37.     private TimerTask task = new TimerTask() { // 定义定时任务
    38.         public void run() { // 重写run方法
    39.             Message message = new Message(); // 创建消息对象
    40.             message.what = 1; // 设置消息类型
    41.             handler.sendMessage(message); // 发送消息
    42.         }
    43.     };
    复制代码
  • onClick:当发送按钮被点击时,获取toEditor中的文本并通过串口发送。如果发送成功,清空输入框并更新表现区域。
    1.     public void onClick(View v) { // 重写onClick方法
    2.         switch (v.getId()) { // 根据点击的视图ID进行处理
    3.             case R.id.sendButton: // 如果点击的是发送按钮
    4.                 String str = toEditor.getText().toString(); // 获取输入框中的文本
    5.                 if (str.length() > 0) { // 如果文本不为空
    6.                     if (str.charAt(str.length() - 1) != '\n') { // 如果文本末尾不是换行符
    7.                         str = str + "\n"; // 添加换行符
    8.                     }
    9.                     int ret = HardwareControler.write(devfd, str.getBytes()); // 发送数据到串口
    10.                     if (ret > 0) { // 如果发送成功
    11.                         toEditor.setText(""); // 清空输入框
    12.                         str = ">>> " + str; // 添加前缀
    13.                         if (remoteData.length() > 0) { // 如果remoteData不为空
    14.                             if (remoteData.charAt(remoteData.length() - 1) != '\n') { // 如果remoteData末尾不是换行符
    15.                                 remoteData.append('\n'); // 添加换行符
    16.                                 fromTextView.append("\n"); // 在TextView中添加换行符
    17.                             }
    18.                         }
    19.                         remoteData.append(str); // 将数据追加到remoteData中
    20.                         fromTextView.append(str); // 将数据追加到TextView中
    21.                         ((ScrollView)findViewById(R.id.scroolView)).fullScroll(View.FOCUS_DOWN); // 滚动到最底部
    22.                     } else { // 如果发送失败
    23.                         Toast.makeText(this, "Fail to send!", Toast.LENGTH_SHORT).show(); // 显示错误信息
    24.                     }
    25.                 }
    26.                 break;
    27.         }
    28.     }
    29. }
    复制代码
以上就是串口助手代码的所有详解。 
3.代码的更改: 

        如果你需要发送固定字符,可以按照我下面的代码对于onClick的部门进行更改:
  1.    int ret;
  2.     public void onClick(View v) {
  3.             switch (v.getId()) {
  4.             case R.id.btn_login1_2:
  5.                 String str4 = "*d0300";
  6.                 String str5 = "*d3000";
  7.                 if (str77 == 2) {
  8.                     ret = HardwareControler.write(devfd, str4.getBytes());//这是发送数据的代码,ret是发送的字节数的返回值
  9.                 }else{
  10.                     ret = HardwareControler.write(devfd, str5.getBytes());
  11.                 }
  12.                     if (ret > 0) {          //如果返回的ret大于0,说明发送成功了
  13.                         Toast.makeText(this, "sucess!", Toast.LENGTH_SHORT).show();
  14.                         Intent intent =null;
  15.                         intent = new Intent(MainActivity2.this,MainActivity6.class);
  16.                         startActivity(intent);
  17.                     } else {
  18.                         Toast.makeText(this, "Fail to send!", Toast.LENGTH_SHORT).show();
  19.                     }
  20.                 break;
  21.             case R.id.btn_login1_1:
  22.                 Intent intent = null;
  23.                 intent = new Intent(MainActivity2.this,MainActivity5.class);
  24.                 startActivity(intent);
  25.                 break;
  26. //以上是加了按钮的代码,没有报错
  27.             }
  28.         }
  29.     }
复制代码
         吸收部门可以添加如下代码对于数据帧进行替换:
  1. if (str.contains("你的数据帧")) {
  2.                                 str77=2;
  3.                                 str = str.replaceAll("你的数据帧", "想要显示的字符");
  4.                                 str = str + "\n";
  5.                                   final Toast toast = Toast.makeText(getApplicationContext(), "Green light ahead", 1000);
  6.                                   View toastView = toast.getView();
  7.                                 //toastView.setBackgroundResource(R.drawable.toast_bg);// 设置背景色为红色
  8.                                 TextView toastText = new TextView(getApplicationContext());
  9.                                 toastText.setText("想要显示的字符");
  10.                                 toastText.setTextColor(Color.GREEN); // 设置文本颜色为黑色
  11.                                 toastText.setTextSize(200); // 设置字体大小为100dp
  12.                                   toast.setGravity(Gravity.CENTER, 0, 0);
  13.                                   toast.setView(toastText); // 将TextView设置为Toast的视图
  14.                                   toast.show();
复制代码
        此外,对于只有按钮发送没有担当数据框的界面,可以查询代码详解删除对应的界面设置。
4.软件的签名与安装: 


  • cmd操作:我们对于软件的签名有两种方式,老师在学在西电的教程都有提及,这里我们主要将用下令行来签名:
    1.打开你的工程中如下对应的路径:工程名称\app\build\outputs\apk\debug
    2.将Help1(文件打包与文末)中的 platform.pk8/platform.x509.pem/signapk.jar 粘贴进文件夹。
    3.随后打开cmd窗口,首先输入X:(X为对应的盘)下令进行跳盘操作,随后使用 cd 文件路径 的指令转到对应的文件夹下。
    4.末了输入如下下令即可完成签名。
    1. java -jar .\signapk.jar .\platform.x509.pem .\platform.pk8 .\app-debug.apk .\Serial1-Signed.apk
    复制代码
  • 签名后使用前面讲过的adb安装apk文件,应用就成功安装啦! 
5.调试方法: 


  • 界面闪退问题与logcat调试:
            如果遇到跳转后克制运行无法打开界面,多半时在组件定义中出现问题,比如button的定义,textview的定义等等,建议可以问问AI(喜) 。这里我们先容一种调试方法,是使用了AS中的logcat日记调试,可以比较清楚的解决组件定义问题。
            具体教程如下链接,使用logcat在界面崩溃时可以定位到java文件的某一行,还是挺好用的。
    logcat使用详解
  • 按钮闪退:
            如果成功进入通信页面但是点击按钮闪退,则大概是按钮对应onClick的问题,这里可以给每一步都加一个弹窗,看看到底是那一步出了问题无法发送数据,有点类似于C语言里的debug手段。
5.跋文: 

        玛雅,没想到一时兴起真的能写完这篇文章,这篇文章也是我的第一篇博客,希望能为学弟学妹们提供力所能及的资助。由于本文只是指南性质,多有不足请诸位包涵。有问题可以在品评区问我,看到就会回复!末了感谢你能够看到这里!
        微控这门课说难不难,说简单不简单,一个组里最少要有三个能人,能覆盖所有技术面,小组才能顺遂进行。希望大家都能调和相处,顺遂完成微控!
附录:


  • 所有提到的文件:串口助手工程与Help1 
  • 调试好的一个java文件:调试(由于组员意见,设置了密码,需要用可以品评阐明,讨论后会决定是否公开)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天空闲话

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表