余炽业 雷瑞庭 宋跃 王健伟,2
(1. 东莞理工学院 电子工程学院,广东东莞 523808;2. 华南理工大学 电子与信息学院,广州 510640)
在ARM、Linux 技术广泛应用的今天,RS485 总线凭其传输距离远、抑制共模干扰能力强、用户可以自定义应用协议等优点在各种工业控制场合中而得到广泛的应用[1-2]。而其设计由于要涉及linux 内核复杂代码的修改,所以设计比较麻烦[3-4],如何简便地完成其RS485 通信设计也是值得研究的。我们在实际的工程设计中就此进行了研究与探索。
工程要求是:在ARM920T 核的S3C2440 处理器和嵌入式LINUX 基础上,完成ARM 和PC 机远程9600 bps 的稳定通信。
本设计以RS232 与半双工RS485 总线在I/O 控制方向的不同点为切入口,通过编写单个IO 的驱动来实现485 总线的方向控制,在应用层编程中利用多进程的发现调用方向控制程序,从而实现RS485 的通信,本文在介绍硬件接口、系统设计过程的同时,重点介绍LINUX 系统的软件设计思想与设计过程。
S3C2440 处理器片内集成了许多嵌入式应用的控制器,可以方便地实现嵌入式应用中的各种接口模块。本设计中用到了S3C2440 片内集成的三个UART(Universal Asynchronous Receiver/Transmitter),由于UART0 在移植嵌入式LINUX 的时候被用作控制台(console),所以如今用到的是UART1。由于ARM处理器的引脚电平和EIA 规定的电器标准不一样,所以必须要外接电平转换芯片[1,5-7],利用片内UART 外接不同的转换芯片可以轻松地实现RS485 或者RS232 串行协议标准。RS485 采用差分信号负逻辑,+2V ~+6V 表示“0”,-6V ~-2V 表示“1”。为了达到RS485 总线的电气特性标准,设计中用到Analog Devices 公司的半双工RS-485 隔离收发器。
ADM2483 是带隔离的增强型RS485 收发器,它包括一个三通道隔离器,一个带三态输出的差分驱动器和一个带三态输入的差分接收器,允许多达256 个收发器接入总线,最高传输速率为500 Kbps,逻辑端兼容3V/5V 工作电源。总线端5 V 供电。
图1 为系统中利用S3C2440 中的UART1 实现半双工的RS-485 总线的原理图,在同一时刻里数据只能往一个方向传输。其中的引脚RE’与DE 分别为接收使能和发送使能端,现在将其并联起来接到S3C2440 的nCTS0 引脚,由该引脚的电平控制芯片数据的方向。要发送数据时要叫其置1,接收数据时要将其清0。
图1 S3C2440-485 接口原理图
由于在RS485 标准中仅仅规定了总线的电气特性,而电气特性的转换则由AMD2483 芯片完成,所以在LINUX 操作系统中,完全可以借助内核的串口驱动来实现[4,8-9]。区别在于要在串口收发数据前增加一个方向控制I/O 的驱动。在linux2.6 内核源码当中,已经实现好了对S3C2440 的GPIO 的设置函数,可以在GPIO 口的驱动程序中直接调用,在本设计中用到了两个内核函数(在arch/arm/plat-s3c24xx/gpio. c)其函数原型如下:
void s3c2410_ gpio_ cfgpin(unsigned int pin,unsigned int function)。此函数的功能是设置引脚的功能,参数pin 是要设置的引脚,对应着是nCTS0 也即是S3C2410_ GPH0 引脚,参数function 是要设置引脚的功能,设置中用到的是输出功能所以该值是S3C2410_ GPH0_ OUTP。
void s3c2410_ gpio_ setpin(unsigned int pin,unsigned int x)。此函数的功能是设置引脚的输出值,参数pin 是要设置的引脚,参数x 是要设置引脚的输出值0 或者1。
单个引脚的驱动可以以简单字符设备的驱动来实现,其中只用到了一个重要的函数为
在嵌入式LINUX 中已经对串口的驱动有了很好的支持,而且已经将很多串口的功能设置都封装好,可以在应用层直接调用。串口的设备文件位于/dev 目录下,对串口的收发数据同样的是通过对设备文件的读写操作来实现的[2,9-10]。
在使用串口之前必须对其进行相关的配置,包括:波特率,数据位,校验位,停止位等。串口的设置有结构体struct termios 来体现的。利用串口相关的函数来设置结构体里面的值就可以完成串口的相关配置[11-12]。在本设计中将串口配置为波特率是9 600 bps,8 位数据位,无校验,1 位停止位。
LINUX 系统上的进程间有父子关系。一个进程有且仅有一个父进程,但是可能有多个子进程。在LINUX 系统中可以使用三个系统调用创建进程:fork(),vfork(),和clone()。其中fork()系统调用是穿件进程最常用的方式,其接口头文件与函数原型如下:
当fork 调用成功返回时,系统中将会出现一个新的进程。新的进程为原进程的子进程,而原进程则是新进程的父进程。子进程几乎完全克隆了父进程的一切特性,包括虚拟地址空间和执行进度。fork 函数返回一个pid_ t 型的进程ID,从程序员的角度看,父子进程的唯一差异在于fork 函数的返回值是不同的:父进程返回的是非零值,是其子进程的ID,如果是-1,就表示创建进程失败;而在子进程中永远返回0。这就是在程序中判断是父进程的依据。
在LINUX 系统中,经常将一个进程的执行流程从一个可执行程序转移到另一个可执行程序,也就是装载并运行一个程序。这些函数通常被称为exec 函数族,它们的接口头文件和原型如下:
以上各个函数的对比如表1 所示:
表1 各个函数的对比
测试环境为在已经移植好linux 嵌入式操作系统的S3C2440 处理器。由于S3C2440 处理器自带着三个串口,本次测试用到的是串口1。串口波特率设置为9 600 bps,8 位数据位,无奇偶校验,1 位停止位。测试的方法是上位机PC 利用串口调试助手不断的往S3C2440 上发送“hello world”字符串,下位机接收到该字符串后改变串口为写模式,然后把该字符串发回给PC 机,这样就可以在PC 机的串口调试助手里面看到发送回来的字符串有无错误。
部分程序片断如下:
由于进程调度的开销,通信中数据的更新的时间间隔不能太短。实验测试中PC 是每间隔1 000 ms往ARM 发送一次数据,通信数据量4 kB,设计达到预期目标。尽管偶尔有误码出现,但本设计中避免了涉及linux 内核复杂代码的的修改,仍不失为有实用价值的设计方法。
[1]尤保常,杨源源,张晓,等.Linux 环境下RS485 通讯软件开发与界面设计[J].自动化仪表,2010(12):22-25.
[2]王志颖,马卫东.Linux 系统下RS-485 串行通信程序设计[J].计算机应用研究,2002,19(2):136-138.
[3]陈铁军,仇洪冰.基于S3C2410 的嵌入式Linux 的移植方法[J].桂林电子工业学院学报,2004,26(4):259-263.
[4]张莉君,庄晓奇,欧阳才.基于S3C2410 的多路高精度数据采集系统设计[J].机床与液压,2010,38(2):71-74.
[5]陈鼐,于盛林.基于S3C2410X 的液晶屏接口设计与实现[J].测控技术,2006,25(12):68-71.
[6]叶顺流.基于ARM 的嵌入式Linux 研究与实现[D].重庆:重庆大学,2005.
[7]王志颖,马卫东.Linux 系统下RS-485 串行通信程序设计[J].计算机应用研究,2002,19(2):136-138.
[8]Michael R Sweet.Serial Programming Guide for POSIX Operating Systems[EB/OL]. http://digilander.libero.it/robang/rubrica/serial.htm.
[9]Peter H Baumann. The Linux Serial Programming HOWTO[EB/OL]. http://www.collective.com.au/howtos/Serial-Programming-HOWTO.html.
[10]江泽涛,吴俊安.用Kylix 实现Linux 环境下的串行通信[J].计算机应用研究,2005,22(9):214-216.
[11]郑燕飞,余海燕.Linux 的多线程机制探讨与实践[J].计算机应用,2001,21(1):81-83.
[12]王子强,刘海燕,李媛州.Linux 下图形用户界面程序的开发与实现[J].计算机应用与软件,2005,22(6):81-83.