《Linux C》串口编程

转自:https://blog.csdn.net/herghost/article/details/51251760

  • 如何找到串口设备号
  • 串口之打开操作
  • 串口之初始化
  • 串口之发送
  • 串口之接收

如何找到串口设备号

如果你使用的是开发板搭载linux系统进行的串口编程,你可以通过原理图进行查看 
如果你电脑安装的linux系统,那么插上串口,通过dmesg命令进行查看 
本文例子使用/dev/ttyS0


串口之打开操作

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(){
    int fd;
    char *com = "/dev/ttyS0";
    if((fd = open(com,O_RDWR|O_CREAT,0777))<0){
        //fd返回-1打开失败
    }else{
        //打开成功
    }
    return 0;
}

串口之初始化

  • 了解termio结构体
  • 常用初始化函数 
    • tcgetattr函数
    • cfgetispeed函数
    • cfgetospeed函数
    • cfsetispeed函数
    • cfsetospeed函数
    • tcflush函数
    • tcsetattr函数
  • 初始化步骤 
    • 读取当前参数
    • 修改参数
    • 配置参数

了解termio结构体

struct termios
{
           tcflag_t c_iflag;//输入模式
           tcflag_t c_oflag;//输出模式
           tcflag_t c_cflag;//控制模式
           tcflag_t c_lflag;//本地模式
           cc_t     c_cc[NCCS];//控制字符
};

c_iflag参数如下:

键值 说明
IGNBRK 忽略BREAK键输入
BRKINT 如果设置了IGNBRK,BREAK键输入将被忽略
IGNPAR 忽略奇偶校验错误
PARMRK 标识奇偶校验错误
INPCK 允许输入奇偶校验
ISTRIP 去除字符的第8个比特
INLCR 将输入的NL(换行)转换成CR(回车)
IGNCR 忽略输入的回车
ICRNL 将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC 将输入的大写字符转换成小写字符(非POSIX)
IXON 允许输出时对XON/XOFF流进行控制
IXANY 输入任何字符将重启停止的输出
IXOFF 允许输入时对XON/XOFF流进行控制
IMAXBEL 当输入队列满的时候开始响铃

c_oflag参数如下:

键值 说明
OPOST 处理后输出
OLCUC 将输入的小写字符转换成大写字符(非POSIX)
ONLCR 将输入的NL(换行)转换成CR(回车)及NL(换行)
OCRNL 将输入的CR(回车)转换成NL(换行)
ONOCR 第一行不输出回车符
ONLRET 不输出回车符
OFILL 发送填充字符以延迟终端输出
OFDEL 以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL
NLDLY 换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY 回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY 水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY 空格输出延迟,可以取BS0或BS1
VTDLY 垂直制表符输出延迟,可以取VT0或VT1
FFDLY 换页延迟,可以取FF0或FF1

c_cflag参数如下:

参数 说明
CBAUD 波特率(4+1位)(非POSIX)
CBAUDEX 附加波特率(1位)(非POSIX)
CSIZE 字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB 设置两个停止位
CREAD 使用接收器
PARENB 使用奇偶校验
PARODD 对输入使用奇偶校验,对输出使用偶校验
HUPCL 关闭设备时挂起
CLOCAL 忽略调制解调器线路状态
CRTSCTS 使用RTS/CTS流控制

c_lflag参数如下:

参数 说明
ISIG 当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON 使用标准输入模式
XCASE 在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO 显示输入字符
ECHOE 如果ICANON同时设置,ERASE将删除输入的字符
ECHOK 如果ICANON同时设置,KILL将删除当前行
ECHONL 如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT 如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP 向后台输出发送SIGTTOU信号

c_cc[NCCS]参数如下:

说明 说明
VINTR Interrupt字符 VEOL 附加的End-of-file字符
VQUIT Quit字符 VTIME 非规范模式读取时的超时时间
VERASE Erase字符 VSTOP Stop字符
VKILL Kill字符 VSTART Start字符
VEOF End-of-file字符 VSUSP Suspend字符
VMIN 非规范模式读取时的最小字符数    

常用初始化函数  

  • tcgetattr函数
  • cfgetispeed函数
  • cfgetospeed函数
  • cfsetispeed函数
  • cfsetospeed函数
  • tcflush函数
  • tcsetattr函数
读取当前参数函数:
int tcgetattr(int fd,struct termios *termios_p)
    fd:open操作后返回的文件句柄
    *termios_p:为前面介绍的结构体
    初始化开始前调用这个函数.

获取当前波特率函数:
int speed_t cfgetispeed(const struct termios *termios_p)
int speed_t cfgetospeed(const struct termios *termios_p)
    *termios_p:为前面介绍的结构体
    成功返回0,失败返回-1

波特率设置函数:
int cfsetispeed(struct termios *termios_p,speed_t speed)
int cfsetospeed(struct termios *termios_p,speed_t speed)
    *termios_p:为前面介绍的结构体
    speed:波特率,常用B2400,B4800,B9600,B115200,B460800
    成功返回0,失败返回-1

清空buffer数据函数:
int tcflush(int fd,int queue_selector)
    queue_selector:有三个常用宏定义
                    TCIFLUSH:清空正读的数据,且不会读出
                    TCOFLUSH:清空正写入的数据,且不会发送到终端
                    TCIOFLUSH:清空所有正在发生的I/O数据.
    成功返回0,失败返回-1

设置串口参数函数:
int tcsetattr(int fd,int optional_actions,cons struct termios *termios_p)
    optional_actions:有三个常用宏定义
                    TCSANOW:不等数据传输完毕,立即改变属性
                    TCSADRAIN:等所有数据传输完毕,再改变属性
                    TCSAFLUSH:清空输入输出缓冲区才改变属性
    成功返回0,失败返回-1                

初始化设置代码如下:

/**
*fd:文件句柄
*nSpeed:波特率
*nBits:数据位
*nEvent:奇偶校验
*nStop:停止位
/
int set_opt(int fd,int nSpeed,int nBits,int nEvent ,int nStop){
        struct termios newtio,oldtio;
        if(tcgetattr(fd,&oldtio)!=0){
            //错误
            return -1;
        }
        bzero(&newtio,sizeof(newtio));
        newtio.c_cflag |=  CLOCAL|CREAD;
        newtio.c_cflag &= ~CSIZE;

        switch(nBits){//设置数据位
            case 7:
                    newtio.c_cflag |= CS7;
                    break;
            case 8:
                    newtio.c_cflag |= CS8;      
                    break;
        }

        switch(nEvent){//设置奇偶校验位
            case 'O':
                newtio.c_cflag |=PARENB;
                newtio.c_cflag |=PARODD;
                newtio.c_iflag |=(INPCK|ISTRIP);
                break;
            case 'E':
                newtio.c_iflag |=(INPCK|ISTRIP);
                newtio.c_cflag |=PARENB;
                newtio.c_cflag &=~PARODD;
                break;
            case 'N':
                newtio.c_cflag &=~PARENB;
                break;
        }

        switch(nSpeed){
            case 2400:
                cfsetispeed(&newtio,B2400);
                cfsetospeed(&newtio,B2400);
                break;
            case 4800:
                cfsetispeed(&newtio,B4800);
                cfsetospeed(&newtio,B4800);
                break;
            case 9600:
                cfsetispeed(&newtio,B9600);
                cfsetospeed(&newtio,B9600);
                break;
            case 115200:
                cfsetispeed(&newtio,B115200);
                cfsetospeed(&newtio,B115200);
                break;
            case 460800:
                cfsetispeed(&newtio,B460800);
                cfsetospeed(&newtio,B460800);
                break;
            default:
                cfsetispeed(&newtio,B9600);
                cfsetospeed(&newtio,B9600);
                break;
        }
        if(nStop==1){//停止位设置
            newtio.c_cflag &= ~CSTOPB;
        }else if(nStop==2){
            newtio.c_cflag |= CSTOPB;
        }
        newtio.c_cc[VTIME] = 0;
        newtio.c_cc[VMIN] = 0;
        tcflush(fd,TCIFLUSH);
        if((tcsetttr(fd,TCSANOW,&newtio))!=0){
            //com set error
            return -1;
        }
        return 0;
}

串口之发送与接收

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>

int set_opt(int,int,int,char,int);
void main()
{
    int fd;
    char *com= "/dev/ttyS0";
    char *buffer = "hello world!\n";

    if((fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY))<0){
        printf("open %s is failed",com);
    }
    else{
        printf("open %s is success\n",com);
        set_opt(fd, 115200, 8, 'N', 1); 
        wr_static = write(fd,buffer, strlen(buffer));
        //读取差不多一样的这里就不介绍了
            if(wr_static<0)
                printf("write failed\n");
            else
                printf("wr_static is %d\n",wr_static);
            close(fd);
       }
}


int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
    if  ( tcgetattr( fd,&oldtio)  !=  0) { 
        return -1;//读取参数错误
    }
    bzero( &newtio, sizeof( newtio ) );
    newtio.c_cflag  |=  CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

    switch( nBits )
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch( nEvent )
    {
    case 'O':
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E': 
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':  
        newtio.c_cflag &= ~PARENB;
        break;
    }

    switch( nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
    if( nStop == 1 )
        newtio.c_cflag &=  ~CSTOPB;
    else if ( nStop == 2 )
    newtio.c_cflag |=  CSTOPB;
    newtio.c_cc[VTIME]  = 0;
    newtio.c_cc[VMIN] = 0;
    tcflush(fd,TCIFLUSH);
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");
        return -1;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wenjin359/article/details/82906463
今日推荐