微控指南针(1)西电通院微控上位机(安卓)指南 2024版本
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库。 package com.example.sang.testserial; // 定义包名
import android.app.Activity; // 导入Activity类
import android.content.res.Configuration; // 导入Configuration类
import android.os.Bundle; // 导入Bundle类
import android.view.View; // 导入View类
import android.view.View.OnClickListener; // 导入OnClickListener接口
import android.widget.Button; // 导入Button类
import android.widget.EditText; // 导入EditText类
import android.widget.ScrollView; // 导入ScrollView类
import android.widget.TextView; // 导入TextView类
import android.util.Log; // 导入Log类
import android.text.Html; // 导入Html类
import android.widget.Toast; // 导入Toast类
import java.util.Timer; // 导入Timer类
import java.util.TimerTask; // 导入TimerTask类
import com.friendlyarm.FriendlyThings.HardwareControler; // 导入HardwareControler类
import com.friendlyarm.FriendlyThings.BoardType; // 导入BoardType类
import android.os.Handler; // 导入Handler类
import android.os.Message; // 导入Message类
import android.content.Context; // 导入Context类
import android.content.Intent; // 导入Intent类
[*] 主类定义与成员变量定义:这些变量用于存储UI组件、串口配置和数据缓冲区等信息。 public class MainActivity extends Activity implements OnClickListener { // 定义MainActivity类,继承Activity并实现OnClickListener接口
private static final String TAG = "SerialPort"; // 定义日志标签
private TextView fromTextView = null; // 定义TextView变量
private EditText toEditor = null; // 定义EditText变量
private final int MAXLINES = 200; // 定义最大行数
private StringBuilder remoteData = new StringBuilder(256 * MAXLINES); // 定义StringBuilder用于存储接收到的数据
// NanoPC-T4 UART4
private String devName = "/dev/ttyAMA3"; // 定义串口设备名
private int speed = 115200; // 定义串口波特率
private int dataBits = 8; // 定义数据位
private int stopBits = 1; // 定义停止位
private int devfd = -1; // 定义设备文件描述符
[*] onDestory:在活动销毁时,取消定时器并关闭串口。 @Override
public void onDestroy() { // 重写onDestroy方法
timer.cancel(); // 取消定时器
if (devfd != -1) { // 如果设备文件描述符有效
HardwareControler.close(devfd); // 关闭串口
devfd = -1; // 重置设备文件描述符
}
super.onDestroy(); // 调用父类的onDestroy方法
}
[*]onCreat:在活动创建时,根据设备的方向加载不同的布局文件,初始化UI组件,并实验打开串口。如果串口打开成功,启动定时器定期检查数据。 @Override
public void onCreate(Bundle savedInstanceState) { // 重写onCreate方法
super.onCreate(savedInstanceState); // 调用父类的onCreate方法
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { // 如果设备处于横屏模式
setContentView(R.layout.serialport_dataprocessview_landscape); // 设置横屏布局
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { // 如果设备处于竖屏模式
setContentView(R.layout.serialport_dataprocessview); // 设置竖屏布局
}
String winTitle = devName + "," + speed + "," + dataBits + "," + stopBits; // 构建窗口标题
setTitle(winTitle); // 设置窗口标题
((Button)findViewById(R.id.sendButton)).setOnClickListener(this); // 设置发送按钮的点击监听器
fromTextView = (TextView)findViewById(R.id.fromTextView); // 获取TextView组件
toEditor = (EditText)findViewById(R.id.toEditor); // 获取EditText组件
/* no focus when begin */
toEditor.clearFocus(); // 清除焦点
toEditor.setFocusable(false); // 设置不可获得焦点
toEditor.setFocusableInTouchMode(true); // 设置在触摸模式下可获得焦点
devfd = HardwareControler.openSerialPort(devName, speed, dataBits, stopBits); // 打开串口
if (devfd >= 0) { // 如果串口打开成功
timer.schedule(task, 0, 500); // 启动定时器,每500毫秒执行一次任务
} else { // 如果串口打开失败
devfd = -1; // 重置设备文件描述符
fromTextView.append("Fail to open " + devName + "!"); // 显示错误信息
}
}
[*]定时器和处理器(吸收部门):定时器每500毫秒发送一次消息给处理器,处理器检查串口是否有数据可读,如果有则读取数据并更新UI。 private final int BUFSIZE = 512; // 定义缓冲区大小
private byte[] buf = new byte; // 定义缓冲区
private Timer timer = new Timer(); // 定义定时器
private Handler handler = new Handler() { // 定义处理器
public void handleMessage(Message msg) { // 重写handleMessage方法
switch (msg.what) { // 根据消息类型进行处理
case 1: // 如果消息类型为1
if (HardwareControler.select(devfd, 0, 0) == 1) { // 检查串口是否有数据可读
int retSize = HardwareControler.read(devfd, buf, BUFSIZE); // 读取串口数据
if (retSize > 0) { // 如果读取到数据
String str = new String(buf, 0, retSize); // 将数据转换为字符串
remoteData.append(str); // 将数据追加到remoteData中
if (fromTextView.getLineCount() > MAXLINES) { // 如果TextView中的行数超过最大行数
int nLineCount = fromTextView.getLineCount(); // 获取当前行数
int i = 0; // 定义计数器
for (i = 0; i < remoteData.length(); i++) { // 遍历remoteData
if (remoteData.charAt(i) == '\n') { // 如果遇到换行符
nLineCount--; // 行数减一
if (nLineCount <= MAXLINES) { // 如果行数小于等于最大行数
break; // 退出循环
}
}
}
remoteData.delete(0, i); // 删除多余的行
fromTextView.setText(remoteData.toString()); // 更新TextView内容
} else { // 如果行数未超过最大行数
fromTextView.append(str); // 追加数据到TextView
}
((ScrollView)findViewById(R.id.scroolView)).fullScroll(View.FOCUS_DOWN); // 滚动到最底部
}
}
break;
}
super.handleMessage(msg); // 调用父类的handleMessage方法
}
};
private TimerTask task = new TimerTask() { // 定义定时任务
public void run() { // 重写run方法
Message message = new Message(); // 创建消息对象
message.what = 1; // 设置消息类型
handler.sendMessage(message); // 发送消息
}
};
[*]onClick:当发送按钮被点击时,获取toEditor中的文本并通过串口发送。如果发送成功,清空输入框并更新表现区域。 public void onClick(View v) { // 重写onClick方法
switch (v.getId()) { // 根据点击的视图ID进行处理
case R.id.sendButton: // 如果点击的是发送按钮
String str = toEditor.getText().toString(); // 获取输入框中的文本
if (str.length() > 0) { // 如果文本不为空
if (str.charAt(str.length() - 1) != '\n') { // 如果文本末尾不是换行符
str = str + "\n"; // 添加换行符
}
int ret = HardwareControler.write(devfd, str.getBytes()); // 发送数据到串口
if (ret > 0) { // 如果发送成功
toEditor.setText(""); // 清空输入框
str = ">>> " + str; // 添加前缀
if (remoteData.length() > 0) { // 如果remoteData不为空
if (remoteData.charAt(remoteData.length() - 1) != '\n') { // 如果remoteData末尾不是换行符
remoteData.append('\n'); // 添加换行符
fromTextView.append("\n"); // 在TextView中添加换行符
}
}
remoteData.append(str); // 将数据追加到remoteData中
fromTextView.append(str); // 将数据追加到TextView中
((ScrollView)findViewById(R.id.scroolView)).fullScroll(View.FOCUS_DOWN); // 滚动到最底部
} else { // 如果发送失败
Toast.makeText(this, "Fail to send!", Toast.LENGTH_SHORT).show(); // 显示错误信息
}
}
break;
}
}
}
以上就是串口助手代码的所有详解。
3.代码的更改:
如果你需要发送固定字符,可以按照我下面的代码对于onClick的部门进行更改:
int ret;
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login1_2:
String str4 = "*d0300";
String str5 = "*d3000";
if (str77 == 2) {
ret = HardwareControler.write(devfd, str4.getBytes());//这是发送数据的代码,ret是发送的字节数的返回值
}else{
ret = HardwareControler.write(devfd, str5.getBytes());
}
if (ret > 0) { //如果返回的ret大于0,说明发送成功了
Toast.makeText(this, "sucess!", Toast.LENGTH_SHORT).show();
Intent intent =null;
intent = new Intent(MainActivity2.this,MainActivity6.class);
startActivity(intent);
} else {
Toast.makeText(this, "Fail to send!", Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_login1_1:
Intent intent = null;
intent = new Intent(MainActivity2.this,MainActivity5.class);
startActivity(intent);
break;
//以上是加了按钮的代码,没有报错
}
}
} 吸收部门可以添加如下代码对于数据帧进行替换:
if (str.contains("你的数据帧")) {
str77=2;
str = str.replaceAll("你的数据帧", "想要显示的字符");
str = str + "\n";
final Toast toast = Toast.makeText(getApplicationContext(), "Green light ahead", 1000);
View toastView = toast.getView();
//toastView.setBackgroundResource(R.drawable.toast_bg);// 设置背景色为红色
TextView toastText = new TextView(getApplicationContext());
toastText.setText("想要显示的字符");
toastText.setTextColor(Color.GREEN); // 设置文本颜色为黑色
toastText.setTextSize(200); // 设置字体大小为100dp
toast.setGravity(Gravity.CENTER, 0, 0);
toast.setView(toastText); // 将TextView设置为Toast的视图
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.末了输入如下下令即可完成签名。 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企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]