Linux 串口驱动

 

1 串口本质上也是字符设备 !!!!!!!!!!!!串口是不支持热拔插的。如果强行热拔插,容易损坏串口芯片!!!!!!!!!!!!!!!!!!!!!

名词解释:流控 "软件”流控制 :帧头帧尾

                          “硬件”流控制:信号线

一。流程

                                          个人建议只要能够读懂代码,根据实际需求进行验证和配置即可。

1打开串口,一般使用 open 函数,打开之后会返回句柄,这个句柄就可以提供给发送和接收函数使用。

2初始化串口,串口需要配置波特率,数据位,校验位等等一系列的参数,初始化的过程掌握了,发送和接收都比较容易实现。

3发送和接收数据,前面提到过串口是属于字符设备的,可以使用 read 函数和 write 函数实现。

4关闭,使用函数 close 即可关闭串口。

1打开串口

1.1确认设备节点 dev目录下,在 4412 开发板中,设备节点使用的是 ttySAC*系列(0-3)

1.2原理图上对应:先在底板上找到外设,在到核心板上找对应的引脚名称

1.3例程:打开串口设备节点

 

2初始化串口

 

2.1 open()读取句柄

 

2.2 struct termio 来自内核文件arch\arm\include\asm

成员 tcflag_t c_iflag:输入模式标志

成员 tcflag_t c_oflag:输出模式标志

成员 tcflag_t c_cflag:控制模式标志

成员 tcflag_t c_lflag:本地模式标志

成员 cc_t c_line:line discipline

成员 cc_t c_cc[NCC]:control characters

 

2.3 #include <termios.h>

#include <unistd.h> //配置串口通用头文件

int tcgetattr(int fd, struct termios *termios_p)//读取当前串口参数

参数 1:fd 是 open 返回的文件句柄。

参数 2:*termios_p 是前面介绍的结构体

执行成功返回 0,失败返回-1

 

int cfsetispeed(struct termios *termios_p, speed_t speed);//修改输入波特率

int cfsetospeed(struct termios *termios_p, speed_t speed);修改输出波特率

参数 1:*termios_p 是前面介绍的结构体。

参数 2:speed 波特率,常用的 B2400,B4800,B9600,B115200,B460800 等等。

执行成功返回 0,失败返回-1

 

speed_t cfgetispeed(const struct termios *termios_p)//读取当前串口输入的波特率

speed_t cfgetospeed(const struct termios *termios_p)//读取当前输出的波特率

 

int tcflush(int fd, int queue_selector);用于清空串口中没有完成的输入或者输出数据。在接收或者发送数据的时候,

串口寄存器会缓存数据,这个函数用于清除这些数据

参数 1:fd 是 open 返回的文件句柄。

参数 2:控制 tcflush 的操作。

TCIFLUSH 清除正收到的数据,且不会读取出来;

TCOFLUSH 清除正写入的数据,且不会发送至终端;

TCIOFLUSH 清除所有正在发生的 I/O 数据。

执行成功返回 0,失败返回-1

 

int tcsetattr(int fd, int optional_actions,const struct termios *termios_p);设置参数

参数 1:fd 是 open 返回的文件句柄。

参数 2:optional_actions 是参数生效的时间。

TCSANOW:不等数据传输完毕就立即改变属性;

TCSADRAIN:等待所有数据传输结束才改变属性;

TCSAFLUSH:清空输入输出缓冲区才改变属性

参数 3:*termios_p 在旧的参数基础上修改的后的参数

执行成功返回 0,失败返回-1

 

2.4代码

A 函数不懂用man命令查,里面有详细的参数介绍

B 关于阻塞与非阻塞要讨论(已解决)

C uartinit01.c ----pds

D 总是读不出数,可能是open函数的选项选错了(不是这个原因,但是参数要好好看)


这仅仅是应用程序,不是驱动程序,驱动程序是直接调用4412开发板写好的串口驱动,今后有时间去看一下

 

#include<stdio.h>        //标准输出头文件
#include<sys/types.h>    //文件操作头文件1
#include<sys/stat.h>    //文件操作头文件2
#include<fcntl.h>       //文件操作头文件3
#include<unistd.h>        //文件操作头文件4
#include<string.h>      //strlen()函数需要 
#include<termios.h>     //串口头文件
#include<error.h>       //Linux定义错误的头文件

int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop);

void main()
{
    int fd,w,i;
    char *uart3 ="/dev/ttySAC3";//需要改动
    char *buffer= "please input";
    char buffer1[100];
    memset(buffer1,0,sizeof(buffer1));
    if((fd = open(uart3,O_RDWR|O_CREAT,0777))<0)
    {
      printf("open %s failed!\n",uart3);    
    }else 
    {
      printf("open %s success!!\n",uart3);
      set_opt(fd,115200,8,'N',1);
      w = write(fd,buffer,strlen(buffer));
      while(1)
      {
          if ((i= read(fd,buffer1,100))>0);
          {
             w = write(fd,buffer1,strlen(buffer1));
             memset(buffer1,0,sizeof(buffer1));
             i=0;
          }
      }
    }
    close(fd);
    
    
}
int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop)
{
    struct termios newtio,oldtio;
    if(tcgetattr(fd,&oldtio) !=0){
        perror("SetupSerial 1");
        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);
           cfsetispeed(&newtio,B2400);
           break;
        case 4800 :
           cfsetispeed(&newtio,B4800);
           cfsetispeed(&newtio,B4800);
           break;
        case 9600 :
           cfsetispeed(&newtio,B9600);
           cfsetispeed(&newtio,B9600);
           break;
        case 115200 :
           cfsetispeed(&newtio,B115200);
           cfsetispeed(&newtio,B115200);
           break;
        default :
           cfsetispeed(&newtio,B9600);
           cfsetispeed(&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;
    
    
}


 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页