单片机串行通信的设计
单片机性能稳定、价格低廉、功能强大,在智能仪器、工业装备以及日用电子消费品中得到了越
来越广泛的应用。在单片机的输入输出控制中,除直接接上小键盘和 LCD 显示屏等方法外,一
般都通过串口和上位机 PC 进行通信,而后一种方法由于能实现远程控制,并且能够利用 PC 机
强大的数据处理功能以及友好的控制界面,显得尤为重要。在一般的利用 PC 机对单片机进行控
制的场合,都是采用 Windows 作为上位机的平台,其优点是界面友好,编程和操作都比较容易,
缺点是稳定性太差,这对于需要连续数天或数月运行的装置来说,尤其不合适。在要求比较苛刻
的场合,一般都采用 UNIX 工作站作为主控平台,如合肥同步辐射加速器的主控平台采用的是
SUN 的 Solaris 工作站系统,然而 UNIX 工作站昂贵的价格又大大限制了其使用的范围。近年来,
随着 Linux 的迅猛发展,使其逐渐从少数人的玩具变成了主流的操作系统。Linux 是遵循 GPL 协
议的免费源代码开放软件,任何人都可以自由的从 Internet 上取得其源程序,也可在 GPL 的协议
下修改其源代码以适应特定的应用,其运行在普通的 PC 上,性能稳定,特别适于做工业控制,
因此实现 Linux 和单片机的串行通信非常有意义,他可以是昂贵的 UNIX 工作站的一种可选的替
代方法。
1 硬件原理
目前国内使用较多的为 MCS-51 系列的单片机,因此选用的单片机实验对象为一片 AT89C51,
图 1 是硬件原理图,由于要实现符合 RS232C 的串行通信,还应该用一片 ICL232CPE(MAX232)
作为串行通信的电平转换电路。在实验过程中,为了查看通信是否成功,除了让单片机对上位机
回送数据外,还在单片机外围扩展了几片锁存器,几个 LED 发光二极管和几个小键盘。串行通
信是采用最简单的 TxD,RxD,GND 三线制连接,注意 TxD 和 RxD 两边应该交叉连线。
上位机是一台普通的 PC 机,共有 2 个串行口 COM1,COM2,其运行 RedHat8.0,实际上,
如果不要求运行 Gnome 或 KDE 等图形界面,Linux 对系统硬件的要求相当低。
实验证明,此电路简单可靠,非常适用于测试串行通信。
2 串行通信程序设计
串行通信程序包括下位机单片机和上位机 PC 机的程序。单片机接收上位机传来的数据,放
到片内 RAM 里面,再将 RAM 内数据同时发送到外部扩展锁存器和上位机,由此可以判断通信
是否成功。此程序由汇编语言写成,初始化时波特率设置为 4 800 b/s,通信方式为 8-N-1。
上位机程序的编写是关键部分,因为要对串口硬件设备进行操作,有 2 种方法,一是利用
Linux 内核自带的串口驱动程序,另外一种方法就是直接读写串口硬件端口,下面分别介绍。
2.1 利用串口驱动程序的编程方法
利用 Linux 自身的串口驱动程序进行编程,实际上就是调用驱动程序的一系列函数,完成串
口通信参数的设置,数据的发送和接收。在这种方法中,Linux 给每个串口都分配一个文件索引
号,有相应的文件名称,实际上是将硬件设备看成一种特殊的文件,如 COM1,COM2 对应的
文件分别为/dev/ttyS0,/dev/ttyS1,操作这 2 个串口实际上就是操作这 2 个文件,而对硬件设备
文件的操作与对普通文件的操作并没有什么不同,都可以使用相同的文件 I/O 调用函数(open,
write,read,close),不同之处在于用系统调用 open()打开串口得到相应设备的文件描述符以后,
先要对其进行初始化,设置一些特定的参数,如波特率、数据位、输入输出方式等,这些参数存
放在 structtermios 中,函数 tcsetattr()可以设置串口的 structtermios,tcgetattr()可以得到串口的
struct termios。设置完通信参数后就可用 read 和 write 对串口文件进行读写了。运行程序时要注
意用户是否有对要操作的串口文件进行读写的权力,可以用 chmod 命令进行文件权限修改。
初始化函数如下:
初始化以后就开始发送和接收数据,先将一个字符串发送给单片机,单片机接收到数据后,
将数据返回给上位机。但需要注意的是,由于上位机速度比单片机快得多,一次不能发送过多的
数据,否则极有可能使发送缓冲区溢出而丢失数据,发送过后,还需等待一段时间,使单片机将
数据完全发送到上位机后,再进行读取。
2.2 直接读写串口硬件端口的方法
在使用这个方法的时候,必须对串口通信的硬件原理有一些了解。PC 机的串口是由通用异
步收发器 8250UART(或 16550)为核心构成的,寄存器基地址分别是 0x3f8(COM1)和
0x2f8(COM2),还有其他的一些用于控制的寄存器。有很多寄存器是与 Modem 相关的,而在使
用三线制进行通信时用不到,只用关心与通信相关的寄存器,比起使用为通用功能编写的串口设
备驱动程序来,直接读写相关寄存器效率更高。
初始化后,就可以进行数据的收发了,接受数据之前必须保证接收数据就绪,这可以通过
0x2fd 的 D0 来判断,发送数据之前必须保证发送寄存器为空,这可以通过 0x2fd 的 D5 来判断,
代码如下:
3 结语
实验表明,此系统采用的 2 种方法都完全实现了 LinuxPC 机与单片机之间点对点的通信,
方法简单可靠,基本上在需要用到 PC 机与单片机串行通信的场合均可采用此种方法。随着近年
来 Linux 在国内应用范围的日益壮大,在工业控制、数据采集等领域也必将越来越多的采用 Linux,
本文可以算作是一个有益的尝试。当然在实际应用中还需要考虑一些问题,比如进行出错处理的
问题,可以在一个要发送的字符串后再发送一个校验和,当收到返回的校验和与发送的校验和不
一致时再进行重发,再比如所采用的 RS232C 传输距离很短,并且抗干扰能力很差,这时需要将
总线转换成差分传输的 RS485/RS422。另外,稍加改进,就可实现 PC 机与多片 51 单片机的串
行通信,这时由于共用一条总线,必须给每个单片机分配一个地址,然后由 PC 机对总线进行仲
裁,只有获得总线使用权的单片机才能与上位机进行通信,这里不再赘述。
总之,本文只是为 Linux PC 和单片机串行通信提供了一个典型的范例,要应用到实际的项
目中去,还需要根据实际的情况具体考虑,灵活应用,最终才能形成一个可靠的基于 Linux 平台
的系统。