测试程序之UART 232/485适用于Android/Linux

简介: 测试程序之UART 232/485适用于Android/Linux

当时写这个的初衷是因为在调试Linux系统 , 串口测试费劲 通过echo/cat 有些功能受限制。

所以就搞了个测试程序 , Android可以不用这个 , 大把的测试工具。

程序功能介绍

这个程序是用来实现串口通信的。它接受三个参数,分别是通信模式(232或485)、串口设备名和波特率。它会根据参数的设置,打开指定的串口,并设置相应的属性。然后,它会创建一个子进程,用于从串口读取数据,并在标准输出上显示。父进程则用于从标准输入读取用户输入的内容,并发送到串口。用户可以输入文本或十六进制字符串,程序会自动识别并转换成字节序列。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
 
#define MODE_232 1
#define MODE_485 2
 
int open_serial_port(const char *port, int baud_rate, int mode)
{
    struct termios tty;
    memset(&tty, 0, sizeof(tty));
 
    int fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd < 0) {
        perror("open");
        return -1;
    }
 
    if (tcgetattr(fd, &tty) != 0) {
        perror("tcgetattr");
        close(fd);
        return -1;
    }
 
    cfsetospeed(&tty, baud_rate);
    cfsetispeed(&tty, baud_rate);
 
    // 设置控制模式(本地连接,接受使能)
    tty.c_cflag |= (CLOCAL | CREAD);
 
    // 设置数据位
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
 
    // 设置奇偶校验位
    tty.c_cflag &= ~PARENB;
    tty.c_iflag &= ~INPCK;
 
    // 设置停止位数
    tty.c_cflag &= ~CSTOPB;
 
    // 设置等待时间和最小字符数(对应VTIME和VMIN两个参数),这里设为 10 秒和 0 个字符
    tty.c_cc[VTIME] = 100;
    tty.c_cc[VMIN] = 0;
 
    if (mode == MODE_485) {
        // 设置为RS485模式
        tty.c_cflag |= CRTSCTS | CLOCAL;
        tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    } else if (mode == MODE_232) {
        // 设置为RS232模式
        tty.c_cflag &= ~CRTSCTS;
        tty.c_iflag |= (IXON | IXOFF | IXANY);
    }
 
    // 清空输入输出缓冲区
    tcflush(fd, TCIOFLUSH);
 
    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        perror("tcsetattr");
        close(fd);
        return -1;
    }
 
    return fd;
}
 
void read_serial_port(int fd)
{
    char buf[256];
    int n;
 
    while (1) {
        memset(buf, 0, sizeof(buf));
        n = read(fd, buf, sizeof(buf));
        if (n > 0) {
            printf("读到: %s", buf);
        }
    }
}
void write_serial_port(int fd)
{
    char buf[256];
    int n;
 
    while (1) {
        printf("请输入发送内容:");
        fgets(buf, sizeof(buf), stdin);
        n = strlen(buf);
 
        if (n > 0) {
            // 去掉最后的换行符
            if (buf[n-1] == '\n') {
                buf[n-1] = '\0';
                n--;
            }
 
            // 判断输入的字符串是否是十六进制格式
            int is_hex = 1;
            int i;
            for (i = 0; i < n; i++) {
                if ((buf[i] >= '0' && buf[i] <= '9')
                    || (buf[i] >= 'a' && buf[i] <= 'f')
                    || (buf[i] >= 'A' && buf[i] <= 'F')) {
                    continue;
                } else if (buf[i] == ' ') {
                    continue;
                } else {
                    is_hex = 0;
                    break;
                }
            }
 
            if (is_hex) {
                // 将输入的十六进制字符串转换成字节序列
                unsigned char data[128];
                int j = 0;
                for (i = 0; i < n; i++) {
                    if (buf[i] == ' ') {
                        continue;
                    }
 
                    sscanf(&buf[i], "%02X", &data[j]);
                    j++;
                    i++;
                }
                n = j;
                if (n > 0) {
                    n = write(fd, data, n);
                    if (n < 0) {
                        perror("write");
                    } else {
                        printf("hex发送成功\n");
                    }
                }
            } else {
                // 直接将输入的文本发送到串口
                n = write(fd, buf, n);
                if (n < 0) {
                    perror("write");
                } else {
                    printf("txt发送成功\n");
                }
            }
        }
    }
}
int main(int argc, char *argv[])
{
    if (argc != 4) {
        printf("Usage: %s [mode] [serial port] [baud rate]\n", argv[0]);
        return 1;
    }
 
    int mode;
    if (strcmp(argv[1], "232") == 0) {
        mode = MODE_232;
    } else if (strcmp(argv[1], "485") == 0) {
        mode = MODE_485;
    } else {
        printf("Invalid mode: %s\n", argv[1]);
        return 1;
    }
 
    const char *port = argv[2];
    int baud_rate = atoi(argv[3]);
 
    int fd = open_serial_port(port, baud_rate, mode);
    if (fd < 0) {
        fprintf(stderr, "Failed to open serial port %s with baud rate %d\n", port, baud_rate);
        return 1;
    }
 
    printf("Serial port %s opened successfully with baud rate %d and mode %d\n", port, baud_rate, mode);
 
    pid_t pid = fork();
    if (pid == 0) {
    // 子进程用于读取数据
    read_serial_port(fd);
} else if (pid > 0) {
    // 父进程用于写数据
    write_serial_port(fd);
} else {
    perror("fork");
    return 1;
}
 
close(fd);
 
return 0;
}

使用示例

要编译这个程序,需要在终端中输入:

./gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc  -o serial serial.c

要运行这个程序,需要在终端中输入:

./serial [mode] [serial port] [baud rate]

例如:

./serial 232 /dev/ttyUSB0 115200 # 使用RS232模式打开/dev/ttyUSB0串口,并设置波特率为115200
./serial 485 /dev/ttyS0 9600 # 使用RS485模式打开/dev/ttyS0串口,并设置波特率为9600

然后就可以看到类似下面的输出:

Serial port /dev/ttyUSB0 opened successfully with baud rate 115200 and mode 232
请输入发送内容:Hello world!
txt发送成功
读到: Hello world!
请输入发送内容:01 02 03 04 05
hex发送成功
读到: 01 02 03 04 05



相关文章
|
2月前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
176 6
|
5天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
1月前
|
Ubuntu Linux Android开发
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
本文介绍了如何在Android设备上安装Termux和AnLinux,并通过这些工具运行Ubuntu系统和桌面环境。
121 2
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
|
29天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
81 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
1月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
35 1
|
1月前
|
安全 Linux 网络安全
Kali渗透测试:远程控制程序基础
Kali渗透测试:远程控制程序基础
Kali渗透测试:远程控制程序基础
|
2月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
167 4
Android性能测试——发现和定位内存泄露和卡顿
|
2月前
|
消息中间件 分布式计算 Java
Linux环境下 java程序提交spark任务到Yarn报错
Linux环境下 java程序提交spark任务到Yarn报错
41 5
|
2月前
|
测试技术 Shell Android开发
Android 性能测试初探 (六)
本节聊聊性能测试的最后一项- 流量,当然我所指的性能测试是针对大部分应用而言的,可能还有部分应用会关注网速、弱网之类的测试,但本系列文章都不去一一探讨了。
54 6
|
1月前
|
安全 Java Linux
Kali渗透测试:通过Web应用程序实现远程控制
Kali渗透测试:通过Web应用程序实现远程控制