Linux之4G模块串口通信

2023-05-16

在使用AT指令给4G模块发信息的时候,我们需要借助到Linux中busybox的microcom工具,该工具用来实现与串口之间的通信,那怎么自己实现编程跟4G模块发信息,以及接收信息把想要的信息放入结构体呢?
编程思想:
在/dev下找到4G模块的设备描述符,然后按照“Linux一切皆文件”的思想,打开这个设备,初始化串口配置后,用write发送AT的指令给4G模块通信,然后用read接收,再把接收到想要的数据分割出来放到结构体里面去。
1.在/dev下找到4G模块的设备描述符,我的是/dev/ttyACM2
在这里插入图片描述
2.打开这个设备

    //deviceName --/dev/ttyACM2  
    //O_NOCTTY  如果打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
    //O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中.
    gg_G4_INFO->deviceFd = open(gg_G4_INFO->deviceName,O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(gg_G4_INFO->deviceFd < 0)
    {
        printf("Open %s failed,fd=%d\n",gg_G4_INFO->deviceName,gg_G4_INFO->deviceFd);
        goto EXIT;
    }

    // 检查串口是否处于阻塞态
    if((retval = fcntl(gg_G4_INFO->deviceFd,F_SETFL,0)) < 0)
    {
        printf("%s,Fcntl check faile.\n",__func__);
        goto EXIT;
    }
}

3.初始化串口
一些函数介绍:
为了便于通过程序来获得和修改终端参数,Linux还提供了tcgetattr函数和tcsetattr函数。tcgetattr用于获取终端的相关参数,而tcsetattr函数用于设置终端参数。

<termios.h>
1.tcgetattr函数:
函数原型:int tcgetattr(int fd, struct termios *termios_p);
功能:
tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios 结构体中
其成员:
tcflag_t c_iflag;    //输入模式标志,控制终端输入方式
tcflag_t c_oflag;    //输出模式标志,控制终端输出方式
tcflag_t c_cflag;    //控制模式标志,指定终端硬件控制信息
tcflag_t c_lflag;    //本地模式标志,控制终端编辑功能
cc_t c_cc[NCCS];     //控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等
返回值:成功返回 0,失败返回 -1


2.tcsetattr函数:
函数原型:int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
功能:
tcsetattr函数用于设置终端参数。函数在成功的时候返回0,失败的时候返回-1,并设置errno的值。
参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。optional_actions可以取如下的值。
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:等待所有数据传输结束,清空输入输出缓冲区才改变属性。

错误信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函数调用被信号中断。
EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENOTTY:非终端的文件描述符。

3.strerror()函数
原型:char * strerror(int errnum);
函数说明:strerror()用来依参数errnum 的错误代码来查询其错误原因的描述字符串, 然后将该字符串指针返回.
返回值:返回描述错误原因的字符串指针.
功能:获取指向错误消息字符串的指针


4.isatty()函数
功能:检查设备类型,判断文件描述词是否为终端机
头文件:<io.h>
原型:int isatty(int handle);
参数:int handle 为要检查的设备文件句柄
返回值:如果参数desc所代表的文件描述词为一终端机则返回1,否则返回0
int decive_init(G4_INFO **g_G4_INFO)
{
	G4_INFO *gg_G4_INFO = *g_G4_INFO;
    if(!gg_G4_INFO )
    { 
        printf("gg_G4_INFO is NULL\n");
        goto EXIT;
    }
    int                   retval;
    char                  baudrate[32] = {0};
    struct termios        NewTermios;

    memset(&NewTermios,0,sizeof(struct termios));
    memset(&(gg_G4_INFO->OldTermios),0,sizeof(struct termios));

    if(tcgetattr(gg_G4_INFO->deviceFd,&(gg_G4_INFO->OldTermios)))
    {
        printf("%s,Get termios to OldTermios failure:%s\n",__func__,strerror(errno));
        return -2;
    }

//tcgetattr功能:获取文件描述符对应串口的原始属性,并保存在第二个参数中
//通常获取的原始属性需要进行备份,在程序退出之前要将其修改回来,否则无法继续使用串口。
    if(tcgetattr(gg_G4_INFO->deviceFd,&NewTermios))
    {    
        printf("%s,Get termios to NewTermios failure:%s\n",__func__,strerror(errno));
        return -3;
    }  
     /* 修改控制模式,保证程序不会占用串口 */
    NewTermios.c_cflag |= CLOCAL;


    /* 启动接收器,能够从串口中读取输入数据 */
    NewTermios.c_cflag |= CREAD;


    /*  CSIZE字符大小掩码,将与设置databits相关的标致位置零 */
    NewTermios.c_cflag &= ~CSIZE;

    NewTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    /* 
     * ICANON: 标准模式
     * ECHO: 回显所输入的字符
     * ECHOE: 如果同时设置了ICANON标志,ERASE字符删除前一个所输入的字符,WERASE删除前一个输入的单词
     * ISIG: 当接收到INTR/QUIT/SUSP/DSUSP字符,生成一个相应的信号
     *
     * */

    NewTermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    /* 
     * BRKINT: BREAK将会丢弃输入和输出队列中的数据(flush),并且如果终端为前台进程组的控制终端,则BREAK将会产生一个SIGINT信号发送到这个前台进程组
     * ICRNL: 将输入中的CR转换为NL
     * INPCK: 允许奇偶校验
     * ISTRIP: 剥离第8个bits
     * IXON: 允许输出端的XON/XOF流控
     *
     * */

    /* OPOST: 表示处理后输出,按照原始数据输出 */ 
    NewTermios.c_oflag &= ~(OPOST);

    if(gg_G4_INFO->BaudRate)
    {
        sprintf(baudrate,"B%d",gg_G4_INFO->BaudRate);
        cfsetispeed(&NewTermios,(int)baudrate); //设置输入输出波特率
        cfsetospeed(&NewTermios,(int)baudrate);
    }
    else 
    {
        cfsetispeed(&NewTermios,B115200);
        cfsetospeed(&NewTermios,B115200);
    }

    // 设置数据位 
    switch(gg_G4_INFO->DataBits)
    {
        case '5':
            NewTermios.c_cflag |= CS5;
            break;

        case '6':
            NewTermios.c_cflag |= CS6;
            break;

        case '7':
            NewTermios.c_cflag |= CS7;
            break;

        case '8':
            NewTermios.c_cflag |= CS8;
            break;

        default:
            NewTermios.c_cflag |= CS8;  //默认数据位为8
            break;
    }
    // 设置校验方式 
    switch(gg_G4_INFO->Parity)
    {
        // 无校验 
        case 'n':
        case 'N':
            NewTermios.c_cflag &= ~PARENB;
            NewTermios.c_iflag &= ~INPCK;
            break;

        // 偶校验 
        case 'e':
        case 'E':
            NewTermios.c_cflag |= PARENB;
            NewTermios.c_cflag &= ~PARODD;
            NewTermios.c_iflag |= INPCK;
            break;

        // 奇校验
        case 'o':
        case 'O':
            NewTermios.c_cflag |= PARENB;
            NewTermios.c_cflag |= PARODD;
            NewTermios.c_iflag |= INPCK;

   // 设置为空格 
        case 's':
        case 'S':
            NewTermios.c_cflag &= ~PARENB;
            NewTermios.c_cflag &= ~CSTOPB;

        /* 默认无校验 */
        default:
            NewTermios.c_cflag &= ~PARENB;
            NewTermios.c_iflag &= ~INPCK;
            break;
    }
        // 设置停止位 
    switch(gg_G4_INFO->StopBits)
    {
        case '1':
            NewTermios.c_cflag &= ~CSTOPB;
            break;

        case '2':
            NewTermios.c_cflag |= CSTOPB;
            break;

        default:
            NewTermios.c_cflag &= ~CSTOPB;
            break;
    }

    NewTermios.c_cc[VTIME] = 0;  //最长等待时间
    NewTermios.c_cc[VMIN] = 0;  //最小接收字符 
    gg_G4_INFO->mSend_Len = 128;  //若命令长度大于mSend_Len,则每次最多发送为mSend_Len

    if(tcflush(gg_G4_INFO->deviceFd,TCIFLUSH))
    {
        printf("%s,Failed to clear the cache:%s\n",__func__,strerror(errno));
        return -4;
    }

    if(tcsetattr(gg_G4_INFO->deviceFd,TCSANOW,&NewTermios) != 0)
    {
        printf("%s,tcsetattr failure:%s\n",__func__,strerror(errno));
        return -5;
    }

    printf("decive_init Successfully......\n");

    return 0;
}

4.用write和send发送和接收

 fd_set rfd, wfd, efd;
    while(1)
    {
        printf("FD_ISSET4\n");
        sleep(2);
        if(g_G4_INFO->deviceFd < 0)
        {
            printf("G4Handler again begin\n");
            G4Handler(&g_G4_INFO); 
            printf("G4Handler again end\n");
            if(g_G4_INFO->deviceFd < 0)
            {
                continue;
            }
            else
            {
                printf("G4Handler init again success\n");
            }
        }
        FD_ZERO(&rfd);
        FD_ZERO(&wfd);
        FD_ZERO(&efd);

        FD_SET(g_G4_INFO->deviceFd, &rfd);
        FD_SET(g_G4_INFO->deviceFd, &wfd);
        FD_SET(g_G4_INFO->deviceFd, &efd);
        iRet = select((g_G4_INFO->deviceFd)+1,&rfd,&wfd,&efd,NULL);
        if(iRet > 0)
        {
            if(FD_ISSET(g_G4_INFO->deviceFd,&rfd))
            {
                nrecv = 0;
                //memset(g_G4_INFO->readBuf,0,strlen(g_G4_INFO->readBuf));
               
                nrecv = recvFromDevice(&g_G4_INFO);
                if(nrecv < 0)
                {
                    printf("recvFromDevice error\n");
                    printf("trying\n");
                    flag = 1;
                    continue;
                }
                  else
                {
                    printf("recv success\n");
                }
            }
            
            else if(FD_ISSET(g_G4_INFO->deviceFd,&wfd))
            {
            //注意:AT指令集发送的实质,例如,当我们发送AT时,其实是发送了" AT\r "
               if( sendToDevice(&g_G4_INFO) == -1)
               {    
                    printf("send error\n");
                    printf("trying...\n");
                    flag = 1;
                    continue;
               }
               else
               {
                    printf("send trying success continue\n");
               }
            }
            
        }
          else
        {
            perror("select error\n");
            goto EXIT;
        }
    }

EXIT:
    if(g_G4_INFO)
    {
        free(g_G4_INFO);
       // g_G4_INFO->deviceName = NULL;
    }
    if(g_G4_INFO->deviceFd >0)
    {
        close(g_G4_INFO->deviceFd);
        g_G4_INFO->deviceFd = -1;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux之4G模块串口通信 的相关文章

  • Linux中的定时器类

    我需要一个计时器来以相对较低的分辨率执行回调 在 Linux 中实现此类 C 计时器类的最佳方法是什么 有我可以使用的库吗 如果您在框架 Glib Qt Wx 内编写 那么您已经拥有一个具有定时回调功能的事件循环 我认为情况并非如此 如果您
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • arm64和armhf有什么区别?

    Raspberry Pi Type 3 具有 64 位 CPU 但其架构不是arm64 but armhf 有什么区别arm64 and armhf armhf代表 arm hard float 是给定的名称Debian 端口 https
  • 如何在 Linux shell 中将十六进制转换为 ASCII 字符?

    假设我有一个字符串5a 这是 ASCII 字母的十六进制表示Z 我需要找到一个 Linux shell 命令 它将接受一个十六进制字符串并输出该十六进制字符串代表的 ASCII 字符 所以如果我这样做 echo 5a command im
  • 如何将目录及其子目录中的所有 PDF 文件复制到一个位置?

    如何全部复制PDF文件从目录及其子目录到单个目录 实际上还有更多的文件 并且深度有些任意 假设四个目录的最大深度是公平的 我想这些文件需要重命名 如果a pdf例如 位于多个目录中 因为我会adding https ebooks stack
  • 如何在apache 2.4.6上安装apxs模块

    我刚刚用过apt get update我的 apache 已更新为2 4 6 我想安装 apxs 来编译模块 但收到此错误 The following packages have unmet dependencies apache2 pre
  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • docker容器大小远大于实际大小

    我正在尝试从中构建图像debian latest 构建后 报告的图像虚拟大小来自docker images命令为 1 917 GB 我登录查看尺寸 du sh 大小为 573 MB 我很确定这么大的尺寸通常是不可能的 这里发生了什么 如何获
  • jq中如何分组?

    这是 json 文档 name bucket1 clusterName cluster1 name bucket2 clusterName cluster1 name bucket3 clusterName cluster2 name bu
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 内核模式下的线程(和进程)与用户模式下的线程(和进程)有什么区别?

    我的问题 1 书中现代操作系统 它说线程和进程可以处于内核模式或用户模式 但没有明确说明它们之间有什么区别 2 为什么内核态线程和进程的切换比用户态线程和进程的切换花费更多 3 现在 我正在学习Linux 我想知道如何在LINUX系统中分别
  • 如何在 Bash 中给定超时后终止子进程?

    我有一个 bash 脚本 它启动一个子进程 该进程时不时地崩溃 实际上是挂起 而且没有明显的原因 闭源 所以我对此无能为力 因此 我希望能够在给定的时间内启动此进程 如果在给定的时间内没有成功返回 则将其终止 有没有simple and r
  • Gtk-ERROR **:检测到 GTK+ 2.x 符号

    我正在使用 gcc 编译我的 c 应用程序 并使用以下标志 gcc evis c pkg config cflags libs gtk 2 0 libs clutter gtk 1 0 libs gthread 2 0 Wall o evi
  • 当 grep "\\" XXFile 我得到“尾随反斜杠”

    现在我想查找是否有包含 字符的行 我试过grep XXFile但它暗示 尾随反斜杠 但当我尝试时grep XXFile没关系 谁能解释一下为什么第一个案例无法运行 谢谢 区别在于 shell 处理反斜杠的方式 当你写的时候 在双引号中 sh
  • MySQL 中的创建/写入权限

    我的设备遇到一些权限问题SELECT INTO OUTFILE陈述 当我登录数据库并执行简单的导出命令时 例如 mysql gt select from XYZ into outfile home mropa Photos Desktop
  • 按进程名称过滤并记录 CPU 使用情况

    Linux 下有选项吗顶部命令 https www man7 org linux man pages man1 top 1 html我可以在哪里按名称过滤进程并将每秒该进程的 CPU 使用情况写入日志文件 top pgrep 过滤输出top
  • 需要一些建议来开始在 ARM(使用 Linux)平台上编程

    我 也许 很快就会在托管 Linux 发行版的 ARM 平台上工作 我不知道哪个发行版 我知道该项目涉及视频流 但我无法告诉你更多信息 其实我只收到通知 还没见到任何人 我从来没有在这样的平台上工作过 所以我的想法是在项目开始之前进行测试
  • Linux:如何设置进程的时区?

    我需要设置在 Linux 机器上启动的各个进程的时区 我尝试设置TZ变量 在本地上下文中 但它不起作用 有没有一种方法可以使用与系统日期不同的系统日期从命令行运行应用程序 这可能听起来很愚蠢 但我需要一种sandbox系统日期将被更改的地方

随机推荐

  • PX4飞控学习与开发(六)-利用 VScode 修改源码

    努力学习 xff0c 珍惜时间 xff1b 全力以赴 xff0c 创造未来 克制欲望 xff0c 摒除心魔 xff1b 心向何处 xff0c 往来圣贤 功崇惟志 xff0c 业广惟勤 xff1b 惟克果断 xff0c 乃罔后艰 面临困难 x
  • 基于VSCode软件的markdown笔记环境配置

    前期在CSDN上用markdown写了一些博客 xff0c 使用时还是觉得不太方便 xff0c 尤其是在编写公式时 xff0c 效率十分低下 但Markdown本身还是一款非常不错的笔记撰写工具 xff0c 所以一直琢磨着怎么改善其使用体验
  • Ubuntu 主机单系统 安装

    首先是安装系统 xff0c 启动盘是USB HDD模式 xff0c 其他基本和下面这篇文章一样 xff0c 除了安装时候没有Install 然后按e什么的 xff0c 应该是因为我的是20 04吧 史上最全Ubuntu18 04单系统安装教
  • 竞拍算法(Auction Algorithm)原理及工作过程分析

    这几天因一些项目工作 xff0c 需要对竞拍算法进行学习 但百度了大部分资料都未找到一篇文章对此算法有着较为深入的介绍 在一番努力之下 xff0c 终于找到了最初提出该算法的论文 xff0c 本文内容主要结合该论文对竞拍算法进行分析 竞拍算
  • PX4飞控学习与开发(七)-Pixhawk源码中的功能模块分析

    本篇博客主要介绍Firmware固件中各功能模块的基本结构 功能模块的编译 从上篇博客内容中的demo我们可以发现 xff0c 如果我们需要给Pixhawk模块新增一个功能模块 xff0c 一般的做法是新建一个文件夹 xff0c 所有这个功
  • XBee模块实现QGC与PX4飞控的组网通信连接

    本篇博客介绍如何利用XBee模块实现QGC地面站与飞控的通信 一 问题的提出 正如 上一篇博客 指出 xff0c PX4飞控原装数传模块 xff08 3DR Radio xff09 只能一对一通信 xff0c 并不能实现多机组网通信 xff
  • 基于PX4飞控的双机领航-跟踪的理论分析与实验验证

    双机领航 跟踪是最简单的无人机分布式控制 xff0c 是实现大规模集群分布式控制的基础 xff0c 本文主要记录对如何实现双机跟踪护航控制的思考以及验证实验 文章目录 一 理论基础二 仿真实验三 实飞实验 一 理论基础 无人机的位置控制模型
  • MATLAB常用命令及操作

    目录 0 MATLAB注释转到Ubuntu下乱码问题1 矩阵的相关操作2 取整函数3 MATLAB排序4 矩阵构造5 各种线条颜色及形状标记 0 MATLAB注释转到Ubuntu下乱码问题 将文件夹下所有m文件转为UTF 8 xff1a e
  • ubuntu里的QGC编译生成的文件到第二台电脑里运行

    QGC编译生成的文件如下 xff1a 将整个debug文件夹复制过去 xff0c 然后执行以下步骤 xff1a sudo chmod 43 x qgroundcontrol start sh 赋予权限 qgroundcontrol star
  • 2021 SLAM会议论文汇总

    目录 1 ICRA2021语义定位与建图视觉SLAM视觉里程计视觉三维重建视觉惯性里程计跟踪深度估计视觉定位激光雷达定位多传感器数据融合多传感器融合建图激光雷达SLAM激光雷达定位激光雷达建图激光里成计 amp 激光惯性里程计标题点云注册特
  • JavaScript 表单操作以及验证

    大家好 xff0c 我们今天分享一下JavaScript 操作验证表单 首先我们要知道 用JavaScript操作表单和操作DOM是类似的 xff0c 因为表单本身也是DOM树 HTML表单的输入控件 xff08 标签 xff09 主要有以
  • 使用OpenCV查找图像中矩形的位置

    import cv2 image 61 cv2 imread 39 1 jpg 39 blur 61 cv2 pyrMeanShiftFiltering image 11 21 gray 61 cv2 cvtColor blur cv2 C
  • 【GD32F310开发板试用】【001】FreeRTOS移植+“正点原子OLED任务线程”

    首发极术社区 如对兆易创新GD32F310 MCU感兴趣 xff0c 欢迎添加微信 aijishu2020 加入GD32技术讨论群 感谢极术社区提供的SG32F310G测试板 xff0c 尝试移植了一下FreeRTOS顺便点个OLED玩一下
  • apt-get的源

    使用 sudo vim etc apt sources list 修改镜像源 然后执行 sudo apt get update 更新 镜像源如下 xff0c 推荐使用国内源 xff0c 速度更快 镜像源内容转载自 https blog cs
  • Nginx+Keepalived实现站点高可用

    Nginx 43 Keepalived实现站点高可用 发表于 2015 05 18 更新于 2015 05 18 分类于 Linux xff0c Nginx 阅读次数 12301 公司内部 OA 系统要做线上高可用 xff0c 避免单点故障
  • 计算模型的FLOPs

    为了探究影响模型运行时间的变量 xff0c 之前运用了参数量做标准 参数量在TF框架下还是很容易计算的 TF框架下运用 tf span class token punctuation span keras span class token
  • stm32学习之路,方法很重要

    学习stm32已经一个月时间了 xff0c 可算是入门了 相信很多人跟我一样 xff0c 刚开始学的时候会遇到很多问题 xff0c 以及对stm32里面众多寄存器的恐惧 要利用stm32官方给的固件库开发 xff0c 少不了的还是要对寄存器
  • github的使用,及将默认分支main改为master

    一 xff0c 将默认分支main改为master github在2020 10 1宣布上的所有新库都将用中性词 main 命名 xff0c 取代原来的 master xff0c 如果我们通过git push u grigin master
  • module ‘cv2‘ has no attribute ‘aruco‘解决

    pip uninstall opencv python 先卸载 pip install opencv contrib python 使用这个可以解决 opencv contrib python属于加强版 xff0c 除了主模块 xff0c
  • Linux之4G模块串口通信

    在使用AT指令给4G模块发信息的时候 xff0c 我们需要借助到Linux中busybox的microcom工具 xff0c 该工具用来实现与串口之间的通信 xff0c 那怎么自己实现编程跟4G模块发信息 xff0c 以及接收信息把想要的信