Demo功能

在学习Linux的串口通信程序之前,我们先来看看Demo的效果,这样比先来一大堆串口知识介绍更加有学习动力,毕竟是能运行的。本文章不会讲解串口的原理,如何接线等,只会讲解在Linux(Android)下如何使用串口。

程序的功能是发送4个8bit的数据,然后serial_comm不断接受数据并且回传会串口,从下图可以看出,程序正常运行。

这里的数据格式是以非标准(Raw)的格式进行传输,即以16进制进行传输,末尾不会发送回车符。这种方式普遍用在两个嵌入式IC之间的通信,而标准格式,则需要在末尾加回车符,数据才能读到。

这里推荐大家使用AccessPort这个软件(免费的),下载地址:http://www.sudt.com,能收发非标准模式,以及标准模式。而另一款SecureCRT软件只能收发标准模式,所以我调试非标准模式时一般都用这个软件。其实选择这个软件的原因嘛,仅仅是界面比较好看,哈哈。

串口配置

一般串口配置有:1、串口号。2、波特率。3、校验位。4、数据位。5、停止位。只要配置这些信息,我们就可以使用Window串口进行调试,而Linux的串口也是类似,代码中也是类似的操作。

Linux一切设备都是文件,串口设备的访问就是访问/dev/ttyS*,我们用ls -l /dev/ttyS*查看当前系统注册的设备,并确认其 运行权限,看是否可读可写。这里也是需要注意的地方,不然调试半天,才发现是没权限访问,那就尴尬了。从下面看出当前系统有3个串口设备其中ttyS0是debug打印log的串口,ttyS1是蓝牙用的串口,ttyS3才是没人使用的串口。ttyS3怎么产生,请查看之前的文章:https://blog.csdn.net/sweetmilkcake/article/details/82749764

petrel-p1:/ # ls -l /dev/ttyS*
crw------- 1 root root 252, 0 2018-01-01 08:00 /dev/ttyS0
crw-rw---- 1 bluetooth net_bt_stack 252, 1 2018-01-01 08:01 /dev/ttyS1
crw------- 1 root root 252, 3 2018-01-01 08:06 /dev/ttyS3

查看串口是否被占用

之前调过一个Bug,就是我的程序无论怎么都接受不到正常数据,甚至进行自己收发回环测试都不行(回环测试,串口端的TX和RX互联,自己进行收发处理,这样可以快捷测试串口的状态),当时也是搞了好久,一度怀疑是硬件问题,最后才发现是有另外一个程序一直访问同一个串口设备,不断的进行读写(它启动的早),导致我的数据不能正常输出,后面直接把它kill掉就好了,当然这是快捷的方法,最终修改还是要两个程序进行协调。那么问题来了,如果你刚接手别人的项目,对别人的系统又不熟悉,那么怎么确保自己使用的串口没有问题呢?其实还是有方法的,我们可以使用lsof | grep ttyS查看串口设备的占用情况。就像下面例子一样,我把serial_comm放到后台运行,所以看到它在占用着我们的ttyS3。用这种方法就可以很快进行问题定位。

petrel-p1:/ # lsof | grep ttyS
droid.blu 3044 bluetooth 74u CHR 252,1 0t0 4227 /dev/ttyS1
petrel-p1:/ # serial_comm &
[1] 19274
petrel-p1:/ # serial test start.petrel-p1:/ # lsof | grep ttyS
droid.blu 3044 bluetooth 74u CHR 252,1 0t0 4227 /dev/ttyS1
serial_co 19274 root 3u CHR 252,3 0t0 4228 /dev/ttyS3

详细配置代码

// dev control date end
// 02 01 12 7F
#define SERIAL_REC_NUM 4
// VTIME and VMIN is very important.
// VTIME: Time to wait for data (tenths of seconds)
#define SERIAL_VTIME 1
// VMIN: Minimum number of characters to read
#define SERIAL_VMIN SERIAL_REC_NUMint serial_set(int fd, int speed, int bits, int event, int stop)
{struct termios ttys;memset(&ttys, 0, sizeof(ttys));// Enable the receiver and set local mode// CLOCAL: Local line - do not change "owner" of port// CREAD: Enable receiverttys.c_cflag |= (CLOCAL | CREAD);// Mask the character size bits// CSIZE: Bit mask for data bitsttys.c_cflag &= ~CSIZE;switch (speed) {case 9600:// B9600: 9600 baudcfsetispeed(&ttys, B9600);cfsetospeed(&ttys, B9600);break;case 115200:// B115200: 115,200 baudcfsetispeed(&ttys, B115200);cfsetospeed(&ttys, B115200);break;default:cfsetispeed(&ttys, B115200);cfsetospeed(&ttys, B115200);break;}switch (bits) {case 7:// 7 data bitsttys.c_cflag |= CS7;break;case 8:// 8 data bitsttys.c_cflag |= CS8;break;default:ttys.c_cflag |= CS8;break;}switch (event) {case 'o':case 'O':// PARENB: Enable parity bitttys.c_cflag |= PARENB;// INPCK: Enable parity check// ISTRIP: Strip parity bitsttys.c_cflag |= (INPCK | ISTRIP);// PARODD: Use odd parity instead of eventtys.c_cflag |= PARODD;break;case 'e':case 'E':ttys.c_cflag |= PARENB;ttys.c_cflag |= (INPCK | ISTRIP);ttys.c_cflag &= ~PARODD;break;case 'n':case 'N':ttys.c_cflag &= ~PARENB;break;default:ttys.c_cflag &= ~PARENB;break;}switch (stop) {case 1:// CSTOPB: 2 stop bits (1 otherwise)ttys.c_cflag &= ~CSTOPB;break;case 2:ttys.c_cflag |= CSTOPB;break;default:ttys.c_cflag &= ~CSTOPB;break;}// VTIME: Time to wait for data (tenths of seconds)ttys.c_cc[VTIME] = SERIAL_VTIME;// VMIN: Minimum number of characters to readttys.c_cc[VMIN] = SERIAL_VMIN;// Hardware flow control using the CTS (Clear To Send) and RTS (Request To Send) signal lines// CNEW_RTSCTS, CRTSCTS: Enable hardware flow control (not supported on all platforms)// CNEW_RTSCTS: Also called CRTSCTS//ttys.c_cflag |= CRTSCTS; // Enable hardware flow controlttys.c_cflag &= ~CRTSCTS; // Disable hardware flow control// Choosing Canonical Input// Canonical input is line-oriented. Input characters are put into a buffer // which can be edited interactively by the user until a CR (carriage return) // or LF (line feed) character is received.// When selecting this mode you normally select the ICANON, ECHO, and ECHOE options//ttys.c_lflag |= (ICANON | ECHO | ECHOE);// Choosing Raw Input// Raw input is unprocessed. Input characters are passed through exactly as they are received,// when they are received. Generally you'll deselect the ICANON, ECHO, ECHOE, and ISIG options when using raw inputttys.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);// OPOST: Postprocess output (not set = raw output)//ttys.c_oflag |= OPOST; // Choosing Processed Outputttys.c_oflag &= ~OPOST; // Choosing Raw Output// Flushes the input and/or output queue.// TCIFLUSH: flushes data received but not read.// TCOFLUSH: flushes data written but not transmitted.// TCIOFLUSH: flushes both data received but not read, and data written but not transmitted.tcflush(fd, TCIOFLUSH);// Sets the serial port settings immediately.// TCSANOW: Make changes now without waiting for data to complete// TCSADRAIN: Wait until everything has been transmitted// TCSAFLUSH: Flush input and output buffers and make the changeif (tcsetattr(fd, TCSANOW, &ttys) != 0) {perror("serial set fail!\n");return -2;}return 0;
}

代码注释已经非常详细了,下面一一详细介绍各变量含义以及,相关注意点:

  • ttys.c_cflag |= (CLOCAL | CREAD); - 本地端口,使能接收器
  • ttys.c_cflag &= ~CSIZE; - 打开数据位的开关,才能设置波特率、停止位等
  • cfsetispeed(&ttys, B9600); - 设置输入的波特率为9600
  • cfsetospeed(&ttys, B9600); - 设置输出的波特率为9600
  • ttys.c_cflag |= CS8; - 8位数据位
  • ttys.c_cflag &= ~PARENB; - 取消奇偶校验
  • ttys.c_cflag &= ~CSTOPB; - 一位停止位
  • ttys.c_cc[VTIME] = SERIAL_VTIME; - 读取数据的最小时间
  • ttys.c_cc[VMIN] = SERIAL_VMIN; - 读取数据的最小位数
  • ttys.c_cflag &= ~CRTSCTS; - 不使用硬件流控制
  • ttys.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); - 选择非标准输入
  • ttys.c_oflag &= ~OPOST; - 选择非标准输出
  • tcflush(fd, TCIOFLUSH); - 刷新串口缓冲区的数据
  • tcsetattr(fd, TCSANOW, &ttys) - 使配置生效

在进行串口通信设计时需要注意以下地方:

  • ttys.c_cc[VTIME]和ttys.c_cc[VMIN]这两个会影响串口接收端的行为,我这里设置为ttys.c_cc[VTIME]=1,ttys.c_cc[VMIN]=4,串口open的时候设置为阻塞读取,ttys.c_cc[VTIME]=1的意思是读取数据超过100ms则会立即返回错误,ttys.c_cc[VMIN]=4的意思时每次需要读取4个自己数据,不然等待数据,两个加一起就是每次阻塞读取4个数据,超时100ms则会退出。其中ttys.c_cc[VMIN]=4一般由开发者自行定义,一般不太复杂的通信,这个固定就好,加入一些数据校验的措施即可保证数据的准确性。ttys.c_cc[VTIME]=1这个是为了保证数据线收到干扰或者接受数据不全而把当前错误数据进行丢弃,不然会打乱接受数据的顺序,影响准确性,相当于一个自我恢复措施。
  • tcflush(fd, TCIOFLUSH);这里设置为清空输入和输出Buffer的数据,设置好串口的状态,如果假如串口Buffer里面有数据,则会导致后续接受不正常。

串口测试

main函数的代码非常简单,打开串口并对串口接收到的数据进行回传。

int main(int argc, char *argv[])
{int fd = 0;int ret = 0;int n = 0;char buf[SERIAL_REC_NUM];printf("serial test start.\n");fd = open("/dev/ttyS3", O_RDWR | O_NOCTTY);if (fd < 0) {fprintf(stderr, "%s, open serial failed!\n", __FUNCTION__);return -1;}// Baud rate: 115200, Data bits: 8, Parity: None, Stop bits: 1ret = serial_set(fd, 115200, 8, 'N', 1);if (ret) {fprintf(stderr, "%s, serial set failed!\n", __FUNCTION__);return -1;}while (1) {memset(&buf, 0, sizeof(buf));// blocking heren = read(fd, &buf, SERIAL_REC_NUM);if (n < SERIAL_REC_NUM) {fprintf(stderr, "serial read fail!, n = %d\n", n);} else {printf("buf[0] = 0x%x, buf[1] = 0x%x, buf[2] = 0x%x, buf[3] = 0x%x, \n",buf[0], buf[1], buf[2], buf[3]);n = write(fd, &buf, SERIAL_REC_NUM);if (n < SERIAL_REC_NUM) {fprintf(stderr, "serial write fail!, n = %d\n", n);}}}close(fd);printf("serial test end.\n");return 0;
}

完整的程序代码:https://github.com/sweetmilkcake/serial_comm

写文章不易,如对您有用,麻烦给个Star,谢谢。

Linux (Android) 串口通信教程相关推荐

  1. Android串口通信apk源码

    1.SerialPortHelper「Android串口通信」介绍 原项目地址 https://github.com/freyskill/SerialPortHelper Android串口通讯助手可 ...

  2. Android串口通信实例分析【附源码】

    Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...

  3. 串口通信工具android,Android串口通信工具

    Android串口通信简单封装,可以用于和连接串口的硬件通信或者进行硬件调试 集成方法: Step 1. Add the JitPack repository to your build file / ...

  4. CH340与Android串口通信

    CH340与Android串口通信 为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio 移植的具体步骤 CH340串口通信驱动函数 通信过程中重难点 还存在的问题 ...

  5. android串口通信——身份证识别器

    android串口通信身份证识别器 一身份证识别器基础 调用身份证识别器的步骤 波特率 基本指令 身份证信息结构 文字结构说明 民族代码对照表 性别代码对照表 二身份证的读取 读取的方法调用 身份证的 ...

  6. modbus协议使用【android串口通信】

    modbus协议使用[android串口通信] 本文的目的是android端与上位机之间使用modbus协议进行串口通信.通过串口与其他设备进行通信,传递数据.可以理解为电脑和键盘.鼠标通信. 关于m ...

  7. msp430g2553串口接受数据_msp430g2553串口通信教程

    msp430g2553串口通信教程 MSP430g2553 串口通信MSP430 的不同型号,其串行通讯工作模式是一样的.以MSP430G2553 为例进行说明. MSP430G2553 是 20 个 ...

  8. android串口通信——电子扫描枪

    android串口通信--电子扫描枪  我们这里开始介绍电子扫描枪(串口的),在开发中我们可能用到电子扫描枪这么一个玩意.比如,我们在做一个可以说扫描条码的app的时候,就会用到,这种情况一般都是运行 ...

  9. Linux c语言虚拟串口,利用socat和cutecom实现Linux虚拟串口通信

    (1)打开终端,输入 sudo apt-get install socat 等待socat安装完成- (2)输入 socat -d -d pty,raw,echo=0 pty,raw,echo=0 我 ...

最新文章

  1. 【纪中集训2019.3.20】铁路
  2. 网络安全模型_基于TCM的网络安全访问模型
  3. python如何编程-怎么用手机编写Python程序?
  4. 计算机系学生thinkbook,ThinkBook系列性能差,只能当一台学习机?其实它只是专注于办公...
  5. android 截屏指定区域,Android截图 截取ContentView 截取指定的View并且保存
  6. Spring 如何解决循环依赖?
  7. 二维有限元方程matlab,有限元法求解二维Poisson方程的MATLAB实现
  8. IOS高级编程之二:IOS的数据存储与IO
  9. 实时屏幕监控 linux面板,分享|LXDE、Xfce 及 MATE 桌面环境下的又一系统监视器应用:Multiload-ng...
  10. Android 性能优化---(7)布局优化
  11. C#调用C语言生成的DLL“未找到入口”
  12. WEB页面实时播放海康、大华等摄像头RTSP视频流完全方案
  13. 为啥海康摄像头网页无法预览
  14. github 提交消息的emoji表情符号规范
  15. 与计算机博弈相关的学术论文,爱恩斯坦棋计算机博弈系统的研究与实现计算机应用技术专业论文.docx...
  16. npm与package.json详解
  17. 香橙派装php_【香橙派】安装宝塔面板 orange pi
  18. 2017年18岁的北京文科状元父母都是外交官,关于高考,他说出了我们竭力回避的戳心真相
  19. java-net-php-python-springtboot校园信息交流互助系统计算机毕业设计程序
  20. 2152: 聪聪可可

热门文章

  1. [Wiki].NET框架
  2. 个人作业-week2:关于微软必应词典的案例分析
  3. Qt 节假日程序 透明+任务栏无图标+星星闪烁+exe图标
  4. 荣耀Magic2锋芒毕露,小米MIX3或因实力不足刻意抢发?
  5. Ajax和Axios 的简介及简单应用案例
  6. Ubuntu系统下,使用python操作MySQL数据库
  7. C/C++实战014:字符串转换及Python传参数组
  8. java class.getmethod_java getmethod 方法
  9. python 等号需要空格_等号两边需要空格吗?
  10. 喜欢你的男孩和爱你的男孩