嵌入式学习(五)嵌入式程序

本文深入讲解了Linux系统下的文件操作,包括open、ioctl、write、read等核心函数的使用,以及串口、管道、消息队列等高级特性。涵盖了文件权限、串口参数设置、时间操作、信号处理等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开发板为迅为Itop4412

open()

1.库函数头文件
​ 在所有Linux系统中,对文件的操作都只需包含下面四个头文件即可:

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

2.打开文件函数open

​  int open(const char *path,int oflags);
​  int open(const char *path,int oflags,mode_t mode);

​ open函数有2到3个参数,其返回值为对应文件的句柄:

​ 1.第一个参数path为绝对路径

​ 2.第二个参数oflags为读写方式等操作

下面三个选项是必须选择其中之一的。

  O_RDONLY 文件只读
  O_WRONLY 文件只写
  O_RDWR 文件可读可写

下面是可以任意选择的。

  O_APPEND 每次写操作都写入文件的末尾
  O_CREAT 如果指定文件不存在,则创建这个文件
  O_EXCL 如果要创建的文件已存在,则返回-1,并且修改errno 的值
  O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
  O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
  O_NONBLOCK 如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O设置为非阻塞模式
  O_NDELAY 和O_NONBLOCK 功能类似,调用O_NDELAY 和使用的O_NONBLOCK 功能是一样的。

3.参数mode为设置创建文件的权限。其参数设置可参照linux下的权限值,例如chmod 777 filename

ioctl()

控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。用于向设备发控制和配置命令 ,有些命令需要控制参数,这些数据是不能用read / write 读写的,称为Out-of-band数据。也就是说,read / write 读写的数据是in-band数据,是I/O操作的主体,而ioctl 命令传送的是控制信息,其中的数据是辅助的数据。

  int ioctl(int handle, int cmd,[int *argdx, int argcx]);

第三个参数总是一个指针,但指针的类型依赖于request 参数。我们可以把和网络相关的请求划分为类:

套接口操作
文件操作
接口操作
ARP 高速缓存操作
路由表操作
流系统

下表列出了网络相关ioctl请求的request 参数以及arg 地址必须指向的数据类型:

类别Request说明数据类型
SIOCATMARK是否位于带外标记int
SIOCSPGRP设置套接口的进程ID 或进程组IDint
SIOCGPGRP获取套接口的进程ID 或进程组IDint
FIONBIO设置/ 清除非阻塞I/O 标志int
FIOASYNC设置/ 清除信号驱动异步I/O 标志int
FIONREAD获取接收缓存区中的字节数int
FIOSETOWN设置文件的进程ID 或进程组IDint
FIOGETOWN获取文件的进程ID 或进程组IDint
SIOCGIFCONF获取所有接口的清单struct ifconf
SIOCSIFADDR设置接口地址struct ifreq
SIOCGIFADDR获取接口地址struct ifreq
SIOCSIFFLAGS设置接口标志struct ifreq
SIOCGIFFLAGS获取接口标志struct ifreq
SIOCSIFDSTADDR设置点到点地址struct ifreq
SIOCGIFDSTADDR获取点到点地址struct ifreq
SIOCGIFBRDADDR获取广播地址struct ifreq
SIOCSIFBRDADDR设置广播地址struct ifreq
SIOCGIFNETMASK获取子网掩码struct ifreq
SIOCSIFNETMASK设置子网掩码struct ifreq
SIOCGIFMETRIC获取接口的测度struct ifreq
SIOCSIFMETRIC设置接口的测度struct ifreq
SIOCGIFMTU获取接口MTUstruct ifreq
SIOCxxx(还有很多取决于系统的实现)
ARPSIOCSARP创建/ 修改ARP 表项struct arpreq
SIOCGARP获取ARP 表项struct arpreq
SIOCDARP删除ARP 表项struct arpreq
SIOCADDRT增加路径struct rtentry
SIOCDELRT删除路径struct rtentry
SIOCRTMSG获取路由表struct rtentry
I_xxx
write 函数介绍
ssize_t write(int fd,const void *buf,size_t count)

参数 fd,使用 open 函数打开文件之后返回的句柄。
参数buf,需要写入的数据。
参数 count,将参数
buf 中最多 count 个字节写入文件中。
返回值为 ssize 类型,出错会返回-1,其它数值表示实际写入的字节数

ssize_t read(int fd,void *buf,size_t len)

参数 fd,使用 open 函数打开文件之后返回的句柄。
参数*buf,读出的数据保存的位置。
参数 len,每次最多读 len 个字节。
返回值为 ssize 类型,出错会返回-1,其它数值表示实际写入的字节数,返回值大于 0 小
于 len 的数值都是正常的。

串口相关
#include <termios.h>
#include <unistd.h>
int tcgetattr(int fd, struct termios *termios_p)

读取当前串口的参数值
参数 1:fd 是 open 返回的文件句柄。
参数 2:*termios_p 是前面介绍的结构体。
使用这个函数前可以先定义一个 termios 结构体,用于存储旧的参数

cfsetispeed(struct termios *termios_p, speed_t speed);

置波特率的函数
参数 1:*termios_p 是前面介绍的结构体。
参数 2:speed 波特率,常用的 B2400,B4800,B9600,B115200,B460800 等等。
执行成功返回 0,失败返回-1

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)

用于读取当前串口输入的波特率。
参数 1:*termios_p 是前面介绍的结构体。
返回值为 speed_t。
函数 speed_t cfgetospeed(const struct termios *termios_p)。这个函数用于读取当前
输出的波特率。
参数 1:*termios_p 是前面介绍的结构体

speed_t cfgetospeed(const struct termios *termios_p)

用于读取当前输出的波特率。
参数 1:*termios_p 是前面介绍的结构体。
返回值为 speed_t 类型,当前波特率。

int tcflush(int fd, int queue_selector);

函数 tcflush 用于清空串口中没有完成的输入或者输出数据。在接收或者发送数据的时候,
串口寄存器会缓存数据,这个函数用于清除这些数据。
参数 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
一般在初始化最后会使用这个函数

unsigned int sleep(unsigned int seconds);

例如:sleep(1),即延时一秒。
返回无符号的整形数值,如果延时成功则返回 0,如果延时过程中被打断,则返回剩余的
秒数。例如 sleep(5),返回值为 3,那么实际延时就是 5-3=2 秒。

int usleep(useconds_t usec);

Useconds 需要小于 1000000
例如:usleep(10),表示延时 10 微秒。
延时成功则返回 0,失败则返回-1

void mdelay(unsigned long msecs);

例如:mdelay(10),表示延时 10 毫秒。

void udelay(unsigned long usecs);

例如:udelay(5),表示延时 5 微秒。

void ndelay(unsigned long nsecs);

例如:ndelay(3),表示延时 3 纳秒。

int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);

高精度时间
参数 tv:用于保存获取的时间。
参数 tz:可以缺省,传入 NULL。

无名管道 pipe

从 UNIX 系统开始,无名管道的通信方式就存在,有点类似硬件中的串口,从最初的设计者定型之后,这种模型就一直延续到今天,说明无名管道当初设计的就极具科学性。
不过无名管道有一定的局限性。
第一:它是属于半双工的通信方式;
第二:只有具有“亲缘关系”的的进程才能使用这种通信方式,也就是父进程和子进程之间

 int pipe(int pipefd[2])

参数 pipefd[0]:用于读管道。
参数 pipefd[1]:用于写管道。
返回值:执行成功返回 0,失败返回-1。

有名管道 fifo

无名管道只能用于有亲缘进程之间的通信,有名管道可以实现无亲缘关系的通信。
有名管道 fifo 给文件系统提供一个路径,这个路径和管道关联,只要知道这个管道路径,
就可以进行文件访问,fifo 是指先进先出,也就是先写入的数据,先读出来。

 int mkfifo(const char *pathname, mode_t mode);

参数*pathname:路径名,管道名称。
参数 mode:管道的权限。
返回值:成功返回 0,错误返回-1。

消息队列 msg

分析一下 msgrcv 和 msgsnd 函数。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数 msqid:消息队列的标识码。
参数*msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用
户可定义的通用结构。
参数 msgsz:消息的长短。
参数 msgflg:标志位。
返回值:成功返回 0,错误返回-1。

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

参数 msqid:消息队列的标识码。
参数*msgp:指向消息缓冲区的指针。
参数 msgsz:消息的长短
参数 msgflg:标志位。
返回值:成功返回数据长度,错误返回-1。

信号 signal
unsigned int alarm(unsigned int seconds);

参数 seconds:闹钟的时间,单位为秒。
返回值:成功返回 0 或者返回剩余时间;错误返回-1。

sighandler_t signal(int signum, sighandler_t handler);

参数 signum:等待的信号。
参数 handler:信号到来之后,触发的处理方式。
返回值:成功返回 0,错误返回-1。

信号量 Semaphore
int semget(key_t key, int nsems, int semflg);

参数 key:一个用来允许不相关的进程访问相同信号量的整数值。
参数 nsems:需要的信号量数目。这个值通常总是 1。
参数 semflg:标记集合,与 open 函数的标记十分类似。
返回值:成功返回标识符,用于其它信号函数,错误返回-1。

共享内存 shmdata
int shmget(key_t key, size_t size, int shmflg);

参数 key:建立新的共享内存对象
参数 size:新建立的内存大小
参数 shmflg:标识符
返回值:成功 shmget 返回一个共享内存标识符或创建一个共享内存对象,错误返回-1。
其它函数,如下所示。

void *shmat(int shmid, const void *shmaddr, int shmflg)

参数 shmid:共享内存标识符
参数 shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为 NULL 让内核
自己决定一个合适的地址位置
参数 shmflg :SHM_RDONLY,为只读模式,其他为读写模式
返回值:成功返回共享的内存地址,否则返回-1。

int shmdt(const void *shmaddr)

参数 shmaddr:连接的共享内存的起始地址。
返回值:成功返回 0,错误返回-1。

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

参数 shmid:共享内存标识符
参数 cmd IPC_RMID:删除这片共享内存
参数 buf:共享内存管理结构体
返回值:成功返回 0,错误返回-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值