5.5.2 Linux 下的网络编程
车载终端可以通过 TCP 或UDP 的方式与上位机进行连接。而TCP/UDP 程序的设计采用的是套接字的方式[46]。套接字是进行程序间通信的一种方法,在客户/服务器通信模型中,一个套接字就是通信的一端,因此可使不同主机间进程实现双向通信。套接字主要有三种类型。流式套接字是最常用的套接字类型,在TCP 协议中使用此类接口,提供面向连接的,无差错的,发送顺序一致的,包长度不限和非重复的网络信息包的传输。数据报套接字在UDP 协议中使用,提供无连接的服务,以独立的数据报进行网络传输,数据报的最大长度为32KB,传输不保证顺序性,可靠性和无重复性,通常用于单个报文传输或者对于可靠性要求不高的场合。还有一类称为原始报套接字,提供对网络下层通信协议的直接访问。原始套接字主要用于开发新的协议或用于提取协议比较隐蔽的功能。对于车载系统而言无论是用 TCP 还是UDP 方式与上位机通信,都只用开发客户端的程序就可以了。因为本系统用的是UDP 方式进行连接的所以详细介绍一下UDP方式的程序设计。UDP 是个面向数据报的简单传输层协议。它为应用程序发送和接收数据报。一个数据报是指从发送方传输到接收方的一个信息单元,这个单元大小一般由发送方决定。它是—种无连接协议,即,它不像TCP 那样需要建立服务器与客户端的连接才可以工作,因此它不能及时地返回数据传输状态,因此不能保证数据可以可靠地传输到日的地。
5.5.3 Linux 下的多线程编程
线程技术早在60 年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,同进程相比线程彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。 多线程程序作为一种多任务、并发的工作方式,具有以下的优点:
提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作置于一个新的线程,可以避免这种尴尬的情况。
使多CPU 系统更加有效。操作系统会保证当线程数不大于CPU 数目时,不同的线程运行于不同的CPU 上。
改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或
半独立的运行部分,这样的程序会利于理解和修改。
正是由于多线程程序由以上的优点所以整个车载终端的程序会按照多线程的方式进行编写。Linux 系统下的多线程遵循POSIX[48]线程接口,称为pthread。编写Linux 下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。创建一个线程的函数是extern int pthread_create __P ((pthread_t *__thread,__const pthread_attr_t *__attr,void*(*__start_routine) (void *),void *__arg));第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。函数pthread_join 用来等待一个线程的结束。函数原型为:extern int pthread_join __P
((pthread_t __th, void **__thread_return)); 第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。
当线程创建了以后就要考虑互斥和同步的问题。互斥,就是对某段代码或某个变量修改的时候只能有一个线程在执行,其它线程不能同时进入该段代码或同时修改变量。Linux 下可以通过pthread_mutex_t 定义互斥锁完成多线程的互斥操作。pthread_mutex_t定义互斥锁变量,用于保护临界区,互斥锁有locked,un locked 两种状态。pthread_mutex_init 用于对互斥锁变量初始化;pthread_mutex_lock 用于对互斥体进行加锁操作(互斥锁被置为locked) ,若互斥锁原来就为locked,则当前线程被阻塞;pthread_mutex_unlock用于用于对互斥体进
行解锁操作(互斥锁被置为unlocked) ,唤醒被锁定的线程。互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来, 条件变量被用来进行线程间的同步。pthread_cond_t用于定义条件变量,pthread_cond_init函数用于初始化一个条件变量,pthread_cond_wait函数使线程阻塞在一个条件变量上,并同时可以解开互斥锁,因此可以避免死锁的产生,pthread_cond_signal 用来释放被阻塞在条件变量cond 上的一个线程,pthread_cond_destroy 函数用于释放一个条件变量。
5.5.4 应用程序介绍
智能车载终端系统的应用程序在功能上可以分为7个功能模块,即初始化模块,控制模块,GPS数据获取模块,上行数据转换模块,用户界面模块,通信模块和下行数据处理模块。各模块的协作示意图如图5.1所示。 初始化模块 控制模块
GPS数据获取模块 上行数据转换模块 下行数据转换模块 用户界面模块 通信模块
初始化模块
控制模块 上行数据转换模块 用户界面模块 GPS数据获 取模块 下行数据转换模块 通信模块
图5.1 主程序各模块协作示意图
6 总结
本车载定位终端融合了 GPS 全球定位技术,GPRS 无线通信技术,ARM 嵌入式技术以及嵌入式Linux 系统的移植于编程,属于一个交叉学科的工程项目。尤其是采用GPRS 通信网络进行无线通信代替了传统的GSM 短信息通信模式,不仅节约了整个系统的运行成本,而且提高了数据的传输速度和可靠性。同时选用了工业级的带有内存管理功能的ARM9 芯片S3C2440作为处理器,并围绕它进行电路设计,使得该终端有很高的可靠性,并且能够适应比较恶劣的环境,因为选用了带内存管理功能的ARM9 芯片,所以可以移植ARMLinux 操作系统,该操作系统自带的资源十分丰富,使得应用程序的功能更加强大,同时也增加了软件的扩展性。
本文的重点即车载定位终端的设计,主要从硬件设计和软件设计两个方面进行了阐述。硬件设计主要包括各个模块的选型及格模块的实际硬件电路。软件部分主要阐述了Linux操作系统,几个关键技术如Linux 下的串口编程、Linxu 下的网络编程、Linux 下的多线程编程,然后把应用程序分成了初始化模块,控制模块,GPS 数据获取模块,上行数据转换模块,用户界面模块,通信模块和下行数据处理模块这七个模块予以介绍。
但限于本人水平和时间有限,还有许多地方需要完善,尤其是软件设计这一块。
参考文献
[1] 刘尚军, 张志兵等 ARM嵌入式技术与应用—基于Xscale处理器及 Vxworks操作系统 北京:北京航空航天大学出版社 2007.9
[2] 田泽 ARM9嵌入式Linux开发实验与实践 北京:北京航空航天大学出版2007
[3] 沈连丰 许波 夏玮玮等 嵌入式系统及其开发应用 北京:电子工业出版社 2011
[4] Embedded microcontrollers and processor Abhik Roychoudhury 北京:清华大学出版社 2010
[5] Embedded systems Tammy Noergaard 北京:人民邮电出版社 2008 [6]童永清 Linux C 编程实践 北京:人民邮电出版社 2008
[7]刘岚,尹勇 基于ARM的嵌入式系统开发 北京:电子工业出版社 2008 [8]三恒星科技 ARM9应用实例 北京:电子工业出版社 2007 [9]庞丽萍 操作系统原理 武汉:华中科技大学出版社 2008