android12 写入文件 简书 安卓11如何写入data

您所在的位置:网站首页 安卓11data文件夹写入速度超级慢 android12 写入文件 简书 安卓11如何写入data

android12 写入文件 简书 安卓11如何写入data

2024-07-15 20:38:32| 来源: 网络整理| 查看: 265

        客户有一个称重的设备,要求要用串口数码管显示对应的重量值,最开始我以为需要在kernel中加驱动,后来看了一下客户提供过来的资料,上电之后通过发串口命令就能显示对应的数据,那接上串口后就不必走kernel驱动,直接在framework里加串口通信就ok了。

        既然是在framework中加串口通信,那么给客户的接口就是一个广播,广播中传一个重量值,然后我们接收到广播之后获取广播中的重量值信息,再将重量值信息转化为对应的串口命令,再通过串口发送命令到数码管显示。

        在开始写代码之前,我们首先要确认串口发送命令到数码管是能够显示对应的数据的,那么我们可以找一个串口apk去发送串口命令,测试串口发送命令到数码管是正常的。我用的是serialtool.apk,因为这个apk只支持ttyS1--ttyS4,所以我硬件上就接的dev/ttyS3。在测试之前我们要首先保证dev/ttyS3有读写权限,通过adb shell命令进去之后,用ls -al dev/ttyS3查看

android12 写入文件 简书 安卓11如何写入data_串口

         如果没有读写权限可以用chmod 0666 dev/ttyS3给串口节点赋读写权限。

        打开串口apk还需要关闭selinux权限,用命令setenforce 0关闭selinux,命令getenforce查看当前selinux状态。

android12 写入文件 简书 安卓11如何写入data_android_02

         打开串口apk,发送串口指令。apk界面如下图所示,我们需要打开Hex Send发送16进制数据,否则会导致数据包错误。

android12 写入文件 简书 安卓11如何写入data_android_03

         接下来我们看一下串口数码管需要发送的命令。

android12 写入文件 简书 安卓11如何写入data_android_04

         我们通过apk发送01 06 6A 00 00 01 55 D2和01 06 6A 00 00 02 15 D3,看一下数码管会不会显示对应的值。如果串口数码管没有显示对应的值,那么首先我们要看一下apk发送的命令是否和接收到的一致,可以用一个串口板接到电脑上,用串口工具看一下串口apk发送过来的命令是否一致;检查命令一致之后还是不显示对应的值再交换一下数码管接的rx和tx引脚,排查是否引脚接错了。如果都排查无误数码管还是没有显示,那么就需要打一下串口发送的波形看一下了,对比参照工具为sscom串口工具发送串口指令和apk发送的波形做对比,因为用sscom串口工具发送的命令是可以显示的,最后两位校验位选择modbus-crc16校验。

android12 写入文件 简书 安卓11如何写入data_android12 写入文件 简书_05

         成功发送的效果如下图所示。

android12 写入文件 简书 安卓11如何写入data_android_06

 

        保证串口命令能正常发送显示之后,接下来就分析一下串口指令的构成。我们需要发送什么指令才能实现客户发送过来的数据能显示对应的值?因为是称重,所以我们需要保留两位小数,通过搜索指令我们发现01 10 74 0D 00 02 04 00 02 00 02 45 35(显示0.2)这个指令比较符合我们的要求,那么就以这个指令为标准吧。

android12 写入文件 简书 安卓11如何写入data_java_07

         01是设备码,10是功能码,74 0D是寄存器地址,00 02是寄存器数量,04是寄存器字节数(寄存器数量*2),00 02表示保留两位小数,00 02表示数据位,45 35表示crc16校验位。此为完整的串口指令构成,接下来我们要写的代码也是基于这个基础上完成的。

        我们先实现modbus-crc16的代码,毕竟校验位是串口指令中最重要的,其他的都是基本固定的指令,只有最后两位校验位是需要我们通过前面所以指令计算所得。我先贴上代码

/** * 获取CRC16校验码 * * @param data 数据 * @return CRC16校验码 */ public static String getCRC(String data) { data = data.replace(" ", ""); int len = data.length(); if (!(len % 2 == 0)) { return "0000"; } int num = len / 2; byte[] para = new byte[num]; for (int i = 0; i < num; i++) { int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16); para[i] = (byte) value; } return getCRC(para); } /** * 计算CRC16校验码 * * @param bytes 字节数组 * @return 校验码 */ private static String getCRC(byte[] bytes) { // CRC寄存器全为1 int CRC = 0x0000ffff; // 多项式校验值 int POLYNOMIAL = 0x0000a001; int i, j; for (i = 0; i < bytes.length; i++) { CRC ^= ((int) bytes[i] & 0x000000ff); for (j = 0; j < 8; j++) { if ((CRC & 0x00000001) != 0) { CRC >>= 1; CRC ^= POLYNOMIAL; } else { CRC >>= 1; } } } // 结果转换为16进制 String result = Integer.toHexString(CRC).toUpperCase(); if (result.length() != 4) { StringBuilder sb = new StringBuilder("0000"); result = sb.replace(4 - result.length(), 4, result).toString(); } // 交换高低位,低位在前高位在后 return result.substring(2, 4) + " " + result.substring(0, 2); }

        因为传入的数据是float的小数,所以还需要一个float转16进制的函数,代码如下

public static String Hex_conversion(float data){ int float_to_int = (int)(data * 100); String Hex_high = Integer.toHexString(float_to_int >> 8); String Hex_low = Integer.toHexString(float_to_int & 0xff); if((float_to_int & 0xff) < 16) Hex_low = "0" + Hex_low; else if((float_to_int >> 8) < 16) Hex_high = "0" + Hex_high; Log.d(TAG,"cgl Hex_high = "+Hex_high+" Hex_low = "+Hex_low); return (Hex_high+" "+Hex_low +" "); }

        串口函数发送的数据格式为byte[],所以串口命令转换完成后还需要将命令转换成对应的byte数组,代码如下。

public static byte[] stringToBytes(String data){ data = data.replace(" ", ""); int len = data.length(); int num = len / 2; byte[] para = new byte[num]; for (int i = 0; i < num; i++) { int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16); para[i] = (byte) value; Log.d(TAG,"stringToBytes para = "+para[i]+" i = "+i); } return para; }

最终传输的数据,通过一个函数封装在一起,代码如下

public byte[] transmitData(float data){ String crcStr = "01 10 74 0D 00 02 04 00 02 "; String crc_result = getCRC(crcStr + Hex_conversion(data)); String final_data = crcStr + Hex_conversion(data) + crc_result; byte[] byte_data = stringToBytes(final_data); Log.d(TAG,"crc_result = "+crc_result+" final_data = "+final_data+" byte_data = "+byte_data); return byte_data; }

接下来我们来看一下如何打开串口并发送串口指令,代码如下

framework/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

+import android.hardware.SerialPort; +import android.hardware.SerialManager; +import java.nio.ByteBuffer; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.File; + private static final String TTYS3_PATH = "dev/ttyS3"; + private static final int BAUD_RATE = 9600; + private SerialManager mSerialManager; + private ByteBuffer mInputBuffer; + private ByteBuffer mOutputBuffer; + public SerialPort mSerialPort; + public InputStream mInputStream; + public OutputStream mOutputStream; //初始化 + mSerialManager =(SerialManager)mContext.getSystemService(Context.SERIAL_SERVICE); + + try { + mSerialPort = mSerialManager.openSerialPort(TTYS3_PATH, 9600); + } catch (IOException e) { + } + mInputBuffer = ByteBuffer.allocate(1024); + mOutputBuffer = ByteBuffer.allocate(1024); //新建发送串口指令函数 + public void sendSerialPort(byte[] data){ + Log.d(TAG,"sendSerialPort data = "+data); + try { + mOutputBuffer.clear(); + mOutputBuffer.put(data); + mSerialPort.write(mOutputBuffer, data.length); + } catch (IOException e) { + e.printStackTrace(); + Log.d(TAG, "COM1 OPEN FAILED!"); + } + }

        需要注意的是,要在AndroidManifest.xml中添加Serial权限

--- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -271,6 +271,9 @@ + + +

        还需要在config.cml中添加对应的串口字符数组,否则会报串口为空的错误,具体代码为 

framework/base/core/java/android/hardware/SerialManager.java

/** * Opens and returns the {@link android.hardware.SerialPort} with the given name. * The speed of the serial port must be one of: * 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, * 1500000, 2000000, 2500000, 3000000, 3500000 or 4000000 * * @param name of the serial port * @param speed at which to open the serial port * @return the serial port */ @UnsupportedAppUsage public SerialPort openSerialPort(String name, int speed) throws IOException { try { ParcelFileDescriptor pfd = mService.openSerialPort(name); if (pfd != null) { SerialPort port = new SerialPort(name); port.open(pfd, speed); return port; } else { throw new IOException("Could not open serial port " + name); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

openSerialPort调用mService的openSerialPort方法

framework/base/services/core/java/com/android/server/SerialService.java

/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions an * limitations under the License. */ package com.android.server; import android.content.Context; import android.hardware.ISerialManager; import android.os.ParcelFileDescriptor; import java.io.File; import java.util.ArrayList; public class SerialService extends ISerialManager.Stub { private final Context mContext; private final String[] mSerialPorts; public SerialService(Context context) { mContext = context; mSerialPorts = context.getResources().getStringArray( com.android.internal.R.array.config_serialPorts); } public String[] getSerialPorts() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); ArrayList ports = new ArrayList(); for (int i = 0; i < mSerialPorts.length; i++) { String path = mSerialPorts[i]; if (new File(path).exists()) { ports.add(path); } } String[] result = new String[ports.size()]; ports.toArray(result); return result; } public ParcelFileDescriptor openSerialPort(String path) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); for (int i = 0; i < mSerialPorts.length; i++) { if (mSerialPorts[i].equals(path)) { return native_open(path); } } throw new IllegalArgumentException("Invalid serial port " + path); } private native ParcelFileDescriptor native_open(String path); }

        在SerialService.java中,openSerialPort通过mSerialPorts[i].equals(path)来比对来打开串口,而mSerialPorts是通过获取config_serialPorts这个String数组,所以我们应该在config_serialPorts中添加dev/ttyS3。

--- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -990,6 +990,7 @@ for example, /dev/ttyUSB0 --> + dev/ttyS3

        串口发送函数添加完之后,就需要添加一个广播接口给客户发送数据。广播添加流程如下:

+ private static final String LED_LIGHT_ACTION = "com.android.led_light_action"; @VisibleForTesting protected void registerBroadcastReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); + filter.addAction(LED_LIGHT_ACTION); mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL); } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { if (mNotificationShadeWindowController != null) { mNotificationShadeWindowController.setNotTouchable(false); } if (mBubbleController.isStackExpanded()) { mBubbleController.collapseStack(); } finishBarAnimations(); resetUserExpandedStates(); } + else if (LED_LIGHT_ACTION.equals(action)) { + Log.d(TAG,"LED_LIGHT_ACTION is send"); + sendSerialPort(transmitData(intent.getFloatExtra("weight",0.0f))); + } else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) { mQSPanel.showDeviceMonitoringDialog(); }

        注册完广播之后,可以通过am broadcast命令发送验证,验证结果如下:

android12 写入文件 简书 安卓11如何写入data_串口_08

 



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭