嵌入式网络编程
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 串行接口网络通信应用开发实例

2.3.1 RS-232C转RS-485通信电路的设计分析

RS-232C转RS-485通信电路图,即RS-232C/RS-485转换器的电路图如图2-16所示。

图2-16 RS-232C/RS-485转换器的电路图

RS-232C/RS-485转换器主要包括了电源、232电平转换、485电路三部分。本电路的232电平转换电路采用了NIH232或者也可以直接使用MAX232集成电路,485电路采用了MAX485集成电路。为了使用方便,电源部分设计成无源方式,整个电路的供电直接从PC的RS-232C接口中的DTR(4脚)和RTS(7脚)截取。PC串口每根线可以提供大约9mA的电流,因此,两根线提供的电流足够供给这个电路使用了。经实验,本电路只使用其中一条线也能够正常工作。使用本电路需注意PC程序必须使串口的DTR和RTS输出高电平,经过VD3稳压后得到VCC,经过实际测试,VCC电压大约在4.7V左右。因此,电路中要说VD3起的作用是稳压还不如说是限压功能。

MAX485接口芯片是Maxim公司的一种RS-485芯片,采用单一电源+5V工作,额定电流为300μA,采用半双工通信方式。它完成将TTL电平转换为RS-485电平的功能,其引脚结构如图2-16右侧所示。从图中可以看出,MAX485芯片的结构和引脚都非常简单,内部含有一个驱动器和接收器。RO和DI引脚分别为接收器的输出端和驱动器的输入端,与单片机连接时只需分别与单片机的RXD和TXD相连即可。RE和DE引脚分别为接收和发送的使能端,当RE为逻辑0时,器件处于接收状态;当DE为逻辑1时,器件处于发送状态。因为MAX485工作在半双工状态,所以只需用单片机的一个引脚控制这两个引脚即可。A和B引脚分别为接收和发送的差分信号端,当A的电平高于B时,代表发送的数据为1;当A的电平低于B时,代表发送的数据为0。在与单片机连接时接线也非常简单,只需要一个信号控制MAX485的接收和发送即可,同时将A和B引脚之间加匹配电阻,一般可选100Ω的电阻。

MAX485是通过两个引脚RE(2脚)和DE(3脚)来控制数据的输入和输出的。当RE为低电平时,MAX485数据输入有效;当DE为高电平时,MAX485数据输出有效。在半双工使用中,通常可以将这两个引脚直接相连,然后由PC或者单片机输出的高低电平就可以让MAX485在接收和发送状态之间转换了。由于本电路DTR和RTS都用于了电路供电,因此使用TX线和HIN232的另外一个通道及VT1来控制MAX485的状态切换。平时NIH232的9脚输出高电平,经VT1倒相后,使MAX485的RE和DE为低电平而处于数据接收状态。当PC发送数据时,NIH232的9引脚输出低电平,经VT1倒相后,使MAX485的RE和DE为高电平而处于数据发送状态。

如图2-17所示为RS-232C转RS-485通信电路图和RS-232C转TTL电平(UART)通信电路图的合并,注意:在图中关键的接口和元器件处都有相应的标注。

图2-17 RS-232C转RS-485通信电路图

2.3.2 基于RS-485主从通信协议的实现

1.软件示意图

协议软件必须准确识别出一个完整帧并进行处理,如果有响应数据,则发送。软件实现状态表示如图2-18所示。

图2-18 软件实现状态表示

2.软件程序

下面用T1的时间产生并在各状态之间切换,接收和发送在串行中断中实现,用Keil C编写。

void timer1(void) interrupt 3
{
    switch(get_commstste())
    {
        case comm_s_init:  /* 初始化 */
            set_commstate(comm_s_idle);   /* 切换初始化至空闲状态 */
            break;
        case comm_s_idle:  /* 空闲状态 */
            break;
        case comm_s_recv:  /* 接收 */
            set_commstate(comm_s_ctrl);    /* 接收完毕,切换至处理状态 */
            break;
        case comm_s_ctrl:  /* 处理 */
            break;
        case comm_s_emit:  /* 发送 */
            break;
        case comm_s_emit:
            set_commstate(comm_s_idle);   /* 发送完毕,切换至空闲状态 */
            break;
    }
/* 定时器重装 */
}
void serial_interrupt(void) interrupt 4
{
    T1=0;  /* 关定时器 */
    switch(getcommstate())
    {
        case comm_s_idle:
            setcommstate(comm_s_recv);  /* 接收首位字符 */
            break;
        case comm_s_recv:  /* 接收其他字符 */
            break;
        case comm_s_emit:  /* 发送 */
            break;
        default:
            break;
    }
/* 重装定时器并启动 */
}