嵌入式Linux编程基础.ppt

上传人:牧羊曲112 文档编号:6158773 上传时间:2023-09-30 格式:PPT 页数:53 大小:313.50KB
返回 下载 相关 举报
嵌入式Linux编程基础.ppt_第1页
第1页 / 共53页
嵌入式Linux编程基础.ppt_第2页
第2页 / 共53页
嵌入式Linux编程基础.ppt_第3页
第3页 / 共53页
嵌入式Linux编程基础.ppt_第4页
第4页 / 共53页
嵌入式Linux编程基础.ppt_第5页
第5页 / 共53页
点击查看更多>>
资源描述

《嵌入式Linux编程基础.ppt》由会员分享,可在线阅读,更多相关《嵌入式Linux编程基础.ppt(53页珍藏版)》请在三一办公上搜索。

1、第4章 嵌入式Linux编程基础4.1 Linux中系统调用的基本概念 4.2 Linux中用户编程接口(API)及系统命令的相互关系 4.3 Linux下设备文件读写方法 4.4 Linux中标准文件I/O函数的使用,4.1 Linux中系统调用的基本概念,系统调用,所谓系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。例如用户可以通过进程控制相关的系统调用来创建进程、实现进程调度、进程管理等。,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑

2、上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的“特殊接口”系统调用规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。,4.2 Linux中用户编程接口(API)及系统命令的相互关系,API,前面讲到的系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。在实际使用中程序员调用的通常是用

3、户编程接口API。比如open,close,read,write,ioctl等都是API接口函数。,2,open read write ioctl 调用其他库函数,open read write ioctl,硬件设备,应用程序,库,内核,驱动程序,Linux软件系统的层次关系(swi是ARM指令),系统命令,系统命令:ls,cd,mkdir,cp,chmod,rm系统命令相对API更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能。,4.3 Linux下设备文件读写方法,文件描述符,Linux中对目录和设备的操作都等同于文件的操作,因此,大大简化了系统对不

4、同设备的处理,提高了效率。Linux中的文件分为4种:普通文件、目录文件、链接文件和设备文件。内核如何区分和引用特定的文件呢?这里用到了一个重要的概念文件描述符。,文件描述符,内核如何区分和引用特定的文件呢?这里用到了一个重要的概念文件描述符。对于Linux而言,所有对设备和文件的操作都是使用文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符(fd);当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数.,通常一个进程启动时,都会打开3个文件:标准输入、标准输出和标

5、准出错处理。这3个文件对应的文件描述符为0、1和2(也就是宏替换STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO)基于文件描述符的I/O操作是Linux系统所特有的文件操作模式。,函数说明,open()函数是用于打开,在打开时可以指定文件的属性及用户的权限等各种参数。close()函数是用于关闭一个被打开的文件。当一个进程终止时,所有被它打开的文件都由内核自动关闭,很多程序都使用这一功能而不显示地关闭一个文件。read()函数是用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。若返回0,则表示没有数据可读,即已达到文件尾。读操作从文件的当

6、前指针位置开始。当从终端设备文件中读出数据时,通常一次最多读一行。,write()函数是用于向打开的文件写数据,写操作从文件的当前指针位置开始。对磁盘文件进行写操作,若磁盘已满或超出该文件的长度,则write()函数返回失败。ioctl()函数是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。也可以通过它实现对简单I/O设备进行控制。上述函数格式如下:,4.4 Linux中标准文件I/O函数的使用,数码管驱动程序中的函数驱动程序s3c2440-led.c#include#include#include

7、#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include,#define DEVICE_NAME s3c2440_led#define DEVICE_MAJOR 251#define DEVICE_MINOR 0struct cdev*mycdev;struct class_simple*myclass;dev_t devno;#define LED_TUBE_IOCTRL 0 x11#defin

8、e LED_DIG_IOCTRL 0 x12#define LED_BASE 0 x08000100static int led_base;,static int s3c2440_led_ioctl(struct inode*inode,struct file*filp,unsigned int cmd,unsigned int arg)printk(DOT buffer is%xn,arg8);printk(DOT buffer is%xn,arg);switch(cmd)case LED_DIG_IOCTRL:writel(arg 8,led_base+0 x10);writel(arg

9、8|arg 16,led_base+0 x11);return readl(led_base+0 x10);default:return printk(your command is not exist);return 0;,static int s3c2440_led_open(struct inode*inode,struct file*filp)printk(led device open sucess!n);return 0;static int s3c2440_led_release(struct inode*inode,struct file*filp)printk(led dev

10、ice releasen);return 0;static struct file_operations s3c2440_led_fops=owner:THIS_MODULE,open:s3c2440_led_open,ioctl:s3c2440_led_ioctl,write:s3c2440_led_write,release:s3c2440_led_release,;,int _init s3c2440_led_init(void)int ret;led_base=ioremap(LED_BASE,0 x20);writel(readl(S3C2410_BWSCON),devno=MKDE

11、V(DEVICE_MAJOR,DEVICE_MINOR);mycdev=cdev_alloc();cdev_init(mycdev,void _exit s3c2440_led_exit(void)cdev_del(mycdev);class_device_destroy(myclass,devno);class_destroy(myclass);module_init(s3c2440_led_init);module_exit(s3c2440_led_exit);,数码管驱动程序中的函数测试程序test_led.c#include#include#include#include#includ

12、e#include#define TUBE_IOCTROL 0 x11#define DOT_IOCTROL 0 x12void jmdelay(int n)int i,j,k;for(i=0;in;i+)for(j=0;j100;j+)for(k=0;k100;k+);,int main()int fd;int i,j,k;unsigned int LEDWORD;unsigned char LEDCODE10=0 xc0,0 xf9,0 xa4,0 xb0,0 x99,0 x92,0 x82,0 xf8,0 x80,0 x90;fd=open(/dev/s3c2440_led0,O_RDW

13、R);if(fd 0)printf(#Led device open fail#n);return(-1);,LEDWORD=0 xff00;printf(will enter TUBE LED,please waiting.n);LEDWORD=0 xff00;ioctl(fd,0 x12,LEDWORD);sleep(1);for(j=0;j2;j+)for(i=0;i10;i+)LEDWORD=(LEDCODEi8)|LEDCODE9-i;ioctl(fd,0 x12,LEDWORD);jmdelay(1500);close(fd);return 0;,Linux串口编程串口串口概述,常

14、见的数据通信的基本方式可分为并行通信与串行通信两种。并行通信是指利用多条数据传输线将一个字数据的各比特位同时传送。它的特点是传输速度快,适用于传输距离短且传输速度较高的通信。串行通信是指利用一条传输线将数据以比特位为单位顺序传送。特点是通信线路简单,利用简单的线缆就可实现通信,降低成本,适用于传输距离长且传输速度较慢的通信。串口是计算机一种常用的接口,常用的串口有RS-232-C接口。它是于1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准,它的全称是“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标

15、准”。该标准规定采用一个DB25芯引脚的连接器或9芯引脚的连接器,串口设置-termios结构,struct termios unsigned short c_iflag;/*输入模式标志*/unsigned short c_oflag;/*输出模式标志*/unsigned short c_cflag;/*控制模式标志*/unsigned short c_lflag;/*本地模式标志*/unsigned char c_line;/*线路规程*/unsigned char c_ccNCC;/*控制特性*/speed_t c_ispeed;/*输入速度*/speed_t c_ospeed;/*输出

16、速度*/;,串口设置-termios结构,termios是在POSIX规范中定义的标准接口,表示终端设备(包括虚拟终端、串口等)。因为串口是一种终端设备,所以通过终端编程接口对其进行配置和控制。终端有三种工作模式,分别为:规范模式(canonical mode);非规范模式(non-canonical mode);原始模式(raw mode)。通过在termios结构的c_lflag中设置ICANNON标 志来定义终端是以规范模式(设置ICANNON标 志)还是以非规范模式(清除ICANNON标志)工作,默认情况为规范模式。,终端模式(1)-规范模式,在规范模式下,所有的输入是基于行进行处理。

17、在用户输入一个行结束符(回车符、EOF等)之前,系统调用read()函数读不到用户输入的任何字符。除了EOF之外的行结束符(回车符等)与普通字符一样会被read()函数读取到缓冲区之中。在规范模式中,行编辑是可行的,而且一次调用read()函数最多只能读取一行数据。如果在read()函数中被请求读取的数据字节数小于当前行可读取的字节数,则read()函数只会读取被请求的字节数,剩下的字节下次再被读取。,终端模式(2)-非规范模式,在非规范模式下,所有的输入是即时有效的,不需要用户另外输入行结束符,而且不可进行行编辑。在非规范模式下,对参数MIN(c_ccVMIN)和TIME(c_ccVTIME

18、)的设置决定read()函数的调用方式。设置可以有4种不同的情况。MIN=0和TIME=0:read()函数立即返回。若有可读数据,则读取数据并返回被读取的字节数,否则读取失败并返回0。MIN 0和TIME=0:read()函数会被阻塞直到MIN个字节数据可被读取。MIN=0和TIME 0:只要有数据可读或者经过TIME个十分之一秒的时间,read()函数则立即返回,返回值为被读取的字节数。如果超时并且未读到数据,则read()函数返回0。MIN 0和TIME 0:当有MIN个字节可读或者两个输入字符之间的时间间隔超过TIME个十分之一秒时,read()函数才返回。因为在输入第一个字符之后系统

19、才会启动定时器,所以在这种情况下,read()函数至少读取一个字节之后才返回。,终端模式(3)-原始模式,按照严格意义来讲原始模式是一种特殊的非规范模式。在原始模式下,所有的输入数据以字节为单位被处理。在这个模式下,终端是不可回显的,而且所有特定的终端输入/输出控制处理不可用。通过调用cfmakeraw()函数可以将终端设置为原始模式,而且该函数通过以下代码可以得到实现。,termios_p-c_iflag,设置串口属性的基本流程(1),保存原先串口配置 首先,为了安全起见和以后调试程序方便,可以先保存原先串口的配置,在这里可以使用函数tcgetattr(fd,&old_cfg)。该函数得到f

20、d指向的终端的配置参数,并将它们保存于termios结构变量old_cfg中。该函数还可以测试配置是否正确、该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1,if(tcgetattr(fd,设置串口属性的基本流程(2),激活选项 CLOCAL和CREAD分别用于本地连接和接收使能,因此,首先要通过位掩码的方式激活这两个选项。,调用cfmakeraw()函数可以将终端设置为原始模式,在后面的实例中,采用原始模式进行串口数据通信。,newtio.c_cflag|=CLOCAL|CREAD;,cfmakeraw(,设置串口属性的基本流程(3),设置波特率设置波特率有专门的函数

21、,用户不能直接通过位掩码来操作。设置波特率的主要函数有:cfsetispeed()和cfsetospeed()。,设置字符大小 与设置波特率不同,设置字符大小并没有现成可用的函数,需要用位掩码。,cfsetispeed(,new_cfg.c_cflag,设置串口属性的基本流程(4),设置奇偶校验位 设置奇偶校验位需要用到termios中的两个成员:c_cflag和c_iflag。首先要激活c_cflag中的校验位使能标志PARENB和是否要进行偶校验,同时还要激活c_iflag中的对于输入数据的奇偶校验使能(INPCK)。,偶校验,奇校验,new_cfg.c_cflag|=(PARODD|PA

22、RENB);new_cfg.c_iflag|=INPCK;/启用输入奇偶检测。,new_cfg.c_cflag|=PARENB;new_cfg.c_cflag,设置串口属性的基本流程(5),设置停止位 设置停止位是通过激活c_cflag中的CSTOPB而实现的。若停止位为一个,则清除CSTOPB,若停止位为两个,则激活CSTOPB。以下分别是停止位为一个和两个时的代码:,new_cfg.c_cflag/*将停止位设置为两个比特*/,设置最少字符和等待时间 在对接收字符和等待时间没有特别要求的情况下,可以将其设置为0,则在任何情况下read()函数立即返回,new_cfg.c_ccVTIME=0

23、;new_cfg.c_ccVMIN=0;,设置串口属性的基本流程(6),清除串口缓冲 由于串口在重新设置之后,需要对当前的串口设备进行适当的处理,这时就可调用在中声明的tcdrain()、tcflow()、tcflush()等函数来处理目前串口缓冲中的数据,int tcdrain(int fd);/*使程序阻塞,直到输出缓冲区的数据全部发送完毕*/int tcflow(int fd,int action);/*用于暂停或重新开始输出*/int tcflush(int fd,int queue_selector);/*用于清空输入/输出缓冲区*/,设置串口属性的基本流程(7),在本实例中使用tc

24、flush()函数,对于在缓冲区中的尚未传输的数据,或者收到的但是尚未读取的数据进行处理。其处理方法取决于queue_selector的值,它可能的取值有以下几种。TCIFLUSH:对接收到而未被读取的数据进行清空处理。TCOFLUSH:对尚未传送成功的输出数据进行清空处理。TCIOFLUSH:包括前两种功能,即对尚未处理的输入输出数据进行清空处理。,tcflush(fd,TCIFLUSH);,设置串口属性的基本流程(8),激活配置 在完成全部串口配置之后,要激活刚才的配置并使配置生效。这里用 到的函数是tcsetattr()。,tcsetattr(int fd,int optional_ac

25、tions,const struct termios*termios_p);,其中参数termios_p是termios类型的新配置变量。参数optional_actions可能的取值有以下三种:TCSANOW:配置的修改立即生效。TCSADRAIN:配置的修改在所有写入fd的输出都传输完毕之后生效。TCSAFLUSH:所有已接受但未读入的输入都将在修改生效之前被丢弃。该函数若调用成功则返回0,若失败则返回1,if(tcsetattr(fd,TCSANOW,串口使用(1),打开串口 打开串口和打开普通文件一样,使用open()函数。,fd=open(/dev/ttyS0,O_RDWR|O_NO

26、CTTY|O_NDELAY);,O_NOCTTY标志用于通知Linux系统,该参数不会使打开的文件成为这个进程的控制终端。如果没有指定这个标志,那么任何一个输入(诸如键盘中止信号等)都将会影响用户的进程。O_NDELAY标志通知Linux系统,这个程序不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。,串口使用(2),读写串口 读写串口操作和读写普通文件一样,使用read()和write()函数:,write(fd,buff,strlen(buff);read(fd,buff,BUFFER_SIZE);,接下来可恢复串口的状态为阻塞状态,用于等待串口数据的读入:,接着可以测试打开文

27、件描述符是否连接到一个终端设备,以进一步确认串口是否正确打开:,fcntl(fd,F_SETFL,0);,isatty(STDIN_FILENO);,示例串行端口程序设计#include#include#include#include#include#include#define BAUDRATE B115200#define COM1/dev/ttyS0#define COM2/dev/ttyS1#define ENDMINITERM 27/*ESC to quit miniterm*/#define FALSE 0#define TRUE 1volatile int STOP=FALSE;

28、volatile int fd;,void child_handler(int s)printf(stop!n);STOP=TRUE;void*keyboard(void*data)int c;for(;)c=getchar();if(c=ENDMINITERM)STOP=TRUE;break;return NULL;,/*modem input handler*/void*receive(void*data)int c;printf(read modemn);while(STOP=FALSE)read(fd,void*send(void*data)int c=0;printf(send da

29、tan);while(STOP=FALSE)c+;c%=255;write(fd,/*wait for child to die or it will become a zombie*/,int main(int argc,char*argv)struct termios oldtio,newtio,oldstdtio,newstdtio;struct sigaction sa;int ok;pthread_t th_a,th_b,th_c;void*retval;if(argc 1)fd=open(COM2,O_RDWR);else fd=open(COM1,O_RDWR);/|O_NOCTTY|O_NONBLOCK);if(fd 0)perror(COM1);exit(-1);,tcgetattr(0,/串口属性设置立即生效。,sa.sa_handler=child_handler;sa.sa_flags=0;sigaction(SIGCHLD,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号