android串口通信

        前端时间调试A33的,做的一款工业使用的平板,全志A33的总共有3个URAT,一个debug,一个蓝牙,一个做串口使用的,外接一个stm32的单片机,作为扩展其他的一些外接口(CAN  IO 485 )使用的。

就列举一些主要的代码  ,这里会涉及到一些JAVA的 jni 的知识点,其实github 上谷歌也提供了开源serialPort的,是基于纯java的,文件流的方式进行读写的。

主要是 

#include <jni.h>
#include <string>
#include <android/log.h>
#include<fcntl.h>
#include<pthread.h>
#include<stdio.h>      /*标准输入输出定义*/
#include<stdlib.h>     /*标准函数库定义*/
#include<unistd.h>     /*Unix 标准函数定义*/
#include<sys/types.h>
#include<sys/stat.h>
#include<termios.h>    /*PPSIX 终端控制定义*/
#include<errno.h>      /*错误号定义*/

#define  LOG_TAG    "ll-jni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
Java_com_zhuoshang_clothespad_thread_SerialTask 
//这个前缀是java的jni工程里必须要这样的做修饰的。如果是使用的android studio 的话,
在下native 的函数的时候,IDE 会自动提示你的。
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhuoshang_clothespad_thread_SerialTask_SerialPortOpen(JNIEnv *env, jobject instance)
{
    // TODO
    int fd = 0;
    fd = open("/dev/ttyS3",O_RDWR);
    std::string str;
    LOGI("2019-04-25 serial_Init()-> fd = %d \n",fd);
    if(fd>=0)
    {
        str ="open /dev/ttyS3 ok";

        if(fcntl(fd,F_SETFL,O_NONBLOCK) < 0)
        {
            LOGE("fcntl failed\n");
        }
        else
        {
            LOGI("serial fcntl=%d set fd noblock sucess\n",fcntl(fd,F_SETFL,O_NONBLOCK));
        }
        int value = setserialport(fd,19200,0,8,1,'N');
        if(value>=0)
        {
            LOGI("set serial success!\n");
        }
    }
    return fd;

}
int setserialport(int fd,int speed,int flow_ctrl,int databits,int stopbits,char parity )
{

    int   i;
    int   status;
    int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};
    int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};

    struct termios options;
    memset(&options,0x00, sizeof(struct termios));
    /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.

    */
    /*if( tcgetattr( fd,&options)  !=  0)
    {
        perror("SetupSerial 1");
        return(-1);
    }
     */

    //设置串口输入波特率和输出波特率
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
    {
        if(speed == name_arr[i])
        {
            cfsetispeed(&options, speed_arr[i]);
            cfsetospeed(&options, speed_arr[i]);
        }
    }

    //修改控制模式,保证程序不会占用串口
    options.c_cflag |= CLOCAL;
    //修改控制模式,使得能够从串口中读取输入数据
    options.c_cflag |= CREAD;


/*    //设置数据流控制
    switch(flow_ctrl)
    {

        case 0 ://不使用流控制
            options.c_cflag &= ~CRTSCTS;
            break;

        case 1 ://使用硬件流控制
            options.c_cflag |= CRTSCTS;
            break;
        case 2 ://使用软件流控制
            options.c_cflag |= IXON | IXOFF | IXANY;
            break;
    }*/
    //设置数据位
    //屏蔽其他标志位
    options.c_cflag &= ~CSIZE;
    switch (databits)
    {
        case 5:
            options.c_cflag |= CS5;
            break;
        case 6:
            options.c_cflag |= CS6;
            break;
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
            fprintf(stderr,"Unsupported data size\n");
            return (-1);
    }
    //设置校验位
    switch (parity)
    {
        case 'n':
        case 'N': //无奇偶校验位。
            options.c_cflag &= ~PARENB;
            options.c_iflag &= ~INPCK;
            break;
        case 'o':
        case 'O'://设置为奇校验
            options.c_cflag |= (PARODD | PARENB);
            options.c_iflag |= INPCK;
            break;
        case 'e':
        case 'E'://设置为偶校验
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            options.c_iflag |= INPCK;
            break;
        case 's':
        case 'S': //设置为空格
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported parity\n");
            return (-1);
    }
    // 设置停止位
    switch (stopbits)
    {
        case 1:
            options.c_cflag &= ~CSTOPB; break;
        case 2:
            options.c_cflag |= CSTOPB; break;
        default:
            fprintf(stderr,"Unsupported stop bits\n");
            return (-1);
    }

    //修改输出模式,原始数据输出
   // options.c_oflag &= ~OPOST;

    //options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//options.c_lflag &= ~(ISIG | ICANON);

    //设置等待时间和最小接收字符
   // options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */
   // options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */

    //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
    tcflush(fd,TCIFLUSH);

    //激活配置 (将修改后的termios数据设置到串口中)
    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        perror("com set error!\n");
        return (-1);
    }
    return (0);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhuoshang_clothespad_thread_SerialTask_RecvSeralPort(JNIEnv *env, jobject instance,jint fd,jbyteArray buf) {

    // TODO
    jchar  i = 0;
    jbyte rcv_buf[256]={0};

    int len=0,fs_sel = 0;
    fd_set fs_read;

    struct timeval time;

    FD_ZERO(&fs_read);
    FD_SET(fd,&fs_read);

    time.tv_sec = 0;
    time.tv_usec = 1000*10;

    //使用select实现串口的多路通信
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
    if(fs_sel >0)
    {
        if (FD_ISSET(fd,&fs_read))
        {
            len = read(fd,rcv_buf,255);
            len = len %256;
            if(len>0)
            {
                jbyte *p = (*env).GetByteArrayElements(buf, NULL);
                if (p != NULL)
                {
                    for (i = 0; i < len; i++)
                    {
                        p[i] = rcv_buf[i];
                        LOGI("%02X ", rcv_buf[i]);
                    }
                    LOGI("serial len=%d ", len);
                    env->ReleaseByteArrayElements(buf, p, NULL);
                }
            }
        }
        return len;
    }
    else if(fs_sel<0)
    {
        //LOGE("select(error  fs_sel=%d\n",fs_sel);
        return 0;
    }
    else if(fs_sel == 0) {
        //LOGE("select  timeout fs_sel=%d\n", fs_sel);
        return  0;
    }
}

在你的anroid  studio 的工程的java代码里添加Native 的接口函数

    public native int RecvSeralPort(int fd,byte buf[]);
    public native int SerialPortOpen();
    public native int SerialPortClose(int fd);
    public native int switchRelay(int fd,int no,int statue);

    static
    {
        System.loadLibrary("serialport");
    }

F:\work_doc\Clothespad\Clothespad-zs\app\CMakeLists.txt  添加一下内容

#add combline serialport.so
add_library( # Sets the name of the library.
             serialport

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/serialport.cpp )

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

target_link_libraries( # Specifies the target library.
                       serialport
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值