嵌入式Linux串口编程简介

简介: 嵌入式Linux串口编程简介

简介


嵌入式Linux下串口编程与Linux系统下的编程没有什么区别,系统API都是一样的。嵌入式设备中串口编程是很常用的,比如会对接一些传感器模块,这些模块大多是RS232或者RS485接口,对于软件层面上来说,RS232与RS48区别不大。RS232与RS485在使用上的区别,RS232是全双工的,只能对接一个设备串口设备。RS485是半双工的总线协议,一般可以挂多个传感器设备,半双工的意思是同时只能有一个设备向串口发数据。


用到的API函数

函数 说明
open 打开设备,用于打开串口设备
fcntl 修改设备描述符属性参数
isatty 检测打开的描述符是否指向一个终端
tcgetattr 用来获取串口终端参数
cfmakeraw 将终端设置为原始模式,该模式下所有的输入数据以字节为单位被处理
tcflush 用于清空输入、输出缓冲区
tcsetattr 设置串口终端参数
read 读取数据
write 写数据
close 关闭串口设备


代码

#include<termios.h>
#include "uart.h"

/***************************************
*name    : open_port
*功能描述: 打开串口
*入口参数: 串口号
*返 回 值: 成功返回文件描述符,失败返回负值
*作    者: 
*修改时间:
***************************************/
int open_port(const char * com_port)
{
    int fd;

  if( com_port == NULL ){
        printf("the port name is null\n");
        return -1;
    }
    /*open port*/
    fd = open(com_port, O_RDWR | O_NOCTTY | O_NDELAY);
    if(fd < 0){
        fd = open(com_port, O_RDWR | O_NOCTTY | O_NDELAY);
        if(fd < 0){
            perror("open serial port");
            return -1;
        }
    }
    printf("open %s OK!\n", com_port);
    if(fcntl(fd, F_SETFL,0) < 0){
        perror("fcntl F_SETFL");
    }

    if(isatty(fd) == 0){
        perror("isatty is not a terminal device");
    }
    return fd;
}

/******************************
*name    : set_port
*功能描述: 设置串口参数
*入口参数: fd 文件描述符, baud_rate 波特率, data_bits 数据位,
*          parity 奇偶校验, stop_bits 停止位
*     调用示例: set_port(fd, 115200, 8, 'N',1);
*返 回 值: 成功返回0,失败返回-1
*作    者: 
*修改: 
******************************/
int set_port(int fd, int baud_rate,
             int data_bits, char parity, int stop_bits)
{
    struct termios new_cfg, old_cfg;
    int speed_arry[]= {B2400, B4800, B9600, B19200, B38400,B57600, B115200};
    int speed[]={2400,4800,9600,19200,38400,57600,115200};
    int i = 0;

    /*save and test the serial port*/
    if(tcgetattr(fd, &old_cfg) < 0){
        perror("tcgetattr");
        return -1;
    }
  
  if(fcntl(fd,F_SETFL,0) < 0)//恢复为阻塞模式
  {
    perror("fcntl(CzjFd,F_SETFL,0)!");
  }

    new_cfg = old_cfg;
    cfmakeraw(&new_cfg);     //配置为原来配置
    new_cfg.c_cflag &= ~ CSIZE;     //用数据位掩码清空数据位的设置

    /*set baud_rate*/
    for(i = sizeof(speed_arry) / sizeof(speed_arry[0]); i > 0; i--)
    {
        if(baud_rate == speed[i]){
            cfsetispeed(&new_cfg,speed_arry[i]);
            cfsetospeed(&new_cfg,speed_arry[i]);
        }
    }

    switch(data_bits)    /*设置数据位*/
    {
        case 7:
                new_cfg.c_cflag |= CS7;
                break;

        default:
        case 8:
                new_cfg.c_cflag |= CS8;
                break;
    }

    switch(parity)
    {
        default:
        case 'N':
        case 'n':
        {
            new_cfg.c_cflag &= ~PARENB;     //清除校验位
            new_cfg.c_iflag &= ~(ICRNL|INPCK|IXON|IXOFF);      //关闭奇偶校验  关闭软件流控
            
      break;
        }

        case 'o':
        case 'O':
        {
            new_cfg.c_cflag |= (PARODD | PARENB); //使用奇校验不是用偶校验
            new_cfg.c_iflag |= INPCK;
      break;
        }

        case 'e':
        case 'E':
        {
            new_cfg.c_cflag |= PARENB;
            new_cfg.c_cflag &= ~PARODD;     //使用偶校验
      new_cfg.c_iflag |= INPCK;
      break;
        }

        case 's':
        case 'S':
        {
            new_cfg.c_cflag &= ~PARENB;
            new_cfg.c_cflag &= ~CSTOPB;
      break;
        }
    }
  
    new_cfg.c_iflag &= ~(ICRNL| IXON | IXOFF  );      //关闭奇偶校验  关闭软件流控
  new_cfg.c_oflag &= ~OPOST;

    switch(stop_bits)
    {
        default:
        case 1:
        {
            new_cfg.c_cflag &= ~CSTOPB;
            new_cfg.c_cflag &= ~CRTSCTS;   //禁用硬件流控
            //new_cfg.c_cflag |= CRTSCTS;    //启用硬件流控
      break;
        }
        case 2:
        {
            new_cfg.c_cflag |= CSTOPB;
      break;
    }
    }

    /*set wait time*/
    new_cfg.c_cc[VTIME] = 0;
    new_cfg.c_cc[VMIN]  = 1;

    tcflush(fd, TCIFLUSH);   //处理未接收字符
  if((tcsetattr(fd, TCSANOW, &new_cfg)) < 0)
    {
        perror("tcsetattr");
        return -1;
    }

    return 0;
}



调用测试代码:

#include "uart.h"
#include <stdio.h>
#include <unistd.h>


int main()
{
  int fd = open_port("/dev/ttyS1");
  if ( fd < 0 )
  {
    perror("open port");
    return -1;
  }
  
  set_port(fd, 115200, 8, 'N',1);
  
  char readBuf[32] ={0};
  const char *pstr="hello world";
  write(fd, pstr, strlen(pstr)+1);
  
  read(fd, readBuf, sizeof(readBuf));
  
  close(fd);
}

目录
相关文章
|
1月前
|
网络协议 算法 Linux
【嵌入式软件工程师面经】Linux网络编程Socket
【嵌入式软件工程师面经】Linux网络编程Socket
68 1
|
3天前
|
Ubuntu 算法 Linux
嵌入式Linux的学习误区
**嵌入式Linux学习误区摘要** 1. **过度聚焦桌面Linux** - 许多学习者误将大量时间用于精通桌面Linux系统(如RedHat、Fedora、Ubuntu),认为这是嵌入式Linux开发的基石。 - 实际上,桌面Linux仅作为开发工具和环境,目标不应是成为Linux服务器专家,而应专注于嵌入式开发工具和流程。 2. **盲目阅读Linux内核源码** - 初学者在不了解Linux基本知识时试图直接研读内核源码,这往往导致困惑和挫败感。 - 在具备一定嵌入式Linux开发经验后再有针对性地阅读源码,才能有效提升技能。
13 4
|
22天前
|
Linux 网络安全 开发工具
linux 常用命令【编程必备】
linux 常用命令【编程必备】
31 4
|
22天前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
|
22天前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
|
1月前
|
算法 Linux 测试技术
Linux编程:测试-高效内存复制与随机数生成的性能
该文探讨了软件工程中的性能优化,重点关注内存复制和随机数生成。文章通过测试指出,`g_memmove`在内存复制中表现出显著优势,比简单for循环快约32倍。在随机数生成方面,`GRand`库在1000万次循环中的效率超过传统`rand()`。文中提供了测试代码和Makefile,建议在性能关键场景中使用`memcpy`、`g_memmove`以及高效的随机数生成库。
|
1月前
|
消息中间件 安全 Java
【嵌入式软件工程师面经】Linux多进程与多线程
【嵌入式软件工程师面经】Linux多进程与多线程
26 1
|
1月前
|
存储 缓存 Unix
【嵌入式软件工程师面经】Linux文件IO
【嵌入式软件工程师面经】Linux文件IO
25 1
|
1月前
|
机器学习/深度学习 Unix Java
技术笔记:Linux之Shell脚本编程(一)
技术笔记:Linux之Shell脚本编程(一)
31 0
|
1月前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
59 1