Andriod入门级开发
这学期有个课设,我们组我负责一个手机APP的开发,虽然刚开始说要实现什么智能导航,类似高德地图那种,但最后阉割的只剩一个Socket通信了,因为之前没有接触过(可能之后也不会再接触),记录一下开发中遇到的问题。
1.开发工具:Andriod Studio,主要功能:实现与开发板的Socket通信,具体是手机端收到板子消息按钮变色或者文本框显示对应文字,手机端也会发送消息给板子,让板子跳转用户操作界面,整个就是一个简单的前端,逻辑不需要手机端处理。手机端只负责显示。
2.实现效果:


3.一些关键问题和收获:
1)andriod studio 的使用:
感觉还是比较复杂的,前期的一些环境配置有点忘了,按照提示做就可以,主要是手机运行环境的一些配置,然后之后在打包程序安装在手机上出了点问题,需要密钥,按网上指导就可以。
对自带模板的灵活使用:as自带很多模板,比如我开发的这个丑陋的app就是在bottom Navigation Activity这个现成模板的基础上进行开发的。

之前as排版的Xml文件,下载手机上就会变乱。后面不知不觉就好了,注意这个问题。
2)Socket通信:
这个是这个项目的一个主要工作,其中遇到的第一个问题,怎么创建Socket通信:
class ConnectThread extends Thread {public void run() {try {//新建Socketsocket = new Socket("192.168.4.1", 8086);System.out.println("创建Socket成功");} catch (IOException e) {e.printStackTrace();}}}
Socket的收发信息:注意Socket的收发信息或者说对网络的操作不能直接在主线程进行,一般都需要开子线程。
Socket的收信息:
final byte[] buffer = new byte[1024];//创建接收缓冲区try {inputStream = socket.getInputStream();System.out.println("Socket接收数据成功");} catch (IOException e) {e.printStackTrace();}int len = 0;//数据读出来,并且返回数据的长try {len = inputStream.read(buffer);System.out.println("接收数据大小" + len);} catch (IOException e) {e.printStackTrace();}//BUFFER 内容转为字符串String recvStr = new String(buffer, 0, len);
Socket的发信息:
//控制子线程开始public void buttonFunc() {// 在主线程中需要发送数据的代码片断前插入// 阻塞主线程,使子线程按照“同步”的方式执行try {System.out.println("线程开始");new Thread(sendthread).start(); // 线程启动new Thread(sendthread).join(); // 线程加入执行队列,主线程被阻塞,等待子线程执行完毕} catch (Exception e) {e.printStackTrace();System.out.println(e.toString());}}// 发送数据子线程final Runnable sendthread = new Runnable() {@Overridepublic void run() {try {System.out.println("发送数据的子线程执行中");try {try {//输出流初始化outputStream = socket.getOutputStream();System.out.println("outputStream创建成功");} catch (IOException e) {e.printStackTrace();}try {//写入数据outputStream.write(sendbuf);outputStream.flush();System.out.println("数据写入成功");} catch (IOException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}System.out.println("数据发送成功,子线程执行完毕");} catch (Exception e) {e.printStackTrace();System.out.println("子线程:"+ e.toString());}}};
socket的数据解析及数据格式:
收信息需要先转换为string类型,发信息如果要发16进制,byte数组直接写成16进制的形式。
源码:
美食城:
package com.example.parkingassitant2.ui.home;import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;import com.example.parkingassitant2.databinding.FragmentHomeBinding;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class HomeFragment extends Fragment {private FragmentHomeBinding binding;//发送数据保存byte[] sendbuf = {(byte) 0xaa, (byte) 0xaa,0x03, (byte) 0x12,0x03,0x18, (byte) 0xaa};Socket socket = null; //定义socketOutputStream outputStream = null; //定义输出流(发送)public View onCreateView(@NonNull LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {HomeViewModel homeViewModel =new ViewModelProvider(this).get(HomeViewModel.class);binding = FragmentHomeBinding.inflate(inflater, container, false);View root = binding.getRoot();ConnectThread ct;ct = new ConnectThread();ct.start();//江底捞final Button jiangdilao = binding.xiaocaiyuan;//湖底捞按钮final Button hudilao = binding.A2;//河底捞按钮final Button hedilao = binding.B1;//海底捞按钮final Button haidilao = binding.B2;//KFC按钮final Button KFC = binding.C1;//小菜园按钮final Button xiaocaiyuan = binding.C2;//万达影城按钮final Button wanda = binding.D1;//星巴克按钮final Button starbuck = binding.D2;//江底捞按钮监听函数jiangdilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x12, 0x03, 0x18, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//湖底捞按钮监听函数hudilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x21, 0x03, 0x27, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//河底捞按钮监听函数hedilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x22, 0x03, 0x28, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//海底捞按钮监听函数haidilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x11, 0x03, 0x17, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//小菜园按钮监听函数xiaocaiyuan.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x13, 0x03, 0x19, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//星巴克按钮监听函数starbuck.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x14, 0x03, 0x1a, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//肯德基按钮监听函数KFC.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x23, 0x03, 0x29, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//电影院按钮监听函数wanda.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x24, 0x03, 0x2a, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});return root;}class ConnectThread extends Thread {public void run() {try {//两个不同IP地址。网络助手和板子//socket = new Socket("192.168.71.1", 8086);//新建Socketsocket = new Socket("192.168.4.1", 8086);System.out.println("创建Socket成功");} catch (IOException e) {e.printStackTrace();}}}@SuppressLint("SuspiciousIndentation")@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;try {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}//控制子线程开始public void buttonFunc() {// 在主线程中需要发送数据的代码片断前插入// 阻塞主线程,使子线程按照“同步”的方式执行try {System.out.println("线程开始");new Thread(sendthread).start(); // 线程启动new Thread(sendthread).join(); // 线程加入执行队列,主线程被阻塞,等待子线程执行完毕} catch (Exception e) {e.printStackTrace();System.out.println(e.toString());}}// 发送数据子线程final Runnable sendthread = new Runnable() {@Overridepublic void run() {try {System.out.println("发送数据的子线程执行中");try {try {//输出流初始化outputStream = socket.getOutputStream();System.out.println("outputStream创建成功");} catch (IOException e) {e.printStackTrace();}try {//写入数据outputStream.write(sendbuf);outputStream.flush();System.out.println("数据写入成功");} catch (IOException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}System.out.println("数据发送成功,子线程执行完毕");} catch (Exception e) {e.printStackTrace();System.out.println("子线程:"+ e.toString());}}};
}
停车场:
package com.example.parkingassitant2.ui.dashboard;import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;import com.example.parkingassitant2.databinding.FragmentDashboardBinding;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class DashboardFragment extends Fragment {private FragmentDashboardBinding binding;Socket socket = null; //定义socketOutputStream outputStream = null; //定义输入流(接收)public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {DashboardViewModel dashboardViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);binding = FragmentDashboardBinding.inflate(inflater, container, false);View root = binding.getRoot();ConnectThread ct;ct = new ConnectThread();ct.start();return root;}class ConnectThread extends Thread{InputStream inputStream=null; //定义输入流(接收)final Button A1 =binding.A1;final Button A2 = binding.A2;final Button D1 = binding.D1;public void run(){System.out.println(Thread.currentThread().getName()+": Hello");try {//socket = new Socket("192.168.71.1", 8086);socket = new Socket("192.168.4.1", 8086);binding.textView5.setText("连接成功");System.out.println("创建Socket成功");} catch (IOException e) {System.out.println("创建Socket失败");e.printStackTrace();}try{while (true){final byte[] buffer = new byte[1024];//创建接收缓冲区try {inputStream = socket.getInputStream();System.out.println("Socket接收数据成功");} catch (IOException e) {e.printStackTrace();}int len = 0;//数据读出来,并且返回数据的长try {len = inputStream.read(buffer);System.out.println("接收数据大小" + len);} catch (IOException e) {e.printStackTrace();}//BUFFER 内容转为字符串String recvStr = new String(buffer, 0, len);//找到读取开始处,一般为0int stadex = recvStr.indexOf("aaaa");System.out.println("解析数据开始位置" + stadex);int check_3,check_4,check_5,check_6;while(stadex < len){stadex = recvStr.indexOf("aaaa",stadex);int funcType_sta = stadex+4;int funcType_end = stadex+6;if(funcType_end > len || funcType_sta >= len){break;}//位置3是操作类型 02 是显示车牌预约停车场String pos3 = recvStr.substring(funcType_sta,funcType_end);// check_3 = Integer.parseInt(pos3);stadex = funcType_end;//停车预约功能中,位置4是车牌号String pos4 = recvStr.substring(stadex,stadex+2);//check_4 = Integer.parseInt(pos4);stadex += 2;//停车预约功能中,位置5是目的地String pos5 = recvStr.substring(stadex,stadex+2);//check_5 = Integer.parseInt(pos5);stadex += 2;String pos6 = recvStr.substring(stadex,stadex+2);//check_6 = Integer.parseInt(pos6);stadex += 2;//if( check_6 != check_3+check_4+check_5) break;stadex += 2;System.out.println("解析数据包" + "aaaa" + pos3 + pos4 + pos5 + pos6 + "aa");System.out.println("操作类型指示值:" + pos3);switch(pos3){case "01": {System.out.println("操作类型为欢迎车牌进站");String showText = null;switch (pos4) {case "01":showText = "欢迎京A00001";break;case "02":showText = "欢迎青ASB520";break;case "03":showText = "欢迎皖A66666";break;case "04":showText = "欢迎宁E88888";break;default:break;}binding.textView5.setText(showText);break;}case "04": {System.out.println("操作类型为停车预约");String showText = null;switch (pos4) {case "01":showText = "京A00001";break;case "02":showText = "青ASB520";break;case "03":showText = "皖A66666";break;case "04":showText = "宁E88888";break;default:break;}String address = null;switch (pos5){case "11":address = "海底捞";break;case "12":address = "江底捞";break;case "13":address = "小菜园";break;case "14":address = "星巴克";break;case "21":address = "湖底捞";break;case "22":address = "河底捞";break;case "23":address = "肯德基";break;case "24":address = "电影院";break;case "a1":address = "A1";break;case "a2":address = "A2";break;case "d1":address = "D1";break;default:break;}binding.textView5.setText(showText+"车主预约车位:" + address);break;}case "03": {System.out.println("操作类型为车位状态变更");switch (pos4) {case "a1": {if (pos5.equals("00")) {binding.A1.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.A1.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.A1.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}case "a2": {System.out.println("pos5: ");System.out.println(pos5);if (pos5.equals("00")) {binding.A2.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.A2.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.A2.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}case "d1": {if (pos5.equals("00")) {binding.D1.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.D1.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.D1.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}default:break;}}default:break;}}}} catch (Exception ex) {ex.printStackTrace();}}}@SuppressLint("SuspiciousIndentation")@Overridepublic void onDestroyView() {super.onDestroyView();try {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}binding = null;}
}相关文章:
Andriod入门级开发
这学期有个课设,我们组我负责一个手机APP的开发,虽然刚开始说要实现什么智能导航,类似高德地图那种,但最后阉割的只剩一个Socket通信了,因为之前没有接触过(可能之后也不会再接触),记…...
DCL 数据控制语言
1、简介 DCL英文全称是Data Control Language(数据控制语言),用来管理数据库用户、控制数据库的访问权限。 2、管理用户 2.1 查询用户 select * from mysql.user;查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅代表只能够在当前本机访问…...
全网超详细的下载与安装VMware虚拟机以及为什么要安装VMware虚拟机
文章目录1. 文章引言2. 下载VMware3. 安装VMware1. 文章引言 我们使用最多的系统是windows系统,因为,国内电脑厂商的操作系统(os)基本是windows系统,比如华为、联想、华硕等电脑。 但线上的服务器大多是Linux系统,而我们经常使用…...
Python获取zabbix问题触发器
背景:阿里云的ECS服务器因为阿里云升级插件,导致安全防护程序重启,产生不同的端口。导致低自动发现注册的端口 大量报警。 解决:杀掉关于因为非业务 变更的端口检测的触发器。 相关文档: Zabbix监控之主机端口监控自…...
原型链污染
目录 前置知识 原型对象 prototype和__proto__的区别 原型链概念 原型链的继承 原型 链污染 原型链污染原理 javascript中可能会存在原型链污染的危险函数 原型链污染的实际应用 JavaScript中可以触发弹窗的函数 前置知识 原型对象 在JavaScript中,每个函…...
ClickHouse详解
一、概念ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。OLAP场景的关键特征绝大多数是读请求数据以相当大的批次(> 1000行)更新,而不是单行更新;或者根本没有更新。已添加到数据库的数据不能修改。对于读取,从数据库中提取相当多的…...
02_Docker 安装
02_Docker 安装 文章目录02_Docker 安装2.1 安装 Docker 的先决条件2.2 在 Ubuntu 和 Debain 中安装 Docker2.2.1 检查前提条件1. 内核2.检查 Device Manager2.2 安装 DockerDocker 支持非常多的Linux平台,包括Ubuntu和RHEL,除此之外,Docker还…...
K8S集群将Docker切换到Containerd
文章目录1. 开启节点维护1.1 将节点设置成不可调度1.2 驱逐节点上的 Pod1.3 停止相关服务2. 升级到 containerd2.1 安装 containerd2.2 调整 containerd 配置2.3 修改 kubelet 启动配置参数3. 重启节点服务4. 验证升级后的节点5. 容器管理工具5.1 容器管理命令行工具对比5.2 cr…...
Kubernetes03:kubernetes 功能和架构
2.1 概述 Kubernetes 是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过 Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中,会将组成应用的容 器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环…...
LabVIEW中CPU和内存使用情况在NI分布式系统管理器中不可见
LabVIEW中CPU和内存使用情况在NI分布式系统管理器中不可见想使用NI分布式系统管理器监测网络连接实时控制器的CPU和内存使用情况。从左侧窗口的树中选择了感兴趣的实时目标,然后通过选择视图自动视图来确保启用自动查看。希望看到CPU/内存选项卡,但它有显…...
buu [NPUCTF2020]Classical Cipher 1
题目描述: 题目分析: 首先输入密码 {gsv_pvb_rh_zgyzhs} 后,得到:可以得知密码是错误的,再看看密码 {gsv_pvb_rh_zgyzhs} ,排列无序,那么尝试用凯撒与栅栏解密,发现还是解不出&…...
分享96个HTML体育竞技模板,总有一款适合您
分享96个HTML体育竞技模板,总有一款适合您 96个HTML体育竞技模板下载链接:https://pan.baidu.com/s/1k2vJUlbd2Boduuqqa0EWMA?pwdj8ji 提取码:j8ji Python采集代码下载链接:采集代码.zip - 蓝奏云 北京奥运火炬PSD模板 奥运…...
Python pandas「原有或者新建」Excel中「追加新或者新建」sheet
1.pandas原有Excel中追加新sheet 使用Pandas库,我们可以轻松将数据追加到现有的Excel工作簿中的新工作表中。以下是追加新工作表的简单步骤: 读取现有的Excel文件 使用Pandas库中的read_excel()函数读取现有的Excel文件。指定Excel文件的路径和文件名&a…...
程序员必备的软技能- CPU“没有灵魂的躯体”
引言 先引用一段比较有意思的论述: 现实中每个人是由两部分构成,灵魂和躯体,灵魂依附于躯体游走于世间,现实中我们面对的每个人其实面对的是其灵魂而非肉体,肉体不过是表象而已。 灵魂本性乃一恶物,寄生于…...
基于微信小程序的青少年生理健康知识小助手
基于微信小程序的青少年生理健康知识小助手 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目…...
【scl】博图程序的导入和导出
导入或者导出博图文件的方法(也叫移植文件) 目录 前言 编辑 编辑 前言 本篇文章主要写一下关于博图文件的导入和导出,具体要怎么样才能将写好的程序或者块移植到其他地方,下面我们一起来看! 一、程序块的导入和导…...
【C语言】指针进阶
目录 一、字符指针 二、指针数组 三、数组指针 四、数组指针的使用 五、函数指针数组 六、指向函数指针数组的指针 七、回调函数 我们知道了指针的概念: 1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。 2. 指针的大小是…...
18:CTK 总结篇(FAQ)
作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 经过了几个月的艰苦奋战,终于到了最后一节啦,是不是和我一样,心里有点儿小激动! 回顾之前的章节,从初级 -> 进阶 -> 高级,我们针对 CTK 做了详细的分类讲解。希望通过这些知识,大家能对模块化…...
概论_第7章_参数估计_真题__求置信区间
真题 2014.10 第30题 测量某物体的质量9次, 测得平均值 x‾15.4\overline x 15.4x15.4 g, 已知测量数据 XXX ~ N(μ,0.09)N(\mu, 0.09)N(μ,0.09) (1) 求该物体质量的置信度为0.95 的置信区间; (2)为了使置信度为0.95 的置信区间…...
Go 1.21的2个语言变化
语言行为变化 Go 1.20已经于今年2月份发布,Go 1.21也不远了,我们来先堵为快,看看Go 1.21版本里几个有趣的变化。 文末附送2道面试题。 panic(nil) func main() {defer func() {print(recover() nil)}()panic(nil) }大家先想一想这段代码…...
终极color库API参考手册:从入门到精通CSS颜色处理
终极color库API参考手册:从入门到精通CSS颜色处理 【免费下载链接】color 项目地址: https://gitcode.com/gh_mirrors/col/color color库是一个功能强大的JavaScript库,专为颜色转换和操作而设计,支持CSS颜色字符串,让开发…...
Focaler-IoU: More Focused Intersection over Union——更聚焦的交并比损失
《Focaler-IoU: More Focused Intersection over Union Loss》主要研究内容可以全面概括如下: 研究背景与问题: 在目标检测任务中,边界框回归的精度很大程度上取决于损失函数的设计。现有的IoU-based损失函数(如GIoU、CIoU、EIoU…...
MOOTDX终极指南:Python通达信数据接口让量化分析变得简单高效
MOOTDX终极指南:Python通达信数据接口让量化分析变得简单高效 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 你是否曾为获取股票数据而烦恼?面对复杂的API接口和繁琐的数据…...
【SpringAI篇04】:从内存到MySQL,构建可重启的智能对话系统
1. 为什么需要从内存存储升级到数据库持久化 刚开始接触SpringAI开发时,很多开发者都会选择默认的内存存储方案。这种方案简单直接,不需要额外配置数据库,特别适合快速原型开发。但当你真正要把应用部署到生产环境时,就会发现内存…...
电子工程师如何提升专业英语能力
电子工程师的专业英语能力培养指南 1. 技术英语的重要性 1.1 行业历史背景 半导体IC产业起源于硅谷,从仙童半导体到Intel的发展历程奠定了现代电子技术的基础。编程语言从最早的机器语言发展到现代高级语言,操作系统从CP/M演进到今天的Windows、Linux和…...
CosyVoice-300M Lite实战案例:在线教育语音课件生成系统
CosyVoice-300M Lite实战案例:在线教育语音课件生成系统 1. 为什么在线教育需要专属语音合成系统? 你有没有遇到过这样的场景:一位初中物理老师想为“浮力原理”这节课制作配套音频讲解,但反复试了三款主流TTS工具——要么普通话…...
给STM32密码锁加个“记忆”:手把手教你用CubeMX配置I2C读写EEPROM(AT24C02)
为STM32密码锁赋予持久记忆:CubeMX驱动AT24C02 EEPROM全攻略 当你的密码锁在断电后依然能记住最后一次设置的密码,这种"记忆"能力往往能大幅提升用户体验。本文将带你深入探索如何通过I2C总线连接AT24C02 EEPROM芯片,为基于STM32F1…...
springboot+vue基于web的大学生课程排课管理系统设计
目录 功能模块分析后台管理系统(SpringBoot)前端系统(Vue) 技术实现要点 项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作 功能模块分析 后台管理系统(SpringBoot&…...
破解除密!ncmdumpGUI让你的NCM音乐文件重获自由
破解除密!ncmdumpGUI让你的NCM音乐文件重获自由 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 当你精心收藏的数百首网易云音乐歌曲,在…...
少样本学习实战指南:从数据增强到多模态融合的5个关键技巧
少样本学习实战指南:从数据增强到多模态融合的5个关键技巧 在工业质检和医疗影像等实际场景中,数据稀缺问题长期困扰着机器学习工程师。传统深度学习模型需要海量标注数据,而现实情况往往是每个类别仅有几个样本可用。这种少样本学习…...
