Android下的串口通信实战之控制客显

本文为博主原创文章,未经博主允许不得转载。如有问题,请与我联系( 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()
	    {//总计亮
		@Override
		public 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

你可能感兴趣的:(实战)