版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第10章 应用程序编程举例 及驱动程序分析(一) 本章重点:本章重点: 读取、转换时间函数编程举例; 多线程编程举例; 串行端口及标准输入/输出/错误编程举例; ADC应用程序编程举例(S3C2410A)。10.1 读取、转换时间函数编程举例 Linux系统中,涉及到时间较为常用的三个名词术语是:n GMT(Greenwich Mean Time),格林尼治标准时间。n UTC(Coordinated Universal Time),世界标准时间,是由原子钟提供的时间,比格林尼治标准时间更为准确。n CST(China Standard Time),中国标准时间,或称北京时间。 我们现在所说的
2、标准时间,通常是指UTC时间。 北京时间CST=UTC+8小时。 另外,本节中所说的时间,除了我们通常所说的时间外,还包含日期。10.1.1Linux查看、设置时间的命令 查看时间 使用date命令可以查看时间,通常显示的是当地时区的时间,例如北京时间: rootvm-dev # date 六 3月 31 09:14:41 CST 2012 上述内容分别表示:年、月、日、星期、时、分、秒以及CST,是主机Linux的输出。 有的目标板,配置为显示UTC时间,例如: /mnt/yaffsdate Sat Mar 31 09:27:06 UTC 2012 设置时间 主机Linux设置时间后,会保留
3、;目标板设置时间后,加电或RESET后不保留。以下是主机显示、设置时间举例。 使用参数u表示UTC时间 设置时间可以使用命令及参数: date u MMDDhhmmYYYY.ss 其中u表示UTC,从MM开始的参数分别表示月、日、时、分、年和秒。 例如: rootvm-dev # date -u 033110162012.30 六 3月 31 10:16:30 UTC 2012 系统会将设置的UTC时间,自动转换成CST时间显示,例如输入date命令后,会显示: rootvm-dev # date 六 3月 31 18:16:42 CST 2012 不使用参数u表示按当地时间设置 以下设置没有
4、设置秒,缺省值为0: rootvm-dev # date 033110162012 六 3月 31 10:16:00 CST 2012 rootvm-dev # date 六 3月 31 10:16:03 CST 201210.1.2 常用的读取、转换时间的函数 所有的Linux系统,把GMT时间的1970年1月1日0时0分0秒,作为时间的起点,所有时间都是从那时起,以经过的秒数来计算。 时间通过一个预定义的类型time_t来处理,这是一个以秒计算的时间的整数类型,是一个长整型,与处理时间的函数一起定义在头文件time.h中。 time()函数 例如代码: #include time_t th
5、e_time;/*定义类型*/ (void)time(&the_time);/*得到时间值,单位为秒*/ printf(“Raw time is %ldn”,the_time);/*输出时间值*/ 上述代码能够输出从Linux时间起点,到time函数读取那一刻所经过的时间的秒数。 关于time()函数进一步的用法,见例10.1。 gmtime()函数 gmtime()函数能够把以秒表示的时间值,转换成用户易读格式的值。 gmtime()函数把底层时间值分解为一个结构,该结构包含一些常用的成员: #include struct tm *gmtime(const time_t timeva
6、l); tm结构被定义为至少包含表10-1所示的成员。 tm成员成员含义含义tm成员成员含义含义int tm_sec秒,秒,061int tm_year从从1900年算起的年算起的年数年数int tm_min分,分,059int tm_wday星期几,星期几,06,0表示周日表示周日int tm_hour时,时,023int tm_yday年 份 中 的 日 ,年 份 中 的 日 ,0365int tm_mday月 份 中 的 日 ,月 份 中 的 日 ,131int tm_isdst是否夏令时是否夏令时int tm_mon月,月,011,0表示表示1月月注:注:tm_sec的范围允许临时闰的
7、范围允许临时闰1秒或秒或2秒。秒。表表10-1 tm结构至少包含的成员结构至少包含的成员 函数gmtime()按GMT返回时间。 如果要看当地时区的时间,可以使用localtime()函数,使用方法是在程序中,用localtime()函数代替gmtime()函数。 有些小规模的目标板,生产商把当地时区的时间直接设置为GMT时间,使用者要引起注意。 ctime()函数 函数ctime()返回一个长度为26个字符、有固定格式、表示当地时间的字符串,函数格式为: char *ctime(const time_t *timeval); 函数ctime()输出字符串格式见例10.1。 函数ctime()
8、将底层的时间值,即秒值,转换成用户易读格式的值。 10.1.3 读取、转换时间的函数编程举例(S3C2410A) 编程举例 【例10.1】以下为读取、转换并输出时间的程序,程序名为time.c,源程序保存在主机Linux,路径为源程序所在路径为/arm2410cl/exp/basic/01_time/。 程序中time()函数读取时间的秒值;gmtime()函数将这个秒值转换成一个结构,保存在tm_ptr中;ctime()函数把秒值转换成一个字符串;printf()函数将秒值、结构、字符串输出。sleep(3)函数表示休眠3秒,然后重复读取秒值、转换成结构和字符串输出。 程序代码为:#incl
9、ude #include /*#include */int main() struct tm *tm_ptr; time_t the_time; (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year, tm_ptr-tm_mon+1,tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min,tm_p
10、tr-tm_sec); printf(The date is:%sn,ctime(&the_time); sleep(3); (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year,tm_ptr-tm_mon+1, tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min, tm_ptr-tm
11、_sec); printf(The date is: %sn,ctime(&the_time); return 0; 程序运行结果解释 例10.1的源代码经过交叉编译,产生的可执行文件为time,能够在目标板运行。 运行可执行文件前,为了与程序输出的时间对比,可以先用date命令查看目标板的时间: /host/exp/basic/01_timedate Fri Mar 30 10:06:00 UTC 2012在目标板运行可执行文件time,输出内容为:/host/exp/basic/01_time./timeRaw time is 1333101971date: 112/ 3/30ti
12、me: 10/ 6/11The date is:Fri Mar 30 10:06:11 2012 Raw time is 1333101974 date: 112/ 3/30 time: 10/ 6/14 The date is: Fri Mar 30 10:06:14 2012 上述内容中,Raw time对应的是秒数;date对应的是112/3/30,表示从1900年算起经过112年(2012年)的3月30日,time对应的是时/分/秒;然后是ctime()函数产生的字符串。10.1.4 例10.1对应的Makefile文件(S3C2410A) 对例10.1代码进行编译的Makefile文
13、件内容如下: rootvm-dev 01_time# vi Makefile TOPDIR=./ include $(TOPDIR)Rules.mak EXEC = $(INSTALL_DIR)/time ./time OBJS = time.o all: $(EXEC) $(EXEC): $(OBJS)$(CC) $(LDFLAGS) -o $ $(OBJS) install:$(EXP_INSTALL) $(EXEC) $(INSTALL_DIR) clean:-rm -f $(EXEC) *.elf *.gdb *.o 上述TOPDIR=./中的./表示父目录,即上一层目录,在该目录中含
14、有Rules.mak文件。另外编译器产生的可执行文件名为time,目标文件名为time.o。 在文件Rules.mak中,指出了交叉编译器的前缀是armv4l-unknown-linux: rootvm-dev basic# vi Rules.mak TOPDIR= . CROSS = armv4l-unknown-linux- CC= $CROSSgcc #CC=gcc #CFLAGS += -g #LDFLAGS += -static EXTRA_LIBS += EXP_INSTALL = install -m 755 INSTALL_DIR = ./bin10.1.5 读取、转换时间的函
15、数编程举例 (OMAP3530)1. 编程举例 【例10.2】以下为读取、转换并输出时间的程序,程序名为time.c,源程序保存在主机Linux,路径为/home/nfs1/01_time,Makefile文件也保存在这个目录。 程序中time()函数读取时间的秒值;gmtime()函数将这个秒值转换成一个结构,保存在tm_ptr中;ctime()函数把秒值转换成一个字符串;printf()函数将秒值、结构、字符串输出。sleep(3)函数表示休眠3秒,然后重复读取秒值、转换成结构和字符串输出。 程序代码为:#include #include /*#include */int main() s
16、truct tm *tm_ptr; time_t the_time; (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year, tm_ptr-tm_mon+1,tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min,tm_ptr-tm_sec); printf(The date is:%sn,cti
17、me(&the_time); sleep(3); (void)time(&the_time); tm_ptr=gmtime(&the_time); printf(Raw time is %ldn,the_time); printf(date:%2d/%2d/%2dn, tm_ptr-tm_year,tm_ptr-tm_mon+1, tm_ptr-tm_mday); printf(time: %2d/%2d/%2dn, tm_ptr-tm_hour,tm_ptr-tm_min, tm_ptr-tm_sec); printf(The date is: %sn,ctime(&
18、amp;the_time); return 0; 程序运行结果解释 例10.2的源代码经过交叉编译,产生的可执行文件为time,能够在目标板运行。 运行可执行文件前,为了与程序输出的时间对比,可以先用date命令查看目标板的时间: rootTechv_OMAP35xx:/# date Fri Jan 11 10:45:00 UTC 2013在目标板运行可执行文件time,输出内容为:rootTechv_OMAP35xx:/# cd /tmp/01_timerootTechv_OMAP35xx:/var/volatile/tmp/01_time# ./timeRaw time is 135790
19、1145date: 113/ 1/11time: 10/45/45The date is:Fri Jan 11 10:45:45 2013 Raw time is 1357901148 date: 113/ 1/11 time: 10/45/48 The date is: Fri Jan 11 10:45:48 2013 上述内容中,Raw time对应的是秒数;date对应的是113/1/1,表示从1900年算起经过113年(2013年)的1月1日,time对应的是时/分/秒;然后是ctime()函数产生的字符串。10.1.6 例10.2对应的Makefile文件(OMAP3530) 对例1
20、0.2代码进行编译的Makefile文件内容如下: rootlocalhost 01_time# vi Makefile CC = /usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gcc all: $(CC) -o time time.c clean: -rm -f *.o time 10.1.7 执行例10.2程序前的操作过程举例 (OMAP3530) 进入例10.2程序所在目录并显示程序名 rootlocalhost nfs1# cd /home/nfs1/01_time rootlocalhost 01_time# ls -l 总
21、计 20 -rwxr-xr-x 1 root root 116 11-19 17:09 Makefile -rwxr-xr-x 1 root root 5813 11-19 17:09 time -rwxr-xr-x 1 root root 959 2012-04-16 time.c -rwxr-xr-x 1 root root 1456 2012-04-16 time.o 检查或设置主机、目标板IP地址 在主机终端窗口设置主机Linux IP地址 rootlocalhost 01_time# ifconfig eth0 192.168.1.5 在目标板终端窗口设置目标板Linux IP地址
22、Techv_OMAP35xx login: root rootTechv_OMAP35xx:# ifconfig eth0 192.168.1.9 eth0: link down rootTechv_OMAP35xx:# eth0: link up, 100Mbps, full-duplex1 在目标板终端窗口测试与主机网络连接状况 rootTechv_OMAP35xx:# ping 192.168.1.5 在目标板终端窗口挂接NFS # mount -o soft,nolock,rsize=1024 -v 192.168.1.5:/home/nfs1 /tmp 在主机终端窗口编译源程序 ro
23、otlocalhost 01_time# make 在目标板进入相应目录、显示文件名、执行文件 rootTechv_OMAP35xx:/# cd tmp/01_time rootTechv_OMAP35xx:/var/volatile/tmp/01_time# ls Makefile time time.c time.o rootTechv_OMAP35xx:/var/volatile/tmp/01_time# ./time 10.2 多线程编程举例10.2.1Linux线程概述 通常把一个程序中的多个执行路线,称为线程(thread)。 Linux系统在1996年第一次获得了线程的支持,当时
24、使用的函数库称为LinuxThread。 本地POSIX线程库(Native POSIX Thread Library,NPTL)项目,是通过修改Linux内核来实现支持新的线程函数库的。通过该项目的实施,极大地提高了Linux线程的性能。NPTL将成为Linux线程的新标准,第一个NPTL的主流版本出现在Red Hat 9.0版上。 绝大部分线程函数是以pthread_开头的,并且要求在应用程序中包含头文件pthread.h,pthread.h文件提供了代码中使用的定义和函数原型。 对应用程序进行编译时,需要使用选项-lpthread来链接线程库,例如可以在Makefile文件中增加语句:
25、EXTRA_LIBS += -lpthread 来实现链接线程库。 10.2.2 线程、互斥量、条件变量函数 线程函数 创建线程函数 创建线程函数的作用是创建一个新的线程,定义如下: int pthread_create(pthread_t *thread,pthread_attr_t *attr,void *(*start_routine)(void *),void *arg); 函数中第1个参数是指向pthread_t类型数据的指针,线程被创建时,这个指针指向的变量中将被写入一个标识符,之后用这个标识符来引用新线程。 函数中第2个参数用于设置线程的属性,通常设置为NULL。 函数中第3、4
26、个参数,分别告诉线程将要启动执行的函数地址和传递给该函数的参数。 创建线程函数调用成功时,返回值为0。 创建线程函数代码举例如下:(p351) 上述代码中,创建线程函数的第1个参数th_a中将被写入一个标识符,以后用th_a中的标识符来引用新线程;函数中第2个参数属性为NULL;第3个参数传递了一个函数地址,即producer函数入口地址,新线程将在这个新的地址开始执行;第4个参数传递的值为0。 等待线程结束函数 等待线程结束函数,将阻塞调用它的线程(在前述创建线程函数代码举例中,main()也是一个线程,等待线程结束函数将阻塞main()线程),直到该函数指定的线程结束为止。 int pth
27、read_join(pthread_t th,void *thread_return); 函数中第1个参数指定了正在等待结束的线程,即创建线程时指定的标识符,如创建线程函数代码举例中th_a中的标识符。 函数中第2个参数是一个指针,它指向另一个指针,而后者指向线程的返回值。 等待线程结束函数调用成功时,返回值为0。 互斥量函数 多线程程序中,可以通过互斥量加锁、解锁机制,控制各个线程对共享数据区访问的同步操作。 通常将多个线程用到的共享数据区,设计成通过函数进行访问;并且对访问的函数,使用同一个互斥量进行保护;进入这个函数后对互斥量加锁,完成访问操作后对互斥量解锁。这样可以保证在一个互斥量的保
28、护下,访问函数的运行不会被其他线程所打断,从而保证了每次只有一个线程访问共享数据区。 常用的互斥量函数有初始化互斥量、互斥量加锁、互斥量解锁和释放互斥量4个函数。 初始化互斥量函数定义: int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr); 互斥量加锁函数定义: int pthread_mutex_lock(pthread_mutex_t *mutex); 互斥量解锁函数定义: int pthread_mutex_unlock(pthread_mutex_t *mutex); 释
29、放互斥量函数定义: int pthread_mutex_destroy(pthread_mutex_t *mutex); 这4个函数的参数,都是一个事先声明过的对象的指针,类型为pthread_mutex_t。 使用互斥量前,要先对互斥量进行初始化。 互斥量加锁函数,首先检查互斥量是否已经处于加锁状态,如果没有处在加锁状态,则对其加锁,并运行后续程序;如果已经处于加锁状态,则使当前运行的程序进入阻塞状态,一直等到其他程序使互斥量解锁,才能退出阻塞状态,运行后续程序。 互斥量解锁函数,使已加锁的互斥量变为解锁状态。加锁和解锁函数,必须在同一段代码中配对使用。如果有多个线程等待互斥量解锁,排在等待
30、队列中的第1个线程首先从阻塞中退出并运行。 使用完互斥量,应该释放互斥量,释放占用的资源。释放前,互斥量应处于未加锁状态。 上述4个函数成功执行后,返回值均为0。 互斥量函数的使用,见例10.3。 条件变量函数 条件变量通常与互斥量相互配合使用,使用条件变量之前要先进行初始化,使用完应该释放条件变量。 常用的条件变量函数有初始化条件变量、等待条件变量、设置条件变量和释放条件变量4个函数。 初始化条件变量函数定义: int pthread_cond_init (pthread_cond_t * cond, _const pthread_condattr_t * cond_attr); 等待条件变
31、量函数定义: int pthread_cond_wait (pthread_cond_t *_restrict_cond, pthread_mutex_t *_restrict _mutex); 设置条件变量函数定义: int pthread_cond_signal (pthread_cond_t *_cond); 释放条件变量函数定义: int pthread_cond_destroy (pthread_cond_t *_cond); 条件变量只有未被使用时才能初始化。 等待条件变量函数,使线程(或函数)阻塞在指定的条件变量上;并且对指定的互斥量解锁,使其他线程可运行;阻塞一直持续到条件变量
32、被其他线程唤醒为止,并且在函数返回前系统自动对互斥量加锁。 设置条件变量函数,是用来唤醒被阻塞在条件变量上的一个线程(或函数),如果有多个线程阻塞在这一个条件变量上,由线程的调度策略来决定唤醒哪一个。如果没有一个关于条件变量的线程被阻塞,则该函数无效。 释放条件变量函数,只有在没有线程被阻塞在该条件变量上时,才能释放这个条件变量。 上述4个函数成功执行后,返回值均为0。 条件变量的使用,见例10.3。 10.2.3 生产者、消费者编程举例(S3C2410A) 生产者、消费者程序编程考虑 假定有一个数据缓冲区,大小为8个单元,整数类型。生产者(程序)要往缓冲区填充数据,比如填充数据0199,并且
33、每填充一个数据同时将该数据送终端显示。而消费者(程序)要从缓冲区读出数据,同时送终端显示。为了填充数据,设置一个写指针;为了读出数据,设置一个读指针。每写入缓冲区一次数据,修改写指针;从缓冲区每读出一次数据,修改读指针。 数据缓冲区设置为环状,即指针从0开始,最大到7,7以后再回到0。生产者将缓冲区填满后,要等消费者从缓冲区读出数据后,使缓冲区处于非满(not full)状态,生产者才能填充下一个数据;同样,消费者如果将缓冲区全部数据读出后,要等生产者往缓冲区填充数据后,使缓冲区处于非空(not empty)状态,消费者才能读取下一个数据。生产者和消费者线程通过使用互斥量和条件变量,交替进行。
34、 生产者producer对应的标识符在th_a中,消费者consumer对应的标识符在th_b中。 互斥量为b-lock,非满条件变量为b-notfull,非空条件变量为b-notempty。 生产者调用填充函数put()填充数据,消费者调用get()函数读出数据。 生产者、消费者程序代码及执行结果 以下程序代码,读者阅读时从主程序main()处开始。 【例10.3】生产者、消费者程序代码。(p354)n上述代码编译后,执行结果(部分)如下: /host/exp/basic/02_pthread./pthread put-0 put-1 put-2 put-3 put-4 put-5 put-
35、6 wait for not full 0-get put-7 1-get put-8 2-get . put-198 192-get put-199 193-get producer stopped! 194-get 195-get 196-get 197-get 198-get 199-get consumer stopped! /host/exp/basic/02_pthread 生产者、消费者程序代码和程序执行结果讨论 本程序中,生产者、消费者线程分别调用put()、get()函数,实现填充和读出数据功能,由于两个函数共用一个缓冲区,所以每个函数中都要对互斥量加锁、解锁。 生产者、消费
36、者程序代码中printf()函数,使用了串行口,将输出内容送到主机Linux下的minicom对应的窗口。在严格意义上讲,两个线程共用一个串行口设备,也应该对其使用互斥量加锁和解锁。 上述生产者、消费者程序代码,已经在两种开发环境下测试通过,一种是PC机只运行Linux;另一种是PC机运行Windows XP,然后启动虚拟机,在虚拟机中运行Linux。虽然程序是在目标板上执行的,但开发环境不一样,输出结果也不一样。例如,当程序中的填充数据从0199改为0999时,在Windows、虚拟机Linux环境下,minicom窗口的显示内容会发生错误;而只运行Linux的环境不会发生错误。经过测试、分
37、析认为,目标板执行的程序在两种环境下是相同的、没有错误的。错误可能产生在目标板-Windows-虚拟机-Linux的传输过程中。因此建议在产品开发阶段,开发环境中主机应该单独运行Linux。10.3 串行端口及 标准输入/输出/错误编程举例10.3.1Linux标准输入/输出/错误系统调用编程举例 系统调用、库函数和设备驱动程序 Linux中系统调用、库函数和设备驱动程序之间的关系,如图10.1所示。图10.1 系统调用、库函数和设备驱动程序之间的关系 由图10.1可见,用户程序可以直接使用系统调用;也可以通过库函数(如标准I/O库函数对应的头文件是stdio.h),由库函数去调用系统调用。由
38、系统调用去调用设备驱动程序,驱动硬件设备工作。 系统调用也是一些函数,它们由Linux直接提供,是通向操作系统本身的接口。 Linux系统把不同的设备,抽象成不同的文件;对设备的操作,抽象成对文件的open、read、write、close和ioctl等操作。 Linux标准输入/输出/错误系统调用 Linux标准输入/输出/错误这一术语的含义,是指标准输入设备/标准输出设备/标准错误输出设备。在一个用户程序运行时,系统已经打开了这3个设备,并且返回了相应的文件描述符。 Linux环境中,每个运行的程序被称为进程(process),每个进程有一些与之相关联的文件描述符。文件描述符是一些小数值的
39、整数,通常由用户打开(open)一个文件或设备时产生的返回值得到。 当一个用户程序开始运行时,它一般可以使用3个已经打开设备返回的文件描述符,这3个描述符不是由用户程序中打开(open)操作返回的,而是由系统产生的。这3个文件描述符是: 0表示标准输入,例如read(0,&c,1);表示从标准输入读入一个字符保存在c中; 1表示标准输出,例如write(1,&c,1);表示输出c中的一个字符到标准输出; 2表示标准错误,例如write(2,&c,1);表示输出c中的一个字符到标准错误。 当一个程序运行结束时,也不用通过这3个文件描述符去关闭(close)对应的文件或设备
40、。 标准输入/输出/错误与串行端口及仿真终端 嵌入式开发系统目标板上运行的程序,通常把标准输入/输出/错误对应的文件,与目标板上第一个串行端口,即/dev/tts/0设备关联起来。对标准输入/输出/错误的操作,就是对该串行端口的读、写操作。 由于目标板第一个串行端口通过电缆与主机串行端口连接,主机Linux系统启动minicom仿真终端程序后,目标板运行的程序中的标准输入系统调用,读入的是主机键盘输入内容,而标准输出和标准错误系统调用将输出的信息,通过串口送到主机仿真终端窗口。 使用标准输入/输出/错误系统调用时,不需要对串行端口重新设置波特率、帧格式、有无调制解调器等参数,默认使用目标板Li
41、nux内核已经设定的值。 10.3.2 Linux标准输入/输出/错误系统调用 编程举例(S3C2410A) 【例10.4】以下程序是使用标准输入/输出/错误系统调用的一个示例。 在目标板运行这个程序后,用户在主机minicom终端输入一个小写字母并回车,程序会自动输出全部小写字母,然后输出回车;继续输出全部小写字母,输出回车;直到用户按下Ctrl+c,程序终止;如果用户最初输入的不是小写字母,则程序直接退出。 程序代码如下:#include /*#include */#define FALSE 0#define TRUE 1/*-*/int main()char c;int STOP=FAL
42、SE;write(2,test std err output is ok.n,27);/*标准错误系统调用*/write(1,start std input test.n,22); /*标准输出系统调用*/write(1,input 1 char from a-z,out a-z string,and reapet.n,49);write (1,if input first char is other char,end.n,39);while (1) read(0,&c,1); /*标准输入系统调用*/ if (c z ) STOP=TRUE; break; write(1,the c
43、har is from read() function,std input:n ,44); write(1,&c,1); write(1,n std output,send data to terminal:n,36); c=a; while (STOP=FALSE) write(1,&c,1); c+; usleep(100000); if (c=z+1) c=n;write(1,&c,1);c=a; write(1,exit from program.n,19);exit(0); n目标板程序执行过程中,在主机仿真终端输出如下信息: test std err out
44、put is ok. start std input test. input 1 char from a-z out a-z string,and reapet. if input first char is other char,end. a std output,send data to terminal: abcdefghijklmnopqrstuvwxyz abc 10.3.3 Linux标准输入/输出/错误系统调用 编程举例(OMAP3530) 【例10.5】 以下程序是使用标准输入/输出/错误系统调用的一个示例。 在目标板运行这个程序后,用户在主机minicom终端输入一个小写字母
45、并回车,程序会自动输出全部小写字母,然后输出回车;继续输出全部小写字母,输出回车;直到用户按下Ctrl+c键,程序终止;如果用户最初输入的不是小写字母,则程序直接退出。 程序代码与例10.4完全相同,此处不再列出。 目标板程序执行过程中,在主机仿真终端输出信息与例10.4完全相同,此处不再列出。 说明:第5行a是从主机minicom终端键盘输入的字符,后面要跟回车。这个字符的显示,是由主机仿真终端程序minicom输出的,不是用户程序输出的。 程序中止用Ctrl+c键。 目标板每次加电或RESET后,都要输入mount命令和参数,重新挂接NFS目录。 Makefile文件代码如下: CC =
46、/usr/local/arm/arm-2007q3/bin/arm-none-linux-gnueabi-gcc all: $(CC) -o term term.c clean: -rm -f *.o term 假定上述程序代码、Makefile文件已经输入,保存在主机Linux的/home/nfs1/03_tty0目录,源程序名为term.c。rootlocalhost nfs1# cd /home/nfs1/03_tty0rootlocalhost 03_tty0# ls -l总计 20-rwxr-xr-x 1 root root 118 11-20 08:56 Makefiledrwxr
47、-xr-x 2 root root 4096 10-18 16:01 old-rwxr-xr-x 1 root root 5838 11-20 09:06 term-rwxr-xr-x 1 root root 1082 11-20 09:04 term.c10.3.4串行端口设备与文件关联及系统调用串行端口设备与文件关联及系统调用 Linux环境中,文件具有非常重要的意义,文件为操作系统服务,对设备的操作提供了一个简单而一致的接口。 在Linux中,一切都是文件。 用户程序完全可以像使用文件那样使用盘文件、目录、串行端口、打印机及其他设备。例10.6中,用户程序将一个串行端口映射为一个文件,然
48、后使用系统调用,对这个文件进行操作,内核通过调用对应的设备驱动程序,对串行端口硬件进行操作。 用于访问设备驱动程序的系统调用有: open:打开文件或设备 read:对打开的文件或设备执行读操作 write:对打开的文件或设备执行写操作 close:关闭文件或设备 ioctl:把控制信息传递给设备驱动程序 open系统调用,创建了一条到达文件或设备的访问路径,如果调用成功,返回一个系统文件描述符,其他几个系统调用,能够使用这个描述符对指定的文件或设备进行操作。 open系统调用中常用参数的含义如下所示: O_RDONLY,规定以读方式打开; O_WRONLY,规定以写方式打开; O_RDWR,
49、规定以读、写方式打开。 read系统调用,从文件描述符相关联的文件里,读入指定字节个数的数据,存入指定的数据区。调用成功,返回实际读入的字节个数,允许实际读入字节个数小于指定字节个数。如果返回为0,表示未读入数据,已到了文件尾;如果返回-1,表示出错。从目标板串口连接的终端键盘读入数据时,输入数据后按下回车键,数据才能由终端程序送到用户程序的read函数。 write系统调用,是把写缓冲区的指定字节个数的数据,写入与文件描述符关联的文件中。它的返回值是实际写入的字节数。如果返回0,表示未写入任何数据;如果返回-1,表示调用中出现了错误。 close系统调用,用于终止文件描述符与对应文件或设备之
50、间的关联。close调用成功时返回0,错误时返回-1。 10.3.5 串行端口设备与文件关联及 系统调用举例(S3C2410A) 在例10.6代码中,前半部分是将串行端口/dev/ttyS0与文件关联,使用系统调用对文件进行读写操作。这些操作实际上是通过目标板指定的串口,对串口连接的主机Linux下minicom仿真终端,进行读写操作。例10.6代码中后半部分,是Linux标准输入/输出/错误系统调用,其读写操作同样是对目标板连接的主机Linux下minicom仿真终端进行读写操作。 【例10.6】 以下程序中,fp是系统文件描述符;nread是实际读写字节个数;buffer是读写缓冲区。程序
51、先打开/dev/ttyS0文件(串行端口),然后对其读、写,最后关闭。后半部分程序中函数的含义同例10.4。 程序代码如下:#include #include #include #include #include #define COM1 /dev/ttyS2/*-*/int main()char buffer80;int nread;int fp;fp=open(COM1,O_RDWR);if (fp=-1) write(2,/dev/ttyS2 open err,exit.n,26); exit (0); write(1,n plese input char string,from /de
52、v/ttyS2:n,43);nread=read(fp,buffer,80);if (nread=-1) write(2,/dev/ttyS2 read err,exit.n,26); exit (0); write(1,n- from /dev/ttyS2 read string, out to /dev/tty2:-n,63);if (write(fp,buffer,nread)!=nread) write(2,/dev/ttyS2 write err,exit.n,27); exit(0); else write(fp,from /dev/ttyS2 read char string,h
53、as output.ok.n,48);close(fp);write(1,n please input char string from std in:n,40);nread=read(0,buffer,80);if (nread=-1) write(2,std in read err,exit.n,22); exit(0); write(1,n- from std in read string, out to std out:-n,56);if (write(1,buffer,nread)!=nread) write(2,std out write err,exitn,23);exit (0
54、); else write(1,from std in read char string,has output.nn,42);exit(0); 如果程序不能正确执行,并显示以下信息: /dev/ttyS0:No such file or directory 表示找不到/dev/ttyS0设备,需要建立以下软链接,然后再执行程序。 /mnt/yaffs cd /dev /dev ln sf /dev/tts/0 ttyS0 如果对目标板文件已经进行了软链接操作,那么在目标板RESET后,要重新链接,因为软链接产生的信息没有被长期保存。 程序执行结果举例如下: please input char
55、string,from /dev/ttyS0: abcd(回车) - from /dev/ttyS0 read string,out to /dev/ttyS0: - abcd from /dev/ttyS0 read char string,has output.ok. please input char string from std in: efgh(回车) - from std in read string,out to std out: - efgh from std in read char string,has output. 10.3.6 串行端口设备与文件关联及 系统调用举例
56、(OMAP3530) 在例10.7代码中,前半部分是将串行端口/dev/ttyS2与文件关联,使用系统调用对文件进行读写操作。这些操作实际上是通过目标板指定的串口,对串口连接的主机Linux下minicom仿真终端,进行读写操作。 例10.7代码中后半部分,是Linux标准输入/输出/错误系统调用,其读写操作同样是对目标板连接的主机Linux下minicom仿真终端进行读写操作。 例10.7代码串行端口参数没有重新设置,仍使用系统默认的波特率、帧格式,不使用调制解调器。 【例10.7】以下程序中,fp是系统文件描述符;nread是实际读写字节个数;buffer是读写缓冲区。程序先打开/dev/
57、ttyS0文件(串行端口),然后对其读、写,最后关闭。后半部分程序中函数的含义同例10.4。 程序代码如下:#include #include #include #include #include #define COM1 /dev/ttyS2/*-*/int main()char buffer80;int nread;int fp;fp=open(COM1,O_RDWR);if (fp=-1) write(2,/dev/ttyS2 open err,exit.n,26); exit (0); write(1,n plese input char string,from /dev/ttyS2:
58、n,43);nread=read(fp,buffer,80);if (nread=-1) write(2,/dev/ttyS2 read err,exit.n,26); exit (0); write(1,n- from /dev/ttyS2 read string, out to /dev/tty2:-n,63);if (write(fp,buffer,nread)!=nread) write(2,/dev/ttyS2 write err,exit.n,27); exit(0); else write(fp,from /dev/ttyS2 read char string,has outpu
59、t.ok.n,48);close(fp);write(1,n please input char string from std in:n,40);nread=read(0,buffer,80);if (nread=-1) write(2,std in read err,exit.n,22); exit(0); write(1,n- from std in read string, out to std out:-n,56);if (write(1,buffer,nread)!=nread) write(2,std out write err,exitn,23);exit (0); else
60、write(1,from std in read char string,has output.nn,42);exit(0);执行程序及输出结果举例如下:rootTechv_OMAP35xx:/var/volatile/tmp/03_tty1# ./term plese input char string,from /dev/ttyS2:abcd- from /dev/ttyS2 read string, out to /dev/tty2:-abcdfrom /dev/ttyS2 read char string,has output.ok. please input char string from std in:qwer- from std in read string, out to std out:-qwerfrom std
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 经济法考核培训试题及答案
- 2026年嘉峪关市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)附答案详解(研优卷)
- 菏泽市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)及参考答案详解一套
- 2025年江西气象面试真题及答案
- 全国模特比赛题库及答案
- 益阳市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)及参考答案详解1套
- 2026年庆阳市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)附答案详解(夺分金卷)
- 铁岭市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)带答案详解
- 2026年宣城市农村信用社联合社秋季校园招聘笔试备考题库(浓缩500题)附答案详解(达标题)
- 绍兴市中医院设备质控检测考核
- 玫瑰知识培训课件
- 青桐鸣大联考2025-2026学年高一上学期10月月考物理试卷
- 2025年10月全国教育学原理自考试题及答案
- 2025济钢集团有限公司校园招聘(48人)笔试参考题库附带答案详解
- 2025版《煤矿安全规程》题库
- 辽宁省名校联盟2025-2026年高三10月联考物理试卷+答案
- 非人力资源经理的人力资源管理
- 公司庆典合同(标准版)
- 诉讼保全险培训课件
- 2025人民出版社供小学用中华民族大家庭教学课件:第7课 中华民族的语言文字 含多个微课视频
- GJB2460A-2020军用夹布橡胶软管规范
评论
0/150
提交评论