Linux环境下使用interrupt方式操作UART

news2024/11/18 10:35:39

目录

概述

1 Linux环境下UART设备

2 轮询方式操作UART功能实现

2.1 打开串口函数:usr_serial_open

2.2 关闭串口函数: usr_serial_close

2.3 发送数据函数: usr_serial_sendbytes

2.4 接收数据函数: usr_serial_readinterrupt

3 完整代码

3.1 usr_serial.c 文件内容

3.1 usr_serial.h 文件内容

4 编写测试代码

4.1 编写测试代码

4.2 编写测试代码的Makefile

5 测试中断模式下串口数据的发送和接收功能


源代码下载地址:Linux环境下使用interrupt方式操作UART资源-CSDN文库

概述

本文介绍Linux环境下使用interrupt方式操作UART的方法,实现了串口打开,关闭,发送数据,接收数据功能,还编写测试代码,验证该功能。

1 Linux环境下UART设备

在linux环境下,UART作为一个终端设备存在,可使用命令, 系统会罗列出该目录下所有的device,其中以tty开头的设备为终端设备。串口也是这些设备之一。

ls /dev/ -l

执行该命令后,可以看见许多以tty开头的设备:

user根据板卡的信息,找到对应的端口,然后才能使用这些串口,笔者使用是基于iMX6ull芯片的板卡,板卡上COM1被用于调试终端,COM3可作为用户终端。

2 轮询方式操作UART功能实现

2.1 打开串口函数:usr_serial_open

函数参数

参数描述
port终端设备: /dev/tty0
baudrate波特率: 1200/2400/4800 ... /115200
databit数据bit位: /5/6/7/8
stopbit停止位:"1" / "1.5" / "2"
parity奇偶位使能: 'N' / 'E' / 'O'

函数实现方法:

代码 43行: 打开端口

代码 49行: 保存termios数据结构中,旧的参数

代码 51行:设置当前用户参数

源代码:

int usr_serial_open( char *port, unsigned int baudrate, 
                     unsigned int databit, const char *stopbit, char parity)
{
    int err;
    
    fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (-1 == fd) {
        fprintf(stderr, "cannot open port %s\n", port);
        return (-1);
    }
    
    tcgetattr (fd, &termios_old);       /* save the form termios value */
      
    err = set_portattr (baudrate, databit, stopbit, parity);
    if ( err ) {
        fprintf ( stderr, "\nport %s cannot set baudrate at %d\n",
                  port, baudrate);
    }
    usr_baudrate = baudrate;
    
    return fd;
}

2.2 关闭串口函数: usr_serial_close

函数实现方法:

代码 64行: 恢复termios default参数

代码 65行:关闭fd端口

void usr_serial_close( void )
{
    /* flush output data before close and restore old attribute */
    tcsetattr(fd, TCSADRAIN, &termios_old);
    close(fd);
}

2.3 发送数据函数: usr_serial_sendbytes

函数参数

参数描述
*data存贮数据的数组
datalength发送的数据长度

函数实现方法:

代码 72行: 使用write函数发送数据

2.4 接收数据函数: usr_serial_readinterrupt

函数参数

参数描述
*data存贮数据的数组
datalength接收的数据长度

函数实现方法:

代码 100~102行: 配置接收中断

代码 104行: 使用read函数写数据

unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength)
{
    int total_len = 0;

    /**
     * caculate the time of 5 characters and get the maxim
     * with 3ms and 5 ch's time
    */
    tv_timeout.tv_sec = 0;
    tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/usr_baudrate));

    while(1){
        FD_ZERO (&fs_read);
        FD_SET (fd, &fs_read);
        select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);
        
        total_len = read(fd, data, datalength);
        if (total_len > 0) {
            printf("Receive %d bytes: %.*s\n", total_len, (char*)data);
            return total_len;
        }
    }

    return total_len;

}

3 完整代码

代码文件命名为usr_serial, 包含两个文件

usr_serial.c
usr_serial.h

3.1 usr_serial.c 文件内容

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : 01_usr_serial.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : linux 串口应用程序接口
其他       : 无
日志       : 初版V1.0 2024/03/01

***************************************************************/
#include "usr_serial.h"

/* Private define ------------------------------------------------------------*/
#define TIMEOUT_SEC(buflen,baud)    (buflen*20/baud+2)
#define TIMEOUT_USEC                 0

#define CH_TO_WAIT 5
#define CH_BITS 11

/* Private variables ---------------------------------------------------------*/
static unsigned int fd;  

static struct timeval tv_timeout;
static struct termios termios_old;
static struct termios termios_new;

static fd_set fs_read;
static unsigned int usr_baudrate;



/* Private function prototypes -----------------------------------------------*/
static speed_t baudrate_to_Bxx (unsigned int baudrate);
static void set_data_bit (unsigned int databit);
static unsigned int set_portattr ( unsigned int baudrate,unsigned int databit, const char *stopbit,char parity);


int usr_serial_open( char *port, unsigned int baudrate, 
                     unsigned int databit, const char *stopbit, char parity)
{
    int err;
    
    fd = open (port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (-1 == fd) {
        fprintf(stderr, "cannot open port %s\n", port);
        return (-1);
    }
    
    tcgetattr (fd, &termios_old);       /* save the form termios value */
      
    err = set_portattr (baudrate, databit, stopbit, parity);
    if ( err ) {
        fprintf ( stderr, "\nport %s cannot set baudrate at %d\n",
                  port, baudrate);
    }
    usr_baudrate = baudrate;
    
    return fd;
}

void usr_serial_close( void )
{
    /* flush output data before close and restore old attribute */
    tcsetattr(fd, TCSADRAIN, &termios_old);
    close(fd);
}

unsigned int usr_serial_sendbytes (void * data, unsigned int datalength)
{
    unsigned int total_len = 0;
    
    total_len = write(fd, data, datalength);

    return (total_len);
}

int usr_serial_readbytes (void *data, unsigned int datalength)
{
    unsigned int total_len = 0;
    total_len = read(fd, data, datalength);
    if (total_len > 0) {
        printf("Receive %d bytes: %.*s\n", total_len, (char*)data);
    }

    return (total_len);
}

unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength)
{
    int total_len = 0;

    /**
     * caculate the time of 5 characters and get the maxim
     * with 3ms and 5 ch's time
    */
    tv_timeout.tv_sec = 0;
    tv_timeout.tv_usec = ( (CH_TO_WAIT * CH_BITS) * (1000000/usr_baudrate));

    while(1){
        FD_ZERO (&fs_read);
        FD_SET (fd, &fs_read);
        select (fd + 1, &fs_read, NULL, NULL, &tv_timeout);
        
        total_len = read(fd, data, datalength);
        if (total_len > 0) {
            printf("Receive %d bytes: %.*s\n", total_len, (char*)data);
            return total_len;
        }
    }

    return total_len;

}

static void set_data_bit (unsigned int databit)
{
    termios_new.c_cflag &= ~CSIZE;
    switch (databit) {
    default:
    case 8:
        termios_new.c_cflag |= CS8;
        break;
    case 7:
        termios_new.c_cflag |= CS7;
        break;
    case 6:
        termios_new.c_cflag |= CS6;
        break;
    case 5:
        termios_new.c_cflag |= CS5;
        break;
    }
}

static void set_stopbit (const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        termios_new.c_cflag &= ~CSTOPB;    /* 1 stop bit */
    }
    else if (0 == strcmp (stopbit, "1.5")) {
        termios_new.c_cflag &= ~CSTOPB;     /* 1.5 stop bits */
    }
    else if (0 == strcmp (stopbit, "2")) {
        termios_new.c_cflag |= CSTOPB;       /* 2 stop bits */
    }
    else {
        termios_new.c_cflag &= ~CSTOPB;     /* 1 stop bit */
    }
}

static void set_parity (char parity)
{
    switch (parity) {
    case 'N':                  /* no parity check */
        termios_new.c_cflag &= ~PARENB;
        break;
    case 'E':                  /* even */
        termios_new.c_cflag |= PARENB;
        termios_new.c_cflag &= ~PARODD;
        break;
    case 'O':                  /* odd */
        termios_new.c_cflag |= PARENB;
        termios_new.c_cflag |= ~PARODD;
        break;
    default:                   /* no parity check */
        termios_new.c_cflag &= ~PARENB;
        break;
    }
}

static speed_t baudrate_to_Bxx (unsigned int baudrate)
{
    switch (baudrate) {
    case 0:
        return (B0);
    case 50:
        return (B50);
    case 75:
        return (B75);
    case 110:
        return (B110);
    case 134:
        return (B134);
    case 150:
        return (B150);
    case 200:
        return (B200);
    case 300:
        return (B300);
    case 600:
        return (B600);
    case 1200:
        return (B1200);
    case 2400:
        return (B2400);
    case 9600:
        return (B9600);
    case 19200:
        return (B19200);
    case 38400:
        return (B38400);
    case 57600:
        return (B57600);
    case 115200:
        return (B115200);
    default:
        return (B9600);
    }
}

static void set_baudrate (unsigned int baudrate)
{
    speed_t speed;
    
    speed = baudrate_to_Bxx (baudrate);  /* set baudrate */
    cfsetispeed(&termios_new, speed);    // set input speed
    cfsetospeed(&termios_new, speed);    // set output speed
}

static unsigned int set_portattr ( unsigned int baudrate,  // 1200 2400 4800 9600 .. 115200
                                   unsigned int databit,   // 5, 6, 7, 8
                                   const char *stopbit,    //  "1", "1.5", "2"
                                   char parity)            // N(o), O(dd), E(ven)
{
    bzero(&termios_new, sizeof (termios_new));
    cfmakeraw (&termios_new);

    set_baudrate (baudrate);
    
    termios_new.c_cflag |= CLOCAL | CREAD;   /* | CRTSCTS */
    
    set_data_bit (databit);
    set_parity (parity);
    set_stopbit (stopbit);
 
    termios_new.c_cc[VTIME] = 1;            /* unit: 1/10 second. */
    termios_new.c_cc[VMIN]  = 255;          /* minimal characters for reading */
    
    return (tcsetattr (fd, TCSANOW, &termios_new));
}



/* End of this file */

3.1 usr_serial.h 文件内容

#ifndef __USR_SERIAL_H
#define __USR_SERIAL_H

#include <termios.h>            /* tcgetattr, tcsetattr */
#include <stdio.h>              /* perror, printf, puts, fprintf, fputs */
#include <unistd.h>             /* read, write, close */
#include <fcntl.h>              /* open */
#include <sys/signal.h>
#include <sys/types.h>
#include <string.h>             /* bzero, memcpy */
#include <limits.h>             /* CHAR_MAX */

#ifdef __cplusplus
extern "C" {
#endif

int usr_serial_open( char *port, unsigned int baudrate, unsigned int databit, const char *stopbit, char parity);
void usr_serial_close( void );

unsigned int usr_serial_sendbytes (void * data, unsigned int datalength);
int usr_serial_readbytes (void *data, unsigned int datalength);
unsigned int usr_serial_readinterrupt (void *data, unsigned int datalength);

#ifdef __cplusplus
}
#endif

#endif /* __USR_SERIAL_H */

4 编写测试代码

4.1 编写测试代码

代码实现功能介绍:

代码 39行:初始化串口设备,设置baud,数据位,停止位等参数

代码 48行:从串口读取数据

代码 55行:向串口写数据

4.2 编写测试代码的Makefile

代码实现功能介绍:

代码 2行:编译器地址

代码 3行:linux内核地址

代码 3行:链接的.o文件名

代码 6行:生成可执行型文件

5 测试中断模式下串口数据的发送和接收功能

使用Make命令编译代码,然后将生成的可执行性文件copy到NFS的共享目录下,然后在板卡中执行。

在代码中,定义要发送的数据如下:

 strcpy(buf, "I am from iMX.6ULL board, hello world! \r\n");

PC端,使用串口调试助手接收数据,详细信息如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv8改进 | 主干篇 | 轻量级的低照度图像增强网络IAT改进YOLOv8暗光检测(全网独家首发)

一、本文介绍 本文给大家带来的改进机制是轻量级的变换器模型&#xff1a;Illumination Adaptive Transformer (IAT)&#xff0c;用于图像增强和曝光校正。其基本原理是通过分解图像信号处理器&#xff08;ISP&#xff09;管道到局部和全局图像组件&#xff0c;从而恢复在低光…

在高并发、高性能、高可用 三高项目中如何设计适合实际业务场景的分布式id(一)

分布式ID组件&#xff1a;黄金链路上的关键基石 在现代分布式系统中&#xff0c;分布式ID组件无疑扮演着至关重要的角色。作为整个系统的黄金链路上的关键组件&#xff0c;它的稳定性和可靠性直接关乎到整个系统的正常运作。一旦分布式ID组件出现问题&#xff0c;黄金链路上的…

微前端之使用无界创建一个微前端项目

wujie 使用手册 使用简介 主应用配置 安装 wujie依赖main.js配置 是否开启预加载 生命周期函数 – lifecycle.js配置 子应用配置 跨域设置运行模式 生命周期改造 在主应用中&#xff0c;使用wujie&#xff0c;将子应用引入到主应用中去 wujie 使用手册 wujie 是一个基于 Web…

加密 / MD5算法 /盐值

目录 加密的介绍 MD5算法 盐值 加密的介绍 加密介绍&#xff1a;在MySQL数据库中, 我们常常需要对密码, 身份证号, 手机号等敏感信息进行加密, 以保证数据的安全性。 如果使用明文存储, 当黑客入侵了数据库时, 就可以轻松获取到用户的相关信息, 从而对用户或者企业造成信息…

11. C语言标准函数库

C语言制定了一组使用方式通用的函数&#xff0c;称为C语言标准函数库&#xff0c;用于实现编程常用功能&#xff0c;标准函数库由编译器系统提供&#xff0c;并按功能分类存储在不同源代码文件中&#xff0c;调用标准库内函数时需要首先使用 #include 连接对应的源代码文件。 【…

MATLAB | MATLAB版玫瑰祝伟大女性节日快乐!!

妇女节到了&#xff0c;这里祝全体伟大的女性&#xff0c;节日快乐&#xff0c;事业有成&#xff0c;万事胜意。 作为MATLAB爱好者&#xff0c;这里还是老传统画朵花叭&#xff0c;不过感觉大部分样式的花都画过了&#xff0c;这里将一段很古老的2012年的html玫瑰花代码转成MA…

Git 内幕探索:从底层文件系统到历史编辑的全面指南

微信搜索“好朋友乐平”关注公众号。 1. Git 底层文件对象 #mermaid-svg-uTkvyr26fNmajZ3n {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-uTkvyr26fNmajZ3n .error-icon{fill:#552222;}#mermaid-svg-uTkvyr26fNmaj…

K8S之实现业务的金丝雀发布

如何实现金丝雀发布 金丝雀发布简介优缺点在k8s中实现金丝雀发布 金丝雀发布简介 金丝雀发布的由来&#xff1a;17 世纪&#xff0c;英国矿井工人发现&#xff0c;金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯&#xff0c;金丝雀也会停止歌唱&#xff1b;当瓦斯…

前端工程化【01】:核心思想、发展历程和面临挑战

前端工程化是指将前端开发中的工具、流程和方法进行规范化和自动化&#xff0c;以提高前端开发效率、提升代码质量和项目可维护性的一种开发方式。通过前端工程化&#xff0c;可以将前端开发过程中的重复工作自动化&#xff0c;减少开发者的重复劳动&#xff0c;提高开发效率。…

✅ Windows11 系统 I 卡独显 A770 安装 深度学习 Pytorch 环境

&#x1f4cb; 文献参考 这里非常感谢知乎上的 ‘丢丢’ 的[**Windows系统下英特尔独显Pytorch的历程**] 为我提供了一开始的 I 卡安装想法&#xff01;但是文中并未介绍如何进行额外的环境变量操作问题&#xff0c;导致很多软件直接安装至系统盘&#xff0c;占用系统盘空间&am…

Go编译报错 link: running gcc failed: exit status 1(已解决)

背景 在对一个开源的Go程序二次开发 重新编译时 &#xff0c; 报错截图如下 报错文字如下&#xff1a;关键信息 link: running gcc failed: exit status 1 $ go build -o orchestrator-didi -i go/cmd/orchestrator/main.go go build: -i flag is deprecated # command-li…

18-Java迭代器模式 ( Iterator Pattern )

Java迭代器模式 摘要实现范例 迭代器模式&#xff08;Iterator Pattern&#xff09;用于顺序访问集合对象的元素&#xff0c;不需要知道集合对象的底层表示 迭代器模式是 Java 和 .Net 编程环境中非常常用的设计模式 迭代器模式属于行为型模式 摘要 1. 意图 提供一种方法…

【MySQL】lower_case_table_names作用及使用

知识点&#xff1a; lower_case_table_names 是mysql设置大小写是否敏感的一个参数。 场景&#xff1a;在使用dataease时&#xff0c;连接外部数据库&#xff0c;启动报错&#xff01;后查看官方文档&#xff0c;特别要求改数据库配置文件&#xff1a;lower_case_table_names …

Service Mesh:如何为您的微服务架构带来可靠性和灵活性

在云原生架构中&#xff0c;Service Mesh 技术成为了微服务架构中不可或缺的一环。本文灸哥将和你一起探讨 Service Mesh 技术的原理、功能和实践&#xff0c;帮助架构师和开发人员更好地理解和应用这一关键技术。 1、Service Mesh 技术概述 Service Mesh 又称为服务网格&…

FPGA 按键控制串口发送

按键消抖 消抖时间一般为10ms&#xff0c;我使用的板子是ACX720&#xff0c;晶振为50MHZ&#xff0c;20ns为一周期。 状态机 模块设计 设计文件 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2023/01/11 12:18:36 // Design Name: // Module Name…

JavaEE进阶(14)Linux基本使用和程序部署(博客系统部署)

接上次博客&#xff1a;JavaEE进阶&#xff08;13&#xff09;案例综合练习——博客系统-CSDN博客 目录 程序配置文件修改和打包 构建项目并打包 分平台配置 数据准备 上传jar包到云服务器并运行 开放端口号 验证程序 如何查看日志得到报错信息 常见问题 关于Linux基…

【自然语言处理】NLP入门(五):1、正则表达式与Python中的实现(5):字符串常用方法:对齐方式、大小写转换详解

文章目录 一、前言二、正则表达式与Python中的实现1.字符串构造2. 字符串截取3. 字符串格式化输出4.字符转义符5. 字符串常用函数函数与方法之比较 6. 字符串常用方法1. 对齐方式center()ljust()rjust() 2. 大小写转换lower()upper()capitalize()title()swapcase() 一、前言 本…

maven项目结构管理统一项目配置操作

一、maven分模块开发 Maven 分模块开发 1.先创建父工程&#xff0c;pom.xml文件中&#xff0c;打包方式为pom 2.然后里面有许多子工程 3.我要对父工程的maven对所有子工程进行操作 二、解读maven的结构 1.模块1 <groupId>org.TS</groupId><artifactId>TruthS…

Java基于微信小程序的医院挂号系统(V2.0),附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal ThreadLocal(TL) 后续部分地方会使用ThraedLocal简称为TL 什么是TL? ThreadLocal是Java中的一个类, 也称为线程本地变量, 它提供了线程局部变量的功能。每个ThreadLocal对象都可以存储一个线程本地的变量副…