当前位置: 首页 > article >正文

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论

部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客

以下直接上代码和效果视频,esp01S的收发硬件代码目前没有分享,但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动自行使用,代码中已经对模块进行了详细注释。本人不是java开发专业人士,也是通过ai完成的。

使用以下文件需要完成AndroidStdio的安装和SDK,SDK插件、gradle的配置,详细可以见之前的文章。

1、主xml文件制作界面

通过linearlayout布局,制作简单的界面,app头部为标题,中间为按钮和text显示。

<?xml version="1.0" encoding="utf-8"?>
<!-- CYA开发,SmartOrderDishes内容,VX:18712214828 -->
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity">
<!--    头部--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="1"android:layout_height="match_parent"android:gravity="top"android:orientation="horizontal"><TextViewandroid:layout_width="match_parent"android:layout_height="100dp"android:text="SmartOrderDishes"android:background="#609E9245"android:gravity="center|left"android:paddingLeft="30dp"android:textSize="20sp"android:textStyle="bold"android:letterSpacing="0.2"android:drawableStart="@mipmap/ic_launcher"/></LinearLayout>
<!--    显示模块--><LinearLayoutandroid:layout_width="match_parent"android:layout_weight="0.5"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"><TextViewandroid:layout_width="400dp"android:layout_height="match_parent"android:text="在连接ESP-01S WIFI后,等待LCD1602显示CanConnectServer。点击连接按钮,连接服务器"android:textSize="20dp"android:gravity="left"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"><Buttonandroid:onClick="Connect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="连接"/><Buttonandroid:onClick="OffConnect"android:layout_width="120dp"android:layout_height="60dp"android:layout_marginLeft="10dp"android:text="断开连接"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingTop="50dp"><TextViewandroid:id="@+id/Show_Text"android:layout_width="wrap_content"android:layout_height="50dp"android:textSize="20sp"android:text="Wait Checking out!"android:gravity="center"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center"android:orientation="horizontal"></LinearLayout>
</LinearLayout>

 2、主xml对应的java文件

此文件中,对socket连接和收发线程进行了使用,并且有两个按钮点击事件,和接收到服务器数据的弹窗和弹窗按钮点击事件。

package com.example.smartorderdishes;
/*
CYA开发,VX:18712214828
自动点餐系统安卓app:
1、主线程进行点击时间和线程侦听
2、手机连接ESP-01S的WIFI后点击连接即可连接ESP服务器。(通过8080端口和192.168.4.1默认服务器ip)
3、接收到数据后进行弹窗显示需要结算的桌面,和总金额。
4、弹窗中点击确定即可结算。ESP会受到数据包。*/
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";//主java文件TAGprivate SocketClient socketClient;//socket自定义库文件变量private TextView textView;//TextView标签变量@SuppressLint("MissingInflatedId")@Overrideprotected void onCreate(Bundle savedInstanceState) {//主java文件函数,只会运行一次super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});socketClient = new SocketClient(this);//变量对象初始化textView = findViewById(R.id.Show_Text);//获取标签id// 设置数据接收回调// 连接成功后启动持续监听socketClient.setDataReceivedCallback(new SocketClient.DataReceivedCallback() {@Overridepublic void onDataReceived(String data) {runOnUiThread(() -> {byte[]  DataPacket = socketClient.hexStringToByteArray(data);int deskNum = ((DataPacket[1]&0xF0)/16)+1;int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;showDialog(data);});}});}// 连接按钮点击事件public void Connect(View view) {// 连接到服务器(内部会自动启动接收循环)socketClient.connectToServer();}//断开连接按钮点击事件public void OffConnect(View view) {// 关闭连接socketClient.closeConnection();}// 显示弹窗private void showDialog(String data) {AlertDialog.Builder builder = new AlertDialog.Builder(this);//新建弹窗对象byte[]  DataPacket = socketClient.hexStringToByteArray(data);//传入的数据转化为字节数组int deskNum = ((DataPacket[1]&0xF0)/16)+1;//桌号获取int priceCount = (DataPacket[1]*256+DataPacket[2])&0x0FFF;//总金额获取builder.setTitle("桌号"+deskNum+",结算请求:");//弹窗标题builder.setMessage("共计总金额$" + priceCount+"是否结算!");//弹窗信息// 确定按钮builder.setPositiveButton("确认结算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {//确认按钮点击事件Toast.makeText(MainActivity.this, "You clicked OK", Toast.LENGTH_SHORT).show();//发送十六进制数据String hexData = "EBAAFF90"; //发送结算成功数据包socketClient.sendHexData(hexData);textView.setText("桌号:" + deskNum+"结算,总金额$"+priceCount+"\n");//显示/*textView.setText("桌号:" + deskNum+"结算,总金额$"+priceCount+"\n"+"Data:"+data);*/}});// 取消按钮builder.setNegativeButton("取消结算", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(MainActivity.this, "You clicked Cancel", Toast.LENGTH_SHORT).show();}});// 显示弹窗AlertDialog dialog = builder.create();dialog.show();}}

 3、socket连接服务器、侦听数据包和发送数据包线程,Java文件

package com.example.smartorderdishes;import android.content.Context;
import android.util.Log;
import android.widget.Toast;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class SocketClient {private static final String SERVER_IP = "192.168.4.1";//连接的指定IPprivate static final int SERVER_PORT = 8080;//连接服务器的指定端口private static final int CONNECTION_TIMEOUT = 5000;//连接超时时间 msprivate static final int READ_TIMEOUT = 5000; // 新增读取超时时间 msprivate Socket socket;//socket变量private BufferedOutputStream out;//输出缓冲区变量private BufferedInputStream in;//输入缓冲区变量private Context context;//private ExecutorService executorService;//单线程 用于连接服务器private ExecutorService receiverExecutor; // 独立线程池用于接收数据public SocketClient(Context context) {this.context = context;executorService = Executors.newSingleThreadExecutor();//单线程的执行器服务(Executor Service),用于管理和调度任务的执行receiverExecutor = Executors.newSingleThreadExecutor(); // 独立线程池 线程用于接收数据}// 连接服务器(修改后的代码)public void connectToServer() {executorService.execute(() -> {//线程提交不需要返回结果的任务try {//异常抛出socket = new Socket();//socket对象socket.connect(new InetSocketAddress(SERVER_IP, SERVER_PORT), CONNECTION_TIMEOUT);//socket连接,指定地址、端口和超时时间socket.setSoTimeout(READ_TIMEOUT); // 设置读取超时out = new BufferedOutputStream(socket.getOutputStream());//发送缓冲区对象in = new BufferedInputStream(socket.getInputStream());//接收缓冲区对象runOnUiThread(() -> {//runOnUiThread() 是 Activity 类中的一个方法 ,用于在主线程执行代码Toast.makeText(context, "Connected to server", Toast.LENGTH_SHORT).show();Log.d("SocketClient", "Connected to server");});// 连接成功后启动接收循环startReceivingData();} catch (IOException e) {runOnUiThread(() -> {Toast.makeText(context, "Failed to connect: " + e.getMessage(), Toast.LENGTH_SHORT).show();Log.e("SocketClient", "Connection error: " + e.getMessage());});}});}// 发送十六进制数据public void sendHexData(String hexData) {executorService.execute(new Runnable() {@Overridepublic void run() {if (out != null && socket != null && !socket.isClosed()) {try {// 将十六进制字符串转换为字节数组byte[] data = hexStringToByteArray(hexData);out.write(data);//发送字节数组out.flush();//发送完毕后,关闭发送Log.d("SocketClient", "Sent (Hex): " + hexData);} catch (IOException e) {e.printStackTrace();runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Failed to send data: " + e.getMessage(), Toast.LENGTH_SHORT).show();}});}} else {runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(context, "Not connected to server", Toast.LENGTH_SHORT).show();}});}}});}// 接收数据包(0xEB 0xXX 0xXX 0x90)// 启动接收循环private void startReceivingData() {receiverExecutor.execute(() -> {//通过单线程执行器,所有提交的任务都会按顺序在一个单独的线程中执行。Log.d("SocketClient", "Starting receive loop");try {while (!Thread.currentThread().isInterrupted()//用于检查当前线程是否已被中断的方法&& socket != null//检查 Socket 对象是否已经被初始化且不为 null。这个检查通常用于确保在尝试使用 Socket 进行网络通信之前,它已经被正确创建和配置。&& !socket.isClosed()//检查 Socket 对象是否被关闭&& in != null) {//确保输入流(InputStream)对象已经被正确初始化且不为 null,避免潜在的 NullPointerExceptionbyte[] buffer = new byte[1024];//存储获取的数据int bytesRead;//存储获取的数据长度try {bytesRead = in.read(buffer); // 阻塞读取(但设置了超时),返回数组长度if (bytesRead == -1) {//未读取到数据Log.d("SocketClient", "Connection closed by server");break;}String hexResponse = byteArrayToHexString(buffer, bytesRead);//转字节数组换为字符串Log.d("SocketClient", "Received (Hex): " + hexResponse);if (isValidDataPacket(buffer, bytesRead)) {//判断是否符合数据包格式Log.d("SocketClient", "Valid packet received");// 触发回调if (dataReceivedCallback != null) {//回调接口变量是否为空dataReceivedCallback.onDataReceived(hexResponse);//回调不为空则运行回调函数,回调接收到的hex字符串}}} catch (SocketTimeoutException e) {Log.d("SocketClient", "Read timeout, retrying...");continue;} catch (IOException e) {Log.e("SocketClient", "Read error: " + e.getMessage());break;}}} finally {Log.d("SocketClient", "Exiting receive loop");}});}// 检查数据包是否符合 0xEB 0xXX 0xXX 0x90 格式private boolean isValidDataPacket(byte[] data, int length) {if (length < 4) {Log.d("SocketClient", "Invalid packet: length < 4");return false;}boolean isValid = (data[0] == (byte) 0xEB) && (data[3] == (byte) 0x90);Log.d("SocketClient", "Data validity: " + isValid);return isValid;}// 关闭连接public void closeConnection() {executorService.execute(new Runnable() {@Overridepublic void run() {try {if (out != null) out.close();if (in != null) in.close();if (socket != null) socket.close();//关闭socket连接Log.d("SocketClient", "Connection closed");} catch (IOException e) {e.printStackTrace();}}});}// 回调接口,用于接收数据/*onDataReceived 是一个常见的回调方法名称,通常用于在数据接收到时通知监听器或处理数据。这个方法一般定义在一个接口中,并由实现该接口的类提供具体的数据处理逻辑。*/public interface DataReceivedCallback {void onDataReceived(String data);}// 设置回调接口private DataReceivedCallback dataReceivedCallback;//回调接口变量,回调接口为自定义,在上面已定义public void setDataReceivedCallback(DataReceivedCallback callback) {this.dataReceivedCallback = callback;}// 在主线程中运行代码private void runOnUiThread(Runnable action) {new android.os.Handler(context.getMainLooper()).post(action);}// 将十六进制字符串转换为字节数组public byte[] hexStringToByteArray(String hex) {int len = hex.length();byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)+ Character.digit(hex.charAt(i + 1), 16));}return data;}// 将字节数组转换为十六进制字符串private String byteArrayToHexString(byte[] bytes, int length) {StringBuilder hex = new StringBuilder();for (int i = 0; i < length; i++) {hex.append(String.format("%02X", bytes[i]));}return hex.toString();}}

 

 4、app获取网络权限文件,以及启动文件配置文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><!-- 配置网络权限 --><!-- 互联网访问 --><uses-permission android:name="android.permission.INTERNET" /> <!-- 访问网络状态 --><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- 访问wifi状态 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 访问WiFi网络的信息 --><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><!-- 允许改变WiFi连接状态(如果需要的话) --><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><!-- 从Android 6.0(API level 23)开始,获取WiFi信息也需要位置权限 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!-- 或者使用粗略的位置权限 --><uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.SmartOrderDishes"tools:targetApi="31"><!-- 配置Activity可启动输出权限 --><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

二、效果

说明:

1、esp8266-01S开启AP模式的多连接的Station模式。设定端口为8080,默认ip应该是192.168.4.1,网络SSID(名称)为ESP-01S。这些里面目前是固定的,配置即ESP8266作为热点和服务器,手机连接ESP8266的WIFI,然后作为客户端手机连接到ESP8266的服务器,进行通信

2、手机连接ESP8266的wifi后。等待配置完毕,然后进行服务器连接,连接完成手机会有信息提醒。

3、连接完成后,esp8266给手机发送0xEB 0xXX 0xXX 0x90的数据包DATA[4](下标从0开始),其中DATA[1]的高4bit作为桌位,低12bit为总金额。

4、接收到数据后手机app进行弹窗,点击确定后手机app界面text改变。并且向ESP8266发送EBAAFF90(HEX)数据作为结账完成的标志数据包。

效果视频

智能点餐系统开发视频

 

代码详解 

 

 

 

其他代码问题(个人理解):

首先执行主线程mainactivity.java内容,创建UI和监听按钮动作。在onCreate创建的生命周期

(只执行一次,设置了数据接收回调的动作内容)。在socketclient.java中定义了回调函数,数据发送函数,数据接收函数,数据处理函数,类对象线程池创建等。

当mainactivity.java点击连接按钮时,触发Connect方法,进行服务器连接,在socketclient.java中的连接方法connectToServer启动了receiverExecutor线程。

receiverExecutor线程有while,会在while内持续运行,当

这些情况,线程才会结束,即意外断开服务器连接或者手动断开连接,线程才会退出,如果 in.read(buffer) 没有数据可读,线程会阻塞(挂起),直到有数据到达或超时。在接收到正确的数据包时,会触发回调,会在receiverExecutor运行mainactivity内的程序(想在主线程运行内容需要使用runOnUiThread())。

----------------------------------------------------------------------------------------

看一下AI的回答:

 

 

 

 

 

 

相关文章:

Android学习制作app(ESP8266-01S连接-简单制作)

一、理论 部分理论见arduino学习-CSDN博客和Android Studio安装配置_android studio gradle 配置-CSDN博客 以下直接上代码和效果视频&#xff0c;esp01S的收发硬件代码目前没有分享&#xff0c;但是可以通过另一个手机网络调试助手进行模拟。也可以直接根据我的代码进行改动…...

docker直接运行arm下的docker

运行环境是树莓派A 处理器是 arm32v6 安装了docker&#xff0c;运行lamp 编译安装php的时候发现要按天来算&#xff0c;于是用电脑vm下的Ubuntu系统运行arm的docker 然后打包到a直接导入运行就可以了 第一种方法 sudo apt install qemu-user-static 导入直接运行就可以了…...

PYH与MAC的桥梁MII/MIIM

在学习车载互联网时&#xff0c;看到了一句话&#xff0c;Processor通过DMA直接存储访问与MAC之间进行数据的交互&#xff0c;MAC通过MII介质无关接口与PHY之间进行数据的交互。常见的以太网硬件结构是&#xff0c;将MAC集成进Processor芯片&#xff0c;将PHY留在Processor片外…...

如何使用SliverList组件

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了沉浸式状态栏相关的内容&#xff0c;本章回中将介绍SliverList组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的SliverList组件是一种列表类组件&#xff0c;类似我们之前介…...

SQL UCASE() 函数详解

SQL UCASE() 函数详解 在SQL中&#xff0c;UCASE() 函数是一个非常有用的字符串处理函数&#xff0c;它可以将字符串中的所有小写字母转换为大写字母。本文将详细介绍UCASE() 函数的用法、语法、示例以及其在实际应用中的优势。 一、UCASE() 函数简介 UCASE() 函数是SQL标准…...

单细胞分析基础-第一节 数据质控、降维聚类

scRNA_pipeline\1.Seurat 生物技能树 可进官网查询 添加链接描述 分析流程 准备:R包安装 options("repos"="https://mirrors.ustc.edu.cn/CRAN/") if(!require("BiocManager")) install.packages("BiocManager",update = F,ask =…...

Vue 与 Electron 结合开发桌面应用

1. 引言 1.1 什么是 Electron? Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它结合了 Chromium 渲染引擎和 Node.js 运行时,使得开发者可以使用 Web 技术创建原生桌面应用。1.2 为什么选择 Vue.js 和 Electron? Vue.js 是一个渐进式 JavaSc…...

Golang 应用的 Docker 部署方式介绍及使用详解

本文将介绍如何使用 Docker 部署一个基于 Go 语言的后台服务应用 godco&#xff0c;并介绍如何配置 MongoDB 数据库容器的连接&#xff0c;确保应用能够成功启动并连接到容器方式部署的mongoDB数据库。 前提条件 1.已安装 Docker/Podman 2.已安装 MongoDB 数据库容器&#xff…...

DeepSeek的提示词使用说明

一、DeepSeek概述 DeepSeek是一款基于先进推理技术的大型语言模型&#xff0c;能够根据用户提供的简洁提示词生成高质量、精准的内容。在实际应用中&#xff0c;DeepSeek不仅能够帮助用户完成各类文案撰写、报告分析、市场研究等工作&#xff0c;还能够生成结构化的内容&#…...

python小知识-typing注解你的程序

python小知识-typing注解你的程序 1. Typing的简介 typing 是 Python 的一个标准库&#xff0c;它提供了类型注解的支持&#xff0c;但并不会强制类型检查。类型注解在 Python 3.5 中引入&#xff0c;并在后续版本中得到了增强和扩展。typing 库允许开发者为变量、函数参数和…...

HTML<hgroup>标签

例子&#xff1a; 使用hgroup元素标记标题和段落是相关的&#xff1a; <hgroup> <h2>Norway</h2> <p>The land with the midnight sun.</p> </hgroup> 定义和用法&#xff1a; 标签<hgroup>用于包围标题和一个或多个<p&g…...

【已解决】黑马点评项目Redis版本替换过程的数据迁移

黑马点评项目Redis版本替换过程的数据迁移 【哭哭哭】附近商户中需要用到的GEO功能只在Redis 6.2以上版本生效 如果用的是老版本&#xff0c;美食/KTV的主页能正常返回&#xff0c;但无法显示内容 上次好不容易升到了5.0以上版本&#xff0c;现在又用不了了 Redis 6.2的windo…...

mybatis辅助配置

驼峰映射 sql里面定义字段通常是使用下划线定义 比如dept_id 而我们的后端属性通常就是驼峰命名 deptId 所以这两匹配进行自动赋值就比较麻烦 可以使用 select dept_id as deptId 来解决&#xff08;起别名&#xff09; 也可以用mybatis的辅助配置解决 第三种就是推荐的在spr…...

基于YOLO11的肺结节检测系统

基于YOLO11的肺结节检测系统 (价格90) LUNA16数据集 数据一共 1186张 按照8&#xff1a;1&#xff1a;1随机划分训练集&#xff08;948张&#xff09;、验证集&#xff08;118张&#xff09;与测试集&#xff08;120张&#xff09; 包含 nodule 肺结节 1种…...

C#面向对象(继承)

1.什么是继承 在 C# 编程语言中&#xff0c;继承是一个核心概念&#xff0c;它允许一个类&#xff08;称为派生类&#xff09;继承另一个类&#xff08;称为基类&#xff09;的成员&#xff0c;如方法、属性和其他成员。继承机制使得代码重用成为可能&#xff0c;简化了应用程…...

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…...

为大模型提供webui界面的利器:Open WebUI 完全本地离线部署deepseek r1

为大模型提供webui界面的利器&#xff1a;Open WebUI Open WebUI的官网&#xff1a;&#x1f3e1; Home | Open WebUI 开源代码&#xff1a;WeTab 新标签页 Open WebUI是一个可扩展、功能丰富、用户友好的自托管AI平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&am…...

Arduino可以做哪些有意思的项目

Arduino 是一个非常适合初学者和高级开发者的开源电子平台&#xff0c;可以用来实现各种有趣的项目。以下是一些有意思的 Arduino 项目&#xff1a; 1. 智能家居自动化 智能灯光控制: 使用 Arduino 控制 LED 灯带&#xff0c;根据时间或传感器输入自动调整亮度和颜色。温湿度…...

EtherCAT主站IGH-- 27 -- IGH之globals.h文件解析

EtherCAT主站IGH-- 27 -- IGH之globals.h文件解析 0 预览一 该文件功能宏定义数据结构打印宏三 h文件翻译四 c文件翻译该文档修改记录:总结0 预览 一 该文件功能 该文件包含了一些全局定义和宏,用于 IgH EtherCAT 主站(EtherCAT Master)的实现。包括了一些超时设定、宏定义…...

17.1 图像操作

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.1.1 Image类 Image类为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。 Image的属性大多数是只读的&#xff1a; FrameDim…...

基于Scrapy采集豆瓣电影Top250的详细数据

基于Scrapy采集豆瓣电影Top250的详细数据 Scrapy 官方文档:https://docs.scrapy.org/en/latest/豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:基于Scrapy框架采集豆瓣电影Top250的详细数据。 电脑系统:Windows 使用软件:PyCharm、Navicat Python…...

软件工程概论试题五

一、多选 1.好的软件的基本属性包括()。 A. 效率 B. 可依赖性和信息安全性 C. 可维护性 D.可接受性 正答&#xff1a;ABCD 2.软件工程的三要素是什么()? A. 结构化 B. 工具 C.面向对象 D.数据流! E.方法 F.过程 正答&#xff1a;BEF 3.下面中英文术语对照哪些是正确的、且是属…...

深入解析“legit”的地道用法——从俚语到正式表达:Sam Altman用来形容DeepSeek: legit invigorating(真的令人振奋)

深入解析“legit”的地道用法——从俚语到正式表达 一、引言 在社交媒体、科技圈甚至日常对话中&#xff0c;我们经常会看到或听到“legit”这个词。比如最近 Sam Altman 在 X&#xff08;原 Twitter&#xff09;上发的一条帖子中写道&#xff1a; we will obviously deliver …...

行业规范要当作业务实体画出来吗

第五元素 总觉得这些没有逻辑的实体&#xff0c;在绘制的时候不应该绘出来&#xff0c;他们没有责任啊。 比如以下:查阅规范 感觉不太对 UMLChina潘加宇 你这个规范是一个电脑系统还是一本书 第五元素 是书 UMLChina潘加宇 书没有智能&#xff0c;唯一暴露的接口是“翻”…...

vscode命令面板输入 CMake:build不执行提示输入

CMake&#xff1a;build或rebuild不编译了&#xff0c;弹出:> [Add a new preset] , 提示输入发现settings.jsons设置有问题 { "workbench.colorTheme": "Default Light", "cmake.pinnedCommands": [ "workbench.action.tasks.configu…...

Cubemx文件系统挂载多设备

cubumx版本&#xff1a;6.13.0 芯片&#xff1a;STM32F407VET6 在上一篇文章中介绍了Cubemx的FATFS和SD卡的配置&#xff0c;由于SD卡使用的是SDIO通讯&#xff0c;因此具体驱动不需要自己实现&#xff0c;Cubemx中就可以直接配置然后生成SDIO的驱动&#xff0c;并将SD卡驱动和…...

Java知识速记 == 与equals

Java知识速记 与equals 1. 操作符概述 操作符用于比较基本数据类型的值&#xff0c;或者比较引用类型的对象是否指向同一内存地址。对于基本数据类型&#xff0c;例如int、float等&#xff0c;会比较其值&#xff1b;但对于对象&#xff0c;只会比较两个对象的引用&#xff…...

[Linux]从零开始的STM32MP157 U-Boot移植

一、前言 在上一次教程中&#xff0c;我们了解了STM32MP157的启动流程与安全启动机制。我们还将FSBL的相关代码移植成功了。大家还记得FSBL的下一个步骤是什么吗&#xff1f;没错&#xff0c;就是SSBL&#xff0c;而且常见的我们将SSBL作为存放U-Boot的地方。所以本次教程&…...

fatal: unable to access ‘https://github

fatal: unable to access ‘https://github.com/protocolbuffers/protobuf.git/’: Failed to connect to github.com port 443: Connection timed out 下载项目的时候出现了这个问题&#xff0c;本以为是网络或者什么的问题&#xff0c;没想到是sudo,sudo sudo git clone -b …...

【apt源】RK3588 平台ubuntu20.04更换apt源

RK3588芯片使用的是aarch64架构&#xff0c;因此在Ubuntu 20.04上更换apt源时需要使用针对aarch64架构的源地址。以下是针对RK3588芯片在Ubuntu 20.04上更换apt源到清华源的正确步骤&#xff1a; 步骤一&#xff1a;打开终端 在Ubuntu 20.04中&#xff0c;按下Ctrl Alt T打…...