分享

android 串口通讯1

 流浪的星星318 2017-05-15

android 串口通讯,如果是做驱动的人应该很容易写一个C语言的JNI,在Linux中串口也是很常用的一个硬件接口,正好我们做android定制型产品的,都会经常用到它。抛开UI,自己写个测试程序做串口的读写还是很容易的,这次在android开发,那么我们就按照android的标准来,网上也有很多人介绍android串口要怎么写,其实都差不多,只是我这个是用写C的人的思维来写的,相对比较容易让人明白点。


首先要搭建NDK的环境,我用Linux的环境,本来我们都是放在android系统去编译代码的,但很多人都是做UI的做UI ,做驱动的做驱动,都是分开的,所以我还是采取分开的写法来。

NDK一般都可以去这个网站上下载:

http://developer./tools/sdk/ndk/index.html


下好后随便放到用户空间吧,然后修改 vim  ~/.profile

把下面的这个

# ---- NDK---- 
ndk=/home/wfliao/android-ndk-r9b
PATH=$PATH:$ndk 
export ndk         

添加进去,然后source .profile 下。没起作用那就重启系统就可以了。我下的是  android-ndk-r9b,我放在   /home/wfliao/android-ndk-r9b下,所以你们只要想对应修改这个路径就可以了。

然后就是开始写JNI啦,我的eclipse写的测试代码一般放在workspace,所以我就直接执行mkdir -p /home/wfliao/workspace/uart/jni

建了一个jni的目录,然后在这个目录分别mkdir几个文件:Android.mk  Application.mk  com_android_uart_Uartjni.c  com_android_uart_Uartjni.h

内容分别如下:

1:Android.mk

#                                                                                                     
# Copyright 2009 Cedric Priscal

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www./licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License. 
#


LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)


LOCAL_MODULE    := uart
LOCAL_SRC_FILES := com_android_uart_Uartjni.c
LOCAL_LDLIBS    := -llog


include $(BUILD_SHARED_LIBRARY)
                                                                                                      


2:Application.mk(我最小是支持 android-8 的)

APP_PLATFORM := android-8       

3:com_android_uart_Uartjni.c



#include <stdio.h> 
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "com_android_uart_Uartjni.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>
#include <android/log.h>
#include <jni.h>
#include <sys/ioctl.h>
#include <sys/time.h> 


#include "android/log.h"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "", __VA_ARGS__))


#undef  TCSAFLUSH
#define TCSAFLUSH  TCSETSF
#ifndef _TERMIOS_H_
#define _TERMIOS_H_
#endif


//定义全局变量
int fd; 
int ttyS6gpioFd;
int ttyS7gpioFd;
//---------------------------
//当需要从ttyS6读一维码扫描数据的时候需要把em13_gpio_state写低电平,一旦退出设备的时候设置为高电平
//当需要从ttyS7写数据的时候需要把uart485_gpio_state写高电平,一旦退出设备的时候设置为低电平,或者写完也是设置低
const char *uart485 = "/sys/class/power_supply/battery/device/uart485_gpio_state";
const char *em13 = "/sys/class/power_supply/battery/device/em13_gpio_state";
const char *ttyS6buf = "/dev/ttyS6";
const char *ttyS7buf = "/dev/ttyS7";
int ttyS6andS7=0; //如果是6 怎是设置ttyS6,如果是7则是设置ttyS7
const char dat0 = '0';
const char dat1 = '1';
//实现本地方法 openUart
//str=> "/dev/ttyS6","/dev/ttyS7", "/dev/rfid_rc522_dev"
JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_openUart(JNIEnv *env,jobject mc, jstring str)
{
    const char *bufchar;
    bufchar=(*env)->GetStringUTFChars(env,str,NULL);
    if(!strcmp(ttyS6buf,bufchar))
    {
        ttyS6gpioFd = open(em13, O_RDWR);
        if(ttyS6gpioFd > 0)
            ttyS6andS7 = 6;
        else
            ttyS6andS7 = 0;


    }
    else if(!strcmp(ttyS7buf,bufchar))
    {
        ttyS7gpioFd = open(uart485, O_RDWR);
        if(ttyS7gpioFd > 0)
            ttyS6andS7 = 7;
        else
            ttyS6andS7 = 0;
    }
    else
    {
        ttyS6andS7 = 0;
    }


    LOGI("--jni ttyS6andS7 = %d--",ttyS6andS7) ;
    fd=open(bufchar,O_RDWR|O_NOCTTY|O_NDELAY); 
    LOGI("jni opne %s device ",bufchar) ;
    (*env)->ReleaseStringUTFChars(env, str, bufchar);
    return fd;
}




JNIEXPORT void JNICALL Java_com_android_uart_Uartjni_closeUart(JNIEnv *env,jobject mc)
{
        if(ttyS6andS7 == 6)
        {
            //--------------------关闭ttyS6的前,设置em13_gpio_state=1
            write(ttyS6gpioFd, &dat1, sizeof(dat1));
            LOGI("jni receive ttyS6, write to %c data to em13_gpio_state !",dat1) ;
            close(ttyS6gpioFd);
        }
        if(ttyS6andS7 == 7)
            close(ttyS7gpioFd);
        
        close(fd);
        LOGI("jni close devices !") ;
}




JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_setUart(JNIEnv *env,jobject mc,jint baudrate)
{
    struct termios newtio,oldtio;
    int  speed_arr[]={B1200,B2400,B4800,B9600,B19200,B38400,B57600,B115200,B230400,B921600};
    int  speed_int[]={ 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 921600};
    int  i;


        LOGI("jni setUart devices baud rate !") ;
        for(i =0 ; i < sizeof(speed_int)/sizeof(int); i++)
        {
            if(baudrate == speed_int[i])
            {
                LOGI("jni setUart devices %d baud rate !",speed_int[i]) ;
                tcgetattr(fd,&oldtio);
                tcgetattr(fd,&newtio);
                cfsetispeed(&newtio,speed_arr[i]);
                cfsetospeed(&newtio,speed_arr[i]);


                newtio.c_lflag=0; 
                newtio.c_cflag = speed_arr[i] | CS8 | CREAD | CLOCAL;
                newtio.c_iflag= BRKINT | IGNPAR | IGNCR | IXON | IXOFF | IXANY ;
                newtio.c_oflag=02;
                newtio.c_line=0;
                newtio.c_cc[7]=255;
                newtio.c_cc[4]=0;
                newtio.c_cc[5]=0; 


                if(tcsetattr(fd,TCSANOW,&newtio)<0)
                {
                    LOGI("ttySx tcsetattr fail !");
                    //exit(1);
                    close(fd); //关闭
                    goto  setend;
                }


                return fd;




            }
        }


setend:
    LOGI("jni not setUart devices baud rate end!") ;
    return -1;
}


JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_sendMsgUart(JNIEnv *env,jobject mc,jstring str)
{
    int len;
    const char *buf;
    buf=(*env)->GetStringUTFChars(env,str,NULL);
    len= (*env)->GetStringLength(env,str );


    write(fd,buf,len);


    LOGI("jni write to %s data to devices !",buf) ;
    (*env)->ReleaseStringUTFChars(env, str, buf);
}


//连续发送一个数组的16进制数据
JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_sendHexUart(JNIEnv *env,jobject mc,jintArray arr)
{
    int *buf;
    char sendbuf[]={0x8A,0x01,0x01,0x11,0x9B};
    int len,h;
    LOGI("jni write to HEX data to devices !") ;
    buf=(*env)->GetIntArrayElements(env,arr,NULL); 
    len = (*env)->GetArrayLength(env,arr);
    for(h =0; h<5; h++)
    {
        sendbuf[h]= (char) buf[h];
        LOGI("java write send HEX => 5 bytes  %x !",buf[h]) ;
    }
    //--------------------写ttyS7前,设置uart485_gpio_state=1
    write(ttyS7gpioFd, &dat1, sizeof(dat1));
    LOGI("jni write to %c data to uart485_gpio_state !",dat1) ;
    sleep(1);
    LOGI("jni write 5 bytes to ttyS7 start !");
    write(fd,sendbuf,sizeof(sendbuf));
    LOGI("jni write 5 bytes to ttyS7 end !" );
    for(h =0; h<5; h++)
    {
        LOGI("java write new HEX => 5 bytes  %x !",sendbuf[h]) ;
    }


    //--------------------写ttyS7后,设置uart485_gpio_state=0
    LOGI("jni write to %c data to uart485_gpio_state !",dat0) ;
    write(ttyS7gpioFd, &dat0, sizeof(dat0));


    (*env)->ReleaseIntArrayElements(env, arr, buf,0);
    LOGI("jni write to  data to devices !") ;
}




//加工后 485发送函数
JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_send485HexUart(JNIEnv *env,jobject mc,jint number)
{


    LOGI("jni write to HEX data to devices !") ;
    char hexStr[16];
    char buf[]={0x8A,0x01,0x01,0x11,0x9B};
    int n = number;    
    char Hextable[]="0123456789ABCDEF";
    char swaphex[16],hex[16];
    int i=0, k,index;
    //整型数转换成16进制数
    while(n){
        swaphex[i++]=Hextable[n%16];
        n /= 16;
    }
    swaphex[i]=0;


    for(k=0;k<i;k++)
    {
        hex[k]=swaphex[i-1-k];
    }
    hex[k]=0;
    memset(hexStr,0,sizeof(hexStr));
    strcpy(hexStr,hex);
    sscanf(hexStr, "%x",&index); 
    LOGI("jni :java write %d and jni change hex => %x!",number,index) ;
    for(k =0; k<5; k++)
    {
        LOGI("jni write old 5 bytes  %x !",buf[k]) ;
    }


    buf[2]= index;
    LOGI("jni write box lock addr(%x) to third bytes!",index) ;


    //锁的地址除于8,如果商是什么就直接赋值给第2个字节,如果是0,则直接赋值0x01;
    index=index / 8;
    if(index == 0)
    {
        buf[1]= 0x01;
        LOGI("jni write the board addr(%x) to second bytes !",buf[1]) ;
    }
    else
    {
        buf[1]= index + 1;
        LOGI("jni write the board addr(%x) to second bytes !",index) ;
    }
    //产生前4个字节的checksum,然后得到第5个字节的数据
    int eof4x= buf[0]^buf[1]^buf[2]^buf[3];
    LOGI("jni write fifth bytes (checksum = %x )!",eof4x) ;
    buf[4]=eof4x;
    //--------------------写ttyS7前,设置uart485_gpio_state=1
    write(ttyS7gpioFd, &dat1, sizeof(dat1));
    LOGI("jni write to %c data to uart485_gpio_state !",dat1) ;
    sleep(1);
    LOGI("jni write 5 bytes to ttyS7 start !") ;
    write(fd,buf,sizeof(buf));
    LOGI("jni write 5 bytes to ttyS7 end !" );
    for(k =0; k<5; k++)
    {
        LOGI("jni write new HEX => 5 bytes  %x !",buf[k]) ;
    }


    //--------------------写ttyS7后,设置uart485_gpio_state=0
    LOGI("jni write to %c data to uart485_gpio_state !",dat0) ;
    write(ttyS7gpioFd, &dat0, sizeof(dat0));




}




JNIEXPORT jstring JNICALL Java_com_android_uart_Uartjni_receiveMsgUart(JNIEnv *env,jobject mc)
{
    int len=0,ret;
    char buffer[128]="";
    char card[16];
    fd_set rdfd; 
    memset(buffer,0,sizeof(buffer));


    //--------------------接收ttyS6的一维码扫描前,设置em13_gpio_state=0
    if(ttyS6andS7 == 6)
    {
        write(ttyS6gpioFd, &dat0, sizeof(dat0));
        //LOGI("jni receive ttyS6, write to %c data to em13_gpio_state !",dat0) ;


    }
    FD_SET(fd, &rdfd);/* 把句柄加入读监视集合 */


    struct timeval timeout={1,0}; //select等待1秒,1秒轮询,要非阻塞就置0


    ret = select(fd + 1, &rdfd, NULL, NULL, &timeout); /* 注意是最大值加1 */


    if(ret < 0)
    {
        LOGI("call select fail");  /* select函数出错 */
        return NULL ;
    }
    else if(ret == 0)
    {
        LOGI("selet timeout "); /* 在设定的timeval 时间内,socket的状态没有发生变化 */
        return NULL ;
    }
    else
    {
        if (ttyS6andS7  != 0) //如果这个变量都不等于O的,那么肯定是ttyS6跟S7啦!
        {


            if(FD_ISSET(fd, &rdfd)) /* 先判断一下 fd 这个被监视的句柄是否真的变成可读的了 */
            {
                FD_ZERO(&rdfd); //清空集合
                /* 读取ttySxfd 句柄里的数据 */
                len=read(fd, buffer, sizeof(buffer));
                //LOGI("len = %d, buffer[0]=%c, buffer[1]=%c",len,buffer[0],buffer[1]);
                if (len > 0)
                {
                    LOGI("jni read  data from ttySx !") ;
                    return (*env)->NewStringUTF(env,buffer);
                }
                else
                    return NULL;


            }
            return NULL ;


        }
        else 
        {
            if(FD_ISSET(fd, &rdfd)) 
            {
                FD_ZERO(&rdfd); //清空集合
                /* 读取 rc522fd 句柄里的数据 */
                len=read(fd, buffer, sizeof(buffer));
                if (len > 0)
                {
                    sprintf(card,"%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11],buffer[12],buffer[13],buffer[14],buffer[15]);
                    LOGI("jni read data from rc522_dev !") ;
                    return (*env)->NewStringUTF(env,card);
                }
                else
                    return NULL;


            }
            return NULL ;


        }


    }
}





4:com_android_uart_Uartjni.h

/* DO NOT EDIT THIS FILE - it is machine generated */
/* Header for class tw_com_dmatek_dma210xp_uart_Uartjni */


#include <jni.h>
#ifndef _Included_com_android_uart_Uartjni
#define _Included_com_android_uart_Uartjni
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_openUart
  (JNIEnv *, jobject, jstring);




JNIEXPORT void JNICALL Java_com_android_uart_Uartjni_closeUart
  (JNIEnv *, jobject);




JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_setUart
  (JNIEnv *, jobject,jint);




JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_sendMsgUart
  (JNIEnv *, jobject, jstring);


JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_sendHexUart
  (JNIEnv *, jobject, jintArray);


JNIEXPORT jint JNICALL Java_com_android_uart_Uartjni_send485HexUart
  (JNIEnv *, jobject, jint);


JNIEXPORT jstring JNICALL Java_com_android_uart_Uartjni_receiveMsgUart
  (JNIEnv *, jobject);




#ifdef __cplusplus
}
#endif
#endif





最后得说明下,我不但在这个JNI中有串口还有对RFID的操作,而且又添加了串口对485的写操作。所以看起来就比较奇怪了。但有些有中文说明,所以我就不再写分析了。

JNI 要注意数据类型的转换。这个是非常重要的。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多