esp32cam的与安卓的udp服务视频传输

esp32cam

/*
下载程序  按住接口板上的IO0 在程序上传的时候 按一下 开发板上的rst按钮  待程序开始上传  在松开 IO0
brownout detector was triggered报错  触发了断电探测器,估计是供电环境本来就不稳定
屏蔽
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"void setup() {WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable   detector//Your code
}*/#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <WiFi.h>  //wifi功能需要的库
#include <Arduino.h>
#include "esp_camera.h"
#include <vector>
#include <WiFiUdp.h> //引用以使用UDP
WiFiUDP Udp;                             //声明UDP对象
const char* wifi_SSID = "esp32";         //存储AP的名称信息 生成一个wifi 网络  方便客户端连接
const char* wifi_Password = "12345678";  //存储AP的密码信息
uint16_t udp_port = 1122;                //存储需要监听的端口号  eps32cam接收数据 和 往其他客户端 发送数据的端口
#define maxcache 1430  //图片数据分帧发送
bool is_tran_camera = false;  //是否传输视频数据
IPAddress ip_address;  //客户端的ip#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
static camera_config_t camera_config = {.pin_pwdn = PWDN_GPIO_NUM,.pin_reset = RESET_GPIO_NUM,.pin_xclk = XCLK_GPIO_NUM,.pin_sscb_sda = SIOD_GPIO_NUM,.pin_sscb_scl = SIOC_GPIO_NUM,.pin_d7 = Y9_GPIO_NUM,.pin_d6 = Y8_GPIO_NUM,.pin_d5 = Y7_GPIO_NUM,.pin_d4 = Y6_GPIO_NUM,.pin_d3 = Y5_GPIO_NUM,.pin_d2 = Y4_GPIO_NUM,.pin_d1 = Y3_GPIO_NUM,.pin_d0 = Y2_GPIO_NUM,.pin_vsync = VSYNC_GPIO_NUM,.pin_href = HREF_GPIO_NUM,.pin_pclk = PCLK_GPIO_NUM,.xclk_freq_hz = 20000000,.ledc_timer = LEDC_TIMER_0,.ledc_channel = LEDC_CHANNEL_0,.pixel_format = PIXFORMAT_JPEG,.frame_size = FRAMESIZE_VGA,.jpeg_quality = 12,.fb_count = 1,
};
//摄像头初始化
esp_err_t camera_init() {//initialize the cameraesp_err_t err = esp_camera_init(&camera_config);if (err != ESP_OK) {Serial.println("Camera Init Failed!");return err;}sensor_t* s = esp_camera_sensor_get();//initial sensors are flipped vertically and colors are a bit saturatedif (s->id.PID == OV2640_PID) {//        s->set_vflip(s, 1);//flip it back//        s->set_brightness(s, 1);//up the blightness just a bit//        s->set_contrast(s, 1);}return ESP_OK;
}
//接收数据的处理函数
void recv_data() {int packetSize = Udp.parsePacket();  //获取当前队首数据包长度if (packetSize)                      //如果有数据可用{char buf[packetSize];Udp.read(buf, packetSize);  //读取当前包数据ip_address = Udp.remoteIP();String tmp = String(buf);//打开视频数据传输if(tmp.substring(0,5) == "camon"){is_tran_camera = true;Udp.beginPacket(ip_address, udp_port);Udp.print("Camera is ON!");Udp.endPacket();}else if(tmp.substring(0,6) == "camoff"){ // 关闭视频数据传输is_tran_camera = false;Udp.beginPacket(ip_address, udp_port);Udp.print("Camera is OFF!");Udp.endPacket();}else{Udp.beginPacket(ip_address, udp_port);Udp.print("RecvData:" + tmp);Udp.endPacket();}}
}
// 传输视频数据
void cssp() {camera_fb_t* fb = esp_camera_fb_get();uint8_t* temp = fb->buf;  //这个是为了保存一个地址,在摄像头数据发送完毕后需要返回,否则会出现板子发送一段时间后自动重启,不断重复if (!fb) {// Serial.print("Camera Capture Failed!");Udp.beginPacket(ip_address, udp_port);Udp.print("Camera Capture Failed!");Udp.endPacket();} else {Udp.beginPacket(ip_address, udp_port);Udp.print("FrameBegin");  //视频数据的标志头Udp.endPacket();// 将图片数据分段发送int leng = fb->len;int timess = leng / maxcache;int extra = leng % maxcache;for (int j = 0; j < timess; j++) {Udp.beginPacket(ip_address, udp_port);Udp.write(fb->buf, maxcache);Udp.endPacket();for (int i = 0; i < maxcache; i++) {fb->buf++;}}// 发送剩余数据Udp.beginPacket(ip_address, udp_port);Udp.write(fb->buf, extra);Udp.endPacket();Udp.beginPacket(ip_address, udp_port);Udp.print("FrameOverr");  //视频数据的标志尾Udp.endPacket();// Serial.print("This Frame Length:");// Serial.print(fb->len);// Serial.println(". \t Succes To Send Image For UDP!");//return the frame buffer back to the driver for reusefb->buf = temp;            //将当时保存的指针重新返还esp_camera_fb_return(fb);  //这一步在发送完毕后要执行,具体作用还未可知。}delay(20);  //不加延时会导致数据发送混乱 稍微延时增加数据传输可靠性
}
// udp服务初始化
void udp_init() {WiFi.softAP(wifi_SSID, wifi_Password);  //打开ESP32热点Udp.begin(udp_port);                    //启动UDP监听这个端口   
}
void setup() {delay(5000);Serial.begin(115200);  //开启串口,波特率为115200//在创建udp服务以后  使用串口输出数据会报错  开发板一直重启 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable   detector  屏蔽 brownout detector was triggered报错  防止一直重启 udp_init();camera_init();Serial.print(WiFi.softAPIP());  //串口输出模块IP地址Serial.print(":");              //串口输出模块IP地址Serial.println(udp_port);   Serial.println("Sys Is Running!");
}void loop() {recv_data();if (is_tran_camera) {cssp();}
}

Android

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:id="@+id/local_ip_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="" /><TextViewandroid:id="@+id/local_port_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="" /><Buttonandroid:id="@+id/startudp_btn_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="开启UDP服务" /><ImageViewandroid:id="@+id/show_cam_kj"android:layout_width="match_parent"android:layout_height="220dp"android:background="#333"android:scaleType="center"android:layout_marginBottom="4dp"/><TextViewandroid:id="@+id/recv_data_kj"android:layout_width="match_parent"android:layout_height="100dp"android:text="" /><TextViewandroid:id="@+id/remote_ip_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="192.168.4.1" /><TextViewandroid:id="@+id/remote_port_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="1122" /><EditTextandroid:id="@+id/msg_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="" /><Buttonandroid:id="@+id/send_btn_kj"android:layout_width="match_parent"android:layout_height="60dp"android:text="发送" /></LinearLayout>
package com.example.esp32cam_udp;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;public class MainActivity extends AppCompatActivity {private TextView local_ip_kj,local_port_kj,remote_ip_kj,remote_port_kj,recv_data_kj;private Button startudp_btn_kj,send_btn_kj;private ImageView show_cam_kj;private EditText msg_kj;String local_ip = "";int port = 1122;private DatagramSocket socket;  //接收数据用的socketint data_len = 1430;//与esp32cam约定的数据传输的长度int headFlag = 0;// 0 数据流不是图像数据   1 数据流是图像数据byte[] RevBuff = new byte[data_len];//定义接收数据流的包的大小byte[] temp = new byte[0];  //存放一帧图像的数据Bitmap bitmap = null; //展示图片MyHandler myHandler; //处理信息String recv_data = ""; //保存接收到的非图像数据@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myHandler = new MyHandler();show_cam_kj = findViewById(R.id.show_cam_kj);local_ip_kj = findViewById(R.id.local_ip_kj);local_port_kj = findViewById(R.id.local_port_kj);remote_ip_kj = findViewById(R.id.remote_ip_kj);remote_port_kj = findViewById(R.id.remote_port_kj);msg_kj = findViewById(R.id.msg_kj);startudp_btn_kj = findViewById(R.id.startudp_btn_kj);send_btn_kj = findViewById(R.id.send_btn_kj);recv_data_kj = findViewById(R.id.recv_data_kj);//获取本机ip地址local_ip = IPUtils.getIpAddress(this);Message msg = myHandler.obtainMessage();msg.what = 0;msg.obj = local_ip;myHandler.sendMessage(msg);//Log.e("IP",local_ip);
//        开启udp服务startudp_btn_kj.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {//生成接受数据使用的sockettry {InetAddress serverAdder = InetAddress.getByName(local_ip); //本手机的ip地址socket = new DatagramSocket(port,serverAdder);Message msg = myHandler.obtainMessage();msg.what = 1;msg.obj = "UDP服务开启成功!";myHandler.sendMessage(msg);
//                    开启接收数据的线程new Thread(new RecvData()).start();} catch (SocketException | UnknownHostException e) {e.printStackTrace();}}});
//        发送消息send_btn_kj.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {new Thread(new SendData()).start();}});}public class SendData implements Runnable{@Overridepublic void run() {String server_ip = remote_ip_kj.getText().toString();int server_port = Integer.parseInt(remote_port_kj.getText().toString());InetAddress server_serverAdder = null;try {server_serverAdder = InetAddress.getByName(server_ip);} catch (UnknownHostException e) {throw new RuntimeException(e);}DatagramSocket send_socket = null;try {send_socket = new DatagramSocket();} catch (SocketException e) {throw new RuntimeException(e);}String tmp = msg_kj.getText().toString();byte[] buf = tmp.getBytes();DatagramPacket send_packet = new DatagramPacket(buf, buf.length, server_serverAdder, server_port);try {send_socket.send(send_packet);} catch (IOException e) {throw new RuntimeException(e);}send_socket.close();}}//    接收数据的线程public class RecvData implements Runnable {public void run() {// 接收UDP广播,有的手机不支持while (true) {byte[] recbuf = new byte[data_len];DatagramPacket recpacket = new DatagramPacket(recbuf,recbuf.length);try {socket.receive(recpacket);RevBuff = recpacket.getData();
//                                              图像数据包的头  FrameBeginboolean begin_cam_flag = RevBuff[0] == 70 && RevBuff[1] == 114 && RevBuff[2] == 97 && RevBuff[3] == 109 && RevBuff[4] == 101&& RevBuff[5] == 66 && RevBuff[6] == 101 && RevBuff[7] == 103 && RevBuff[8] == 105 && RevBuff[9] == 110;
//                            图像数据包的尾  FrameOverrboolean end_cam_flag = RevBuff[0] == 70 && RevBuff[1] == 114 && RevBuff[2] == 97 && RevBuff[3] == 109 && RevBuff[4] == 101&& RevBuff[5] == 79 && RevBuff[6] == 118 && RevBuff[7] == 101 && RevBuff[8] == 114 && RevBuff[9] == 114;if (headFlag == 0 && begin_cam_flag) {headFlag = 1;} else if (end_cam_flag) {  //判断包是不是图像的结束包 是的话 将数据传给 myHandler  3 同时将headFlag置0Message msg = myHandler.obtainMessage();msg.what = 3;myHandler.sendMessage(msg);headFlag = 0;} else if (headFlag == 1) { //如果 headFlag == 1 说明包是图像数据  将数据发给byteMerger方法 合并一帧图像temp = byteMerger(temp, RevBuff);}else{//接收到的非图像数据Message msg = myHandler.obtainMessage();msg.what = 2;msg.obj = new String(RevBuff); //字符串长度myHandler.sendMessage(msg);
//                        Log.v("Message:",new String(RevBuff));}} catch (IOException e) {e.printStackTrace();}}}}//处理一些不能在线程里面执行的信息class MyHandler extends Handler {public void handleMessage(Message msg){super.handleMessage(msg);switch (msg.what){case 0:
//                    获取ip c成功local_ip_kj.setText(local_ip);local_port_kj.setText(String.valueOf(port));break;case 1:
//                    UDP服务开启成功Toast.makeText((Context) MainActivity.this, msg.obj.toString(),Toast.LENGTH_SHORT).show();break;case 2:
//                    处理接收到的非图像数据
//                    Toast.makeText((Context) MainActivity.this, msg.obj.toString(),Toast.LENGTH_SHORT).show();String tmp = recv_data + msg.obj.toString() + "\n";recv_data = tmp;recv_data_kj.setText(tmp);break;case 3:try {//处理接受到的图像数据 并展示bitmap = BitmapFactory.decodeByteArray(temp, 0,temp.length);show_cam_kj.setImageBitmap(bitmap);//这句就能显示图片(bitmap数据没问题的情况下) 存在图像闪烁情况 待解决temp = new byte[0];  //一帧图像显示结束  将 temp清零}catch (Exception e){Log.i("Error","Error image data!");}break;default: break;}}}//    合并一帧图像数据  a 全局变量 temp   b  接受的一个数据包 RevBuffpublic byte[] byteMerger(byte[] a,byte[] b){int i = a.length + b.length;byte[] t = new byte[i]; //定义一个长度为 全局变量temp  和 数据包RevBuff 一起大小的字节数组 tSystem.arraycopy(a,0,t,0,a.length);  //先将 temp(先传过来的数据包)放进  tSystem.arraycopy(b,0,t,a.length,b.length);//然后将后进来的这各数据包放进treturn t; //返回t给全局变量 temp}@Overrideprotected void onDestroy() {super.onDestroy();socket.close();}
}package com.example.esp32cam_udp;import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;/*** =======================================================* 版权:Copyright LiYing 2015-2016. All rights reserved.* 作者:liying - liruoer2008@yeah.net* 日期:2016/12/19 19:43* 版本:1.0* 描述:IP地址工具类* 备注:返回本机IP地址  文件名称 IPUtils.java   与MainActivity并列位置* =======================================================*/
public class IPUtils {/*** 获取本机IPv4地址** @param context* @return 本机IPv4地址;null:无网络连接*/public static String getIpAddress(Context context) {// 获取WiFi服务WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);// 判断WiFi是否开启if (wifiManager.isWifiEnabled()) {// 已经开启了WiFiWifiInfo wifiInfo = wifiManager.getConnectionInfo();int ipAddress = wifiInfo.getIpAddress();String ip = intToIp(ipAddress);return ip;} else {// 未开启WiFireturn getIpAddress();}}private static String intToIp(int ipAddress) {return (ipAddress & 0xFF) + "." +((ipAddress >> 8) & 0xFF) + "." +((ipAddress >> 16) & 0xFF) + "." +(ipAddress >> 24 & 0xFF);}/*** 获取本机IPv4地址** @return 本机IPv4地址;null:无网络连接*/private static String getIpAddress() {try {NetworkInterface networkInterface;InetAddress inetAddress;for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {networkInterface = en.nextElement();for (Enumeration<InetAddress> enumIpAddr = networkInterface.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {inetAddress = enumIpAddr.nextElement();if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {return inetAddress.getHostAddress();}}}return null;} catch (SocketException ex) {ex.printStackTrace();return null;}}
}
<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
</manifest>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/216005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js中分号产生的问题详解,第一次出现分号导致的问题的记录

图示: 现在 这段代码本来是两行,但是格式化后注意下面一行缩进了,代表按一行解析了, 结果: 加上分号后再格式化就自动对齐了,代表按两行解析. 要是按照没有分号进行解析是怎样的? GPT回答: 这段代码是一行 JavaScript 代码&#xff0c;涉及到了 JSON 对象、条件语句和跳转页面…

python python输入位置的坐标(即经纬度),计算两点的距离结果保留两位

以下是Python代码实现&#xff1a; from math import radians, sin, cos, sqrtdef distance(lat1, lon1, lat2, lon2):R 6371 # 地球平均半径&#xff0c;单位为公里d_lat radians(lat2 - lat1)d_lon radians(lon2 - lon1)lat1 radians(lat1)lat2 radians(lat2)a sin(d…

非法窃取、下载、打印公司商业秘密但未利用,构成犯罪吗?

公司的电子邮箱内往往存储了大量商业秘密&#xff0c;而商业秘密又是公司生存的根本。未经许可登录他人电子邮箱&#xff0c;并窃取、下载、兜售或以其他目的&#xff0c;泄露商业秘密属违法行为&#xff0c;但没有利用这些数据也构成犯罪吗&#xff1f; 案件 武汉一家技术公…

业务中台解释

业务中台是一个组织管理名词&#xff0c;也被称为有形的中台&#xff0c;因为是有实体部门存在的。业务中台多半是传统的成本中心&#xff0c;把后台的资源整合成前台打仗需要的“中间件”&#xff0c;方便被随需调用。典型的业务中台如字节跳动的直播中台、腾讯的技术中台等。…

图形化编程学习攻略:从新手到专家的指南

在编程世界中&#xff0c;图形化编程已经成为越来越多初学者的首选。它通过直观的图形化界面&#xff0c;让编程变得更加简单和有趣。6547网将为你提供一份全面的图形化编程攻略&#xff0c;帮助你从新手成为专家。 一、选择合适的图形化编程工具 Scratch&#xff1a;适合儿童…

深入理解RBAC权限系统

最近&#xff0c;一位朋友在面试中被问及如何设计一个权限系统。我们注意到目前许多后台管理系统&#xff08;包括一些热门的如若依快速开发平台&#xff09;都采用了RBAC访问控制策略。该策略通过将权限授予角色&#xff0c;然后将角色分配给用户&#xff0c;从而实现对系统资…

推荐一个FL Studio最适配的midi键盘?

Hello大家好&#xff01;好消息&#xff01;好消息&#xff01;特大好消息&#xff01; 水果党们&#xff01;终于有属于自己的专用MIDI键盘啦&#xff01; 万众期待的Novation FLKEY系列 正式出炉&#xff01; 做编曲和音乐制作的朋友们&#xff0c;对水果软件FLSTUDIO应该…

mysql开启查询日志

mysql默认不开启查询日志&#xff0c;可以通过命令查询 show VARIABLES LIKE general%; 开启查询日志&#xff0c;并更改日志存放目录&#xff0c;不过存放的目录一定要有权限不然会报错 手动创建一下log目录下的mysql目录并赋予权限 mkdir /var/log/mysql chown -R mysql:m…

在vue3的js中将一组数据赋值的问题

代码: if (res.data) { myPrizeList.value res.data console.log(myPrizeList.value,myPrizeList.value) const giftList ref() console.log(JSON.parse(JSON.stringify(myPrizeList.val…

【计算机网络】URL概念及组成

目录 一、什么是URL 二、URL格式 示例&#xff1a; 1. Scheme&#xff08;协议&#xff09;&#xff1a; 2. Host&#xff08;主机&#xff09;&#xff1a; 3. Port&#xff08;端口&#xff09;&#xff1a; 4. Path&#xff08;路径&#xff09;&#xff1a; 5. Quer…

二叉树--基础OJ

1.对称二叉树 题目链接&#xff1a;101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a; 我们可以用递归的方法去做&#xff1a; 如果两个树互为镜像&#xff08;1.根节点的值相同&#xff0c;2.左子树的值与右子树的值对称&#xff09;则为对称二叉树&a…

SpringBoot文件下载Controller方法的几种返回值的写法与优劣

1. void 方法&#xff0c;使用 HttpServletResponse 进行文件下载&#xff1a; PostMapping("/downloadFile") public void downloadFile(HttpServletResponse response) {// 实现文件下载逻辑byte[] fileData /* 从某处获取文件数据 */;try (OutputStream outputS…

十三、C#笔记

/// <summary> /// 第二十三章&#xff1a;使用任务提高吞吐量 /// </summary> namespace Chapter23 { class Program { static void Main(string[] args) { //23.1使用并行处理执行多任务处理 /* * …

Vue--第八天

Vue3 1.优点&#xff1a; 2.创建&#xff1a; 3.文件&#xff1a; 换运行插件&#xff1a; 4.运行&#xff1a; setup函数&#xff1a; setup函数中获取不到this&#xff08;this 在定义的时候是Undefined) reactive()和ref(): 代码&#xff1a; <script setup> // …

数字孪生技术的应用场景

数字孪生技术具有广泛的应用场景&#xff0c;涉及多个行业和领域。以下是一些数字孪生的常见应用场景&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.制造业优化&#xff1a; 数字孪生可用于建模和…

前后端交互—数据库与身份认证

数据库 代码下载 数据库(database)是用来组织、存储和管理数据的仓库。常见的数据库有如下几个: MySQL 数据库(目前使用最广泛、流行度最高的开源免费数据库;Community Enterprise)Oracle 数据库(收费)SQL Server 数据库(收费)Mongodb 数据库(Community Enterprise) MySQ…

易基因:MeRIP-seq等揭示m6A RNA甲基化以ABA依赖性方式调控草莓果实成熟 | 作物育种

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 DNA甲基化等表观遗传标记在调控不同成熟阶段果实成熟中起着关键作用。m6A甲基化已被证明可以调控番茄成熟&#xff0c;但目前尚不清楚 mRNA m6A甲基化是否对不同类型水果的成熟调控具有功…

快速入门Tailwind CSS:从零开始构建现代化界面

快速入门Tailwind CSS&#xff1a;从零开始构建现代化界面 介绍 Tailwind CSS 是一个以原子类的方式快速构建界面的 CSS 框架。它提供了丰富的预定义类&#xff0c;使得开发者能够快速构建样式和布局。 安装和设置 首先&#xff0c;我们需要在项目中安装 Tailwind CSS。可以…

linux应用层编程问题--沙雕问题

1.调用沁恒 USB读取接口 读不到数据 static bool CH37XASyncReadData(int iIndex, uint32_t epindex, void *oBuffer, uint32_t *ioLength) {struct _bulkUp {uint32_t len;uint8_t epindex;uint8_t data[0];} __attribute__((packed));struct _bulkUp *bulkUp;int retval;bul…

​shutil --- 高阶文件操作​

源代码&#xff1a; Lib/shutil.py shutil 模块提供了一系列对文件和文件集合的高阶操作。 特别是提供了一些支持文件拷贝和删除的函数。 对于单个文件的操作&#xff0c;请参阅 os 模块。 警告 即便是高阶文件拷贝函数 (shutil.copy(), shutil.copy2()) 也无法拷贝所有的文件…