当前位置:文档之家› linux内核通信-netlink

linux内核通信-netlink

linux内核通信-netlink
linux内核通信-netlink

一、Netlink介绍

前面有一篇文章其实已经介绍过Netlink方面的知识,还有一个内核和用户空间之间的一个交互例子,这篇文章主要是更细节和基础的知识介绍!

Netlink 是一种特殊的 socket,它是 Linux 所特有的,由于传送的消息是暂存在socket接收缓存中,并不被接收者立即处理,所以netlink是一种异步通信机制。系统调用和 ioctl 则是同步通信机制。

用户空间进程可以通过标准socket API来实现消息的发送、接收,在Linux 中,有很多用户空间和内核空间的交互都是通过Netlink机制完成的,在Linux3.0的内核版本中定义了下面的21个用于Netlink通信的宏,其中默认的最大值为32.我这里重点关注的是IPv6路由部分的通信过程。

在include/linux/`netlink.h文件中定义了下面的用于通信的宏!

#define NETLINK_ROUTE 0 /* Routing/device hook */

#define NETLINK_UNUSED 1 /* Unused number */

#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols*/ #define NETLINK_FIREWALL 3 /* Firewalling hook */

#define NETLINK_INET_DIAG 4 /* INET socket monitoring */

#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */

#define NETLINK_XFRM 6 /* ipsec */

#define NETLINK_SELINUX 7 /* SELinux event notifications */

#define NETLINK_ISCSI 8 /* Open-iSCSI */

#define NETLINK_AUDIT 9 /* auditing */

#define NETLINK_FIB_LOOKUP 10

#define NETLINK_CONNECTOR 11

#define NETLINK_NETFILTER 12 /* netfilter subsystem */

#define NETLINK_IP6_FW 13

#define NETLINK_DNRTMSG 14 /* DECnet routing messages */

#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ #define NETLINK_GENERIC 16 /* leave room for NETLINK_DM (DM Events)*/ #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */

#define NETLINK_ECRYPTFS 19

#define NETLINK_RDMA 20

#define MAX_LINKS 32

二、Socket API

用户态可以使用标准的socket APIs, socket(), bind(), sendmsg(), recvmsg() 和 close() 等函数就能很容易地使用 netlink socket,我们在用户空间可以直接通过socket函数来使用Netlink通信,例如可以通过下面的方式:

1、socket

sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

说明:第一个参数必须是 AF_NETLINK 或 PF_NETLINK,在 Linux 中,它们俩实际为一个东西,它表示要使用netlink,第二个参数必须是SOCK_RAW或SOCK_DGRAM,第三个参数指定netlink协议类型,可以是自己在netlink.h中定义的,也可以是内核中已经定义好的。上面的例子使用主要是路由的Netlink 协议。也可以是上面21中协议类型的其中之一。

NETLINK_GENERIC是一个通用的协议类型,它是专门为用户使用的,因此,用户可以直接使用它,而不必再添加新的协议类型。

对于每一个netlink协议类型,可以使用多播的概念,最多可以有 32个多播组,每一个多播组用一个位表示,netlink 的多播特性使得发送消息给同一个组仅需要一次系统调用,因而对于需要多播消息的应用而言,大大地降低了系统调用的次数。

下面介绍一下主要的数据结构:

struct sockaddr_nl {

sa_family_t nl_family;/* AF_NETLINK */

unsigned short nl_pad;/* zero */

__u32 nl_pid;/* port ID */

__u32 nl_groups;/* multicast groups mask */

};

说明:

1)sa_family_t nl_family; 一般为AF_NETLINK,

2)unsigned short nl_pad; 字段 nl_pad 当前没有使用,因此要总是设置为 0。

3)__u32 nl_pid; 绑定时用于指定绑定者的进程号,发送消息时用于指定接收进程号,如果希望内核处理多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。传递给 bind 函数的地址的 nl_pid 字段应当设置为本进程的进程 ID,这相当于 netlink socket 的本地地址。但是,对于一个netlink socket 的情况,字段 nl_pid 则可以设置为其它的值,如:

pthread_self() << 16 | getpid();

因此字段 nl_pid 实际上未必是进程 ID,它只是用于区分不同的接收者或发送者的一个标识,用户可以根据自己需要设置该字段。

4) __u32 nl_groups;绑定时用于指定绑定者所要加入的多播组,这样绑定者就可以接收多播消息,发送消息时可以用于指定多播组,这样就可以将消息发给多个接收者。这里nl_groups 为32位的无符号整形,所以可以指定32个多播组,每个进程可以加入多个多播组,因为多播组是通过“或”操作,如果设置为 0,表示调用者不加入任何多播组。这里就是Netlink多播的概念!和通信中的多播概念有点类似。

2、bind

Bind的调用方式如下!

struct sockaddr_nl snl;

memset (&snl, 0, sizeof snl);

snl.nl_family = AF_NETLINK;

snl.nl_groups = groups;

ret = bind (sock,(struct sockaddr *)&snl, sizeof snl);

其中sock为前面的 socket 调用返回的文件描述符,参数snl为 struct sockaddr_nl 类型的地址。为了发送一个 netlink 消息给内核或其他用户态应用,需要填充目标 netlink socket 地址,此时,字段 nl_pid 和 nl_groups 分别表示接收消息者的进程 ID 与多播组。如果字段 nl_pid 设置为 0,表示消息接收者为内核或多播组,如果 nl_groups为 0,表示该消息为单播消息,否则表示多播消息。

3、sendmsg

用户态使用函数 sendmsg 发送 netlink 消息时还需要引用结构 struct msghdr、struct nlmsghdr 和 struct iovec,结构 struct msghdr 的定义如下:

struct msghdr {

void * msg_name;/* Socket name */

int msg_namelen;/* Length of name */

struct iovec * msg_iov;/* Data blocks */

__kernel_size_t msg_iovlen;/* Number of blocks */

void * msg_control; /*Per protocol magic (eg BSD file descriptor passing)*/ __kernel_size_t msg_controllen;/* Length of cmsg list */

unsigned msg_flags;

};

使用方法如下:

struct msghdr msg;

memset(&msg, 0, sizeof(msg));

msg.msg_name =(void *)&(snl);

msg.msg_namelen = sizeof(snl);

struct nlmsghdr 为 netlink socket 自己的消息头,因此它也被称为netlink 控制块。应用层在向内核发送 netlink 消息时必须提供该控制头。

消息头

struct nlmsghdr

{

__u32 nlmsg_len;/* Length of message including header */

__u16 nlmsg_type;/* Message content */

__u16 nlmsg_flags;/* Additional flags */

__u32 nlmsg_seq;/* Sequence number */

__u32 nlmsg_pid;/* Sending process PID */

};

字段 nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小,字段 nlmsg_type 用于应用内部定义消息的类型,它对netlink 内核实现是透明的,因此大部分情况下设置为 0,字段 nlmsg_seq 和 nlmsg_pid 用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID。字段

nlmsg_flags 用于设置消息标志,可用的标志包括下面的宏定义:

kernel/include/linux/netlink.c

/* Flags values */

#define NLM_F_REQUEST 1 /* It is request message. */

#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */

#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */

#define NLM_F_ECHO 8 /* Echo this request */

/* Modifiers to GET request */

#define NLM_F_ROOT 0x100 /* specify tree root*/

#define NLM_F_MATCH 0x200 /* return all matching*/

#define NLM_F_ATOMIC 0x400 /* atomic GET*/

#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)

/* Modifiers to NEW request */

#define NLM_F_REPLACE 0x100 /* Override existing */

#define NLM_F_EXCL 0x200 /*Do not touch,if it exists */

#define NLM_F_CREATE 0x400 /* Create,if it does not exist */

#define NLM_F_APPEND 0x800 /* Add to end of list */

标志NLM_F_REQUEST用于表示消息是一个请求,所有应用首先发起的消息都应设置该标志。

标志NLM_F_MULTI 用于指示该消息是一个多部分消息的一部分,后续的消息可以通过宏NLMSG_NEXT来获得。

宏NLM_F_ACK表示该消息是前一个请求消息的响应,顺序号与进程ID可以把请求与响应关联起来。

标志NLM_F_ECHO表示该消息是相关的一个包的回传。

标志NLM_F_ROOT 被许多 netlink 协议的各种数据获取操作使用,该标志指示被请求的数据表应当整体返回用户应用,而不是一个条目一个条

地返回。有该标志的请求通常导致响应消息设置 NLM_F_MULTI标志。注意,当设置了该标志时,请求是协议特定的,因此,需要在字段

nlmsg_type 中指定协议类型。

标志 NLM_F_MATCH 表示该协议特定的请求只需要一个数据子集,数据子集由指定的协议特定的过滤器来匹配。

标志 NLM_F_ATOMIC 指示请求返回的数据应当原子地收集,这预防数据在获取期间被修改。

标志 NLM_F_DUMP 未实现。

标志 NLM_F_REPLACE 用于取代在数据表中的现有条目。

标志 NLM_F_EXCL_ 用于和 CREATE 和 APPEND 配合使用,如果条目已经存在,将失败。

标志 NLM_F_CREATE 指示应当在指定的表中创建一个条目。

标志 NLM_F_APPEND 指示在表末尾添加新的条目。

内核需要读取和修改这些标志,对于一般的使用,用户把它设置为 0 就可以,只是一些高级应用(如 netfilter 和路由 daemon 需要它进行一些设置),

下面是在调用sendmsg函数之前的各个结构体的赋值操作:

struct nlmsghdr *n

struct iovec iov ={(void*) n, n->nlmsg_len };

struct msghdr msg ={(void*)&snl, sizeof snl,&iov, 1,NULL, 0, 0};

其中snl为 struct sockaddr_nl snl;在结构体struct msghdr中包含有struct iovec结构,其实就是我们要传输的数据块,它为一个指针,定义了数据块的基址和长度。

struct iovec{

void __user * iov_base;/* BSD uses caddr_t (1003.1g requires void *)*/

__kernel_size_t iov_len;/* Must be size_t (1003.1g)*/

};

上面的数据结构全部初始化以后就可以调用sendmsg函数进行发送操作了。

status = sendmsg (sock,&msg, 0);

其中sock就是我们创建的sock套接字,msg就是上面结构体struct msghdr 的实例。如果我们需要返回一个ACK消息,可以对flags标志进行设置如下:

/* Request an acknowledgement by setting NLM_F_ACK */

n->nlmsg_flags |= NLM_F_ACK;

4、recvmsg

使用下面的函数进行接收处理时,status;为返回的状态,这里可能的结果为:

#define NLMSG_NOOP 0x1 /*Nothing.*/

#define NLMSG_ERROR 0x2 /*Error*/

#define NLMSG_DONE 0x3 /*End of a dump */

#define NLMSG_OVERRUN 0x4 /* Data lost

int status;

char buf[4096];

struct iovec iov ={ buf, sizeof buf };

struct sockaddr_nl snl;

struct msghdr msg ={(void*)&snl, sizeof snl,&iov, 1,NULL, 0, 0};

struct nlmsghdr *h;

status = recvmsg (sock,&msg, 0);

在linux/netlink.h中定义了一些方便对消息进行处理的宏,这些宏包括:

#define NLMSG_ALIGNTO 4

#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )

/*宏NLMSG_ALIGN(len)用于得到不小于len且字节对齐的最小数值*/

#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))

#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))

/*宏NLMSG_LENGTH(len)用于计算数据部分长度为len时实际的消息长度。它一般用于分配消息缓存*/

#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))

/*宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字节对齐的最小数值,它也用于分配消息缓存*/

#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))

/*宏NLMSG_DATA(nlh)用于取得消息的数据部分的首地址,设置和读取消息数据部分时需要使用该宏*/

#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \

(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))

/*宏NLMSG_NEXT(nlh,len)用于得到下一个消息的首地址,同时len也减少为剩余消息的总长度,该宏一般在一个消息被分成几个部分发送或接收时使用*/

#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \

(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \

(nlh)->nlmsg_len <= (len))

/*宏NLMSG_OK(nlh,len)用于判断消息是否有len这么长*/

#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))

/*宏NLMSG_PAYLOAD(nlh,len)用于返回payload的长度*/

在/kernel/net/netlink/af_netlink.c文件中定义了netlink套接字的结构体

struct netlink_sock {

/* struct sock has to be the first member of netlink_sock */

struct sock sk;

u32 pid;//内核自己的pid,=0

u32 dst_pid;

u32 dst_group;//目的组

u32 flags;

u32 subscriptions;

u32 ngroups;//组数量

unsigned long *groups;//组号

unsigned long state;

wait_queue_head_t wait;//进程在接收数据包时等待队列

struct netlink_callback *cb;

spinlock_t cb_lock;

void (*data_ready)(struct sock *sk,int bytes);///内核态接收到用户态信息后的处理函数

struct module *module;

};

5、netlink协议注册

在af_netlink.c文件中我们可以看到netlink协议的注册

static struct proto netlink_proto ={

.name ="NETLINK",

.owner = THIS_MODULE,

.obj_size = sizeof(struct netlink_sock),

};

在static int __init netlink_proto_init(void)函数中会调用注册协议的函数,对netlink协议进行注册,其中,netlink_proto就是上面的struct proto netlink_proto协议。

int err= proto_register(&netlink_proto, 0);

三、内核中的处理流程

这里我以路由中的netlink为例,看一下内核中的处理流程是怎么样的!

1、skb

在内核中接收的数据和存储发送的数据都是放在了skb_buff的结构体中struct netlink_skb_parms

{

struct ucred creds;/* Skb credentials */

__u32 pid;

__u32 dst_pid;

__u32 dst_group;

kernel_cap_t eff_cap;

__u32 loginuid;/* Login (audit) uid */

};

使用下面的宏获取skb_bff中的数据部分

#define NETLINK_CB(skb)(*(struct netlink_skb_parms*)&((skb)->cb))

2、接收

在/kernel/net/core/rtnetlink.c文件中,有一个接收从用户空间过来的Netlink消息的函数。

static void rtnetlink_rcv(struct sock *sk,int len)

{

unsigned int qlen = 0;

do{

rtnl_lock();

netlink_run_queue(sk,&qlen,&rtnetlink_rcv_msg);

up(&rtnl_sem);

netdev_run_todo();

}while(qlen);

}

上面的内核函数就是用来接收用户路由方面Netlink消息的,当我们使用route命令添加一条路由时,就会调用该函数接收。该函数是在netlink的初始化是注册的。

同样在rtnetlink.c文件中。

void __init rtnetlink_init(void)

{

int i;

rtattr_max = 0;

for(i = 0; i < ARRAY_SIZE(rta_max); i++)

if(rta_max[i]> rtattr_max)

rtattr_max = rta_max[i];

rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL);

if(!rta_buf)

panic("rtnetlink_init: cannot allocate rta_buf\n");

//在创建内核的netlink时,注册了路由netlink的接收函数,rtnetlink_rcv.

rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX,

rtnetlink_rcv,THIS_MODULE);

if(rtnl ==NULL)

panic("rtnetlink_init: cannot initialize rtnetlink\n");

netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);

register_netdevice_notifier(&rtnetlink_dev_notifier);

rtnetlink_links[PF_UNSPEC]= link_rtnetlink_table;

rtnetlink_links[PF_PACKET]= link_rtnetlink_table;

}

在netlink_kernel_create函数中,可以看到内核接收用户空间传过来的消息的接收函数,

struct sock *

netlink_kernel_create(int unit, unsigned int groups,

void (*input)(struct sock *sk,int len),

struct module *module)

{

struct socket *sock;

struct sock *sk;

struct netlink_sock *nlk;

if(!nl_table)

return NULL;

if(unit<0 || unit>=MAX_LINKS)

return NULL;

if(sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit,&sock))

return NULL;

if(__netlink_create(sock, unit)< 0)

goto out_sock_release;

sk = sock->sk;

sk->sk_data_ready = netlink_data_ready;

if(input)

nlk_sk(sk)->data_ready = input; //设置内核接收Netlink消息的函数,这里就是前面的rtnetlink_rcv函数

if(netlink_insert(sk, 0))

goto out_sock_release;

nlk = nlk_sk(sk);//取得sock嵌入的netlink_sock结构体

nlk->flags |= NETLINK_KERNEL_SOCKET;

netlink_table_grab();

nl_table[unit].groups = groups < 32 ? 32 : groups;

nl_table[unit].module = module;

nl_table[unit].registered = 1; //更新netlink_table结构体信息,每中协议对应一个netlink_table结构

netlink_table_ungrab();

return sk;

out_sock_release:

sock_release(sock);

return NULL;

}

到此,内核创建netlink到接收用户空间发送过来消息整个流程就清晰了。

3、处理

当我们添加一条新路由时,在接收函数rtnetlink_rcv中的循环中,会从一个队列中调用实际的接收处理函数,这里为rtnetlink_rcv_msg函数。

/**

* nelink_run_queue - Process netlink receive queue.

* @sk: Netlink socket containing the queue

* @qlen: Place to store queue length upon entry

* @cb: Callback function invoked for each netlink message found

*

* Processes as much as there was in the queue upon entry and invokes

* a callback function for each netlink message found. The callback

*function may refuse a message by returning a negative error code

* but setting the error pointer to 0 in which case this function

* returns with a qlen != 0.

*

* qlen must be initialized to 0 before the initial entry, afterwards

* the function may be called repeatedly until qlen reaches 0.

*/

void netlink_run_queue(struct sock *sk, unsigned int*qlen,

int(*cb)(struct sk_buff *, struct nlmsghdr *,int*))

{

struct sk_buff *skb;

if(!*qlen ||*qlen > skb_queue_len(&sk->sk_receive_queue))

*qlen = skb_queue_len(&sk->sk_receive_queue);

for(;*qlen;(*qlen)--){

skb = skb_dequeue(&sk->sk_receive_queue);

if(netlink_rcv_skb(skb, cb)){

if(skb->len)

skb_queue_head(&sk->sk_receive_queue, skb);

else{

kfree_skb(skb);

(*qlen)--;

}

break;

}

kfree_skb(skb);

}

}

下面是rtnetlink_rcv_msg()函数的实现,对netlink消息进行相应的处理。其中有一个数据结构struct rtnetlink_link *link; 其定义如下:是两个不同的处理函数

struct rtnetlink_link

{

int(*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);

int(*dumpit)(struct sk_buff *, struct netlink_callback *cb);

};

/* Process one rtnetlink message.*/

static __inline__ int

rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,int*errp) {

struct rtnetlink_link *link;

struct rtnetlink_link *link_tab;

int sz_idx, kind;

int min_len;

int family;

int type;

int err;

/* Only requests are handled by kernel now*/

if(!(nlh->nlmsg_flags&NLM_F_REQUEST))

return 0;

type = nlh->nlmsg_type;

/* A control message: ignore them */

if(type < RTM_BASE)

return 0;

/* Unknown message: reply with EINVAL */

if(type > RTM_MAX)

goto err_inval;

type -= RTM_BASE;

/* All the messages must have at least 1 byte length */

if(nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))

return 0;

family =((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;

if(family >= NPROTO){

*errp =-EAFNOSUPPORT;

return -1;

}

link_tab =rtnetlink_links[family]; //根据用户空间传过来的不同德family类型,调用不同的处理函数,这里以路由为例的话为AF_ROUTE或者AF_NETLINK

if(link_tab ==NULL)

link_tab = rtnetlink_links[PF_UNSPEC];

link=&link_tab[type];//根据不同的type调用不同的处理函数。这里的type为RTM_NEWROUTE

sz_idx = type>>2;

kind = type&3;

if(kind != 2 && security_netlink_recv(skb)){

*errp =-EPERM;

return -1;

}

if(kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP){

if(link->dumpit ==NULL)

link=&(rtnetlink_links[PF_UNSPEC][type]);

Linux 下串口编程入门

Linux 下串口编程入门 级别: 初级 左锦 (zuo170@https://www.doczj.com/doc/ed412154.html, ), 副总裁, 南沙资讯科技园 2003 年 7 月 03 日 Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编 程进行简单的介绍。 串口简介 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS 称 EIA RS-232-C )它是在 1970 年由美国电子工业协会(EIA )联合贝尔系统、 调制解调器厂家及厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE )和数据通讯设备(DCE )之据交换接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行要非常深入了解,建议看看本文所参考的 《Serial Programming Guide for POSIX Operating S 计算机串口的引脚说明 串口操作 串口操作需要的头文件文档选

打开串口 在 Linux 下串口文件是位于 /dev 下的 串口一为 /dev/ttyS0 串口二为 /dev/ttyS1 打开串口是通过使用标准的文件打开函数操作: int fd; /*以读写方式打开串口*/ fd = open( "/dev/ttyS0", O_RDWR); if (-1 == fd){ /* 不能打开串口一*/ perror(" 提示错误!"); } 设置串口 最基本的设置串口包括波特率设置,效验位和停止位设置。

Linux下串口通信编程

Linux下串口通信编程 一、什么是串口通信? 串口通信是指计算机主机与外设之间以及主机系统与主机系统之间数据的串行传送。使用串口通信时,发送和接收到的每一个字符实际上都是一次一位的传送的,每一位为1或者为0。 二、串口通信的分类 串口通信可以分为同步通信和异步通信两类。同步通信是按照软件识别同步字符来实现数据的发送和接收,异步通信是一种利用字符的再同步技术的通信方式。 2.1 同步通信 同步通信是一种连续串行传送数据的通信方式,一次通信只传送一帧信息。这里的信息帧与异步通信中的字符帧不同,通常含有若干个数据字符。 它们均由同步字符、数据字符和校验字符(CRC)组成。其中同步字符位于帧开头,用于确认数据字符的开始。数据字符在同步字符之后,个数没有限制,由所需传输的数据块长度来决定;校验字符有1到2个,用于接收端对接收到的字符序列进行正确性的校验。 同步通信的缺点是要求发送时钟和接收时钟保持严格的同步。 2.2 异步通信 异步通信中,数据通常以字符或者字节为单位组成字符帧传送。字符帧由发送端逐帧发送,通过传输线被接收设备逐帧接收。发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,互不同步。 接收端检测到传输线上发送过来的低电平逻辑"0"(即字符帧起始位)时,确定发送端已开始发送数据,每当接收端收到字符帧中的停止位时,就知道一帧字符已经发送完毕。 在异步通行中有两个比较重要的指标:字符帧格式和波特率。 (1)字符帧,由起始位、数据位、奇偶校验位和停止位组成。 1.起始位:位于字符帧开头,占1位,始终为逻辑0电平,用于向接收设备表示发送端开始发送一帧信息。 2.数据位:紧跟在起始位之后,可以设置为5位、6位、7位、8位,低位在前高位在后。 3.奇偶校验位:位于数据位之后,仅占一位,用于表示串行通信中采用奇校验还是偶校验。 (2)波特率,波特率是每秒钟传送二进制数码的位数,单位是b/s。 异步通信的优点是不需要传送同步脉冲,字符帧长度也不受到限制。缺点是字符帧中因为包含了起始位和停止位,因此降低了有效数据的传输速率。 三、什么是RS-232? RS-232-C 接口(又称EIA RS-232-C)它是在1970 年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25 个脚的DB25 连接器,对连接器的每个引脚的信号内容加

设备驱动加到Linux内核中

7.2.3 设备驱动加到Linux内核中 设备驱动程序编写完后将该驱动程序加到内核中。这需要修改Linux 的源代码,然后重新编译内核。 ①将设备驱动程序文件(比如mydriver.c)复制到/Linux/drivers/char目录下。该目录保存了Linux下字符设备的设备驱动程序。修改该目录下mem.c 文件,在int chr_dev_init()函数中增加如下代码: #ifdef CONFIG_MYDRIVER device_init(); #endif 其中CONFIG_MYDRIVER是在配置Linux内核时赋值。 ②在/linux/drivers/char目录下Makefile中增加如下代码: ifeq ($(CONFIG_MYDRIVER),y) L_OBJ + = mydriver.o endif 如果在配置Linux内核时选择了支持新定义的设备,则在编译内核时会编译mydriver.c生成mydriver.o文件。 ③修改/linux/drivers/char目录下config.in文件,在 comment Character devices 语句下面加上 bool suppot for mydriver CONFIG_MYDRIVER 这样,若编译内核,运行make config,make menuconfig或make xconfig,那么在配置字符设备时就会有选项: Support for mydriver 当选中这个设备时,设备驱动就加到了内核中了。 重新编译内核,在shell中将当前目录cd 到Linux目录下,然后执行以下代码: # make menuconfig # make dep # make 在配置选项时要注意选择支持用户添加的设备。这样得到的内核就包含用户的设备驱动程序。 Linux通过设备文件来提供应用程序和设备驱动的接口,应用程序通过标准的文件操作函数来打开、关闭、读取和控制设备。查看Linux文件系统下的/proc/devices,可以看到当前的设备信息。如果设备驱动程序已被成功加进,这里应该由该设备对应的项。/proc/interrupts纪录了当时中断情况,可以用来查看中断申请是否正常;对于DMA和I/O口的使用,在/proc下都有相应的文件进行记录;还可以在设备驱动程序中申请在/proc 文件系统下创建一个文件,该文件用来存放设备相关信息。这样通过查看该文件就可以了解设备的使用情况。总之,/proc文件系统为用户提供了查

Linux内核—文件系统模块的设计和开发

Linux内核—文件系统模块的设计和开发 郑小辉 摘要:目前,Linux技术已经成为IT技术发展的热点,投身于Linux技术研究的社区、研究机构和软件企业越来越多,支持Linux的软件、硬件制造商和解决方案提供商也迅速增加,Linux在信息化建设中的应用范围也越来越广,Linux产业链已初步形成,并正在得到持续的完善。随着整个Linux产业的发展,Linux技术也处在快速的发展过程中,形成了若干技术热点。 本文介绍了Linux的发展和特点,以及与其他文件系统的区别。文中主要是对Linux2.4.0内核文件系统源代码的分析,并参考其文件格式设计一个简洁的文件系统。源代码的分析主要介绍了VFS文件系统的结构,Linux自己的Ext2文件系统结构,以及文件系统中的主要函数操作。 在设计的简洁文件系统中,通过调用一些系统函数实现了用户的登录、浏览目录、创建目录、更改目录、创建文件以及退出系统功能。 关键字:Linux 源代码分析文件系统Ext2 Linux内核

Linux kernel -Design and development for the File System Module Zheng xiaohui Abstract: Currently, Linux IT technology has become a hot development technology. Participating in Linux technology research communities, research institutes and software enterprises are in support of Linux more and more, software and hardware manufacturers and solution providers have increased rapidly, In the development of the information industry the Linux application is also increasing, Linux industry chain has taken shape, and is sustained improvemently. With the entire industry in the development of Linux, and Linux is also at the rapid development process, formed a number of technical points. This paper presents the development of Linux and features, and with other file system differences. The main text of the document is Linux2.4.0 system kernel source code analysis, and I reference its file format to design a simple file system. The analysis of the source code mainly on the VFS file system structure, Linux Ext2 its own file system structures, file systems and the main function operation. In the design of the file simple system, some system function is used to achieve function such as: the user's login, browse catalogs, create directories, Change directory, create documents and withdraw from the system function and etc. Key words: Linux, the source code, file system, Ext2, Linux kernel

Linux下的串口编程

Linux下的串口编程(二) 分类:Linux S3C24402012-03-21 15:52 5557人阅读评论(1) 收藏举报linux编程终端terminalstruct测试 Linxu下的串口编程(二) /************声明:本人只是见到这篇文章对我帮助很大才转载的,但是这个完整的程序里面本来有语法错误的,现在让我改过来了************/ --------------------------------------------------------- Author :tiger-john WebSite :https://www.doczj.com/doc/ed412154.html,/tigerjb Email :jibo.tiger@https://www.doczj.com/doc/ed412154.html, Update-Time : 2011年2月14日星期一 Tiger声明:本人鄙视直接复制本人文章而不加出处的个人或团体,但不排斥别人转载tiger-john的文章,只是请您注明出处并和本人联系或留言给我。3Q --------------------------------------------------------- 前面已经提到过Linux下皆为文件,这当然也包括我们今天的主角àUART0串口。因此对他的一切操作都和文件的操作一样(涉及到了open,read,write,close等文件的基本操作)。 一.Linux下的串口编程又那几部分组成

1. 打开串口 2. 串口初始化 3. 读串口或写串口 4. 关闭串口 二.串口的打开 既然串口在linux中被看作了文件,那么在对文件进行操作前先要对其进行打开操作。 1.在Linxu中,串口设备是通过串口终端设备文件来访问的,即通过访问/dev/ttyS0,/dev/ttyS1,/dev/ttyS2这些设备文件实现对串口的访问。

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Linux内核与跟文件系统的关系

Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题!一语破天机:“尽管内核是Linux 的核心,但文件却是用户与操作系统交互所采用的主要工具。这对Linux 来说尤其如此,这是因为在UNIX 传统中,它使用文件I/O 机制管理硬件 设备和数据文件。” 一.什么是文件系统 文件系统指文件存在的物理空间,linux系统中每个分区都是一个文件系统,都有自己的目 录层次结构。 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其 中。这种机制有利于用户和操作系统的交互。 每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS 的通用接口。由于软件将Linux 文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。Linux 的虚拟文件系统允许用户同时能透明地安装 许多不同的文件系统。 在Linux文件系统中,EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的 文件系统。 二.什么是根文件系统 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。 那么根文件系统在系统启动中到底是什么时候挂载的呢?先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.根文件系统执行完之后,也就是到了Start_kernel()函数的最后,执行init的进程,也就第一个用户进程。对系统进行各 种初始化的操作。 根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux 一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt 目录上,/mnt目录下就有这个分区的各个目录,文件。

基于linux的嵌入式串口通信

天津电子信息职业技术学院 嵌入式软件编程》课程报告 课程名称:基于linux 的嵌入式串口通信 课程代码:115229 姓名:甘琦 学号:48 专业:物联网应用技术 班级:物联S14-1 完成时间:2016 年10 月28 日

目录 摘要 (1) 前言 (2) 一、嵌入式串口通信概述 (2) 1.1嵌入式串口通信的原理 (2) 1.2嵌入式串口通信的开发工具 (2) 1.2.1 ............................................................. CC2530 功耗 2 1.2.2........................................................... ARM 简介 3 1.2.3................................................................ L inux 系统简介 3 1.3嵌入式串口通信的基本任务 (4) 1.4嵌入式串口通信协议及实现 (4) 二、RS-232C 标准 (5) 2.1引脚定义 (5) 2.2字符(帧)格式 (6) 2.3握手协议 (8) 2.4双机互连方式 (9) 2.4.1无硬件握手情况 (9) 2.4.2 .................................................................. DTR 和DSR握手情况9 三、嵌入式串口驱动程序设计 (10) 3.1嵌入式串口操作需要的头文件 (10) 3.2打开串口 (10) 3.3串口设置 (11) 3.4串口读写 (13) 3.5关闭串口 (14) 四、源程流程图 (15) 五、源程序代码 (15) 总结 (19)

Linux串口打印设置

一、基于VM虚拟机linux系统串口配置 配置分为虚拟机下配置及linux系统下minicom配置两部分。 虚拟机模块配置如下: 打开虚拟机配置界面。 选择Edit virtual machine settings。进入配置界面。

选择Add…按钮,添加相关的设备文件。

选中串口选项后继续选择下一步。

此处选择”使用主机上的物理串口设备”选项,继续下一步。此处我们选择文件。 对于物理串口选项,此处可以采用自动检测选项。如果下来菜单中有对应于串口的端口号,则可以选择。注意,对于设备状态,要确保选中“connect at power on“,即,上电连接状态。至此,虚拟机端串口配置完毕。 注意:此处我们串口添加成功后默认未COM2.

Linux下串口配置及使用。 Linux下一般使用minicom来作为串口数据输入输出的终端。类似于Windows下的超级终端。虚拟机下配置完毕后,进入Linux系统中,在Shell 终端下输入minicom -s即可配置串口终端。配置完成后执行minicom启动串口终端。 在终端界面下完成相关的参数配置并保存后,启动终端设备,即可在minicom中观察到数据输出。 <四>Minicom的使用 (1)minicom界面介绍 第一次运行minicom,启动minicom要以root权限登录系统,需要进行minicom的设置,输入下了命令#minicom –s,显示的屏幕如下所示,按

上下光标键进行上下移动选择,我们要对串行端口进行设置,因此选中 Serial port setup,然后回车: __[configuration]─-─—┐//配置 │ Filenames and paths │//文件名和路径 │ File transfer protocols│//文件传输协议 │ Serial port setup │//串行端口设置 │ Modem and dialing │//调制解调器和拨号 │ Screen and keyboard │//屏幕和键盘 │ Save setup as dfl │//设置保存到 │ Save setup as.. │//储存设定为 │ Exit │//退出 │ Exit from Minicom │//退出minicom └──────────┘ (2)minicom的参数设置 选中设置串行端口,点击回车后,弹出设置的界面如下: 点击”A”设置串行设置为/dev/ttyS1,这表示使用串口2(com2),如果是 /dev/ttyS1则表示使用串口2(com 2).按”E”键进入设置”bps/par/Bits”(波 特率)界面,如下图所示。再按”I”以设置波特率为115200,点”F”键硬 件流控制设置为NO,回车 最终的设置结果如下,然后回车返回到串口设置主菜单中 │A-Serial Device(串口设备): /dev/ttyS1 │B-Lockfile Location(锁文件位置): /var/lock │C-Callin Program(调入程序): │D-Callout Program(调出程序): │E-Bps/Par/Bits(): 115200 8N1 │F-Hardware Flow Control(硬件数据流控制): No │G-Software Flow Control(软件数据流控制): No 二、Linux 标准输入输出重定向到串口指南 设置linux 系统的标准输入输出到com2(console 口),以便维护人员 在无网络、无显示器的情况下对系统维护。在各文件(/etc/grub.conf、 /etc/inittab、/etc/securetty)中添加红色部分!文件修改完成后 reboot 系统即可在com2 口看到标准输入输出信息。

Linux--串口操作及设置详解

串口操作需要的头文件 #include /*标准输入输出定义*/ #include /*标准函数库定义*/ #include /*Unix 标准函数定义*/ #include #include #include /*文件控制定义*/ #include /*PPSIX 终端控制定义*/ #include /*错误号定义*/ 1.打开串口 在前面已经提到linux下的串口访问是以设备文件形式进行的,所以打开串口也即是打开文件的操作。函数原型可以如下所示: int open(“DE_name”,int open_Status) 参数说明: (1)DE_name:要打开的设备文件名 比如要打开串口1,即为/dev/ttyS0。 (2)open_Status:文件打开方式,可采用下面的文件打开模式: O_RDONLY:以只读方式打开文件 O_WRONLY:以只写方式打开文件 O_RDWR:以读写方式打开文件 O_APPEND:写入数据时添加到文件末尾 O_CREATE:如果文件不存在则产生该文件,使用该标志需要设置访问权限位mode_t O_EXCL:指定该标志,并且指定了O_CREATE标志,如果打开的文件存在则会产生一个错误 O_TRUNC:如果文件存在并且成功以写或者只写方式打开,则清除文件所有内容,使得文件长度变为0 O_NOCTTY:如果打开的是一个终端设备,这个程序不会成为对应这个端口的控制终端,如果没有该标志,任何一个输入,例如键盘中止信号等,都将影响进程。 O_NONBLOCK:该标志与早期使用的O_NDELAY标志作用差不多。程序不关心DCD信号线的状态,如果指定该标志,进程将一直在休眠状态,直到DCD信号线为0。 函数返回值: 成功返回文件描述符,如果失败返回-1 例如:

linux内核中Kconfig文档的作用以及Kconfig的语法

linux内核中Kconfig文档的作用以及Kconfig的语法 2.6内核的源码树目录下一般都会有两个文文:Kconfig 和Makefile。分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。在内核编译时,主Makefile调用这个.config,就知道了用户对内核的配置情况。上面的内容说明:Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,可以通过修改Kconfig来增加对我们驱动的配置菜单,这样就有途径选择我们的驱动,假如想使这个驱动被编译,还要修改该驱动所在目录下的Makefile。因此,一般添加新的驱动时需要修改的文件有两种(注意不只是两个)*Kconfig*Makefile要想知道怎么修改这两种文件,就要知道两种文档的语法结构。First: Kconfig每个菜单项都有一个关键字标识,最常见的就是config。语法:config symboloptions<!--[if !supportLineBreakNewLine]-->< ;!--[endif]-->symbol就是新的菜单项,options是在这个新的菜单项下的属性和选项其中options部分有:1、类型定义:每个config菜单项都要有类型定义,bool:布尔类型,tristate

三态:内建、模块、移除,string:字符串,hex:十六进制,integer:整型例如config HELLO_MODULEbool "hello test module"bool类型的只能选中或不选中,tristate类型的菜单项多了编译成内核模块的选项,假如选择编译成内核模块,则会在.config中生成一个 CONFIG_HELLO_MODULE=m的配置,假如选择内建,就是直接编译成内核影响,就会在.config中生成一个CONFIG_HELLO_MODULE=y的配置.2、依赖型定义depends on或requires指此菜单的出现是否依赖于另一个定义config HELLO_MODULEbool "hello test module"depends on ARCH_PXA 这个例子表明HELLO_MODULE这个菜单项只对XScale处理器有效,即只有在选择了ARCH_PXA,该菜单才可见(可配置)。3、帮助性定义只是增加帮助用关键字help或 ---help---<!--[if !supportLineBreakNewLine]--><!--[en dif]-->更多详细的Kconfigconfig语法可参考:Second: 内核的Makefile内核的Makefile分为5个组成部分:Makefile 最顶层的Makefile.config 内核的当前配置文档,编译时成为顶层Makefile的一部分arch/$(ARCH)/Makefile 和体系结构相关的Makefiles/ Makefile.* 一些Makefile的通用规则kbuild Makefile 各级目录下的大概约500个文档,编译时根据上层Makefile传下来的宏定义和其他编译

Linux下 QT串口与51单片机通信实例

QT串口与51单片机通信

通过这个小例子主要想说明QT怎样进行线程编程的思想,实例如图,好吧,下面是过程 上一个例子我们采用的是手工编写代码的方法,这个例子我们来玩一下designer,其实Qt4己经把界面与功能分开了,用designer来进行界面 设计,再手工编写一些功能,如信号与槽,这样开发效率会大大提高,呵呵,开一个终端,输入/usr/local/Trolltech/Qt-4.5.1/bin/designer ,如果第一次打开出现字体不对,可以打开qtconfig进行一些相关配置,打开后我们新建一个Main Window,在右边的属性框中设置一下界面大小, 1.我ARM板的LCD大小为320x240,所以我也设为320x240; 2.左边是一些我们常用的窗口部件,这里我们用到一个lable标签来做显示,再放几个pushButton按钮,在属性objectName重新更改它的名字,改为我们记得的,这样在写功能时记得哪个按钮叫什么名字,对于一个初学QT的人来说,很想知道每一个部件到底有什么信号和槽,别急,我们可以这样来看,选中一个lable,按F4,再点击lable拖动出现接地符号时松开,弹出编辑信号与槽,这时左边列出的是信号,右边为槽,这里我们不用配置连接,等下我们再手工写, 3最后我们用到一个lable标签和三个pushButton按钮,并命名为dis_label、writeButton、readButton、closeButton,然后保存为mainwindow.ui,这样designer就完工了,呵呵..

4.下面我们编写一个线程,用于管理串口收发工作,它不涉及到任何界面,只做好它的本份工作就得了,编写一个thread.h文件gedit thread.h, #ifndef THREAD_H #define THREAD_H #include class Thread:public QThread { Q_OBJECT public: Thread(); char buf[128]; volatile bool stopped; volatile bool write_rs; volatile bool read_rs; protected: virtual void run(); }; #endif 我们定义一个Thread类,它继承于QThread,看到只设有一些变量和一个run函数,virtual表示为虚函数,你也可以去掉,加上去会增加一些内存开销, 但提高了效率,对于这个小程序是看不出什么效果的,volatile这个大家都懂了吧,就是防止偷懒,呵呵, 5.再看看thread.cpp #include"thread.h" #include #include #include #include //串口用到的 #include #include #include #include #define BAUDRATE B9600 //#define RS_DEVICE "/dev/ttyS0" //串口1 #define RS_DEVICE "/dev/ttySAC1" //串口1 Thread::Thread() {} //析构 void Thread::run() //这就是线程的具体工作了

linux下的tty串口通信

异步通信:以单字符为发送单位,字符间发送能存在间隔 起始位:发送”0”,表示字符传送开始 数据位:可允许4 5 6 7的数据位 停止位:一个字符结束的标志位, 奇偶校验位:根据传送数据内“1”的个数是偶数还是奇数来校验数据是否准确 空闲位:在没有数据发送时,设置“1” Structure termios{ tcflag_t c_iflag; 输入方式 tcflag_t c_oflag; 输出方式 tcflag_t c_cflag; 控制模式标志 tcflag_t c_Iflag; 本地 tcflag_t c_cc[NCCS]; 控制字符,用于保存终端的特殊字符} c_iflag 标志常量:Input mode ( 输入模式) input mode可以在输入值传给程序之前控制其处理的方式。 其中输入值可能是由序列埠或键盘的终端驱动程序所接收到的字元。我们可以利用termios结构的c_iflag的标志来加以控制,其定义的方式皆以OR 来加以组合。 IGNBRK :忽略输入中的 BREAK 状态。(忽略命令行中的中断) BRKINT :(命令行出现中断时,可产生一插断)如果设置了 IGNBRK,将忽略 BREAK。如果没有设置,但是设置了 BRKINT,那么 BREAK 将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到 SIGINT 信号。如果既未设置 IGNBRK 也未设置 BRKINT,BREAK 将视为与NUL 字符同义,除非设置了 PARMRK,这种情况下它被视为序列 377 � �。 IGNPAR :忽略桢错误和奇偶校验错。 PARMRK :如果没有设置 IGNPAR,在有奇偶校验错或桢错误的字符前插入377 �。如果既没有设置 IGNPAR 也没有设置 PARMRK,将有奇偶校验错或桢错误的字符视为 �。 INPCK :启用输入奇偶检测。 ISTRIP :去掉第八位。 INLCR :将输入中的 NL 翻译为 CR。(将收到的换行符号转换为Return)IGNCR :忽略输入中的回车。 ICRNL :将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则当输入信号有 CR 时不会终止输入)。 IUCLC :(不属于 POSIX) 将输入中的大写字母映射为小写字母。 IXON :启用输出的 XON/XOFF 流控制。 IXANY :(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出。(?) IXOFF :启用输入的 XON/XOFF 流控制。 IMAXBEL:(不属于 POSIX) 当输入队列满时响零。Linux 没有实现这一位,总是将它视为已设置。

Linux内核启动流程分析(一)

很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下。由于是word直接粘过来的有点乱,敬请谅解! S3C2410 Linux 2.6.35.7启动分析(第一阶段) arm linux 内核生成过程 1. 依据arch/arm/kernel/vmlinux.lds 生成linux内核源码根目录下的vmlinux,这个vmlinux属于未压缩, 带调试信息、符号表的最初的内核,大小约23MB; 命令:arm-linux-gnu-ld -o vmlinux -T arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o init/built-in.o --start-group arch/arm/mach-s3c2410/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o drivers/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o 2. 将上面的vmlinux去除调试信息、注释、符号表等内容,生成arch/arm/boot/Image,这是不带多余信息的linux内核,Image的大小约 3.2MB; 命令:arm-linux-gnu-objcopy -O binary -S vmlinux arch/arm/boot/Image 3.将 arch/arm/boot/Image 用gzip -9 压缩生成arch/arm/boot/compressed/piggy.gz大小约 1.5MB;命令:gzip -f -9 < arch/arm/boot/compressed/../Image > arch/arm/boot/compressed/piggy.gz 4. 编译arch/arm/boot/compressed/piggy.S 生成arch/arm/boot/compressed/piggy.o大小约1.5MB,这里实 际上是将piggy.gz通过piggy.S编译进piggy.o文件中。而piggy.S文件仅有6行,只是包含了文件piggy.gz; 命令:arm-linux-gnu-gcc -o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/piggy.S 5. 依据arch/arm/boot/compressed/vmlinux.lds 将arch/arm/boot/compressed/目录下的文件head.o 、piggy.o 、misc.o链接生成arch/arm/boot/compressed/vmlinux,这个vmlinux是经过压缩且含有自解压代码的内核, 大小约1.5MB; 命 令:arm-linux-gnu-ld zreladdr=0x30008000 params_phys=0x30000100 -T arch/arm/boot/compressed/vmlinux.lds a rch/arm/boot/compressed/head.o arch/arm/boot/compressed/piggy.o arch/arm/boot/compressed/misc.o -o arch/arm /boot/compressed/vmlinux

Linux_C_C++串口读写串口读写

Linux C/C++串口读写 串口简介 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是RS-232-C 接口(又称EIA RS-232-C)它是在1970 年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25 个脚的DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于4% 的情况下,传输电缆长度应为50 英尺。 Linux 操作系统从一开始就对串行口提供了很好的支持 串口操作

打开串口 在Linux 下串口文件是位于/dev 下的 串口一为/dev/ttyS0 串口二为/dev/ttyS1 设置串口 最基本的设置串口包括波特率设置,效验位和停止位设置。

设置这个结构体很复杂,我这里就只说说常见的一些设置: 波特率设置 设置波特率的例子函数: /** *@brief 设置串口通信速率 *@param fd 类型 int 打开串口的文件句柄 *@param speed 类型 int 串口速度 *@return void */ int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; void set_speed(int fd, int speed){ int i; int status; struct termios Opt; tcgetattr(fd, &Opt);

基于linux的嵌入式串口通信

天津电子信息职业技术学院《嵌入式软件编程》课程报告 课程名称:基于linux的嵌入式串口通信 课程代码:115229 姓名:甘琦 学号:48 专业:物联网应用技术 班级:物联S14-1 完成时间:2016 年10 月28日

目录 摘要 (1) 前言 (2) 一、嵌入式串口通信概述 (2) 1.1 嵌入式串口通信的原理 (2) 1.2 嵌入式串口通信的开发工具 (2) 1.2.1 CC2530功耗 (2) 1.2.2 ARM简介 (3) 1.2.3 Linux系统简介 (3) 1.3 嵌入式串口通信的基本任务 (4) 1.4嵌入式串口通信协议及实现 (4) 二、 RS-232C标准 (5) 2.1引脚定义 (5) 2.2 字符(帧)格式 (6) 2.3握手协议 (8) 2.4 双机互连方式 (9) 2.4.1无硬件握手情况 (9) 2.4.2 DTR和DSR握手情况 (9) 三、嵌入式串口驱动程序设计 (10) 3.1 嵌入式串口操作需要的头文件 (10) 3.2 打开串口 (10) 3.3 串口设置 (11) 3.4 串口读写 (13) 3.5 关闭串口 (14) 四、源程流程图 (15) 五、源程序代码 (15) 总结 (19)

摘要 随着Internet的发展和后PC时代的到来,嵌入式系统以其可靠性强、体积小、专用性、成本低等特性得到日益广泛的应用。目前嵌入式系统技术已经成为了最热门的技术之一。与此同时,一个独立的嵌入式系统的功能缺陷也逐渐暴露出来。新一代嵌入计算系统的功能集成和应用模式使之迅速向网络化嵌入计算的方向发展,标准和统一的TCP/IP通信协议是独立于任何厂家的硬件的,因此嵌入环境下的实时网络通信成为嵌入计算技术研究的重点和热点。本文通过基于2410F 的嵌入式串口通信的实现,按照嵌入式系统的软、硬件结构组成,较为详细地介绍了串口通信的硬件电路和软件实现方法。 关键词:嵌入式串口通信 2410F

相关主题
文本预览
相关文档 最新文档