(第2版)
主讲内容 第8章 嵌入式系统Boot Loader技术 第9章 嵌入式Linux操作系统移植 第10章 嵌入式Linux设备驱动程序开发
第11章 嵌入式Linux应用程序设计 11.1 嵌入式Linux C语言应用程序开发基础 11.1.1 编写源程序 从经典的“Hello World!”程序入手。首先打开编辑器VIM。在Linux PC上打开一个终端窗口,输入命令vi helloworld.c,打开并建立源文件。输入源代码 VIM相关的操作命令。 1.VIM中文件打开相关命令(在终端窗口中使用): 2.VIM光标操作类命令(VIM界面中使用): 3.屏幕操作类命令: 4.插入文本类命令: 5.删除操作相关命令:
第11章 嵌入式Linux应用程序设计 7.搜索及替换命令: 8.选项设置: 9.文本缓存操作:
第11章 嵌入式Linux应用程序设计 11.1.2 交叉编译程序 对于Makefile文件的编辑依然可以使用VIM。在Helloworld.c所在的目录中建立Makefile文件 Makefile文件保存好后,接下来就可以在helloworld.c文件目录下执行make命令进行编译了。编译后会产生ARM-Linux下的可执行文件helloworld,可以将此文件下载到目标板进行调试运行。
第11章 嵌入式Linux应用程序设计 11.1.3 调试程序 由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采用gdb+gdbserver的方式进行调试。 要采用远程调试(remote)的方法。 1.建立安装gdb组件 2.调试运行 3.调试命令(注意命令列表中括号里的内容为命令简写方式)
第11章 嵌入式Linux应用程序设计 11.2 文件I/O编程 Linux中的文件主要分为4种:普通文件、目录文件、链接文件和设备文件。 11.2.2 文件I/O操作API 1.open函数说明 open函数是用于打开或创建文件,在打开或创建文件时以指定文件的属性及用户的权限等各种参数。 (1)open函数原型: int open(const char *pathname, int flags, mode_t mode); (2)open函数相关头文件:
第11章 嵌入式Linux应用程序设计 (3)open函数的参数说明: pathname:被打开的文件名(包括路径名)。 flags:文件打开方式:(flag 参数可通过“|”组合构成) O_RDONLY:只读方式打开文件; O_WRONLY:写方式打开文件; O_RDWR:读写方式打开文件; 以上三个选项必须且只能使用其中一个 mode:被打开文件的存取权限,为8进制表示法 (4)open函数返回值: 打开成功返回文件描述符,通常是最小的未被使用的描述符;失败返回-1,并且错误代码存入errno,错误代码(定义于errno.h中,如需要处理错误需包含该头文件)
第11章 嵌入式Linux应用程序设计 2.close函数说明 close函数是用于关闭一个打开文件。当一个进程终止时,它所有已打开的文件都由内核自动关闭,很多程序都使用这一功能而不显示地关闭一个文件。 (1)close函数原型: int close(int fd); (2)close函数相关头文件: #include <unistd.h> (3)close函数的参数说明: fd:open函数打开成功返回的文件描述符。 (4)close函数返回值: 成功返回0;返回-1表示出错。
第11章 嵌入式Linux应用程序设计 3. read函数说明 ssize_t read(int fd,void * buf ,size_t count); (2)read函数相关头文件: #include <unistd.h> #include <stddef.h>//size_t为无符号整型型代表数量,ssize_t为signed size (3)read函数的参数说明: fd:文件描述符; buf:指定存储器读出数的缓冲区; count:指定读出的字节数。若参数count为0,则read()不会有作用并返回0。
第11章 嵌入式Linux应用程序设计 (4)read函数返回值: 返回值为实际读取到的字节数;如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动;当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期。
第11章 嵌入式Linux应用程序设计 4.write函数说明 write 函数是用于向打开的文件写数,写操作从文件的当前位移量处开始。若磁盘已满或超出该文件的长度,则write 函数返回失败。 (1)write函数原型: ssize_t write(int fd,void *buf,size_t count); (2)write函数相关头文件: 同read函数。 (3)write函数的参数说明: write会把参数buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动。
第11章 嵌入式Linux应用程序设计 (4)write的返回值: 如果顺利write会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。错误代码: EINTR:此调用被信号所中断; EAGAIN:当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值; EADF:参数fd非有效的文件描述词,或该文件已关闭。
第11章 嵌入式Linux应用程序设计 5.lseek函数说明 (1)lseek函数原型: off_t lseek(int fd,off_t offset,int whence); (2)lseek函数相关头文件: #include <unistd.h> #include <sys/types.h> (3)lseek函数的参数说明: (4)lseek的返回值: 当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno会存放错误代码。
第11章 嵌入式Linux应用程序设计 6.fcntl函数说明 Linux采用上锁的方法避免共享的资源产生竞争的状态。 fcntl 是一个非常通用的函数,它还可以改变文件进程各方面的属性。 (1)fcntl函数原型: (2)fcntl函数相关头文件: (3)fcntl函数的参数说明: (4)fcntl的返回值:
第11章 嵌入式Linux应用程序设计 11.3 网络编程 11.3.1 网络通信基础及例程 嵌入式Linux的网络通信程序是基于套接字(Socket)模式的。Socket实际是网络传输层供给应用层的编程接口。常见的socket有三种类型如下: 1.流式socket(SOCK_STREAM) 流式套接字提供可靠的、面向连接的通信流;它使用TCP 协议,从而保证了数据传输的正确性和顺序性。 Socket编程采用客户/服务器模式。因此编程分为服务器端和客户端两部分。 2.数据报socket(SOCK_DGRAM) 数据通过相互独立的报文进行传输,数据报套接字定义了一种无连接的服务,是无序的,并且不保证是可靠、无差错的。它使用数据报协议UDP。
第11章 嵌入式Linux应用程序设计 3. 原始socket(SOCK_RAM) 以源程序为例,介绍流式Socket编程的基本方法: (1)服务器端源程序(server.c) (2)客户端源程序(client.c) 11.3.2 网络通信API 1.网络地址相关操作 (1)重要数据结构 sockaddr 和sockaddr_in两个结构体都是用来保存socket信息的。 ①sockaddr定义 ②sockaddr_in定义
第11章 嵌入式Linux应用程序设计 (2)IP地址转换函数 通常用户在表达地址时采用的是点分十进制表示的数值 (或者是以冒号分开的十六进制IPv6地址),而在通 常使用的socket 编程中所使用的则是二进制值,这就 需要将这两个数值进行转换。 ①inet_ntoa函数说明: ②inet_addr函数说明 ③inet_pton函数说明 ④inet_ntop函数说明
第11章 嵌入式Linux应用程序设计 2.其它转换函数 (1)存储顺序转换 (2)名字转换 在Linux中,有一些函数可以实现主机名和地址的转化,最为常见的有gethostbyname、gethostbyaddr、getaddrinfo 等,它们定义在<netdb.h>头文件中 3.Socket编程函数 (1)socket函数说明 该函数用于建立一个socket 连接,可指定socket类型等信息 ①函数原型 ②相关头文件 ③函数参数说明 ④函数返回值
第11章 嵌入式Linux应用程序设计 (2)bind函数说明 该函数是用于将本地IP地址定端口号的,若定其他地址则不能成功。另外,它主要用于TCP的连接,而在UDP的连接中则无必要。 ①函数原型 ②相关头文件 ③函数参数说明 ④函数返回值
第11章 嵌入式Linux应用程序设计 (3)listen函数说明 listen函数用于流式Socket(TCP协议)中使用。用于监听网络通信端口,检测客户端的服务请求。 ①函数原型 ②相关头文件 ③函数参数说明 ④函数返回值
第11章 嵌入式Linux应用程序设计 (4)connect函数说明 该函数在流式Socket中是用于bind的之后的client端,用于与服器端建立连接。 ①函数原型 int connect(int sockfd, struct sockaddr *serv_addr, int addrlen) ②相关头文件 #include <sys/socket.h> ③函数参数说明 socktd:套接字描述符; serv_addr:服务器端地址; addrlen:地址长度。 ④函数返回值 成功返回非负套接字描述符;出错返回-1
第11章 嵌入式Linux应用程序设计 (5)send函数说明 发送数据。 ①函数原型 int send(int sockfd, const void *msg, int len, int flags) ②相关头文件 #include <sys/socket.h> ③函数参数说明 socktd:套接字描述符; msg:指向要发送数据的指针; len:数据长度; flags:一般为0。 ④函数返回值 成功返回发送的字节数;失败返回-1。
第11章 嵌入式Linux应用程序设计 (6)recv函数说明 接收数据。 ①函数原型 int recv(int sockfd,void *buf,int len,unsigned int flags) ②相关头文件 #include <sys/socket.h> ③函数参数说明 socktd:套接字描述符; buf:存放接收数据的缓冲区; len:数据长度; flags:一般为0。 ④函数返回值 成功返回接收的字节数;失败返回-1。
第11章 嵌入式Linux应用程序设计 (7)sendto和recvfrom函数说明 功能类似5、6,只是在发送和接收数据时需要指定目的地址,可以再没有执行connect函数时直接发送或接收数据,常用于数据报Socket方式。 原型分别为: int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen) 参数to为目地机的IP 地址和端口号信息; int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen) 参数from为源机的IP 地址和端口号信息。
第11章 嵌入式Linux应用程序设计 11.4 应用实例 11.4.1 ADC应用实例 11.4.2 PWM蜂鸣器控制应用实例 11.4.3 触摸屏应用实例
11.5 本章小结 本章介绍了嵌入式Linux应用程序的一般开发方法。通过实例分析了简单应用、文件I/O操作和网络通信应用程序的设计的方法;并详细讲解了一些常用的API。