ARM Tiny210v2开发板Android系统读写串口设备

之前买了块Tiny210v2开发板,需要在Android系统下读写串口,于是自己在JNI层封装了下串口读写,PS:友善官方也提供了底层硬件的读写库,这个纯粹是自己写了玩的。

代码主要分为5个部分,ReadWriteSerialPortLib.c+stty.h+Android.mk+accessarmborddevlib.java+MainActivity.java

stty.h主要是对于串口设备/dev/s3c2410_serial3的读写,参考常见的linux系统串口读写代码编写

ReadWriteSerialPortLib.c是JNI的C语言层封装代码

Android.mk是Android NDK编译脚本

accessarmborddevlib.java是JNI的Java语言层封装代码

MainActivity.java是Android最上层的调用代码

stty.h代码如下:

//filename:stty.h 
#ifndef __STTY_H__ 
#define __STTY_H__ 

//包含头文件
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <termios.h> 
#include <errno.h> 
#include <pthread.h> 
#include <sys/ioctl.h> 
#include<string.h>
#include<time.h>

#define DEVPATHLEN 40
// 串口设备信息结构 
typedef struct tty_info_t 
{ 
	int fd; // 串口设备ID 
	pthread_mutex_t mt; // 线程同步互斥对象 
	char name[DEVPATHLEN]; // 串口设备名称,例:"/dev/ttyS0" 
	struct termios ntm; // 新的串口设备选项 
	struct termios otm; // 旧的串口设备选项 
} TTY_INFO; 

// 串口操作函数 
TTY_INFO *readyTTY(char* devname); 
int setTTYSpeed(TTY_INFO *ptty, int speed); 
int setTTYParity(TTY_INFO *ptty,int databits,char parity,int stopbits); 
int cleanTTY(TTY_INFO *ptty); 
int sendnTTY(TTY_INFO *ptty,char *pbuf,int size); 
int recvnTTY(TTY_INFO *ptty,char *pbuf,int size); 
int lockTTY(TTY_INFO *ptty); 
int unlockTTY(TTY_INFO *ptty); 
void thread_receive(TTY_INFO *ptty);
void thread_send(TTY_INFO *ptty);

#endif 

/*
从头文件中的函数定义不难看出,函数的功能,使用过程如下: 
(1) 打开串口设备,调用函数setTTYSpeed(); 
(2) 设置串口读写的波特率,调用函数setTTYSpeed(); 
(3) 设置串口的属性,包括停止位、校验位、数据位等,调用函数setTTYParity(); 
(4) 向串口写入数据,调用函数sendnTTY(); 
(5) 从串口读出数据,调用函数recvnTTY(); 
(6) 操作完成后,需要调用函数cleanTTY()来释放申请的串口信息接口; 
其中,lockTTY()和unlockTTY()是为了能够在多线程中使用。在读写操作的前后,需要锁定和释放串口资源。 
具体的使用方法,在代码实现的原文件中,main()函数中进行了演示。下面就是源代码文件: 
*/

// 初始化串口设备并进行原有设置的保存
TTY_INFO *readyTTY(char* DevName)
{ 
	TTY_INFO *ptty; 
	
	ptty = (TTY_INFO *)malloc(sizeof(TTY_INFO)); 
	if(ptty == NULL) 
		return NULL; 
	memset(ptty,0,sizeof(TTY_INFO)); 
	pthread_mutex_init(&ptty->mt,NULL);
	memset(ptty->name,0,DEVPATHLEN);
	strcat(ptty->name,"/dev/");
	strcat(ptty->name,DevName); //填充字符串数组内存

	// 打开并且设置串口 
	ptty->fd = open(ptty->name, O_RDWR | O_NOCTTY |O_NDELAY); 
	if (ptty->fd <0) 
	{ 
		free(ptty); 
		return NULL; 
	} 
	
	// 取得并且保存原来的设置 
	tcgetattr(ptty->fd,&ptty->otm);
	return ptty; 
} 

// 清理串口设备资源 
int cleanTTY(TTY_INFO *ptty) 
{ 
	// 
	// 关闭打开的串口设备 
	if(ptty->fd>0) 
	{ 
		tcsetattr(ptty->fd,TCSANOW,&ptty->otm); 
		close(ptty->fd); 
		ptty->fd = -1; 
		free(ptty); 
		ptty = NULL; 
	} 
	
	return 0; 
} 


// 设置串口通信速率 
// ptty 参数类型(TTY_INFO *),已经初始化的串口设备信息结构指针 
// speed 参数类型(int),用来设置串口的波特率 
// return 返回值类型(int),函数执行成功返回零值,否则返回大于零的值 
int setTTYSpeed(TTY_INFO *ptty, int speed) 
{ 
	int i; 
	// 
	// 进行新的串口设置,数据位为8位 
	bzero(&ptty->ntm, sizeof(ptty->ntm)); 
	tcgetattr(ptty->fd,&ptty->ntm); 
	ptty->ntm.c_cflag = /*CS8 |*/ CLOCAL | CREAD; 
	
	switch(speed) 
	{ 
	case 300: 
		ptty->ntm.c_cflag |= B300; 
		break; 
	case 1200: 
		ptty->ntm.c_cflag |= B1200; 
		break; 
	case 2400: 
		ptty->ntm.c_cflag |= B2400; 
		break; 
	case 4800: 
		ptty->ntm.c_cflag |= B4800; 
		break; 
	case 9600: 
		ptty->ntm.c_cflag |= B9600; 
		break; 
	case 19200: 
		ptty->ntm.c_cflag |= B19200; 
		break; 
	case 38400: 
		ptty->ntm.c_cflag |= B38400; 
		break; 
	case 115200: 
		ptty->ntm.c_cflag |= B115200; 
		break; 
	} 
	ptty->ntm.c_iflag = IGNPAR; 
	ptty->ntm.c_oflag = 0; 
 
	tcflush(ptty->fd, TCIFLUSH); 
	tcsetattr(ptty->fd,TCSANOW,&ptty->ntm); 
	return 0; 
}

// 设置串口数据位,停止位和效验位 
// ptty 参数类型(TTY_INFO *),已经初始化的串口设备信息结构指针 
// databits 参数类型(int), 数据位,取值为7或者8 
// stopbits 参数类型(int),停止位,取值为1或者2 
// parity 参数类型(int),效验类型 取值为N,E,O,,S 
// return 返回值类型(int),函数执行成功返回零值,否则返回大于零的值 
int setTTYParity(TTY_INFO *ptty,int databits,char parity,int stopbits) 
{ 
	// 取得串口设置 
	if( tcgetattr(ptty->fd,&ptty->ntm) != 0) 
	{ 
		printf("SetupSerial [%s]\n",ptty->name); 
		return 1; 
	} 
	
	bzero(&ptty->ntm, sizeof(ptty->ntm)); 
	ptty->ntm.c_cflag = CS8 | CLOCAL | CREAD; 
	ptty->ntm.c_iflag = IGNPAR; 
	ptty->ntm.c_oflag = 0; 

	// 设置串口的各种参数 
	ptty->ntm.c_cflag &= ~CSIZE; 
	switch (databits) 
	{ 
		//设置数据位数 
	case 7: 
		ptty->ntm.c_cflag |= CS7; 
		break; 
	case 8: 
		ptty->ntm.c_cflag |= CS8; 
		break; 
	default: 
		printf("Unsupported data size\n"); 
		return 5; 
	} 

	switch (parity) 
	{ 
		// 设置奇偶校验位数 
	case 'n': 
	case 'N': 
		ptty->ntm.c_cflag &= ~PARENB; /* Clear parity enable */ 
		ptty->ntm.c_iflag &= ~INPCK; /* Enable parity checking */ 
		break; 
	case 'o': 
	case 'O': 
		ptty->ntm.c_cflag |= (PARODD|PARENB); /* 设置为奇效验*/ 
		ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */ 
		break; 
	case 'e': 
	case 'E': 
		ptty->ntm.c_cflag |= PARENB; /* Enable parity */ 
		ptty->ntm.c_cflag &= ~PARODD; /* 转换为偶效验*/ 
		ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */ 
		break; 
	case 'S': 
	case 's': /*as no parity*/ 
		ptty->ntm.c_cflag &= ~PARENB; 
		ptty->ntm.c_cflag &= ~CSTOPB; 
		break; 
	default: 
		printf("Unsupported parity\n"); 
		return 2; 
	} 

	// 设置停止位 
	switch (stopbits) 
	{ 
	case 1: 
		ptty->ntm.c_cflag &= ~CSTOPB; 
		break; 
	case 2: 
		ptty->ntm.c_cflag |= CSTOPB; 
		break; 
	default: 
		printf("Unsupported stop bits\n"); 
		return 3; 
	} 
 
	ptty->ntm.c_lflag = 0; 
	ptty->ntm.c_cc[VTIME] = 0; // inter-character timer unused 
	ptty->ntm.c_cc[VMIN] = 1; // blocking read until 1 chars received 
	tcflush(ptty->fd, TCIFLUSH); 
	if (tcsetattr(ptty->fd,TCSANOW,&ptty->ntm) != 0) 
	{ 
		printf("SetupSerial \n"); 
		return 4; 
	} 
	
	return 0; 
} 

int recvnTTY(TTY_INFO *ptty,char *pbuf,int size) 
{ 
	int ret,left,bytes; 
	
	left = size; 
	
	while(left>0) 
	{ 
		ret = 0; 
		bytes = 0; 
		
		pthread_mutex_lock(&ptty->mt); 
		ioctl(ptty->fd, FIONREAD, &bytes); 
		if(bytes>0) 
		{ 
			ret = read(ptty->fd,pbuf,left); 
		} 
		pthread_mutex_unlock(&ptty->mt); 
		if(ret >0) 
		{ 
			left -= ret; 
			pbuf += ret; 
		} 
		usleep(100); 
	} 
	
	return size - left; 
} 

int sendnTTY(TTY_INFO *ptty,char *pbuf,int size) 
{ 
	int ret,nleft; 
	char *ptmp; 
	
	ret = 0; 
	nleft = size; 
	ptmp = pbuf; 
	
	while(nleft>0) 
	{ 
		pthread_mutex_lock(&ptty->mt); 
		ret = write(ptty->fd,ptmp,nleft); 
		pthread_mutex_unlock(&ptty->mt); 
		
		if(ret >0) 
		{ 
			nleft -= ret; 
			ptmp += ret; 
		} 
		//usleep(100); 
	} 
	
	return size - nleft; 
} 

int lockTTY(TTY_INFO *ptty) 
{ 
	if(ptty->fd < 0) 
	{ 
		return 1; 
	} 
	
	return flock(ptty->fd,LOCK_EX); 
} 
int unlockTTY(TTY_INFO *ptty) 
{ 
	if(ptty->fd < 0) 
	{ 
		return 1; 
	} 
	
	return flock(ptty->fd,LOCK_UN); 
} 

//多线程读写相关函数
//ptty作为参数传入两个线程处理函数
//data->8 bits
void thread_receive(TTY_INFO *ptty)
{
	int nbyte,idx=0; 
	unsigned char data[16]; 
	
	while(1)
	{
		nbyte = recvnTTY(ptty,data,1);
		printf("Receive Data %d:%02X\n",idx++,data[0]); 
	}

	pthread_exit(0);
}

void thread_send(TTY_INFO *ptty)
{
	unsigned char data; 

	while(1)
	{
		//printf("Please input the data(HEX:such as 0x00) you want to send:\n");
		//scanf("%x",&data) ;
		//sendnTTY(ptty,&data,1); 
	}

	pthread_exit(0);
}

ReadWriteSerialPortLib.c代码如下:

// Serial Port接口
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>

#include "stty.h"

#include <android/log.h>
#define TAG "ReadWriteSerialPortLib"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)

//#define DEVNAMELEN 35
TTY_INFO *ptty;

jint Java_org_echo_prox_accessarmborddevlib_openserialdev(JNIEnv* env, jobject thiz, jstring devname, jint baudrate)
{
	const jbyte *DevNameStr;
	char DevNameStrArray[DEVPATHLEN-5];

	pthread_t id_rec,id_send;
	int ret;

	DevNameStr = (*env)->GetStringUTFChars(env, devname, NULL);
	if (DevNameStr == NULL) 
	{
		return -1;
	}
	memset(DevNameStrArray,0,DEVPATHLEN-5);
	strcpy(DevNameStrArray,DevNameStr);

	LOGE("devname:%s",DevNameStrArray);

	ptty = readyTTY(DevNameStrArray);
	if(ptty == NULL) 
	{ 
		LOGE("readyTTY error"); 
		return -1;
	}

	lockTTY(ptty);
	if(setTTYSpeed(ptty,baudrate)>0) 
	{ 
		LOGE("setTTYSpeed() error"); 
		return -1; 
	} 
	if(setTTYParity(ptty,8,'N',1)>0) 
	{ 
		LOGE("setTTYParity() error"); 
		return -1; 
	}
	LOGE("readyTTY OK");
	return 0;
}

jint Java_org_echo_prox_accessarmborddevlib_writedata(JNIEnv* env, jobject thiz, jbyteArray dataarray, jint datalen)
{
	jbyte * dataarraybuf = (jbyte*)(*env)->GetByteArrayElements(env, dataarray, 0);
	int ret=-1;
	ret=sendnTTY(ptty,dataarraybuf,datalen);
	(*env)->ReleaseByteArrayElements(env, dataarray, dataarraybuf, 0);
	return ret;
}

jint Java_org_echo_prox_accessarmborddevlib_closeserialdev(JNIEnv* env, jobject thiz)
{
	unlockTTY(ptty);
	cleanTTY(ptty);
	LOGE("cleanTTY OK");
	return 0;
}

Android.mk代码如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS += -llog

LOCAL_MODULE    := AccessARMBordDevLib
LOCAL_SRC_FILES := ReadWriteSerialPortLib.c

include $(BUILD_SHARED_LIBRARY)

accessarmborddevlib.java代码如下:

package org.echo.prox;

import android.util.Log;

public class accessarmborddevlib
{
	static public native int openserialdev(String DevName,int BaudRate);
	static public native int writedata(byte[] SendDataArray,int SendDataLen);
	static public native int closeserialdev();
	
	static {
		try {
			System.loadLibrary("AccessARMBordDevLib");
		} catch (UnsatisfiedLinkError e) {
			Log.d("readwriteserialportlib","ReadWriteSerialPortLib library not found!");
		}
	}
}

MainActivity.java核心代码如下:

        org.echo.prox.accessarmborddevlib AccessDev =new org.echo.prox.accessarmborddevlib();
        AccessDev.openserialdev("s3c2410_serial3", 9600);
        byte[] data=new byte[4];
        data[0]='p';
        data[1]='r';
        data[2]='o';
        data[3]='x';
        AccessDev.writedata(data, data.length);
        AccessDev.closeserialdev();

要注意修改串口设备/dev/s3c2410_serial3的读写权限,至于如何修改可以参考这篇 http://blog.csdn.net/chenxupro/article/details/8746544


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值