本文为博主原创文章,未经博主允许不得转载。如有问题,请与我联系( QQ:3290985311)朱小姐。


需求:Android下的控制客显(如图)

Android下的串口通信实战之控制客显_第1张图片


1、Android下的串口连接

串口:串行接口,通常指COM接口,是采用串行通信方式的扩展接口。电脑端的接口名称一般是COM1或COM2或SCMO1方式命名,Android下的串口名称一般是ttyS0或ttyS1等。串行接口是指数据一位一位地顺序传送,双向通信。

目前,Android下的串口通信,都是在Google的开源项目的基础上实现的。正常情况下直接导入工程就可以了。不过Google提供的工程是使用eclipse开发的项目。

需要注意的是,Google提供的工程已经生成.so文件了。如果想要在自己的项目中使用,就要用NDK生成自己工程的包名对应的.so文件。至于如何生成自己的应用的.so文件,要先配置ndk环境编译。

Google开源项目结构如下

Android下的串口通信实战之控制客显_第2张图片

SerialPort.java和SerialPortFinder.java两个文件用于打开、关闭串口和查找串口。


Android.mk文件是用来生成.so文件的配置文件。文件内容如下所示

Android下的串口通信实战之控制客显_第3张图片

include $(BUILD_SHARED_LIBRARY):表示生成动态链接库.so文件,文件名的命名格式是lib*.so,*的值就是LOCAL_MODULE的值。

在这个配置文件下,生成的.so文件的名称是libserial_port.so。

LOCAL_SRC_FILES:生成.so文件的源文件。在这个配置文件里,生成.so文件的源文件是SerialPort.c

LOCAL_PATH:是用来查找LOCAL_SRC_FILES指定的文件的路径,是基于当前路径的相对路径。并且这个变量必须放在所有的include $(CLEAR_VARS)的前面,至于为什么一定要放在所有的include $(CLEAR_VARS)的前面,可以参考官方文档的解释。

TARGET_PLATFORM:构建api最低版本


Application.mk文件是描述程序正常运行所需要的模块列表。项目中Application.mk文件内容如下


 

默认情况下,NDK编译系统会默认生成支持“armeabi” CPU的机器码。在上图Application.mk文件中列出了三种ABI即三种CPU。NDK编译之后,会在lib文件夹下生成指定的ABI文件夹及相应的动态库.so文件。Android下目前支持7中CPU,文件中只列了三种CPU,一个CPU关联一个ABI。Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起)。


gen_SerialPort_h.sh:文件内容如下。意思是将当前工程路径下的src下的android_serialport_api包里的SerialPort文件的.class文件编译成SerialPort.h文件。需要注意的是,使用javah文件需要在cmd命令模式下进入bin文件目录。所以在使用.class文件编译成.h文件要先输入命令 #!/bin/sh



2、如何在自己项目中使用串口通信

流程:使用串口路径和波特率打开串口、传输数据、关闭串口。

a、将Google开源项目中的SerialPort类、SerialPortFinder.java类、Application.java中获取和jni文件夹下的所有文件copy入自己的项目中,Android下的串口通信实战之控制客显_第4张图片

b、通过设置串口路径和波特率打开串口

private SerialPort mSerialPort = null;

mSerialPort = new SerialPort(new File("/dev/ttyS3"), 9600, 0);


c、发送客显指令

public class Sending01010101Activity extends SerialPortActivity {private EditText e1;  byte[] mBuffer;  byte[] mBuffer1;  byte[] mBuffer2;  byte[] mBuffer3;  SendingThread mSendingThread;  String strPrint;  public static byte[] byteMerger(byte[] paramArrayOfByte1, byte[] paramArrayOfByte2)  {    byte[] arrayOfByte = new byte[paramArrayOfByte1.length + paramArrayOfByte2.length];    System.arraycopy(paramArrayOfByte1, 0, arrayOfByte, 0, paramArrayOfByte1.length);    System.arraycopy(paramArrayOfByte2, 0, arrayOfByte, paramArrayOfByte1.length, paramArrayOfByte2.length);    return arrayOfByte;  }  public void DisplayData(String paramString, byte[] paramArrayOfByte)  {    this.mBuffer = new byte[1];    this.mBuffer[0] = 12;    SendStr(this.mBuffer);    this.mBuffer = new byte[3];    this.mBuffer[0] = 27;    this.mBuffer[1] = 115;    this.mBuffer[2] = paramArrayOfByte[0];    if (this.mSerialPort != null)      SendStr(this.mBuffer);    this.mBuffer = new byte[10];    this.mBuffer[0] = 27;    this.mBuffer[1] = 81;    this.mBuffer[2] = 65;    this.mBuffer[3] = 49;    this.mBuffer[4] = 50;    this.mBuffer[5] = 46;    this.mBuffer[6] = 49;    this.mBuffer[7] = 13;    if (this.mSerialPort == null)      return;    SendStr(this.mBuffer);  }  public void SendStr(byte[] paramArrayOfByte)  {    try    {      if (this.mOutputStream != null)        this.mOutputStream.write(paramArrayOfByte);      return;    }    catch (IOException localIOException)    {      localIOException.printStackTrace();    }  }  protected void onCreate(Bundle paramBundle)  {    super.onCreate(paramBundle);    setContentView(R.layout.sending);    e1 = (EditText) findViewById(R.id.e1);    ((Button)findViewById(R.id.b1)).setOnClickListener(new View.OnClickListener()    {//单价亮      public void onClick(View paramView)      {        Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 49;        if (Sending01010101Activity.this.mSerialPort == null)          return;        Sending01010101Activity.this.DisplayData(e1.getText().toString(), Sending01010101Activity.this.mBuffer);      }    });    ((Button)findViewById(R.id.b2)).setOnClickListener(new OnClickListener()    {//总计亮@Overridepublic void onClick(android.view.View arg0) {// TODO Auto-generated method stub Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 50;        if (Sending01010101Activity.this.mSerialPort == null)          return;        Sending01010101Activity.this.DisplayData(e1.getText().toString(), Sending01010101Activity.this.mBuffer);}    });    ((Button)findViewById(R.id.b3)).setOnClickListener(new View.OnClickListener()    {//收款亮      public void onClick(View paramView)      {        Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 51;        if (Sending01010101Activity.this.mSerialPort == null)          return;        Sending01010101Activity.this.DisplayData(e1.getText().toString(), Sending01010101Activity.this.mBuffer);      }    });    ((Button)findViewById(R.id.b4)).setOnClickListener(new View.OnClickListener()    {//找零亮      public void onClick(View paramView)      {        Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 52;        if (Sending01010101Activity.this.mSerialPort == null)          return;        Sending01010101Activity.this.DisplayData(e1.getText().toString(), Sending01010101Activity.this.mBuffer);      }    });    ((Button)findViewById(R.id.b5)).setOnClickListener(new View.OnClickListener()    {//全灭      public void onClick(View paramView)      {        Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 48;        if (Sending01010101Activity.this.mSerialPort != null)          Sending01010101Activity.this.DisplayData(e1.getText().toString(), Sending01010101Activity.this.mBuffer);        Sending01010101Activity.this.mBuffer = new byte[1];        Sending01010101Activity.this.mBuffer[0] = 12;        if (Sending01010101Activity.this.mSerialPort == null)          return;        Sending01010101Activity.this.SendStr(Sending01010101Activity.this.mBuffer);      }    });  }  protected void onDataReceived(byte[] paramArrayOfByte, int paramInt)  {  }  private class SendingThread extends Thread  {    private SendingThread()    {    }    public void run()    {      while (true)      {        if (isInterrupted())          return;        try        {          if (Sending01010101Activity.this.mOutputStream != null);          Sending01010101Activity.this.mOutputStream.write(Sending01010101Activity.this.mBuffer);        }        catch (IOException localIOException)        {          localIOException.printStackTrace();        }      }    }  }}

“单价”亮的指令是ESC n 1 这个是ASCII码,转成十进制就是要发送的字节数组是{27,73,49}

“总价”亮的指令是ESC n 2 转成十进制要发送的字节数组就是{27,73,50}

“收款”亮的指令是ESC n 3 转成十进制,{27,73,51}

“找零”亮的指令是ESC n 4 转成十进制{27,73,52}

所有灯全灭的指令是ESC n 0 转成十进制{27,73,48}


d、关闭串口

if (mSerialPort != null) {mSerialPort.close();mSerialPort = null;}

注意:硬件接收的指令是ASCII码值,注意转换。

附上客显指令和ASCII码表对照表

附上本篇文章例子源码demo。源码串口是ttyS1,波特率2400

附上Google开源项目源码


本篇实战篇是串口通信,手机端发送指令给外接设备。但是在文章的开头说过,串口通信是双向的,所以下一篇实战篇 

Android下的串口通信实战之电子秤交互

总结:只要是串口连接,对串口的操作都是一样的。不同的硬件之间只有识别的指令不一样,即发送的数据不同。


Google开源地址:

https://code.google.com/archive/p/android-serialport-api/issues

参考文章:

http://blog.csdn.net/u011625768/article/details/53337177

更多相关文章

  1. Android中的R.java文件你知多少
  2. 如何给你的Android 安装文件(APK)瘦身(一)
  3. 在Android使用XML文件控制按钮文字在各种状态下的颜色
  4. Android中自定义MultipartEntity实现文件上传以及使用Volley库实
  5. Android串口开发之使用JNI实现ANDROID和串口通信详解
  6. android http通过post上传文件和提交参数(通过拼装协议)

随机推荐

  1. android 图片与byte数组间的转换
  2. Android 显示网页图片
  3. android自动化测试[一]
  4. .NET和Android解压缩处理
  5. Android下横竖屏切换的处理
  6. Android代码实现飞行模式的打开
  7. Android 时间 日期 时区
  8. 20150618_Andriod_设置TextView垂直滚动
  9. Android 读取并显示通讯录
  10. Android实现对imageview的拖动以及缩放