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

py可以做网站吗长沙网红打卡地

py可以做网站吗,长沙网红打卡地,网络宣传广告费多少,北滘 网站建设目录 android设备串口是什么为什么Android设备的系统一般版本比较低?停止位粘包、半包如何处理 默认不处理包头包尾标识长度字段固定长度代码实战: 包头包尾标识缓冲区管理超时处理 流控是什么校验和 前言 串口是什么?只知道拿来进行使用&a…

目录

  1. android设备
  2. 串口是什么
  3. 为什么Android设备的系统一般版本比较低?
  4. 停止位
  5. 粘包、半包如何处理
    1. 默认不处理
    2. 包头包尾标识
    3. 长度字段
    4. 固定长度
    5. 代码实战: 包头包尾标识+缓冲区管理+超时处理
  6. 流控是什么
  7. 校验和

前言

串口是什么?只知道拿来进行使用,只能使用别人封装好的,导致如果下位机更换了,就不知道如何去对接了,出现拆包,粘包,就不知道如何去使用了。所以这篇文章,就来认识一下串口究竟是什么。


一、android 设备

我们会发现,一些智能家居,门禁,人脸考勤,自动售卖机等等,都会使用android设备来实现控制硬件来动作。

这里我们所说的android设备,和我们所使用的手机,虽然都是android系统,但android设备的系统是经过定制化才得出来的。比如厂商主动开放Root权限,我们才能进行设备驱动,才能进行串口开发,进行数据的传输,从而实现软件控制硬件的联动,并且这些android设备,往往会提供更多的接口去和硬件通讯,比如串口,a和b,tx和rx。


二、串口是什么?

在Linux/Android系统中,​​一切皆文件​​!我们经常使用串口,就会看到有输入流,输出入流,其实,无论是硬盘里的文档、摄像头、还是串口,都被看作“文件”。

  • ​打开文件​​:open("/dev/ttyS0") → 就像双击打开一个文档。
  • ​读取数据​​:read() → 像从文档里读文字。
  • ​写入数据​​:write() → 像往文档里打字。
  • ​关闭文件​​:close() → 关闭文档。

Android基于Linux内核,所以串口也是/dev/tty*文件。但普通APP无法直接访问,需要以下方法:

  1. ​Root权限​​:

    • 直接操作/dev/ttyS0,但会破坏系统安全。
    adb shell "su -c 'chmod 666 /dev/ttyS0'"  # 强制修改文件权限
  1. ​使用android设备,厂商开放接口​​:

    • 通过Android的​​硬件抽象层(HAL)​​或​​JNI​​调用底层驱动。
// Java通过JNI调用C代码操作串口
public native int openSerialPort(String path, int baudRate);

三、一般android设备的系统,不会使用太高的版本

一般android 设备,会使用android4,android5,或者android7。为什么呢?

一方面是因为智能家居设备通常采用 ​​低成本硬件方案​​(如全志A33、瑞芯微RK3308等低端芯片),其配置远低于主流手机。并且旧版本AOSP(Android开源项目)代码量更小。例如:

  • Android 4.4代码库约40GB,编译后系统镜像≤800MB
  • Android 11代码库超100GB,系统镜像≥2GB

并且,做android智能家居,追求的是稳定性,智能家居设备需 ​​7×24小时运行​​,旧版本Android经过多年工业场景验证:

  • ​Android 4.4​​:2013年发布,已修复大量稳定性问题(如内存泄漏、死锁)。

所以,智能家居设备选择旧版Android的原因是:​​在有限的硬件资源下,通过成熟稳定的系统版本实现功能、成本与维护效率的最优平衡​​。


四、停止位

​1. 停止位是什么?​
停止位是数据包末尾的​​标志信号​​,表示当前数据包传输结束。

  • ​简单理解​​:停止位就像说话时的​​句号​​,告诉对方“我说完了,该你回应了”。

​2. 为什么需要停止位?​

  • ​同步复位​​:接收方检测到停止位后,复位内部计时器,准备接收下一个数据包。

3. 停止位的作用时机​

  • ​数据包结束时生效​​:发送方发送停止位,接收方检测到后确认当前数据包接收完成。

五、粘包、半包如何处理呢?

出现粘包的原因,有很多种情况:

  1. 发送方连续发送多个数据包,接收方处理速度不足,导致缓冲区堆积。
  2. 若协议未定义数据包长度,接收方无法判断何时结束。
  3. 读取数据的频率控制不了,也无法干涉,有几率出现拿不到完整的数据,可能是因为发送方阻塞,或者发一半的时候被取走了。

4种处理方式:

  1. 固定长度
  2. 包头包尾标识
  3. 长度字段
  4. 默认不处理

5.1 默认不处理【测试时使用】

一般生产环境中不使用这种模式。

建议使用场景:

1. 对数据完整性要求低的简单调试

2. 传输固定长度数据包的场景

3. 需快速验证基础通信功能的场景

 @Overridepublic byte[] execute(InputStream is) {try {// 获取当前可读取的字节数(不保证后续实际读取数量)int available = is.available();if (available > 0) {// 创建与可用字节数相等的缓冲区byte[] buffer = new byte[available];// 尝试读取数据(实际读取数可能<=available)int size = is.read(buffer);if (size > 0) {// 返回实际读取的字节(可能包含不完整数据包)return buffer;}} else {// 无可用数据时暂停,避免CPU空转(可能引入延迟)SystemClock.sleep(50);}} catch (IOException e) {// 异常处理(建议记录日志而非仅打印堆栈)e.printStackTrace();}// 无数据或异常时返回nullreturn null;}

5.2 包头包尾标识【使用较多】

适用场景:协议明确规定了数据包的开始和结束标记.

在数据包头部和尾部添加特殊标记(如0xAA 0x55)。

// 示例:数据包格式
[0xAA][0x55][数据][CRC校验][0x55][0xAA]

拿到数据以后,就解析头和尾,取出数据,如果尾没有,可以判断为是半包,需要先把前面的数据存储起来,继续从串口里面拿数据,进行拼接。

需要结合缓冲区。

5.3 长度字段【使用较多】

包头中明确声明数据长度,接收方按长度读取。

// 示例:包头包含长度信息
struct PacketHeader {uint8_t start_marker;  // 0xAAuint8_t length;        // 数据部分长度uint8_t data[256];     // 数据uint8_t crc;           // 校验码
};

有了长度字段以后,我们获取数据的时候,就会根据字段的长度来拿到指定的数据。如果长度不符号,那么数据就是出现了问题。

5.4 固定长度

需要和下位机,约定每个数据包固定长度(如64字节),不足部分填充空值。

// 示例:温度数据固定为8字节(含填充)
uint8_t packet[8] = {'T', '2', '5', 0x00, 0x00, 0x00, 0x00, 0x00};

数据固定长度,那么就更加好办了,需要严格按照这个长度要求,如果超出,那么就会出现问题。比较严格,不利于扩展。

5.5 下面我们使用头尾标识+缓冲区+超时写一个处理半包,粘包问题的代码。

  1. 这里我们主要看读线程,所以先粘贴一个不做任何处理粘包问题的代码。
@Overridepublic byte[] execute(InputStream is) {try {int available = is.available();if (available > 0) {byte[] buffer = new byte[available];int size = is.read(buffer);if (size > 0) {return buffer;}} else {SystemClock.sleep(50);}} catch (IOException e) {e.printStackTrace();}return null;}
  1. 我们创建一个缓冲区出来,将收到的数据存储起来

private final ByteArrayOutputStream receiveBuffer = new ByteArrayOutputStream();

将收到的数据,放到缓冲区里面

    @Overridepublic byte[] execute(InputStream is) {try {int available = is.available();if (available > 0) {byte[] buffer = new byte[available];int size = is.read(buffer);if (size > 0) {synchronized (receiveBuffer) {// 将新数据追加到缓冲区 追加到 receiveBuffer(ByteArrayOutputStream)的尾部。receiveBuffer.write(received, 0, size);// 尝试解析缓冲区processBuffer();}}} else {SystemClock.sleep(50);}} catch (IOException e) {e.printStackTrace();}return null;}

下面我们看看如何解析缓冲区的

// 解析缓冲区核心逻辑
private void processBuffer() {// 1. 将缓冲区数据转为字节数组byte[] bufferData = receiveBuffer.toByteArray();int bufferSize = bufferData.length;// 2. 查找起始符位置(如:0xAA 0xBB)int startIndex = findStartIndex(bufferData);if (startIndex == -1) {// 情况1:未找到起始符,清空无效数据(避免内存溢出)resetBuffer(bufferSize); return;}// 3. 在起始符之后查找结束符位置(如:0x0D 0x0A)int endIndex = findEndIndex(bufferData, startIndex);if (endIndex == -1) {// 情况2:找到起始符但未找到结束符,保留起始符之后的未处理数据retainUnprocessedData(startIndex); return;}// 4.提取完整数据帧(排除起始符和结束符)int dataStart = startIndex + START_FLAG.length;int dataEnd = endIndex - END_FLAG.length + 1;if (dataEnd >= dataStart) {byte[] packet = Arrays.copyOfRange(bufferData, dataStart, dataEnd);//将完整的数据报传递给业务层处理onPacketReceived(packet); }// 5. 保留结束符之后的数据,用于下次处理【处理粘包】retainRemainingData(endIndex + 1, bufferSize);
}

逻辑步骤:

1. 将缓冲区数据转为字节数组
2. 查找起始符位置(如:0xAA 0xBB)
3. 在起始符之后查找结束符位置(如:0x0D 0x0A)
(1)找到起始符但未找到结束符,保留起始符之后的未处理数据【解决半包的问题】
4. 提取有效数据(排除起始符和结束符)
5. 保留结束符之后的数据,用于下次处理【解决粘包的问题】

retainRemainingData、retainUnprocessedData方法的代码


/*** 保留剩余数据(当完整包处理完成后)* @param endIndex 当前数据包结束位置* @param totalSize 缓冲区总大小*/
private void retainRemainingData(int endIndex, int totalSize) {if (endIndex < totalSize) {byte[] remaining = Arrays.copyOfRange(receiveBuffer.toByteArray(), endIndex, totalSize);receiveBuffer.reset();receiveBuffer.write(remaining, 0, remaining.length);} else {receiveBuffer.reset();}
}/*** 保留未处理数据(当找到起始符但未找到结束符时)* @param startIndex 起始符的起始位置*/
private void retainUnprocessedData(int startIndex) {byte[] remaining = Arrays.copyOfRange(receiveBuffer.toByteArray(), startIndex, receiveBuffer.size());receiveBuffer.reset();receiveBuffer.write(remaining, 0, remaining.length);
}

假如说,一直都没有尾呢?所以我们需要定期清理缓冲区的内容,避免出现内存问题。

private static final long TIMEOUT_MS = 1000; // 超时时间1秒
public void init() {timeoutTask = new Runnable() {@Overridepublic void run() {synchronized (receiveBuffer) {if (receiveBuffer.size() > 0) {receiveBuffer.reset();}}}};
}

注意,得处理多线程的问题。

缓冲区是什么?

• 实时解析串口输入的字节流,动态分割为完整数据包

• 解决粘包(多个包粘连)和半包(一个包分多次到达)问题。


六、流控

流控,简单理解,就是控制数据收发的频率。比如你处理数据不过来的时候,让其先不发。

  1. 硬件流控(可选)​

    • 启用 RTS/CTS 硬件流控,防止缓冲区溢出导致丢数据。
    • 适合高速传输场景(如波特率 ≥ 115200)。

七、校验和

  • ​累加和校验​​(简单):

    • 将数据所有字节相加,取低8位作为校验码。
    • 示例:数据 0x01 0x02 → 校验码 = 0x03。
  • ​CRC 校验​​(更可靠):

    • 通过复杂算法生成校验码(如 CRC16),可检测多位错误。
    • 工具:在线 CRC 计算工具生成代码。
http://www.dtcms.com/wzjs/186848.html

相关文章:

  • 学做陶艺作品的网站免费的舆情网站app
  • 网站一个页面多少钱恩城seo的网站
  • 网站建设 gei l fb站推广网站2022
  • 网站的建设与维护需要资质吗搜狗站长平台验证不了
  • 沈阳公司网站建设爱站网长尾关键词挖掘查询工具
  • 网站建设是属于虚拟产品吗性价比高seo的排名优化
  • 网站建设及 维护百度竞价网站
  • 找外国男人做老公网站网址收录平台
  • wordpress主题ent破解版廊坊网络推广优化公司
  • 那个网站有免费的模板河南郑州最近的热搜事件
  • 南昌网站建设培训学校惠州网站seo排名优化
  • 南通企业建站程序seo搜索引擎优化原理
  • java php做网站的区别今日刚刚发生的军事新闻
  • 网站模版免费下载seo经典案例分析
  • 武汉哪家网站建设公司好网站建设优化的技巧
  • 找室内设计师上哪个网站知乎推广渠道
  • 北京网站推广seo优化泰安网站建设
  • 建筑设计怎么学成都网站seo收费标准
  • 网站建设要用H5吗企业网络营销方案设计
  • 网站能找到做网站的人广东seo外包服务
  • 设计个人网站的步骤seo外链在线提交工具
  • 琼海做网站优化20条措施
  • 网站规划可以分成哪几步视频app推广
  • 网站域名更改后怎么做映射自创网站
  • 第一网站ppt模板免费下载武汉seo推广优化
  • 网页美工实例教程江门网站优化公司
  • 邯郸58同城网如何优化seo
  • 做网站累吗广州seo招聘信息
  • 济南建设集团有限公司seo网页优化公司
  • 可视化网页开发互联网seo是什么意思