精华内容
下载资源
问答
  • 想要制作一些电路以增强Palm的功能,首先就必须知道如何才能与Palm的接口...这里就将Palm本机上的Cradle接口和同步座上的DB9M接口及其他的有关外设的管脚信号含义一一列出。以方便各位Palm友在开发新产品的时候参考。
  • POSIX 串口编程指南

    2017-05-20 09:41:56
    信号定义 异步通信 什么是全双工和半双工 流控 Break信号 同步通信 操作串口 串口文件 打开串口 写数据到串口串口读取数据 关闭串口 第二章 配置串口 POSIX 终端接口 控制选项 本地选项 输入选项 输出选项 控制...

    介绍


    POSIX 串口编程指南将教会你在你的 UNIX 工作站或者 PC 上面如何成功、有效以及可移植性的对串口编程。每一章提供了使用 POSIX 终端控制函数的编程例程,可以基本不经修改地工作在 IRIX®, HP-UX, SunOS®, Solaris®, Digital UNIX®, Linux® 以及其他大多数 UNIX 操作系统。你会发现操作系统之间的最大差异是串口设备文件名和锁文件。
    本指南分为以下章节和附录:
    • 第一章 串口通信基础
    • 第二章 串口配置
    • 第三章 MODEM 通信
    • 第四章 高级串口编程
    • 附录A 引脚分布
    • 附录B ASCII 码

    第一章 串口通信基础


    本章介绍了串口通信,RS-232 和 大多数计算机上使用的其他标准,以及如何通过 C 程序操作串口。

    什么是串口通信


    计算机一次传输信息(数据)一位或多个比特位。串行是指传输数据一次只传输一位。当进行串口通信时你发送或者接收的每个字(即字节或字符)一次发送一位。每一位都是 on 或者 off。术语用mark代表 on,用 space代表 off。
    串口数据速率使用 bits-per-second ("bps") 或者 baudot rate ("baud")。这表示一秒内可以传输多少逻辑 1 和 0。当波特率超过 1000,你会经常看到用 kilo baud 表示的速率。对于超过 1000000 的速率用 megabaud,或者 Mbps 来表示。
    当涉及到串口设备或者端口,它们被标识为“数据通讯设备”("DCE")或者“数据终端设备”("DTE")。两者之间的区别很简单 - 每个信号对,如发送和接收,是交叉的。

    什么是 RS-232


    RS-232 是由 EIA 定义的用于串口通信的标准电气接口。RS-232 实际上有三种不同的类型(A,B和C),每一种对于 on 和 off 电平定义了不同的电压范围。最常用的种类是 RS-232C,它定义mark位电压范围:-3V~-12V 和space位电压范围:+3V~+12V。RS-232C 规范上说,这些信号可以传输 25英尺(8m),通常你可以传输更远一些只要波特率足够低。
    除了数据输入和输出数据线,还有其他提供时序、状态与握手的信号线。这里我们仅列举最为常见的 DB-9 接口分布图,引脚和功能描述如下所示:
    • 1 - DCD - 数据载波检测
    • 2 - RXD - 接收数据
    • 3 - TXD - 发送数据
    • 4 - DTR - 数据终端就绪
    • 5 - GND - 地
    • 6 - DSR - 数据装置就绪
    • 7 - RTS - 请求发送
    • 8 - CTS - 清除发送
    • 9 - RI - 振铃指示
    你还可能遇到 RS-422 以及 RS-485 串口标准。RS-422 使用更低电压与差分信号允许线缆长达 1000英尺(300m)。在实际应用中,使用 TTL 电平逐渐成为趋势,在 MCU  与串口转接芯片提供的串口中比较常见,此时mark 电平:+5V或+3.3V等,space位:0V(逻辑地)。

    信号定义


    RS-232 标准针对串口通信定义了18种不同的信号。其中,在 UNIX 环境下通常只有 6 种可用。

    GND - 逻辑地
    从技术上讲,逻辑接地不是信号,但没有它,其他信号就不能工作。从根本上说,逻辑地充当一个参考电压,从而知道哪些电压为正或负。

    TXD - 发送数据
    mark 电平为逻辑 1,space 电平为逻辑 0。注意 RS232 电平与 TTL 电平反相。

    RXD - 接收数据
    同样的,mark 电平为逻辑 1,space 电平为逻辑 0。注意 RS232 电平与 TTL 电平反相。

    DCD - 数据载波检测
    DCD 信号接收自串口线缆的另一端的计算机或设备。信号线低电平表示计算机或设备当前已连接或在线。DCD 不经常使用。

    DTR - 数据终端就绪
    DTR 信号用于通知对端计算机或设备己方已就绪(space 电平)或未就绪(mark 电平)。DTR 通常在打开串口时自动使能。

    CTS - 清除发送
    CTS 信号接收自串口线缆的另一端。信号线 space 电平表示可以己方可以发送数据。CTS 通常用于串口数据流控。

    RTS - 请求发送
    RTS 设置为 space 电平表示己方准备好就接收数据。一般与 CTS 一起用于串口流控,通常被设置为默认有效状态。

    异步通信


    解析串口数据需要确定一个字符的结束与下一个字符的开始。本章专门讲述异步串口数据。
    在异步模式下串口数据线保持在 mark 状态(逻辑 '1')直到有字符发送,也即串口的空闲态是 mark 态。每个字节起始位在前,字节的每一位紧随其后,一位可选校验位以及一位或者两位停止位。起始位始终是 space 电平(逻辑'0'),通知对方有新串口数据可用。数据可以同时发送和接收,因此称为“异步”。

    可选校验位是数据位的简单累加和,指示数据是否包含奇数或者偶数个 1。偶校验时,如果一个字符中有偶数个 1 那么校验位是 0。奇校验时,如果一个字符中有奇数个 1 那么校验位是 0。除此之外,你还可能听过术语 space 校验,mark 校验以及无校验。Space 校验指示校验位永远是 0,而 mark 校验是指校验位一直为 1。无校验意味着没有校验位存在或被传输。
    剩下的位称作停止位。在字符之间可能会有 1,1.5 或者 2 位停止位并且这些位总为 1。停止位过去用于腾出时间为硬件处理之前的数据,但现在只用于接收字符与硬件设备的同步。异步数据格式通常表达成“8N1”,“7E1”等。

    什么是全双工和半双工


    全双工是指设备可以同时发送和接收数据 - 有两个独立数据通道(一路输入,一路输出)。
    半双工是指设备不能同时发送和接收数据。这通常意味着只有一路可以通讯。这并不代表有任何的 RS-232 信号未被使用,相反,这通常意味着使用的一些非 RS-232 标准的通讯链路不支持全双工操作。

    流控


    在两个串口设备间传输数据时经常有必要进行数据流控。这可能是受到中间串口通信线路、其中一个设备或者其他存储介质的限制。异步数据流控通常使用的有两种方法。
    第一种方法通常称为“软件”流控,使用特殊字符开始(XON or DC1)或者停止(XOFF or DC3)数据流。这些字符定义参见 ASCII 码表。这些码值在传输文本信息时很有用,但不能在未经特殊编程时用于传输其他类型的信息。
    第二种方法称作“硬件”流控,使用 CTS 和 RTS 信号线取代特殊字符。当接收方准备好接收数据时会将 RTS 置为 space 电压以请求对方发送数据,当未准备好时置为 mark 电压,因此发送方会通过检测 CTS 电平状态判断是否可以发送数据。由于硬件流控使用独立的信号集合,因此比软件流控速度要快。

    Break信号


    通常情况下收发数据信号线保持在 mark 电平状态直到传输一个新字节。如果信号拉低至 space 电压一段时间,通常是 1/4 到 1/2 秒,那么就说一个 break 条件满足。一个 break 信号有时用于复位通讯或者改变通讯硬件的操作模式,如 MODEM。

    同步通信


    不同于异步数据,同步数据以恒定比特流显示。为了读取数据,通讯方必须提供或接收一通用位作为时钟使发送和接收者同步
    尽管有时钟同步,通讯方也必须以某种方式标记数据开始。实现的最常用方法是使用像“串行数据链路控制”(“SDLC”)或者“高速数据链路控制”(“HDLC”)的数据包协议。
    每种协议定义了一定的位序列来表示数据包的开始和结束,也定义了没有数据时的位序列。这些位序列使得通讯方明确数据包的开始。由于同步协议不使用每字节同步位它们比异步通信有至少25%的性能提升并且在多余两个串口的情形下更适合于远程网络和配置。
    尽管同步通信有速度优势,由于需要额外的软硬件大多数 RS-232 硬件不支持。

    编程指南的其他章节内容我先前翻译过,但是由于内容和部分知识点较为陈旧,因此我用其他整录的博客系列 -《Linux 串口编程》中进行详细讲解,感兴趣的可以移步至:


    展开全文
  • 串口通信

    2021-01-23 23:36:48
    UART,“串口”时序协议的名称,定义了各个信号时序协议; USART,相比UART增加了同步信号,可实现ISO-7816智能卡接口; COM口,在PC等操作系统上,区别于USB、SATA接口的串行接口,定义了在操作系统中的规范; TTL/...
    本文为作者学习笔记
    欢迎交流讨论,喜欢的话点个赞吧
    

    串口


    UART

    UART,全称UniversalAsynchrONous Receiver/Transmitter,译为通用异步收发器。

    1. UART,“串口”时序协议的名称,定义了各个信号时序协议;
    2. USART,相比UART增加了同步信号,可实现ISO-7816智能卡接口;
    3. COM口,在PC等操作系统上,区别于USB、SATA接口的串行接口,定义了在操作系统中的规范;
    4. TTL/CMOS,嵌入式硬件系统的信号电平;
    5. RS-232,在UART基础上再定义了信号的电气特性
    6. RS-422,在RS-232基础上定义了差分信号传输的电气特性
    7. RS-485,在RS-422基础上定义了半双工模式

    UART信号线

    UART常用的信号线有:

    1. RxD,当前终端设备的接收管脚
    2. TxD,当前终端设备的发送管脚
    3. GND,当前终端设备的地

    一般的,设计者在设计PCB时,对外连接做的一些预留接口,标记接口管脚时,都会添加丝印标记,这时标记的都是当前终端设备的管脚信息。

    例如标记着RxD的引脚,应该与外部的UART接口TxD连接
    PCB板的标记

    UART信号时序

    信号线空闲时,处于高电平,当有数据发送时,信号线以1个bit时长的低电平标志开始通信,通信过程中,单个字节在信号线上的帧结构如下图:
    image
    信号管脚传输每个数据时,在管脚上呈现的是电气信号为高低电平的变化,对应数据每个bit的逻辑“1”和“0”。


    UART在不同电气规范下的接口

    对于不同平台或者使用环境,信号管脚的电气特性依次可以分为:

    TTL/CMOS、RS232、RS422、RS485

    TTL/CMOS

    TTL电平,逻辑“0”等于0V电压,逻辑“1”等于+5V电压

    CMOS电平,逻辑“0”接近0V电压,逻辑“1”接近电源电压(3.3V或其他)

        TTL电路与CMOS电路比较:
        1)TTL电路是电流控制器件,而CMOS电路是电压控制器件。
        2)TTL电路的速度快,传输延迟时间短(5-10ns),但是功耗大。
        CMOS电路的速度慢,传输延迟时间长(25-50ns),但功耗低。
        CMOS电路本身的功耗与输入信号的脉冲频率有关,频率越高,芯片即越热,这是正常现象。
    

    常见的,在嵌入式开发时,UART的电平信号由MCU芯片决定。

    日常的开发过程中,MCU管脚上的UART通信电平就是TTL/CMOS电平信号。

    RS-232

    RS232对电气特性、逻辑电平和各种信号线功能都作了规定。

    在TxD和RxD信号管脚上:

    逻辑“1”电压范围-3V~-15V

    逻辑“0”电压范围+3~+15V

    在RTS、CTS、DSR、DTR和DCD等控制线上:

    信号有效(接通,ON状态,正电压)电压范围+3V~+15V

    信号无效(断开,OFF状态,负电压)电压范围-3V~-15V

    可见RS232的信号管脚特性为负逻辑电平的信号。

    UART快速使用串口及应用

    调试-输出

    C库函数printf格式输出重定向到串口输出

    输出串口数据过程中,需要向寄存器逐字节传入数据的,而在传送之前必不可少的,就是将要发送的数据、字符放到同一个Buffer后,执行轮询的方式传送直到buffer内容全部被传送。

    而这个“放”的过程也是需要做些计算、判断,尤其是增加必要的字符来描述输出信息,保证信息的可识读。

    在C标准库printf函数就有格式输出的功能,利用这个接口更便于调试输出这个过程。

    这就需要将printf函数重定向到串口输出上!

    实现重定向只需3步:

    1. Options for target选项卡内勾选UseMicroLIB

    image

    1. 在串口实现的*.c文件内,将stdio.h文件和stdarg.h文件包含进来
    2. 重新定义int fputc函数的内部实现

    image

    完成以上3步,即可利用printf函数来格式化输出,并且能够在串口上接收到。


    SPI

    SPI是串行外设接口(SerialPeripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。

    SPI信号线

    SPI被称为四线串行总线,其信号线分别有:

    1. SCLK:串行时钟(主机输出)
    2. MOSI:主输出从机输入或主机输出从机输入(主机输出的数据)
    3. MISO:主输入从输出或主输入从输出(从输出的数据输出)
    4. SS:从机选择(通常为低电平有效,主机输出)
    信号线命名也是五花八门,以下的命名也是会遇见的:
        串口时钟:
        SCLK:SCK
        主输出--->从输入(MOSI):
        SIMO,MTSR - 对应主设备和从设备上的MOSI,相互连接
        SDI,DI,DIN,SI - 在从设备上; 连接到主设备上的MOSI,或连接到下面的连接
        SDO,DO,DOUT,SO - 在主设备上; 连接到从站上的MOSI,或连接到上面的连接
        主输入<---从输出(MISO):
        SOMI,MRST - 对应主设备和从设备上的MISO,相互连接
        SDO,DO,DOUT,SO - 在从设备上; 连接到主设备上的MISO,或连接到下面的连接
        SDI,DI,DIN,SI - 主设备; 连接到奴隶上的MISO或上面的连接
        从机选择:
        SS:S̅S̅,SSEL,CS,C̅S̅,CE,nSS,/ SS,SS#
    

    SPI作为同步串行接口,可以认为有两个同步信号,第一个是从机选择SS信号,告知被选中的从机,准备开始进行SPI通信,第二个是同步时钟信号SCLK,收发双方进行数据的交互时,都是基于SCLK的跳变进行逐BIT输出和采样的。

    四根信号线并非全部都需要,根据工作模式,可以配置成两线、三线。

    在STM32CubeMX工具的配置页面,可以很清楚看到,配置不同的工作模式时,对应被使能的芯片管脚有何不同:
    image
    image
    image

    对比发现,全双工的四线和三线的区别是从机选择信号NSS。这种情况一般是因为SPI总线上只有一主一从的通信架构,从机的NSS信号一直接低电平,不需要做从机选择。

    SPI信号时序

    四线SPI接口的时序一般的总是先拉低从机选择信号线SS,然后输出SCLK,带着数据MOSI,此时MISO为高阻态。大致如下如:
    image

    SPI接口配置项

    一般在开发时,接口的可选配置有:接口模式(实际配置的是单、双工模式选择)、设备主从模式、数据宽度、时钟极性(CPOL:)、时钟相位(CPHA)、时钟速率、数据bit位大小端选择。

    接口模式

    1. 标准的四线SPI接口,使用的场景是主从机进行数据交互的通信,两方都有数据的收发过程。
    2. 在LCD/OLED这样的SPI接口作为从设备的器件中,就不需要数据返回给主机,只需要接收来自主机的控制信息和显示的数据。基于这样的使用场景,就可以配置成三线的单工通信,即仅需要从机选择SS、时钟SCLK、数据输出MOSI即可。

    设备主从模式

    这个配置一般需要看芯片是否支持,可将芯片配置成SPI主机或者从机,能更好地集成在项目的系统中。

    数据宽度

    顾名思义,就是发送数据可以配置成8bit、16bit等,这也是根据芯片而定。

    时钟极性、时钟相位

    这两者分别是CPOL(Clock Polarity)、CPHA(Clock Phase),极性就是指高低电平,这个定义了SPI总线在空闲状态下,时钟保持高电平还是低电平,因为这个关系到了SPI通信时第一个时钟跳变沿是上升还是下降沿;相位指的是时钟的跳变沿,指定了数据信号的输出和采样如何与时钟对齐

    时钟速率

    速率选择定义了时钟信号线在数据传输是的翻转速率,这体现到每个芯片定义的接口时序图中,即可承受的速率范围,如果主机设的速率太快,而从机响应过慢会导致通信失败

    数据bit位大小端选择

    数据的发送优先bit可配置,SPI是可配置优先发送bit的,可设置最低位或者最高位。


    IIC

    IIC 即Inter-IntegratedCircuit(集成电路总线),这种总线类型是一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。

    IIC信号线

    IIC作为两线串行总线,信号线分别是:

    1. SCL(Serial ClockLine):串行时钟,主机输出
    2. SDA(Serial DataLine):串行数据,双向传输

    总线信号的电平在电路连接上,一般加上拉电阻Rp,使得总线在空闲时,信号管脚处于高电平状态。

    IIC信号时序

    IIC作为同步串行总线,可以认为有两个同步信号,第一个是通信起始、结束标志,告知挂在IIC总线上的从机设备,何时开始通信并且何时结束;第二个是同步时钟信号SCL,收发双方进行数据的交互时,都是基于SCL的跳变进行逐bit输出和采样的。
    image

    • 起始标志
      处于空闲状态下时,SCL和SDA都是高电平,某一时刻,SDA拉低,则此刻认为开始IIC传输。
    • 结束标志
      即将完成数据传输时,在SCL处于高电平时,将SDA强制拉高,则此刻认为结束IIC传输。
    • 数据输出
      在SCL为低电平时,发送方根据传输的数据内容逐bit改变SDA的电平。
    • 数据采样
      在SCL为高电平时,接收方读取SDA的电平逐bit接收,并逐8个bit组成1个Byte。
    • 应答ACK
      ACK表示在8bit数据后的第9个时钟的高电平期间,SDA保持低电平。
    • 应答NACK
      NACK表示在8bit数据后的第9个时钟的高电平期间,SDA保持高电平。

    IIC要实现主机与指定从机的通信,需要每次开始通信时,主机会先把指定从机设备的地址通过接口发出,这样一来,对应的从机设备即可被选中,才能进行后续的通信操作。

    IIC接口配置项

    相比于SPI接口丰富的配置项,然而IIC仅有2根数据线,可配置的也就是时钟SCL的翻转速率,因为这个时钟的速率直接影响到数据的传输速率。

    这里所配置的推荐值,应该确认IIC总线上各个从机设备的速率极限,这样在设计IIC接口时,能够兼容总线上的所有设备通信速率。


    参考资料:

    1. 《嵌入式硬件通信接口协议-UART(一)协议基础》
    2. 《嵌入式硬件通信接口协议-UART(二)不同电气规范下的标准》
    3. 《嵌入式硬件通信接口协议-UART(三)快速使用串口及应用》
    4. 《嵌入式硬件通信接口协议-SPI(一)协议基础》
    5. 《嵌入式硬件通信接口协议-IIC(一)协议基础》
    展开全文
  • linux串口

    2012-09-17 23:24:32
    口本身,标准和硬件什么是串行通信什么是RS-232 信号定义异步通讯什么是全双工和半双工什么是流控制什么是BREAK 同步通讯用户看到的串口和用户空间的串口编程串口的设备文件打开串口打开文件的选项给端口上写数据从...
    口本身,标准和硬件什么是串行通信什么是RS-232 信号定义异步通讯什么是全双工和半双工什么是流控制什么是BREAK 同步通讯用户看到的串口和用户空间的串口编程串口的设备文件打开串口打开文件的选项给端口上写数据从端口上读取数据关闭串口配置串口 POSIX终端接口控制选项设置波特率设置字符大小设置奇偶校验设置硬件流控制本地设置选择经典输入选择原始输入输入选项设置输入奇偶校验选项设置软件流控制输出选项选择加工过的输出选择原始输出控制字符设置软件流控制字符设置读取超时调制解调器通讯什么是调制解调器与调制解调器通讯标准调制解调器命令高级串口编程串口的ioctl
     取得控制信号设置控制信号英文原文串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口。计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备。虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接通常特指那些与RS-232标准兼容的硬件或者调制解调器的接口。虽然现在在很多个人计算机上,原来用以连接外部设备的串口已经广泛的被USB和Firewire替代;而原来用以连接网络的串口则被以太网替代,还有用以连接终端的串口设备则已经被MDA或者VGA取而代之。但是,一方面因为串口本身造价便宜技术成熟,另一方面因为串口的控制台功能RS-232标准高度标准化并且非常普及,所以直到现在它仍然被广泛应用到各种设备上。
     某些计算机使用一个叫做UART的集成电路来作为串口设备。这个集成电路可以进行字符和异步串行通讯序列之间的转换,并且可以自动地处理数据的时序。而某些低端设备则会让CPU直接通过输出针来传送数据,这种技术叫做bit-banging。 因为“串口”,RS-232和UARTs基本上总是在同一个语境中出现,所以这些名词通常会被搞混。下面逐一解释以下一些重要的名词和术语。 ↑ 什么是串行通信 † 计算机可以每次传送一个或者多个位(bit)的数据。“串行”指的式每次只传输一位(1bit)数据。 当需要通过串行通讯传输一个字(word)的数据时,只能以每次一位的方式接收或者发送。每个位可能是on(1)或者off(0)。很多技术术语中经常用mark表示on,而space表示off。
     串行数据的速度通常用每秒传输的字节数bits-per-second(bps)或者波特率(baud)表示。这个值表示的是每秒钟被送出的0和1的个数。很久很久以前,300bps就是很快的速度了,而现在的电脑可以处理高达430,800的RS-232速率。表示波特率的单位还有kpbs和Mbps,1kps=1000bps而1Mbps=1000kbps。 一般有人提到串行设备的时候,它通常说可能是某种数据通讯设备-DCE(Data Communications Equipment)或者数据终端设备-DTE(Data Terminal
     Equipment)。它们之间的区别非常简单,每个信号对,比如传送和接收,它们俩正好是相反的。如果需要将两个DTE或者DCE设备连接起来的话,需要适配器或者交叉线缆将信号对交换。 ↑ 什么是RS-232 † RS-232是EIA(Electronic Industries Association)定义的串行通信的电器接口。RS-232事实上有三种(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。虽然RS-232C标准说信号最远被传输8m,但事实上你可以使用它传输更长的距离,直到信号波特率已经小到不行了为止。
     RS-232的连结线中除去用来传入传出数据的电线,还有一些用来提供时序,状态和握手的电线: RS-232 针脚定义 DB-25 针脚 描述 针脚 描述 针脚 描述 针脚 描述 针脚 描述 1 Earth Ground 6 DSR - Data Set Ready 11 Unassigned 16 Secondary RXD 21 Signal Quality Detect 2 TXD - Transmitted Data 7 GND - Logic Ground 12 Secondary DCD 17 Receiver
     Clock 22 Ring Detect 3 RXD - Received Data 8 DCD - Data Carrier Detecter 13 Secondary CTS 18 Unassigned 23 Data Rate Select 4 RTS - Request To Send 9 Reserved 14 Secondary TXD 19 Secondary RTS 24 Transmit Clock 5 CTS - Clear To Send 10 Reserved 15 Transmit
     Clock 20 DTR - Data Terminal Ready 25 Unassigned DB-9 针脚 名称 全名 方向(主机 外设) 3 TD Transmit Data -> 2 RD Receive Data <- 7 RTS Request To Send -> 8 CTS Clear To Send <- 6 DSR Data Set Ready <- 4 DTR Data Terminal Ready -> 1 CD Data Carrier Detect <- 9 RI Ring Indicator
     <- 5 - Signal Ground 另外两个比较常见的串行接口的标准式RS-422和RS-574。RS-422使用更低的电压和差分信号,这样可以将传输距离扩张到300m。而RS-574定义了通常可以见到的用在电脑上的9针连接器和电压。 ↑ 信号定义 † RS-232标准定义了18个不同的串行通信的信号。而这些之中,仅仅有如下6个可以在UNIX环境中使用。 GND - Logic Ground 从技术角度讲,GND不能算是信号。但是没有它其他信号都不能用了。基本上,logic ground有点像一个参考电压,通过它来判断哪个电压表示正哪个电压表示负。
     TXD - Transmitted Data TXD信号负载着从你的电脑或者设备到另一端(比如调制解调器)的数据。Mark范围的电压被解析成1,而space范围电压被解析成0。 RXD - Received Data RXD于TXD正好相反。它负载着从另一端的电脑或者设备上传到你的工作站的数据。Mark和space的解析方法于TXD一致。 DCD - Data Carrier Detect DCD信号通常来自串口连结线的另一端。这条信号线上的space电压表示另一端的电脑或者设备现在已经连接。但是,DCD信号线却不是总可以得到的,有些设备上有这条信号线,而有的则没有。
     DTR - Data Terminal Ready DTR信号是你的工作站产生的,用以告诉另一端的电脑或者设备你已经是否已经准备好了。Space电压表示准备好了,而mark电压表示没有准备好。当你在工作站上打开串行接口时,DTR通常自动被设置位有效。 CTS - Clear To Send CTS则通常来自连结线的另一端。Space电压表示你可以从工作站送出更多的数据。CTS通常用来协调你的工作站和另一端之间的串行数据流。 RTS - Request To Send 如果RTS信号被设置成space电压,这表示你准备好了一些数据需要传送。和CTS一样,RTS也被用来协调工作站和另一端的电脑或者设备之间的数据流。有些工作站上会一直将这个信号设置位space。
     ↑ 异步通讯 † 计算机为了弄懂传给它的串行数据,它需要确定每个字符开始和结束的位置。这通常是用异步串行数据来完成的。 在异步模式中,除非有字符被传输,否则串行数据线总是处于mark(1)状态。有一个start位会被加入传输字符的各个位之前,在字符本身的位之后会有一个可选的parity位和一个或者多个stop位。Start位总是space(0)并且它会告诉计算机新的串行数据过来了。数据可以随时被送出或者接收,这就是所谓的异步。 #ref(): File not found: "async.gif" at page
     "Linux串口编程详解" 那个可选的parity位仅仅是所有传输位的和,这个和用以表示传输字符中有奇数个1还是偶数个1。在偶数parity中,如果有传输字符中有偶数个1,那么parity位被设置成0,而传输字符中有奇数个1,那么parity位被设置成1。在奇数parity中,位设置与此相反。还有一些术语,比如space parity, mark parity和no parity。Space parity是指parity位会一直被设置位0,而mark parity正好与此相反,parity会一直是1。No
     parity的意思就是根本不会传输parity位。 剩余的位叫做stop位。传输字符之间可以有1个,1.5个或者2个stop位,而且,它们的值总是1。传统上,Stop位式用给计算机一些时间处理前面的字符的,但是它只是被用来同步接收数据的计算机和接受的字符。 异步数据通常被表示成"8N1","7E1",或者与此类似的形式。这表示“8数据位,no parity和1个stop bit”,还有相应得,“7数据位,even parity和1个stop bit”。 ↑ 什么是全双工和半双工 † 全双工(Full duplex)是说计算机可以同时接受和发送数据——也就是它有两个分开的数据传输通道
    
    展开全文
  • Linux串口编程详解

    2017-05-17 10:45:36
    信号定义 异步通讯 什么是全双工和半双工 什么是流控制 什么是BREAK 同步通讯 用户看到的串口和用户空间的串口编程 串口的设备文件 打开串口 打开文件的选项 给端口上写数据 从端口上读取...


    串口本身,标准和硬件
  • 用户看到的串口和用户空间的串口编程
  • 配置串口
  • 调制解调器通讯
  • 英文原文串口本身,标准和硬件 ?

    串口是计算机上的串行通讯的物理接口。计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备。虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接通常特指那些与RS-232标准兼容的硬件或者调制解调器的接口。虽然现在在很多个人计算机上,原来用以连接外部设备的串口已经广泛的被USB和Firewire替代;而原来用以连接网络的串口则被以太网替代,还有用以连接终端的串口设备则已经被MDA或者VGA取而代之。但是,一方面因为串口本身造价便宜技术成熟,另一方面因为串口的控制台功能RS-232标准高度标准化并且非常普及,所以直到现在它仍然被广泛应用到各种设备上。 某些计算机使用一个叫做UART的集成电路来作为串口设备。这个集成电路可以进行字符和异步串行通讯序列之间的转换,并且可以自动地处理数据的时序。而某些低端设备则会让CPU直接通过输出针来传送数据,这种技术叫做bit-banging。 因为“串口”,RS-232和UARTs基本上总是在同一个语境中出现,所以这些名词通常会被搞混。下面逐一解释以下一些重要的名词和术语。

    什么是串行通信 ?

    计算机可以每次传送一个或者多个位(bit)的数据。“串行”指的式每次只传输一位(1bit)数据。 当需要通过串行通讯传输一个字(word)的数据时,只能以每次一位的方式接收或者发送。每个位可能是on(1)或者off(0)。很多技术术语中经常用mark表示on,而space表示off。

    串行数据的速度通常用每秒传输的字节数bits-per-second(bps)或者波特率(baud)表示。这个值表示的是每秒钟被送出的0和1的个数。很久很久以前,300bps就是很快的速度了,而现在的电脑可以处理高达430,800的RS-232速率。表示波特率的单位还有kpbs和Mbps,1kps=1000bps而1Mbps=1000kbps。 一般有人提到串行设备的时候,它通常说可能是某种数据通讯设备-DCE(Data Communications Equipment)或者数据终端设备-DTE(Data Terminal Equipment)。它们之间的区别非常简单,每个信号对,比如传送和接收,它们俩正好是相反的。如果需要将两个DTE或者DCE设备连接起来的话,需要适配器或者交叉线缆将信号对交换。

    什么是RS-232 ?

    RS-232是EIA(Electronic Industries Association)定义的串行通信的电器接口。RS-232事实上有三种(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。虽然RS-232C标准说信号最远被传输8m,但事实上你可以使用它传输更长的距离,直到信号波特率已经小到不行了为止。 RS-232的连结线中除去用来传入传出数据的电线,还有一些用来提供时序,状态和握手的电线:

    RS-232 针脚定义

    DB-25

    针脚 描述 针脚 描述 针脚 描述 针脚 描述 针脚 描述
    1 Earth Ground 6 DSR - Data Set Ready 11 Unassigned 16 Secondary RXD 21 Signal Quality Detect
    2 TXD - Transmitted Data 7 GND - Logic Ground 12 Secondary DCD 17 Receiver Clock 22 Ring Detect
    3 RXD - Received Data 8 DCD - Data Carrier Detecter 13 Secondary CTS 18 Unassigned 23 Data Rate Select
    4 RTS - Request To Send 9 Reserved 14 Secondary TXD 19 Secondary RTS 24 Transmit Clock
    5 CTS - Clear To Send 10 Reserved 15 Transmit Clock 20 DTR - Data Terminal Ready 25 Unassigned

    DB-9

    针脚 名称 全名 方向(主机 外设)
    3 TD Transmit Data ->
    2 RD Receive Data <-
    7 RTS Request To Send ->
    8 CTS Clear To Send <-
    6 DSR Data Set Ready <-
    4 DTR Data Terminal Ready ->
    1 CD Data Carrier Detect <-
    9 RI Ring Indicator <-
    5 - Signal Ground  

    另外两个比较常见的串行接口的标准式RS-422和RS-574。RS-422使用更低的电压和差分信号,这样可以将传输距离扩张到300m。而RS-574定义了通常可以见到的用在电脑上的9针连接器和电压。

    信号定义 ?

    RS-232标准定义了18个不同的串行通信的信号。而这些之中,仅仅有如下6个可以在UNIX环境中使用。

    • GND - Logic Ground

      从技术角度讲,GND不能算是信号。但是没有它其他信号都不能用了。基本上,logic ground有点像一个参考电压,通过它来判断哪个电压表示正哪个电压表示负。

    • TXD - Transmitted Data

      TXD信号负载着从你的电脑或者设备到另一端(比如调制解调器)的数据。Mark范围的电压被解析成1,而space范围电压被解析成0。

    • RXD - Received Data

      RXD于TXD正好相反。它负载着从另一端的电脑或者设备上传到你的工作站的数据。Mark和space的解析方法于TXD一致。

    • DCD - Data Carrier Detect

      DCD信号通常来自串口连结线的另一端。这条信号线上的space电压表示另一端的电脑或者设备现在已经连接。但是,DCD信号线却不是总可以得到的,有些设备上有这条信号线,而有的则没有。

    • DTR - Data Terminal Ready

      DTR信号是你的工作站产生的,用以告诉另一端的电脑或者设备你已经是否已经准备好了。Space电压表示准备好了,而mark电压表示没有准备好。当你在工作站上打开串行接口时,DTR通常自动被设置位有效。

    • CTS - Clear To Send

      CTS则通常来自连结线的另一端。Space电压表示你可以从工作站送出更多的数据。CTS通常用来协调你的工作站和另一端之间的串行数据流。

    • RTS - Request To Send

      如果RTS信号被设置成space电压,这表示你准备好了一些数据需要传送。和CTS一样,RTS也被用来协调工作站和另一端的电脑或者设备之间的数据流。有些工作站上会一直将这个信号设置位space。

    异步通讯 ?

    计算机为了弄懂传给它的串行数据,它需要确定每个字符开始和结束的位置。这通常是用异步串行数据来完成的。

    在异步模式中,除非有字符被传输,否则串行数据线总是处于mark(1)状态。有一个start位会被加入传输字符的各个位之前,在字符本身的位之后会有一个可选的parity位和一个或者多个stop位。Start位总是space(0)并且它会告诉计算机新的串行数据过来了。数据可以随时被送出或者接收,这就是所谓的异步。

    #ref(): File not found: "async.gif" at page "Linux串口编程详解"

    那个可选的parity位仅仅是所有传输位的和,这个和用以表示传输字符中有奇数个1还是偶数个1。在偶数parity中,如果有传输字符中有偶数个1,那么parity位被设置成0,而传输字符中有奇数个1,那么parity位被设置成1。在奇数parity中,位设置与此相反。还有一些术语,比如space parity, mark parity和no parity。Space parity是指parity位会一直被设置位0,而mark parity正好与此相反,parity会一直是1。No parity的意思就是根本不会传输parity位。 剩余的位叫做stop位。传输字符之间可以有1个,1.5个或者2个stop位,而且,它们的值总是1。传统上,Stop位式用给计算机一些时间处理前面的字符的,但是它只是被用来同步接收数据的计算机和接受的字符。 异步数据通常被表示成"8N1","7E1",或者与此类似的形式。这表示“8数据位,no parity和1个stop bit”,还有相应得,“7数据位,even parity和1个stop bit”。

    什么是全双工和半双工 ?

    全双工(Full duplex)是说计算机可以同时接受和发送数据——也就是它有两个分开的数据传输通道(一个传入,一个传出)。

    半双工(Half duplex)表示计算机不能同时接受和发送数据,而在某一时刻它只能单一的传送或者接收。这通常意味着,它只有一个数据通道。半双工并不是说RS-232的某些信号不能使用,而是,它通常是使用了有别于RS-232的其他不支持全双工的标准。

    什么是流控制 ?

    两个串行接口之间的传输数据流通常需要协调一致才行。这可能是由于用以通信的某个串行接口或者某些存储介质的中间串行通信链路的限制造成的。对于异步数据这里有两个方法做到这一点。

    第一种方法通常被叫做“软件”流控制。这种方法采用特殊字符来开始(XON,DC1,八进制数021)或者结束(XOFF,DC3或者八进制数023)数据流。而这些字符都在ASCII中定义好了。虽然这些编码对于传输文本信息非常有用,但是它们却不能被用于在特殊程序中的其他类型的信息。

    第二种方法叫做“硬件”流控制。这种方法使用RS-232标准的CTS和RTS信号来取代之前提到的特殊字符。当准备就绪时,接受一方会将CTS信号设置成为space电压,而尚未准备就绪时它会被设置成为mark电压。相应得,发送方会在准备就绪的情况下将RTS设置成space电压。正因为硬件流控制使用了于数据分隔的信号,所以与需要传输特殊字符的软件流控制相比它的速度很快。但是,并不是所有的硬件和操作系统都支持CTS/RTS流控制。

    什么是BREAK ?

    通常,直到有数据传输时,接收和传输信号会保持在mark电压。如果一个信号掉到space电压并且持续了很长时间,一般来说是1/4到1/2秒,那么就说有一个break条件存在了。

    BREAK经常被用来重置一条数据线或者用来改变像调制解调器这样的设备的通讯模式。

    同步通讯 ?

    与异步数据不同,同步数据是一个稳定的字节流。为了能够在线路上读取到数据,计算机必须提供或者接受一个时钟,这样才能保证发送端和接收端同步。尽管已经有同步时钟,计算机还是必须以某种方式标志数据流的开端。做这件事情最常见的办法就是使用像Serial Data Link Control("SDLC")或者High-Speed Data Link Control("HDLC")这样的数据包通讯协议。

    这些协议每个都定义了一个确定的比特序列来表示数据包的开始和结束。当然,它们也定义了一个用来表示没有数据传输的比特序列。这些比特序列可以帮助计算机识别数据包的开端。

    因为同步协议可以不使用每个字符的同步比特位,所以通常它们的性能比异步通讯快最少25%,而且一般比较适用于远距离的网络链接或者有两个串口接口的配置的情况。尽管同步通讯的速度有优势,大部分RS-232硬件却不支持它,因为同步通讯需要其他的硬件和软件。

    用户看到的串口和用户空间的串口编程 ?

    和其他设备一样,Linux也是通过设备文件来提供访问串口的功能。当需要访问串口的时候,你只需要open相应的文件。

    串口的设备文件 ?

    Linux系统上一般有一个或者多个串口,而这些串口设备文件名字比较奇怪,如比下面这样

    串口设备文件名

    操作系统 串口1 串口2 USB/RS-232转换器
    Windows COM1 COM2 -
    Linux /dev/ttyS0 /dev/ttyS1 /dev/ttyUSB0
    打开串口 ?

    因为串口和其他设备一样,在类Unix系统中都是以设备文件的形式存在的,所以,理所当然得你可以使用open(2)系统调用/函数来访问它。但Linux系统中却有一个稍微不方便的地方,那就是普通用户一般不能直接访问设备文件。你可以选择以下方式做一些调整,以便你编写的程序可以访问串口。

    • 改变设备文件的访问权限设置 [#cd9bd1e0]
    • 以root超级用户的身份运行程序 [#kdd0e577]
    • 将你的程序编写位setuid程序,以串口设备所有者的身份运行程序 [#s7b703ff]

    OK.假如你已经准备好了让串口设备文件可以被所有用户访问,你可以在Linux系统中实验一下下面这个程序,它可以打开计算机的串口1。

    #include

    #include

     #include

     #include /* File control definitions */

     #include #include /* POSIX terminal control definitions */ /* * 'open_port()' - Open serial port 1 * Returns the file descriptor on success or -1 on error. */ int open_port(void) { int fd; /* File descriptor for the port */ fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { /* * Could not open the port. */ perror("open_port: Unable to open /dev/ttyS0 -"); } else { fcntl(fd, F_SETFL, 0); return (fd); } }

    打开文件的选项 ?

    打开串口连接的时候,程序在open函数中除了Read+Write模式以外还指定了两个选项;

    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

    标志O_NOCTTY可以告诉UNIX这个程序不会成为这个端口上的“控制终端”。如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。而有些程序比如getty(1M/8)则会在打开登录进程的时候使用这个特性,但是通常情况下,用户程序不会使用这个行为。

    O_NDELAY标志则是告诉UNIX,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接。如果不指定这个标志的话,除非DCD信号线上有space电压否则这个程序会一直睡眠。

    给端口上写数据 ?

    给端口上写入数据也很简单,使用write(2)系统调用就可以发送数据了:

    n = write(fd, "ATZ\r", 4); if (n < 0) fputs("write() of 4 bytes failed!\n", stderr);

    和写入其他设备文件的方式相同,write函数也会返回发送数据的字节数或者在发生错误的时候返回-1。通常,发送数据最常见的错误就是EIO,当调制解调器或者数据链路将Data Carrier Detect(DCD)信号线弄掉了,就会发生这个错误。而且,直至关闭端口这个情况会一直持续。

    从端口上读取数据 ?

    从串口上读取数据的时候就得耍花招了。因为,如果你在原数据模式(raw data mode)操作端口的话,每个read(2)系统调用都会返回从串口输入缓冲区中实际得到的字符的个数。在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生。如果需要read(2)函数迅速返回的话,你可以使用下面这个方式:

    fcntl(fd, F_SETFL, FNDELAY);

    标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0。需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数:

    fcntl(fd, F_SETFL, 0);

    当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式。

    关闭串口 ?

    可以使用close(2)系统调用关闭串口:

    close(fd);

    关闭串口会将DTR信号线设置成low,这会导致很多调制解调器挂起。

    配置串口 ? POSIX终端接口 ?

    很多系统都支持POSIX终端(串口)接口。程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等。要使用这个端口的话,你必须将头文件包含到你的程序中。这个头文件中定义了终端控制结构体和POSIX控制函数。

    与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3)。顾名思义,这两个函数分别用来取得设设置终端的属性。调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体:

    termios结构体成员

    成员 描述
    c_cflag 控制选项
    c_lflag 行选项
    c_iflag 输入选项
    c_oflag 输出选项
    c_cc 控制字符
    c_ispeed 输入波特率(NEW)
    c_ospeed 输出波特率(NEW)
    控制选项 ?

    通过termios结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制。下面这张表列出了所有可以使用的常数。

    c_cflag常数

    常量 描述
    CBAUD Bit mask for baud rate
    B0 0 baud (drop DTR)
    B50 50 baud
    B75 75 baud
    B110 110 baud
    B134 134.5 baud
    B150 150 baud
    B200 200 baud
    B300 300 baud
    B600 600 baud
    B1200 1200 baud
    B1800 1800 baud
    B2400 2400 baud
    B4800 4800 baud
    B9600 9600 baud
    B19200 19200 baud
    B38400 38400 baud
    B57600 57,600 baud
    B76800 76,800 baud
    B115200 115,200 baud
    EXTA External rate clock
    EXTB External rate clock
    CSIZE Bit mask for data bits
    CS5 5 data bits
    CS6 6 data bits
    CS7 7 data bits
    CS8 8 data bits
    CSTOPB 2 stop bits (1 otherwise)
    CREAD Enable receiver
    PARENB Enable parity bit
    PARODD Use odd parity instead of even
    HUPCL Hangup (drop DTR) on last close
    CLOCAL Local line - do not change "owner" of port
    LOBLK Block job control output
    CNEW_RTSCTS/CRTSCTS Enable hardware flow control (not supported on all platforms)

    在传统的POSIX编程中,当连接一个本地的(不通过调制解调器)或者远程的终端(通过调制解调器)时,这里有两个选项应当一直打开,一个是CLOCAL,另一个是CREAD。这两个选项可以保证你的程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节。

    波特率常数(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成员的旧的接口上。后面文章将会提到如何使用其他POSIX函数来设置波特率。

    千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志。不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性。

    设置波特率 ?

    不同的操作系统会将波特率存储在不同的位置。旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值。

    程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口。下面的代码是个非常典型的设置波特率的例子。

    struct termios options; /* * Get the current options for the port... */ tcgetattr(fd, &options);/* * Set the baud rates to 19200... */ cfsetispeed(&options, B19200); cfsetospeed(&options, B19200); /* * Enable the receiver and set local mode... */ options.c_cflag |= (CLOCAL | CREAD); /* * Set the new options for the port... */ tcsetattr(fd, TCSANOW, &options);

    函数tcgetattr(3)会将当前串口配置回填到termio结构体option中。然后,程序设置了输入输出的波特率并且将本地模式(CLOCAL)和串行数据接收(CREAD)设置为有效,接着将新的配置作为参数传递给函数tcsetattr(3)。常量TCSANOW标志所有改变必须立刻生效而不用等到数据传输结束。其他另一些常数可以保证等待数据结束或者刷新输入输出之后再生效。

    tcsetattr常量

    常量 描述
    TCSANOW Make changes now without waiting for data to complete
    TCSADRAIN Wait until everything has been transmitted
    TCSAFLUSH Flush input and output buffers and make the change

    不同的系统上可能支持不同的输入输出速度,所以,通过串口连接两台机器或者设备的时候,应该将波特率设置成两者中较小的那个,即MIN(speed1, speed2)。

    设置字符大小 ?

    设置字符大小的时候,这里却没有像设置波特率那么方便的函数。所以,程序中需要一些位掩码运算来把事情搞定。字符大小以比特为单位指定:

    options.c_flag &= ~CSIZE; /* Mask the character size bits */ options.c_flag |= CS8; /* Select 8 data bits */ 设置奇偶校验 ?

    与设置字符大小的方式差不多,这里仍然需要组合一些位掩码来将奇偶校验设为有效和奇偶校验的类型。UNIX串口驱动可以生成even,odd和no parity位码。设置space奇偶校验需要耍点小手段。

    • No parity (8N1)
    options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8;
    • Even parity (7E1)
    options.c_cflag |= PARENB options.c_cflag &= ~PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;
    • Odd parity (7O1)
    options.c_cflag |= PARENB options.c_cflag |= PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;
    • Space parity is setup the same as no parity (7S1)
    options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; 设置硬件流控制 ?

    某些版本的UNIX系统支持通过CTS(Clear To Send)和RTS(Request To Send)信号线来设置硬件流控制。如果系统上定义了CNEW_RTSCTS和CRTSCTS常量,那么很可能它会支持硬件流控制。使用下面的方法将硬件流控制设置成有效:

    options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS

    将它设置成为无效的方法与此类似:

    options.c_cflag &= ~CNEW_RTSCTS; 本地设置 ?

    本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符。通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。

    成员变量c_lflag可以使用的常量

    ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
    ICANON Enable canonical input (else raw)
    XCASE Map uppercase \lowercase (obsolete)
    ECHO Enable echoing of input characters
    ECHOE Echo erase character as BS-SP-BS
    ECHOK Echo NL after kill character
    ECHONL Echo NL
    NOFLSH Disable flushing of input buffers after interrupt or quit characters
    IEXTEN Enable extended functions
    ECHOCTL Echo control characters as ^char and delete as ~?
    ECHOPRT Echo erased character as character erased
    ECHOKE BS-SP-BS entire line on line kill
    FLUSHO Output being flushed
    PENDIN Retype pending input at next read or input char
    TOSTOP Send SIGTTOU for background output
    选择经典输入 ?

    经典输入是以面向行设计的。在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符。

    选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:

    options.c_lflag |= (ICANON | ECHO | ECHOE); 选择原始输入 ?

    原始输入根本不会被处理。输入字符只是被原封不动的接收。一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 输入选项 ?

    可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程。与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合。

    c_iflag成员可以使用的常量

    常量 描述
    INPCK Enable parity check
    IGNPAR Ignore parity errors
    PARMRK Mark parity errors
    ISTRIP Strip parity bits
    IXON Enable software flow control (outgoing)
    IXOFF Enable software flow control (incoming)
    IXANY Allow any character to start flow again
    IGNBRK Ignore break condition
    BRKINT Send a SIGINT when a break condition is detected
    INLCR Map NL to CR
    IGNCR Ignore CR
    ICRNL Map CR to NL
    IUCLC Map uppercase to lowercase
    IMAXBEL Echo BEL on input line too long
    设置输入奇偶校验选项 ?

    当程序在c_cflag中设置了奇偶校验成员(PARENB)的时候,程序就需要将输入奇偶校验设置成为有效。与奇偶校验相关的常量有INPCK,IGNPAR,PARMRK和ISTRIP。一般情况下,你可能需要选择INPCK和ISTRIP将奇偶校验设置为有效同时从接收字串中脱去奇偶校验位:

    options.c_iflag |= (INPCK | ISTRIP);

    IGNPAR是一个比较危险选项,即便有错误发生时,它也会告诉串口驱动直接忽略奇偶校验错误给数据放行。这个选项在测试链接的通讯质量时比较有用而通常不会被用在实际程序中。

    PARMRK会导致奇偶校验错误被标志成特殊字符加入到输入流之中。如果IGNPAR选项也是有效的,那么一个NUL(八进制000)字符会被加入到发生奇偶校验错误的字符前面。否则,DEL(八进制177)和NUL字符会和出错的字符一起送出。

    设置软件流控制 ?

    软件流控制可以通过IXON,IXOFF和IXANY常量设置成有效:

    options.c_iflag |= (IXON | IXOFF | IXANY);

    将其设置为无效的时候,很简单,只需要对这些位取反:

    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    XON(start data)和XOFF(stop data)字符却是在c_cc数组中定义的,下面会详细描述这个数组。

    输出选项 ?

    成员变量c_oflag之中包括了输出过滤选项。和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出。

    c_oflag成员的常量

    常量 描述
    OPOST Postprocess output (not set = raw output)
    OLCUC Map lowercase to uppercase
    ONLCR Map NL to CR-NL
    OCRNL Map CR to NL
    NOCR No CR output at column 0
    ONLRET NL performs CR function
    OFILL Use fill characters for delay
    OFDEL Fill character is DEL
    NLDLY Mask for delay time needed between lines
    NL0 No delay for NLs
    NL1 Delay further output after newline for 100 milliseconds
    CRDLY Mask for delay time needed to return carriage to left column
    CR0 No delay for CRs
    CR1 Delay after CRs depending on current column position
    CR2 Delay 100 milliseconds after sending CRs
    CR3 Delay 150 milliseconds after sending CRs
    TABDLY Mask for delay time needed after TABs
    TAB0 No delay for TABs
    TAB1 Delay after TABs depending on current column position
    TAB2 Delay 100 milliseconds after sending TABs
    TAB3 Expand TAB characters to spaces
    BSDLY Mask for delay time needed after BSs
    BS0 No delay for BSs
    BS1 Delay 50 milliseconds after sending BSs
    VTDLY Mask for delay time needed after VTs
    VT0 No delay for VTs
    VT1 Delay 2 seconds after sending VTs
    FFDLY Mask for delay time needed after FFs
    FF0 No delay for FFs
    FF1 Delay 2 seconds after sending FFs
    选择加工过的输出 ?

    通过在c_oflag成员变量中设置OPOST选项的方法程序可以选择加工过的输入。

    options.c_oflag |= OPOST;

    在所有选项当中,你可能只需要使用ONLCR选项来将行分隔符映射到CR-LF组合对上。其他选项主要是历史遗留,仅仅与行打印机和终端跟不上串行数据的年代有关。

    选择原始输出 ?

    原始输出方式可以通过在c_oflag中重置OPOST选项来选择:

    options.c_oflag &= ~OPOST;

    如果OPOST选项被设置成无效的话,其他c_oflag中的选项都会失效。

    控制字符 ?

    字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。

    成员变量c_cc中的控制字符

    常量 描述
    VINTR Interrupt CTRL-C
    VQUIT Quit CTRL-Z
    VERASE Erase Backspace (BS)
    VKILL Kill-line CTRL-U
    VEOF End-of-file CTRL-D
    VEOL End-of-line Carriage return (CR)
    VEOL2 Second end-of-line Line feed (LF)
    VMIN Minimum number of characters to read -
    VSTART Start flow CTRL-Q (XON)
    VSTOP Stop flow CTRL-S (XOFF)
    VTIME Time to wait for data (tenths of seconds) -
    设置软件流控制字符 ?

    用来做软件流控制的字符包含在数组c_cc的VSTART和VSTOP元素里面。通常情况下,它们应该被设置成DC1(八进制021)和DC3(八进制023),它们在ASCII标准中代表着XON和XOFF字符。

    设置读取超时 ?

    UNIX串口驱动提供了设置字符和包超时的能力。数组c_cc中有两个元素可以用来设置超时:VMIN和VTIME。在经典输入模式或者通过open(2)和fcntl(2)函数传递NDELAY选项时,超时设置会被忽略。

    VMIN可以指定读取的最小字符数。如果它被设置为0,那么VTIME值则会指定每个字符读取的等待时间。

    如果VMIN不为零,VTIME会指定等待第一个字符读取操作的时间。如果在这个指定时间中可以开始读取某个字符,直到VMIN个数的所有字符全部被读取,其他读取操作将会被阻塞(等待)。也就是说,一旦读取第一个字符,串口驱动的预期就是接收到整个字符包(一共VMIN字节)。如果在允许的时间内没有字符被读取,那么read(2)调用就会返回0。通过这个方法可以确切得告诉串口驱动程序需要读取N个字节,而且read(2)调用只会返回N或者0。然而,超时设置只对第一个字符的读取操作有效,所以,如果因为某些原因驱动程序在N字节的包中丢失某个字符的话,read(2)调用将会一直等下去。

    VTIME可以以十分之一秒为单位指定等待字符输入的时间。如果VTIME设置为0(默认情况),除非open(2)或者fcntl(2)函数设置了NDELAY选项,否则read(2)将会永久得阻塞(等待)。

    调制解调器通讯 ?

    说到串口通讯就不得不提一下通过调剂解调器通讯的方式。这里给出的程序例子都适用于支持“事实上的”标准AT命令集的调制解调器。

    什么是调制解调器 ?

    调制解调器是一种可以将数字信号的串行数据转化为模拟信号频率的设备。通过这种转换,信息就可以通过像电话线或者有线电视线缆那样的模拟数据链路来传输了。口语中,经常将调制解调器称作“猫”。标准的电话调制解调器可以将串行数据转化为能够通过电话线传输的音频;因为这种转化非常之快又非常复杂,所以如果你去听一下的话,这些音频很像是大声尖叫时发出来的声音。

    今天可以见到的调制解调器可以通过电话线每秒传输53000比特——5.3Kbps——的数据。还有就是,大多数调制解调器都使用数据压缩技术,这样就可以将某些类型数据的传输比特率提高到100kbps。

    与调制解调器通讯 ?

    于调制解调器通讯的第一步就是要以原始输入模式打开和配置串口。

    int fd; struct termios options;/* open the port */ fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); fcntl(fd, F_SETFL, 0); /* get the current options */ tcgetattr(fd, &options); /* set raw input, 1 second timeout */ options.c_cflag |= (CLOCAL | CREAD); options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; /* set the options */ tcsetattr(fd, TCSANOW, &options);

    接下来就需要和调制解调器建立通讯连接。最好的办法就是给调制解调器发送“AT”命令。这也会让比较只能的调制解调器探测到你正在使用的波特率。如果正确地连接到调制解调器上,并且调制解调器开启电源,它会返回一个回应信号“OK”。

    int /* O - 0 = MODEM ok, -1 = MODEM bad */ init_modem(int fd) /* I - Serial port file */ { char buffer[255]; /* Input buffer */ char *bufptr; /* Current char in buffer */ int nbytes; /* Number of bytes read */ int tries; /* Number of tries so far */ for (tries = 0; tries < 3; tries ++) { /* send an AT command followed by a CR */ if (write(fd, "AT\r", 3) < 3) continue; /* read characters into our string buffer until we get a CR or NL */ bufptr = buffer; while ((nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0) { bufptr += nbytes; if (bufptr[-1] == '\n' | bufptr[-1] == '\r') break; } /* nul terminate the string and see if we got an OK response */ *bufptr = '\0'; if (strncmp(buffer, "OK", 2) == 0) return (0); } return (-1); } 标准调制解调器命令 ?

    大多数调制解调器都支持“AT”命令集。之所以这样叫是因为这个命令集中的每个命令都是以“AT”字符开头。每个命令都是以第一列的AT开头字符后面跟上特殊命令参数和一个回车符CR(八进制015)。调制解调器处理完这条命令之后会根据命令回复一些文本消息。

    • ATD 拨号 [#b39592a6]

    通过ATD命令可以拨打一个指定号码。除过号码和分隔符(-)以外,你还可以指定以音频("T")或者脉冲("P")方式拨号,暂停一秒(",")和等待拨号音("W"):

    ATDT 555-1212 ATDT 18008008008W1234,1,1234 ATD T555-1212WP1234

    调制解调器可能回复下面列出的某个消息:

    NO DIALTONE BUSY NO CARRIER CONNECT CONNECT baud
    • ATH 挂断

    通过ATH命令可以让调制解调器挂断。因为,调制解调器如果在“命令”模式的话,你可能就不能打普通电话了。

    如果DTR信号线掉了的话,大部分调制解调器也会挂断。你可以将波特率设置成0并且持续至少1秒来做到这一点。再次让DTR掉落同样也可以把调制解调器重新拉回命令模式。

    调制解调器成功挂断以后,它会回复一个"NO CARRIER"回来。如果调制解调器仍然保持连接,它则会发送"CONNECT"或者"CONNECT baud"这样的消息。

    • ATZ 重置调制解调器

    通过ATZ命令可以重置调制解调器。重置之后它会回复字符串"OK"。

    • 与调制解调器通讯的常见问题

    首先,也是最重要的一点,千万不要使用回声输入(input echoing)。回声输入会导致调制解调器和计算机之间产生反馈循环。

    其次,当发送调制解调器命令时,命令必须以回车(CR)而不是换行(NL)结束。C语言中回车的字符常量是"\r"。

    最后,处理调制解调器通讯的时候,要一定保证你使用了调制解调器支持的波特率。虽然大多数调制解调器都支持自动探测波特率,但你也会注意到某些(通常是19.2kbps或者比较老的调制解调器)有局限性。

    高级串口编程 ?

    所谓高级串口编程其实说的就是使用更直接的底层的ioctl(2)和select(2)系统调用来操作串口。

    串口的ioctl ?

    前文中曾经提到使用tcgetattr和tcsetattr函数来配置串口。UNIX环境下,这些函数都是使用ioctl(2)系统调用来实现的。

    系统调用ioctl可以带三个参数:

    int ioctl(int fd, int request, ...);

    显然,fd参数对于串口编程来说就是串口设备文件的文件描述符咯。而request参数是在头文件中定义的常量,而且一般不会超出下表所列的范围。

    串口的IOCTL请求

    REQUEST 描述 POSIX函数
    TCGETS Gets the current serial port settings. tcgetattr
    TCSETS Sets the serial port settings immediately. tcsetattr(fd, TCSANOW, &options)
    TCSETSF Sets the serial port settings after flushing the input and output buffers. tcsetattr(fd, TCSAFLUSH, &options)
    TCSETSW Sets the serial port settings after allowing the input and output buffers to drain/empty. tcsetattr(fd, TCSADRAIN, &options)
    TCSBRK Sends a break for the given time. tcsendbreak, tcdrain
    TCXONC Controls software flow control. tcflow
    TCFLSH Flushes the input and/or output queue. tcflush
    TIOCMGET Returns the state of the "MODEM" bits. None
    TIOCMSET Sets the state of the "MODEM" bits. None
    FIONREAD Returns the number of bytes in the input buffer. None
    取得控制信号 ?

    TIOCMGET ioctl可以取得当前调制解调器的状态位。这个状态位囊括了除去RXDTXD信号线的所有RS-232信号,这些都在下表中列出。

    控制信号常量

    常量 描述
    TIOCM_LE DSR (data set ready/line enable)
    TIOCM_DTR DTR (data terminal ready)
    TIOCM_RTS RTS (request to send)
    TIOCM_ST Secondary TXD (transmit)
    TIOCM_SR Secondary RXD (receive)
    TIOCM_CTS CTS (clear to send)
    TIOCM_CAR DCD (data carrier detect)
    TIOCM_CD Synonym for TIOCM_CAR
    TIOCM_RNG RNG (ring)
    TIOCM_RI Synonym for TIOCM_RNG
    TIOCM_DSR DSR (data set ready)

    例如下面这个程序片段,你可以通过给ioctl带一个用来保存状态位的整形变量的指针来取得状态位。

    #include #include int fd; int status; ioctl(fd, TIOCMGET, &status); 设置控制信号 ?

    TIOCMSET ioctl可以设置上面定义的调制解调器状态位。下面的例子展示如何使用它来将DTR信号线设成掉线状态。

    #include #include int fd; int status; ioctl(fd, TIOCMGET, &status); status &= ~TIOCM_DTR; ioctl(fd, TIOCMSET, &status);

    可能被设置的状态位取决于操作系统,驱动和正在使用的模式。关于更详细的信息应该去看以下你所使用的操作系统的文档。

    英文原文 ?

    http://www.easysw.com/~mike/serial/serial.html

    http://www.adamjiang.com/pukiwiki/index.php?Linux%E4%B8%B2%E5%8F%A3%E7%BC%96%E7%A8%8B%E8%AF%A6%E8%A7%A3#k35d6396串口本身,标准和硬件

  • 用户看到的串口和用户空间的串口编程
  • 配置串口
  • 调制解调器通讯
  • 英文原文

    串口本身,标准和硬件 ?

    串口是计算机上的串行通讯的物理接口。计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备。虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接通常特指那些与RS-232标准兼容的硬件或者调制解调器的接口。虽然现在在很多个人计算机上,原来用以连接外部设备的串口已经广泛的被USB和Firewire替代;而原来用以连接网络的串口则被以太网替代,还有用以连接终端的串口设备则已经被MDA或者VGA取而代之。但是,一方面因为串口本身造价便宜技术成熟,另一方面因为串口的控制台功能RS-232标准高度标准化并且非常普及,所以直到现在它仍然被广泛应用到各种设备上。 某些计算机使用一个叫做UART的集成电路来作为串口设备。这个集成电路可以进行字符和异步串行通讯序列之间的转换,并且可以自动地处理数据的时序。而某些低端设备则会让CPU直接通过输出针来传送数据,这种技术叫做bit-banging。 因为“串口”,RS-232和UARTs基本上总是在同一个语境中出现,所以这些名词通常会被搞混。下面逐一解释以下一些重要的名词和术语。

    什么是串行通信 ?

    计算机可以每次传送一个或者多个位(bit)的数据。“串行”指的式每次只传输一位(1bit)数据。 当需要通过串行通讯传输一个字(word)的数据时,只能以每次一位的方式接收或者发送。每个位可能是on(1)或者off(0)。很多技术术语中经常用mark表示on,而space表示off。

    串行数据的速度通常用每秒传输的字节数bits-per-second(bps)或者波特率(baud)表示。这个值表示的是每秒钟被送出的0和1的个数。很久很久以前,300bps就是很快的速度了,而现在的电脑可以处理高达430,800的RS-232速率。表示波特率的单位还有kpbs和Mbps,1kps=1000bps而1Mbps=1000kbps。 一般有人提到串行设备的时候,它通常说可能是某种数据通讯设备-DCE(Data Communications Equipment)或者数据终端设备-DTE(Data Terminal Equipment)。它们之间的区别非常简单,每个信号对,比如传送和接收,它们俩正好是相反的。如果需要将两个DTE或者DCE设备连接起来的话,需要适配器或者交叉线缆将信号对交换。

    什么是RS-232 ?

    RS-232是EIA(Electronic Industries Association)定义的串行通信的电器接口。RS-232事实上有三种(A,B和C),它们分别采用不同的电压来表示on和off。最被广泛使用的是RS-232C,它将mark(on)比特的电压定义为-3V到-12V之间,而将space(off)的电压定义到+3V到+12V之间。虽然RS-232C标准说信号最远被传输8m,但事实上你可以使用它传输更长的距离,直到信号波特率已经小到不行了为止。 RS-232的连结线中除去用来传入传出数据的电线,还有一些用来提供时序,状态和握手的电线:

    RS-232 针脚定义

    DB-25

    针脚 描述 针脚 描述 针脚 描述 针脚 描述 针脚 描述
    1 Earth Ground 6 DSR - Data Set Ready 11 Unassigned 16 Secondary RXD 21 Signal Quality Detect
    2 TXD - Transmitted Data 7 GND - Logic Ground 12 Secondary DCD 17 Receiver Clock 22 Ring Detect
    3 RXD - Received Data 8 DCD - Data Carrier Detecter 13 Secondary CTS 18 Unassigned 23 Data Rate Select
    4 RTS - Request To Send 9 Reserved 14 Secondary TXD 19 Secondary RTS 24 Transmit Clock
    5 CTS - Clear To Send 10 Reserved 15 Transmit Clock 20 DTR - Data Terminal Ready 25 Unassigned

    DB-9

    针脚 名称 全名 方向(主机 外设)
    3 TD Transmit Data ->
    2 RD Receive Data <-
    7 RTS Request To Send ->
    8 CTS Clear To Send <-
    6 DSR Data Set Ready <-
    4 DTR Data Terminal Ready ->
    1 CD Data Carrier Detect <-
    9 RI Ring Indicator <-
    5 - Signal Ground  

    另外两个比较常见的串行接口的标准式RS-422和RS-574。RS-422使用更低的电压和差分信号,这样可以将传输距离扩张到300m。而RS-574定义了通常可以见到的用在电脑上的9针连接器和电压。

    信号定义 ?

    RS-232标准定义了18个不同的串行通信的信号。而这些之中,仅仅有如下6个可以在UNIX环境中使用。

    • GND - Logic Ground

      从技术角度讲,GND不能算是信号。但是没有它其他信号都不能用了。基本上,logic ground有点像一个参考电压,通过它来判断哪个电压表示正哪个电压表示负。

    • TXD - Transmitted Data

      TXD信号负载着从你的电脑或者设备到另一端(比如调制解调器)的数据。Mark范围的电压被解析成1,而space范围电压被解析成0。

    • RXD - Received Data

      RXD于TXD正好相反。它负载着从另一端的电脑或者设备上传到你的工作站的数据。Mark和space的解析方法于TXD一致。

    • DCD - Data Carrier Detect

      DCD信号通常来自串口连结线的另一端。这条信号线上的space电压表示另一端的电脑或者设备现在已经连接。但是,DCD信号线却不是总可以得到的,有些设备上有这条信号线,而有的则没有。

    • DTR - Data Terminal Ready

      DTR信号是你的工作站产生的,用以告诉另一端的电脑或者设备你已经是否已经准备好了。Space电压表示准备好了,而mark电压表示没有准备好。当你在工作站上打开串行接口时,DTR通常自动被设置位有效。

    • CTS - Clear To Send

      CTS则通常来自连结线的另一端。Space电压表示你可以从工作站送出更多的数据。CTS通常用来协调你的工作站和另一端之间的串行数据流。

    • RTS - Request To Send

      如果RTS信号被设置成space电压,这表示你准备好了一些数据需要传送。和CTS一样,RTS也被用来协调工作站和另一端的电脑或者设备之间的数据流。有些工作站上会一直将这个信号设置位space。

    异步通讯 ?

    计算机为了弄懂传给它的串行数据,它需要确定每个字符开始和结束的位置。这通常是用异步串行数据来完成的。

    在异步模式中,除非有字符被传输,否则串行数据线总是处于mark(1)状态。有一个start位会被加入传输字符的各个位之前,在字符本身的位之后会有一个可选的parity位和一个或者多个stop位。Start位总是space(0)并且它会告诉计算机新的串行数据过来了。数据可以随时被送出或者接收,这就是所谓的异步。

    #ref(): File not found: "async.gif" at page "Linux串口编程详解"

    那个可选的parity位仅仅是所有传输位的和,这个和用以表示传输字符中有奇数个1还是偶数个1。在偶数parity中,如果有传输字符中有偶数个1,那么parity位被设置成0,而传输字符中有奇数个1,那么parity位被设置成1。在奇数parity中,位设置与此相反。还有一些术语,比如space parity, mark parity和no parity。Space parity是指parity位会一直被设置位0,而mark parity正好与此相反,parity会一直是1。No parity的意思就是根本不会传输parity位。 剩余的位叫做stop位。传输字符之间可以有1个,1.5个或者2个stop位,而且,它们的值总是1。传统上,Stop位式用给计算机一些时间处理前面的字符的,但是它只是被用来同步接收数据的计算机和接受的字符。 异步数据通常被表示成"8N1","7E1",或者与此类似的形式。这表示“8数据位,no parity和1个stop bit”,还有相应得,“7数据位,even parity和1个stop bit”。

    什么是全双工和半双工 ?

    全双工(Full duplex)是说计算机可以同时接受和发送数据——也就是它有两个分开的数据传输通道(一个传入,一个传出)。

    半双工(Half duplex)表示计算机不能同时接受和发送数据,而在某一时刻它只能单一的传送或者接收。这通常意味着,它只有一个数据通道。半双工并不是说RS-232的某些信号不能使用,而是,它通常是使用了有别于RS-232的其他不支持全双工的标准。

    什么是流控制 ?

    两个串行接口之间的传输数据流通常需要协调一致才行。这可能是由于用以通信的某个串行接口或者某些存储介质的中间串行通信链路的限制造成的。对于异步数据这里有两个方法做到这一点。

    第一种方法通常被叫做“软件”流控制。这种方法采用特殊字符来开始(XON,DC1,八进制数021)或者结束(XOFF,DC3或者八进制数023)数据流。而这些字符都在ASCII中定义好了。虽然这些编码对于传输文本信息非常有用,但是它们却不能被用于在特殊程序中的其他类型的信息。

    第二种方法叫做“硬件”流控制。这种方法使用RS-232标准的CTS和RTS信号来取代之前提到的特殊字符。当准备就绪时,接受一方会将CTS信号设置成为space电压,而尚未准备就绪时它会被设置成为mark电压。相应得,发送方会在准备就绪的情况下将RTS设置成space电压。正因为硬件流控制使用了于数据分隔的信号,所以与需要传输特殊字符的软件流控制相比它的速度很快。但是,并不是所有的硬件和操作系统都支持CTS/RTS流控制。

    什么是BREAK ?

    通常,直到有数据传输时,接收和传输信号会保持在mark电压。如果一个信号掉到space电压并且持续了很长时间,一般来说是1/4到1/2秒,那么就说有一个break条件存在了。

    BREAK经常被用来重置一条数据线或者用来改变像调制解调器这样的设备的通讯模式。

    同步通讯 ?

    与异步数据不同,同步数据是一个稳定的字节流。为了能够在线路上读取到数据,计算机必须提供或者接受一个时钟,这样才能保证发送端和接收端同步。尽管已经有同步时钟,计算机还是必须以某种方式标志数据流的开端。做这件事情最常见的办法就是使用像Serial Data Link Control("SDLC")或者High-Speed Data Link Control("HDLC")这样的数据包通讯协议。

    这些协议每个都定义了一个确定的比特序列来表示数据包的开始和结束。当然,它们也定义了一个用来表示没有数据传输的比特序列。这些比特序列可以帮助计算机识别数据包的开端。

    因为同步协议可以不使用每个字符的同步比特位,所以通常它们的性能比异步通讯快最少25%,而且一般比较适用于远距离的网络链接或者有两个串口接口的配置的情况。尽管同步通讯的速度有优势,大部分RS-232硬件却不支持它,因为同步通讯需要其他的硬件和软件。

    用户看到的串口和用户空间的串口编程 ?

    和其他设备一样,Linux也是通过设备文件来提供访问串口的功能。当需要访问串口的时候,你只需要open相应的文件。

    串口的设备文件 ?

    Linux系统上一般有一个或者多个串口,而这些串口设备文件名字比较奇怪,如比下面这样

    串口设备文件名

    操作系统 串口1 串口2 USB/RS-232转换器
    Windows COM1 COM2 -
    Linux /dev/ttyS0 /dev/ttyS1 /dev/ttyUSB0

    打开串口 ?

    因为串口和其他设备一样,在类Unix系统中都是以设备文件的形式存在的,所以,理所当然得你可以使用open(2)系统调用/函数来访问它。但Linux系统中却有一个稍微不方便的地方,那就是普通用户一般不能直接访问设备文件。你可以选择以下方式做一些调整,以便你编写的程序可以访问串口。

    • 改变设备文件的访问权限设置 [#cd9bd1e0]
    • 以root超级用户的身份运行程序 [#kdd0e577]
    • 将你的程序编写位setuid程序,以串口设备所有者的身份运行程序 [#s7b703ff]

    OK.假如你已经准备好了让串口设备文件可以被所有用户访问,你可以在Linux系统中实验一下下面这个程序,它可以打开计算机的串口1。

    #include #include #include #include /* File control definitions */ #include #include /* POSIX terminal control definitions */ /* * 'open_port()' - Open serial port 1 * Returns the file descriptor on success or -1 on error. */ int open_port(void) { int fd; /* File descriptor for the port */ fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { /* * Could not open the port. */ perror("open_port: Unable to open /dev/ttyS0 -"); } else { fcntl(fd, F_SETFL, 0); return (fd); } }

    打开文件的选项 ?

    打开串口连接的时候,程序在open函数中除了Read+Write模式以外还指定了两个选项;

    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

    标志O_NOCTTY可以告诉UNIX这个程序不会成为这个端口上的“控制终端”。如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程。而有些程序比如getty(1M/8)则会在打开登录进程的时候使用这个特性,但是通常情况下,用户程序不会使用这个行为。

    O_NDELAY标志则是告诉UNIX,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接。如果不指定这个标志的话,除非DCD信号线上有space电压否则这个程序会一直睡眠。

    给端口上写数据 ?

    给端口上写入数据也很简单,使用write(2)系统调用就可以发送数据了:

    n = write(fd, "ATZ\r", 4); if (n < 0) fputs("write() of 4 bytes failed!\n", stderr);

    和写入其他设备文件的方式相同,write函数也会返回发送数据的字节数或者在发生错误的时候返回-1。通常,发送数据最常见的错误就是EIO,当调制解调器或者数据链路将Data Carrier Detect(DCD)信号线弄掉了,就会发生这个错误。而且,直至关闭端口这个情况会一直持续。

    从端口上读取数据 ?

    从串口上读取数据的时候就得耍花招了。因为,如果你在原数据模式(raw data mode)操作端口的话,每个read(2)系统调用都会返回从串口输入缓冲区中实际得到的字符的个数。在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生。如果需要read(2)函数迅速返回的话,你可以使用下面这个方式:

    fcntl(fd, F_SETFL, FNDELAY);

    标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0。需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数:

    fcntl(fd, F_SETFL, 0);

    当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式。

    关闭串口 ?

    可以使用close(2)系统调用关闭串口:

    close(fd);

    关闭串口会将DTR信号线设置成low,这会导致很多调制解调器挂起。

    配置串口 ?

    POSIX终端接口 ?

    很多系统都支持POSIX终端(串口)接口。程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等。要使用这个端口的话,你必须将头文件包含到你的程序中。这个头文件中定义了终端控制结构体和POSIX控制函数。

    与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3)。顾名思义,这两个函数分别用来取得设设置终端的属性。调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体:

    termios结构体成员

    成员 描述
    c_cflag 控制选项
    c_lflag 行选项
    c_iflag 输入选项
    c_oflag 输出选项
    c_cc 控制字符
    c_ispeed 输入波特率(NEW)
    c_ospeed 输出波特率(NEW)

    控制选项 ?

    通过termios结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制。下面这张表列出了所有可以使用的常数。

    c_cflag常数

    常量 描述
    CBAUD Bit mask for baud rate
    B0 0 baud (drop DTR)
    B50 50 baud
    B75 75 baud
    B110 110 baud
    B134 134.5 baud
    B150 150 baud
    B200 200 baud
    B300 300 baud
    B600 600 baud
    B1200 1200 baud
    B1800 1800 baud
    B2400 2400 baud
    B4800 4800 baud
    B9600 9600 baud
    B19200 19200 baud
    B38400 38400 baud
    B57600 57,600 baud
    B76800 76,800 baud
    B115200 115,200 baud
    EXTA External rate clock
    EXTB External rate clock
    CSIZE Bit mask for data bits
    CS5 5 data bits
    CS6 6 data bits
    CS7 7 data bits
    CS8 8 data bits
    CSTOPB 2 stop bits (1 otherwise)
    CREAD Enable receiver
    PARENB Enable parity bit
    PARODD Use odd parity instead of even
    HUPCL Hangup (drop DTR) on last close
    CLOCAL Local line - do not change "owner" of port
    LOBLK Block job control output
    CNEW_RTSCTS/CRTSCTS Enable hardware flow control (not supported on all platforms)

    在传统的POSIX编程中,当连接一个本地的(不通过调制解调器)或者远程的终端(通过调制解调器)时,这里有两个选项应当一直打开,一个是CLOCAL,另一个是CREAD。这两个选项可以保证你的程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节。

    波特率常数(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成员的旧的接口上。后面文章将会提到如何使用其他POSIX函数来设置波特率。

    千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志。不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性。

    设置波特率 ?

    不同的操作系统会将波特率存储在不同的位置。旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值。

    程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口。下面的代码是个非常典型的设置波特率的例子。

    struct termios options; /* * Get the current options for the port... */ tcgetattr(fd, &options);/* * Set the baud rates to 19200... */ cfsetispeed(&options, B19200); cfsetospeed(&options, B19200); /* * Enable the receiver and set local mode... */ options.c_cflag |= (CLOCAL | CREAD); /* * Set the new options for the port... */ tcsetattr(fd, TCSANOW, &options);

    函数tcgetattr(3)会将当前串口配置回填到termio结构体option中。然后,程序设置了输入输出的波特率并且将本地模式(CLOCAL)和串行数据接收(CREAD)设置为有效,接着将新的配置作为参数传递给函数tcsetattr(3)。常量TCSANOW标志所有改变必须立刻生效而不用等到数据传输结束。其他另一些常数可以保证等待数据结束或者刷新输入输出之后再生效。

    tcsetattr常量

    常量 描述
    TCSANOW Make changes now without waiting for data to complete
    TCSADRAIN Wait until everything has been transmitted
    TCSAFLUSH Flush input and output buffers and make the change

    不同的系统上可能支持不同的输入输出速度,所以,通过串口连接两台机器或者设备的时候,应该将波特率设置成两者中较小的那个,即MIN(speed1, speed2)。

    设置字符大小 ?

    设置字符大小的时候,这里却没有像设置波特率那么方便的函数。所以,程序中需要一些位掩码运算来把事情搞定。字符大小以比特为单位指定:

    options.c_flag &= ~CSIZE; /* Mask the character size bits */ options.c_flag |= CS8; /* Select 8 data bits */

    设置奇偶校验 ?

    与设置字符大小的方式差不多,这里仍然需要组合一些位掩码来将奇偶校验设为有效和奇偶校验的类型。UNIX串口驱动可以生成even,odd和no parity位码。设置space奇偶校验需要耍点小手段。

    • No parity (8N1)

    options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8;

    • Even parity (7E1)

    options.c_cflag |= PARENB options.c_cflag &= ~PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;

    • Odd parity (7O1)

    options.c_cflag |= PARENB options.c_cflag |= PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;

    • Space parity is setup the same as no parity (7S1)

    options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8;

    设置硬件流控制 ?

    某些版本的UNIX系统支持通过CTS(Clear To Send)和RTS(Request To Send)信号线来设置硬件流控制。如果系统上定义了CNEW_RTSCTS和CRTSCTS常量,那么很可能它会支持硬件流控制。使用下面的方法将硬件流控制设置成有效:

    options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS

    将它设置成为无效的方法与此类似:

    options.c_cflag &= ~CNEW_RTSCTS;

    本地设置 ?

    本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符。通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。

    成员变量c_lflag可以使用的常量

    ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
    ICANON Enable canonical input (else raw)
    XCASE Map uppercase \lowercase (obsolete)
    ECHO Enable echoing of input characters
    ECHOE Echo erase character as BS-SP-BS
    ECHOK Echo NL after kill character
    ECHONL Echo NL
    NOFLSH Disable flushing of input buffers after interrupt or quit characters
    IEXTEN Enable extended functions
    ECHOCTL Echo control characters as ^char and delete as ~?
    ECHOPRT Echo erased character as character erased
    ECHOKE BS-SP-BS entire line on line kill
    FLUSHO Output being flushed
    PENDIN Retype pending input at next read or input char
    TOSTOP Send SIGTTOU for background output

    选择经典输入 ?

    经典输入是以面向行设计的。在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符。

    选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:

    options.c_lflag |= (ICANON | ECHO | ECHOE);

    选择原始输入 ?

    原始输入根本不会被处理。输入字符只是被原封不动的接收。一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

    输入选项 ?

    可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程。与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合。

    c_iflag成员可以使用的常量

    常量 描述
    INPCK Enable parity check
    IGNPAR Ignore parity errors
    PARMRK Mark parity errors
    ISTRIP Strip parity bits
    IXON Enable software flow control (outgoing)
    IXOFF Enable software flow control (incoming)
    IXANY Allow any character to start flow again
    IGNBRK Ignore break condition
    BRKINT Send a SIGINT when a break condition is detected
    INLCR Map NL to CR
    IGNCR Ignore CR
    ICRNL Map CR to NL
    IUCLC Map uppercase to lowercase
    IMAXBEL Echo BEL on input line too long

    设置输入奇偶校验选项 ?

    当程序在c_cflag中设置了奇偶校验成员(PARENB)的时候,程序就需要将输入奇偶校验设置成为有效。与奇偶校验相关的常量有INPCK,IGNPAR,PARMRK和ISTRIP。一般情况下,你可能需要选择INPCK和ISTRIP将奇偶校验设置为有效同时从接收字串中脱去奇偶校验位:

    options.c_iflag |= (INPCK | ISTRIP);

    IGNPAR是一个比较危险选项,即便有错误发生时,它也会告诉串口驱动直接忽略奇偶校验错误给数据放行。这个选项在测试链接的通讯质量时比较有用而通常不会被用在实际程序中。

    PARMRK会导致奇偶校验错误被标志成特殊字符加入到输入流之中。如果IGNPAR选项也是有效的,那么一个NUL(八进制000)字符会被加入到发生奇偶校验错误的字符前面。否则,DEL(八进制177)和NUL字符会和出错的字符一起送出。

    设置软件流控制 ?

    软件流控制可以通过IXON,IXOFF和IXANY常量设置成有效:

    options.c_iflag |= (IXON | IXOFF | IXANY);

    将其设置为无效的时候,很简单,只需要对这些位取反:

    options.c_iflag &= ~(IXON | IXOFF | IXANY);

    XON(start data)和XOFF(stop data)字符却是在c_cc数组中定义的,下面会详细描述这个数组。

    输出选项 ?

    成员变量c_oflag之中包括了输出过滤选项。和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出。

    c_oflag成员的常量

    常量 描述
    OPOST Postprocess output (not set = raw output)
    OLCUC Map lowercase to uppercase
    ONLCR Map NL to CR-NL
    OCRNL Map CR to NL
    NOCR No CR output at column 0
    ONLRET NL performs CR function
    OFILL Use fill characters for delay
    OFDEL Fill character is DEL
    NLDLY Mask for delay time needed between lines
    NL0 No delay for NLs
    NL1 Delay further output after newline for 100 milliseconds
    CRDLY Mask for delay time needed to return carriage to left column
    CR0 No delay for CRs
    CR1 Delay after CRs depending on current column position
    CR2 Delay 100 milliseconds after sending CRs
    CR3 Delay 150 milliseconds after sending CRs
    TABDLY Mask for delay time needed after TABs
    TAB0 No delay for TABs
    TAB1 Delay after TABs depending on current column position
    TAB2 Delay 100 milliseconds after sending TABs
    TAB3 Expand TAB characters to spaces
    BSDLY Mask for delay time needed after BSs
    BS0 No delay for BSs
    BS1 Delay 50 milliseconds after sending BSs
    VTDLY Mask for delay time needed after VTs
    VT0 No delay for VTs
    VT1 Delay 2 seconds after sending VTs
    FFDLY Mask for delay time needed after FFs
    FF0 No delay for FFs
    FF1 Delay 2 seconds after sending FFs

    选择加工过的输出 ?

    通过在c_oflag成员变量中设置OPOST选项的方法程序可以选择加工过的输入。

    options.c_oflag |= OPOST;

    在所有选项当中,你可能只需要使用ONLCR选项来将行分隔符映射到CR-LF组合对上。其他选项主要是历史遗留,仅仅与行打印机和终端跟不上串行数据的年代有关。

    选择原始输出 ?

    原始输出方式可以通过在c_oflag中重置OPOST选项来选择:

    options.c_oflag &= ~OPOST;

    如果OPOST选项被设置成无效的话,其他c_oflag中的选项都会失效。

    控制字符 ?

    字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。

    成员变量c_cc中的控制字符

    常量 描述
    VINTR Interrupt CTRL-C
    VQUIT Quit CTRL-Z
    VERASE Erase Backspace (BS)
    VKILL Kill-line CTRL-U
    VEOF End-of-file CTRL-D
    VEOL End-of-line Carriage return (CR)
    VEOL2 Second end-of-line Line feed (LF)
    VMIN Minimum number of characters to read -
    VSTART Start flow CTRL-Q (XON)
    VSTOP Stop flow CTRL-S (XOFF)
    VTIME Time to wait for data (tenths of seconds) -

    设置软件流控制字符 ?

    用来做软件流控制的字符包含在数组c_cc的VSTART和VSTOP元素里面。通常情况下,它们应该被设置成DC1(八进制021)和DC3(八进制023),它们在ASCII标准中代表着XON和XOFF字符。

    设置读取超时 ?

    UNIX串口驱动提供了设置字符和包超时的能力。数组c_cc中有两个元素可以用来设置超时:VMIN和VTIME。在经典输入模式或者通过open(2)和fcntl(2)函数传递NDELAY选项时,超时设置会被忽略。

    VMIN可以指定读取的最小字符数。如果它被设置为0,那么VTIME值则会指定每个字符读取的等待时间。

    如果VMIN不为零,VTIME会指定等待第一个字符读取操作的时间。如果在这个指定时间中可以开始读取某个字符,直到VMIN个数的所有字符全部被读取,其他读取操作将会被阻塞(等待)。也就是说,一旦读取第一个字符,串口驱动的预期就是接收到整个字符包(一共VMIN字节)。如果在允许的时间内没有字符被读取,那么read(2)调用就会返回0。通过这个方法可以确切得告诉串口驱动程序需要读取N个字节,而且read(2)调用只会返回N或者0。然而,超时设置只对第一个字符的读取操作有效,所以,如果因为某些原因驱动程序在N字节的包中丢失某个字符的话,read(2)调用将会一直等下去。

    VTIME可以以十分之一秒为单位指定等待字符输入的时间。如果VTIME设置为0(默认情况),除非open(2)或者fcntl(2)函数设置了NDELAY选项,否则read(2)将会永久得阻塞(等待)。

    调制解调器通讯 ?

    说到串口通讯就不得不提一下通过调剂解调器通讯的方式。这里给出的程序例子都适用于支持“事实上的”标准AT命令集的调制解调器。

    什么是调制解调器 ?

    调制解调器是一种可以将数字信号的串行数据转化为模拟信号频率的设备。通过这种转换,信息就可以通过像电话线或者有线电视线缆那样的模拟数据链路来传输了。口语中,经常将调制解调器称作“猫”。标准的电话调制解调器可以将串行数据转化为能够通过电话线传输的音频;因为这种转化非常之快又非常复杂,所以如果你去听一下的话,这些音频很像是大声尖叫时发出来的声音。

    今天可以见到的调制解调器可以通过电话线每秒传输53000比特——5.3Kbps——的数据。还有就是,大多数调制解调器都使用数据压缩技术,这样就可以将某些类型数据的传输比特率提高到100kbps。

    与调制解调器通讯 ?

    于调制解调器通讯的第一步就是要以原始输入模式打开和配置串口。

    int fd; struct termios options;/* open the port */ fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); fcntl(fd, F_SETFL, 0); /* get the current options */ tcgetattr(fd, &options); /* set raw input, 1 second timeout */ options.c_cflag |= (CLOCAL | CREAD); options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; /* set the options */ tcsetattr(fd, TCSANOW, &options);

    接下来就需要和调制解调器建立通讯连接。最好的办法就是给调制解调器发送“AT”命令。这也会让比较只能的调制解调器探测到你正在使用的波特率。如果正确地连接到调制解调器上,并且调制解调器开启电源,它会返回一个回应信号“OK”。

    int /* O - 0 = MODEM ok, -1 = MODEM bad */ init_modem(int fd) /* I - Serial port file */ { char buffer[255]; /* Input buffer */ char *bufptr; /* Current char in buffer */ int nbytes; /* Number of bytes read */ int tries; /* Number of tries so far */ for (tries = 0; tries < 3; tries ++) { /* send an AT command followed by a CR */ if (write(fd, "AT\r", 3) < 3) continue; /* read characters into our string buffer until we get a CR or NL */ bufptr = buffer; while ((nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0) { bufptr += nbytes; if (bufptr[-1] == '\n' | bufptr[-1] == '\r') break; } /* nul terminate the string and see if we got an OK response */ *bufptr = '\0'; if (strncmp(buffer, "OK", 2) == 0) return (0); } return (-1); }

    标准调制解调器命令 ?

    大多数调制解调器都支持“AT”命令集。之所以这样叫是因为这个命令集中的每个命令都是以“AT”字符开头。每个命令都是以第一列的AT开头字符后面跟上特殊命令参数和一个回车符CR(八进制015)。调制解调器处理完这条命令之后会根据命令回复一些文本消息。

    • ATD 拨号 [#b39592a6]

    通过ATD命令可以拨打一个指定号码。除过号码和分隔符(-)以外,你还可以指定以音频("T")或者脉冲("P")方式拨号,暂停一秒(",")和等待拨号音("W"):

    ATDT 555-1212 ATDT 18008008008W1234,1,1234 ATD T555-1212WP1234

    调制解调器可能回复下面列出的某个消息:

    NO DIALTONE BUSY NO CARRIER CONNECT CONNECT baud

    • ATH 挂断

    通过ATH命令可以让调制解调器挂断。因为,调制解调器如果在“命令”模式的话,你可能就不能打普通电话了。

    如果DTR信号线掉了的话,大部分调制解调器也会挂断。你可以将波特率设置成0并且持续至少1秒来做到这一点。再次让DTR掉落同样也可以把调制解调器重新拉回命令模式。

    调制解调器成功挂断以后,它会回复一个"NO CARRIER"回来。如果调制解调器仍然保持连接,它则会发送"CONNECT"或者"CONNECT baud"这样的消息。

    • ATZ 重置调制解调器

    通过ATZ命令可以重置调制解调器。重置之后它会回复字符串"OK"。

    • 与调制解调器通讯的常见问题

    首先,也是最重要的一点,千万不要使用回声输入(input echoing)。回声输入会导致调制解调器和计算机之间产生反馈循环。

    其次,当发送调制解调器命令时,命令必须以回车(CR)而不是换行(NL)结束。C语言中回车的字符常量是"\r"。

    最后,处理调制解调器通讯的时候,要一定保证你使用了调制解调器支持的波特率。虽然大多数调制解调器都支持自动探测波特率,但你也会注意到某些(通常是19.2kbps或者比较老的调制解调器)有局限性。

    高级串口编程 ?

    所谓高级串口编程其实说的就是使用更直接的底层的ioctl(2)和select(2)系统调用来操作串口。

    串口的ioctl ?

    前文中曾经提到使用tcgetattr和tcsetattr函数来配置串口。UNIX环境下,这些函数都是使用ioctl(2)系统调用来实现的。

    系统调用ioctl可以带三个参数:

    int ioctl(int fd, int request, ...);

    显然,fd参数对于串口编程来说就是串口设备文件的文件描述符咯。而request参数是在头文件中定义的常量,而且一般不会超出下表所列的范围。

    串口的IOCTL请求

    REQUEST 描述 POSIX函数
    TCGETS Gets the current serial port settings. tcgetattr
    TCSETS Sets the serial port settings immediately. tcsetattr(fd, TCSANOW, &options)
    TCSETSF Sets the serial port settings after flushing the input and output buffers. tcsetattr(fd, TCSAFLUSH, &options)
    TCSETSW Sets the serial port settings after allowing the input and output buffers to drain/empty. tcsetattr(fd, TCSADRAIN, &options)
    TCSBRK Sends a break for the given time. tcsendbreak, tcdrain
    TCXONC Controls software flow control. tcflow
    TCFLSH Flushes the input and/or output queue. tcflush
    TIOCMGET Returns the state of the "MODEM" bits. None
    TIOCMSET Sets the state of the "MODEM" bits. None
    FIONREAD Returns the number of bytes in the input buffer. None

    取得控制信号 ?

    TIOCMGET ioctl可以取得当前调制解调器的状态位。这个状态位囊括了除去RXDTXD信号线的所有RS-232信号,这些都在下表中列出。

    控制信号常量

    常量 描述
    TIOCM_LE DSR (data set ready/line enable)
    TIOCM_DTR DTR (data terminal ready)
    TIOCM_RTS RTS (request to send)
    TIOCM_ST Secondary TXD (transmit)
    TIOCM_SR Secondary RXD (receive)
    TIOCM_CTS CTS (clear to send)
    TIOCM_CAR DCD (data carrier detect)
    TIOCM_CD Synonym for TIOCM_CAR
    TIOCM_RNG RNG (ring)
    TIOCM_RI Synonym for TIOCM_RNG
    TIOCM_DSR DSR (data set ready)

    例如下面这个程序片段,你可以通过给ioctl带一个用来保存状态位的整形变量的指针来取得状态位。

    #include #include int fd; int status; ioctl(fd, TIOCMGET, &status);

    设置控制信号 ?

    TIOCMSET ioctl可以设置上面定义的调制解调器状态位。下面的例子展示如何使用它来将DTR信号线设成掉线状态。

    #include #include int fd; int status; ioctl(fd, TIOCMGET, &status); status &= ~TIOCM_DTR; ioctl(fd, TIOCMSET, &status);

    可能被设置的状态位取决于操作系统,驱动和正在使用的模式。关于更详细的信息应该去看以下你所使用的操作系统的文档。

    英文原文 ?

    http://www.easysw.com/~mike/serial/serial.html

    http://www.adamjiang.com/pukiwiki/index.php?Linux%E4%B8%B2%E5%8F%A3%E7%BC%96%E7%A8%8B%E8%AF%A6%E8%A7%A3#k35d6396

  • 展开全文
  • 串口编程

    千次阅读 2013-08-23 12:23:31
    目录序言第一章 基本的串口通讯 什么是串口通讯 什么是RS-232 信号定义 异步通讯 什么是双工和单工 流量控制 什么是断开/break 同步通讯 访问串行端口 串行端口文件 打开串行端口 写入端口 读出端口 ...
  • linux串口编程详解

    2012-04-17 14:29:05
    信号定义 异步通讯 什么是全双工和半双工什么是流控制什么是BREAK 同步通讯 用户看到的串口和用户空间的串口编程 串口的设备文件打开串口打开文件的选项给端口上写数据从端口上读取数据关闭串口 配置串口 ...
  • 串口编程的资料

    2010-06-10 09:30:00
    第一章 基本的串口通讯什么是串口通讯什么是RS-232信号定义异步通讯什么是双工和单工流量控制什么是断开/break同步通讯访问串行端口串行端口文件打开串行端口写入端口读出端口关闭端口第二章配置串行端口POSIX终端...
  • STM32串口异步通信需要定义的参数 奇偶矫正位 如果GPIO作为串口,如何配置输入输出模式? 异步串口通信框图讲解 串口通信基本原理 并行通信与串行通信 ① 并行通信传送八路信号,一次并行传送传送完整的一...
  • 串口本身,标准和硬件 ...信号定义 异步通讯 什么是全双工和半双工 什么是流控制 什么是BREAK 同步通讯 用户看到的串口和用户空间的串口编程 串口的设备文件 打开串口 打开文件的选项
  • 串口是串行接口的简称,分为同步传输(USRT)和异步传输(UART)。在同步通信中,发送端和接收端使用同一个时钟。在异步通信中,接受时钟和发送时钟是不同步的,即发送端和接收端都有自己独立的时钟和相同的速度约定...
  • 书中精选来自工程实践的应用范例,主要涵盖串口通信的理论基础、Visual c++集成开发环境简介、MSComm控件串口编程、Windows API串口编程、TAPI通信编程、串口实现双机互连、串口调试精灵、串口控制Modem设备、串口...
  • 各位朋友大家好,有一个项目需要用C++实现串口通信(采用同步方式因为需要轮询下位机)并将串口的数据通过socket发送给服务器,现在基本功能已经实现,还存在一个小bug。当上位机用writefile函数向下位机写数据时,...
  • 一种是采用轮询串口的方式,例如每3s向每个串口的buffer区去取一次数据,但是这样可能会有缓冲区溢出的可能,同时,数据的同步也可能会出现一定的问题,因为数据的上传周期是可以用户自定义的,一旦用户定义的上传...
  • UART简介  通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常...不像SPI,I2C等同步传输信号。所以串口的传输速度和其它协议的速度相比是比较慢的。下面具体讲解一些uart协议以及是如何通信
  • 使用拾音器获取吉他模拟音频信号,经转换芯片成为数字信号后分帧输入到DSP芯片的多通道缓冲同步串口,使用芯片完成最后音频信号的数模转换并输出到音响。软件主要使用内存中定义的环形缓冲区从而以DSP的零消耗循环...

空空如也

空空如也

1 2 3
收藏数 57
精华内容 22
关键字:

同步串口信号定义