本文为博主原创文章,未经博主允许不得转载。如有问题,请与我联系( QQ:3290985311)朱小姐。
需求:Android下的控制客显(如图)
1、Android下的串口连接
串口:串行接口,通常指COM接口,是采用串行通信方式的扩展接口。电脑端的接口名称一般是COM1或COM2或SCMO1方式命名,Android下的串口名称一般是ttyS0或ttyS1等。串行接口是指数据一位一位地顺序传送,双向通信。
目前,Android下的串口通信,都是在Google的开源项目的基础上实现的。正常情况下直接导入工程就可以了。不过Google提供的工程是使用eclipse开发的项目。
需要注意的是,Google提供的工程已经生成.so文件了。如果想要在自己的项目中使用,就要用NDK生成自己工程的包名对应的.so文件。至于如何生成自己的应用的.so文件,要先配置ndk环境编译。
Google开源项目结构如下
SerialPort.java和SerialPortFinder.java两个文件用于打开、关闭串口和查找串口。
Android.mk文件是用来生成.so文件的配置文件。文件内容如下所示
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入自己的项目中,
b、通过设置串口路径和波特率打开串口
private SerialPort mSerialPort = null;
mSerialPort = new SerialPort(new File("/dev/ttyS3"), 9600, 0);
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开源项目源码
本篇实战篇是串口通信,手机端发送指令给外接设备。但是在文章的开头说过,串口通信是双向的,所以下一篇实战篇
总结:只要是串口连接,对串口的操作都是一样的。不同的硬件之间只有识别的指令不一样,即发送的数据不同。
Google开源地址:
https://code.google.com/archive/p/android-serialport-api/issues
参考文章:
http://blog.csdn.net/u011625768/article/details/53337177