美文网首页
Android USB转串口通信

Android USB转串口通信

作者: 阿拉贡居民 | 来源:发表于2021-09-02 18:33 被阅读0次

最近需要在Android板卡上面对接些串口控制的外设,比如,4G模块、呼吸灯、光感传感器等,这些都是串口指令控制。
目前Android板卡只有一个串口,想再控制其他外设,只能通过usb转串口, 下面做个记录。

java串口驱动

在网上搜索了下android下面usb转串口驱动,有些直接用java实现,比如ch340, 我也根据网上资料用java把usb转串口跑通,
但是如果换一个usb转串口芯片就不好使, 通过修改串口驱动源码,也没有调好。github上面都有源码,有需要的自己下载调试,这里不多说明。
关于java实现usb转串口驱动的原理,还没来得及细研究,有时间再研究下!。

参数博客:
https://blog.csdn.net/tianruxishui/article/details/38338087
https://blog.csdn.net/tangchao5206/article/details/76999475

Android_CH34xUART官方驱动实例
https://github.com/BestCoderXQX/Android_CH34xUARTDemo

这个人反编译了CH34xUART驱动jar包源码开发, 省了我很多工作,本来准备自己反编译。
https://github.com/HeHongdan/CH34xUART

Kernel配置USB转串口驱动

由于java串口驱动调试通了ch340,另外一个使用cp210, 没有调试通, 去silicon官网查看,他们只支持kenrel驱动,于是根据官网pdf文档,配置kernel驱动,测试了CH341, CP210X USB串口都没有问题。
我这里把编译成模块,编译成ko后自己插入!

+++ b/kernel/linux-4.9.y/arch/arm64/configs/hi3751v810_arm64_android_defconfig
@@ -3019,7 +3019,10 @@ CONFIG_USB_STORAGE=y
 #
 # USB port drivers
 #
-# CONFIG_USB_SERIAL is not set
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_CP210X=m

串口测试程序

这个串口操作接口封装挺好的,也分享出来。
swserial.h

#ifndef __SW_SERIAL_H_
#define __SW_SERIAL_H_

#ifdef __cplusplus
extern "C" {
#endif

int32_t sw_serial_open(const char *dev);
void sw_serial_close(int fd);
int32_t sw_serial_read(int fd, unsigned char *buf, int len, int timeout);
int32_t sw_serial_write(int fd, unsigned char *buf, int len, int timeout);
int32_t sw_serial_set_parity(int fd,int speed,int databits,int stopbits,int parity);

#ifdef __cplusplus
}
#endif
#endif

swserial.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <android/log.h>

#undef LOG_TAG
#define LOG_TAG "swserial"

#define USE_NON_ICANON

typedef struct {
    int fd;
    char * dev;
}sw_serial_t;
#define MAX_SERIAL_NUM 3
sw_serial_t m_sList[MAX_SERIAL_NUM] = {
    {-1, NULL},
    {-1, NULL},
    {-1, NULL}
};

int32_t sw_serial_open(const char *dev)
{
    int fd, err, i;
    if( dev == NULL )
    {
        fprintf(stderr,"%s: Invalid parameter\n",__func__);
        return -1;
    }
    for( i=0; i<MAX_SERIAL_NUM; i++)
    {
        if( m_sList[i].fd >= 0 && m_sList[i].dev && strcmp(m_sList[i].dev, dev) == 0 )
        {
            fprintf(stderr,"[%s:%d] %s alread opened\n",__func__,__LINE__,dev);
            return m_sList[i].fd;
        }
    }
    for( i=0; i<MAX_SERIAL_NUM; i++)
    {
        if( m_sList[i].fd == -1 )
            break;
    }

    fd = open(dev, O_NOCTTY|O_NONBLOCK|O_RDWR);
    if( fd == -1 )
    {
        err = errno;
        fprintf(stderr,"open %s failed: %s\n",dev, strerror(err));
        return -1;
    }

    if( i == MAX_SERIAL_NUM )
    {
        i = 0;
        close(m_sList[i].fd);
        if( m_sList[i].dev )
            free(m_sList[i].dev);
        m_sList[i].dev = NULL;
    }
    m_sList[i].fd = fd;
    m_sList[i].dev = (char *)malloc(strlen(dev)+1);
    if( m_sList[i].dev )
        snprintf(m_sList[i].dev,sizeof(m_sList[i].dev), "%s", dev);

    return fd;
}

void sw_serial_close(int fd)
{
    int i;
    close(fd);
    for( i=0; i<MAX_SERIAL_NUM; i++)
    {
        if( m_sList[i].fd == fd )
        {
            m_sList[i].fd = -1;
            if( m_sList[i].dev )
                free( m_sList[i].dev );
            m_sList[i].dev = NULL;
            break;
        }
    }
}

int32_t sw_serial_read(int fd, unsigned char *buf, int len, int timeout)
{
    int rsize, rlen=0, err;
    struct timeval tv;
    fd_set readfds;
    FD_ZERO(&readfds);

    tv.tv_sec = timeout/1000;
    tv.tv_usec = (timeout%1000)*1000;
    fprintf(stderr,"[%s:%d] fd:%d\n",__func__,__LINE__, fd);

select_again:
    FD_SET(fd, &readfds);
    err = select( fd+1, &readfds, NULL, NULL, (tv.tv_sec>0 || tv.tv_usec>0)? (&tv):NULL );
    if( err == -1 )
    {
        fprintf(stderr,"select error: %s\n", strerror(errno));
        return -1;
    }
    else if( err )
    {
        if( FD_ISSET(fd, &readfds) )
        {
            if( (rsize = read( fd, buf+rlen, len-rlen)) > 0 )
            {
                rlen += rsize;
            }
        }
        else
        {
            fprintf(stderr,"[%s:%d] select again\n",__func__,__LINE__);
            goto select_again;
        }
    }
    else
        fprintf(stderr,"[%s:%d] select timeout\n",__func__,__LINE__);
    buf[rlen] = 0;
    fprintf(stderr,"[%s:%d] read(%d bytes): [%s]\n",__func__,__LINE__, rlen, buf);
    return rlen;
}

int32_t sw_serial_write(int fd, unsigned char *buf, int len, int timeout)
{
    int wsize = 0, err;
    struct timeval tv;
    fd_set writefds;
    FD_ZERO(&writefds);

    tv.tv_sec = timeout/1000;
    tv.tv_usec = (timeout%1000)*1000;

    fprintf(stderr,"[%s:%d] fd:%d\n",__func__,__LINE__, fd);
write_again:
    FD_SET(fd, &writefds);
    err = select( fd+1, NULL, &writefds, NULL, (tv.tv_sec>0 || tv.tv_usec>0)? (&tv):NULL );
    if( err == -1 )
    {
        fprintf(stderr,"select error: %s\n", strerror(errno));
        return -1;
    }
    else if( err )
    {
        if( FD_ISSET(fd, &writefds) )
        {
            wsize = write( fd, buf, len);
        }
        else
            goto write_again;
    }
    return wsize;
}

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

/**
 *  @brief 设置串口参数
 *  
 *  @param fd 串口句柄
 *  @param speed 波特率
 *  @param databits 数据位数
 *  @param stopbits 停止位位数
 *  @param parity 模式
 *  
 *  @return 设置成功返回0,失败返回-1
 */
int sw_serial_set_parity(int fd,int speed,int databits,int stopbits,int parity)
{
    int i;
    int is_speed_true = 0;
    struct termios options; 
    fprintf(stderr,"[%s:%d] fd:%d\n",__func__,__LINE__, fd);
    tcflush(fd, TCIOFLUSH);
    if  ( tcgetattr( (int)fd, &options )  !=  0)
    { 
        fprintf(stderr,"tcgetattr failed: %s\n",strerror(errno));
        return -1;  
    }
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {
        if  (speed == name_arr[i]) {
            is_speed_true = 1;
            break;
        }
    }
    if(is_speed_true == 1)
    {
        cfsetispeed(&options, speed_arr[i]);
        cfsetospeed(&options, speed_arr[i]);     
    }
    else
    {
        fprintf(stderr,"set speed failed: %s\n",strerror(errno));
        return -1;  
    }
    options.c_iflag = 0;
    options.c_oflag = 0;

    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 sizen"); 
            return -1;  
    }
    switch (parity) 
    {   
        case 'n':
        case 'N':    
            options.c_cflag &= ~PARENB;     /* Clear parity enable */
            options.c_iflag &= ~INPCK;      /* Disable parity checking */ 
            break;  
        case 'o':   
        case 'O':     
            options.c_cflag |= PARENB;      /* Enable parity */    
            options.c_cflag |= PARODD;      /* Parity for input and output is odd */
            options.c_iflag |= INPCK;       /* Enable input parity checking */ 
            break;  
        case 'e':  
        case 'E':   
            options.c_cflag |= PARENB;      /* Enable parity */    
            options.c_cflag &= ~PARODD;     /* Parity for input and output is even */ 
            options.c_iflag |= INPCK;       /* Enable input parity checking */
            break;
        case 'S': 
        case 's':  /*as no parity*/   
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;  
        default:   
            fprintf(stderr,"Unsupported parityn");    
            return -1;  
    }
    /* .....*/  
    switch (stopbits)
    {   
        case 1:    
            options.c_cflag &= ~CSTOPB;  
            break;  
        case 2:    
            options.c_cflag |= CSTOPB;  
            break;
        default:    
            fprintf(stderr,"Unsupported stop bitsn");  
            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 bitsn");  
            return -1; 
    }

#ifdef USE_NON_ICANON
    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
#else
    options.c_lflag  &= ~( ECHO | ECHOE | ISIG);  /*Input*/
#endif
    options.c_oflag  &= ~OPOST;   /*Output*/

    tcflush( (int)fd, TCIFLUSH );
#ifdef USE_NON_ICANON
    options.c_cc[VTIME] = 10; /* ....15 seconds*/   
    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
#endif
    if (tcsetattr( (int)fd, TCSANOW, &options ) != 0)   
    { 
        fprintf(stderr,"tcgetattr failed: %s\n",strerror(errno));
        return -1;  
    }

    //fcntl((int)fd, F_SETFL, O_NDELAY); 
    return 0;

}

serial_main.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>

#include "swserial.h"


static int m_serial_fd = -1;
static int m_quit = 0;

static void * abs_serial_read_proc(void *arg)
{
    int ret = 0;
    char recvbuf[1024]= {0}; 
    while(!m_quit){
        memset(recvbuf, 0, sizeof(recvbuf));
        //ret = sw_serial_read(m_serial_fd, (unsigned char *)recvbuf, 1024, -1);    
        ret = read(m_serial_fd, (unsigned char *)recvbuf, 1024);    
        if (ret == 0)
            continue;
        if(ret>0){
            printf("recv[%d]: %s \n",ret, recvbuf);
        }
        usleep(200*1000);
    }
    pthread_exit(NULL);
}

int main(int argc, char*argv[])
{
    char sendbuf[512] = {0};    
    int ret = -1;
    pthread_t read_id;
    void *status;


    m_serial_fd = sw_serial_open("/dev/ttyUSB0");
    if(m_serial_fd == -1)
    {
        printf(" /dev/ttyUSB0 open failed!\n");
        return -1;
    }
    ret = sw_serial_set_parity(m_serial_fd, 115200, 8, 1, 'n');
    if(ret != 0)
    {
        printf("seial set parity failed! \n");
        return -1;
    }
    
    //创建串口读线程
    ret = pthread_create(&read_id, NULL, abs_serial_read_proc, 0); 
    if(ret != 0)
    { 
        printf("pthread_create failed! \n");
        return -1;
    }

    //读取数据,发送给串口
    //__fpurge(stdin);
    printf("please input$:");
    while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
    {
        if(strncmp(sendbuf, "\n", 1) == 0)
        {
            printf("please input$: ");
            continue;
        }
        if(strncmp(sendbuf, "quit", 4) == 0)
        {
            printf("serial test quit!\n ");
            break;
        }

        sendbuf[strlen(sendbuf)-1] = '\r';
        sendbuf[strlen(sendbuf)] = '\n';
    
        //ret = sw_serial_write(m_serial_fd, (unsigned char*)sendbuf, strlen(sendbuf), 200);
        ret = write(m_serial_fd, (unsigned char*)sendbuf, strlen(sendbuf));
        printf("send[%d]: %s", ret , sendbuf );

        memset(sendbuf, 0 , sizeof(sendbuf));
    }
    
    m_quit = 1;
    pthread_join(read_id, &status);
    sw_serial_close(m_serial_fd);
    m_serial_fd = -1;

    return 0;
}

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_SRC_FILES:= \
        swserial.c \
        serial_main.c

LOCAL_MODULE_TAGS := optional
#LOCAL_STATIC_LIBRARIES += 
LOCAL_SHARED_LIBRARIES := \
    libutils\
    libcutils\
    liblog\
LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)

#LOCAL_CLANG := false
LOCAL_MODULE:= serial_test

ALL_DEFAULT_INSTALLED_MODULES += $(LOCAL_MODULE)
include $(BUILD_EXECUTABLE)

相关文章

  • Android USB转串口通信

    一、引用 1、Git上最火的USB转串口通信2、Android之USB转串口通信3、安卓开发中的USB转串口通讯 ...

  • Android USB转串口通信

    最近需要在Android板卡上面对接些串口控制的外设,比如,4G模块、呼吸灯、光感传感器等,这些都是串口指令控制。...

  • Android USB通信与USB转串口通信

    前段时间公司有个项目,涉及Android BLE硬件通讯,需要用到Android USB转PL232、FD2...

  • android usb串口通信

    引用 implementation'com.github.mik3y:usb-serial-for-android...

  • 1月9日

    今天学习的串口通信,有输入输出两条线,通过USB转串口,实现通信,老讲解了memcmp内存比较函数,老师还教了做串...

  • Android USB转串口通信开发基本流程

    好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设...

  • serial.serialutil.SerialExceptio

    今天在Ubuntu板子上进行串口通信时使用的是USB转串口进行连接,运行Python程序时报以下错误: 解决办法如...

  • Android之USB数据通信

    一.USB串口通信步骤: 连接USB设备 获取USB设备的权限 打开设备openDevice(UsbDevice ...

  • Android USB串口通信开发流程

    1.发现USB设备 UsbManager是负责管理USB设备的类,该类的主要方法有: getDeviceList(...

  • arduino——串口控制开关灯(笔记)

    串口简介 Arduino与计算机通信的最常用方式就是串口通信,当使用USB线将二者连接时,便建立了串口连接,通过串...

网友评论

      本文标题:Android USB转串口通信

      本文链接:https://www.haomeiwen.com/subject/kmjcwltx.html