rs232串行通信_基于c语言的rs232串行接口通信实现 - CSDN
  • 上一次了解了最基本的串行通信。尽管RS-232本身带有奇偶校验位,但是其检错能力非常有限,同时,在串口的数据传输中,数据出错的可能随着传输距离的增长不断变大。同时,收发两方如何进行同步也是一个需要考虑的问题...

    上一次了解了最基本的串行通信。

    尽管RS-232本身带有奇偶校验位,但是其检错能力非常有限,同时,在串口的数据传输中,数据出错的可能随着传输距离的增长不断变大。同时,收发两方如何进行同步也是一个需要考虑的问题,为了解决这一系列问题,有一个行之有效的方法——协议。通过增加多余的冗余部分来确保信息可靠的传输。

    首先需要解决的问题是帧头与帧尾,用来界定一个完整的帧。在这里我们简单的将帧头与帧尾分别设置为0x02与0x03。在更多的时候,会采用巴格码来设置帧头。主要的目的是避免帧内容中出现了与帧尾相同的字符而导致提前结束。这里我们采用另一种方法来解决这个问题。

    在传输的过程中,可能会发生数据丢失的情况,也可能数据过多,接收方还未接收完毕,发送方又进行发送,导致数据溢出等诸多问题。因此,需要有一个方法来避免这种情况的问题。博主选择参考滑动窗口协议的类容,设置一个发送序号与接收序号,只有当确认回复的接收序号与发送序号相同时,才会发送下一帧。同时,若长时间没有收到确认帧,则会重发该数据。

    同时,本次串行通讯的应用场景主要是用于控制总机与执行分机之前,因此,需要对帧的类型进行划分,即控制帧(01)与表示帧(10)。

    如果没有建立连接就进行发送,可能会导致接收方未曾做好准备,或者,在信息传输的介质出现问题,没有建立连接时发送方可能会陷入不断重发的死循环。为了避免这种问题,可以参考TCP/IP的三次握手方法,建立握手协议来解决。同时也需要设立专门的连接状态字,来进行心跳检查,检验通讯是否正常。

    之前提到过,通常的奇偶校验能力有限,当下大多采用CRC循环校验来进行差错检验。因此需要设立CRC校验位。

    经过以上分析,我们的通信协议可以简单的设计为:

    帧头

    发送序号

    确认序号

    帧类型

    标志位

    连接状态

    数据位

    校验位

    帧尾

    1byte

    4bit

    4bit

    2bit

    2bit

    4bit

    8byte

    4byte

    1byte

    ------------------------------------------------------------

    在上一次串口通信的基础上,我们可以编写成帧函数来将我们的数据封装成帧,再将其发送。

    因为在程序中采用的是serialport.writeLine的形式,即字符串发送,这里我们用1个字符来代替1个比特进行操作。

    首先是确定一些全局变量,用来记录整个通讯状态。

            private static bool con = true;//连接状态
            private static int i = 1;//发送帧序号
            private static int j = 0;//握手标志
            private static int reSend = 1;//重发次数

    然后根据我们的协议内容依次建立:

                string Data = "00000000";//初始化为8个数字 
                string message = "";
                string head = "02";//帧头
                string Sendnum = "0"+(i % 8).ToString();//发送帧序号
                string Getnum = Sendnum;//接受帧序号
                string type = "01";//帧类型

    需要说明的是,在对数据的处理我们的数据位为8个字节,若依然用一个字节代替一个比特,会导致数据长度过高,且意义不大,因此,我们用一个字符来代替一个字节。

    然后将这些数据依次组合起来,形成帧的前部分,对这前部分进行32位CRC校验得到CRC的校验码,将其作为校验位,最后再加上帧尾。这样我们的帧就设立完毕了,将封装成帧的数据当成一组字符串,通过serialport.writeLine进行发送即可。

    同时,在接收方,收到数据后需要对数据进行解析。

    我们在提取时,需要知道的信息的数据位以及校验位,以及对数据进行再校验,与校验位进行比较,因此我们分别对这三个部分进行提取:

                    string getcrc = strRev.Substring(0, 20);//提取接受数据中的代校验位
                    string Crc = strRev.Substring(20, strRev.Length-22);//提取数据中的校验位

    同样,对代校验位进行CRC校验,与校验码进行比较,若一直,则传输正确,反之则丢弃该数据,请求重传。

    在未出错的情况下,读取数据位:

     string getdata = strRev.Substring(12,8);//提取接受数据中的数据位

    由此,则经历了数据成帧-发送-接受-解析等4个过程。

    但是本次学习中只是模拟了一个简单的通信过程,整个过程由人工进行参与与设计,但是如何让2台机器自动运行,两台计算机如何进行互动,需要考虑更多的问题。

    -------------------------------------------------

    本次学习中涉及到的一些问题:

    1.C#中string函数的相关操作,本次运用到的是remove与substring。此类操作非常基础,但需要多加练习,不然容易生疏遗忘。

    2.本次的CRC校验函数是从网络上获取的源码,只是对CRC的基本工作原理进行了了解,有机会要自己动手进行32CRC校验函数的编写。


    展开全文
  • 单片机间的RS232串行通信程序 #include#include #include #include #include #define uchar unsigned char#define uint unsigned intuchar FREQ; /*定时器计数变量*/ voi
     
    

    单片机间的RS232串行通信程序<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

     

    #include<reg52.h>

    #include <absacc.h>

    #include <stdio.h>

    #include <math.h>

    #include <stdlib.h>

     

    #define uchar unsigned char

    #define uint unsigned int

    uchar FREQ;                                 /*定时器计数变量*/

     

    void main(void)

    {  

    // 以下是设置中断和定时器

        EA=1; PT0=1;

        ET0=1;

        IT0=1;IT1=1;

        EX0=1;EX1=1;ET2=1;

        T2CON=0x08;

        TMOD=0x21;

       

    // 定时器0为产生1ms的中断,定时器19600bit/s 的波特率发生器

        TH0=-1000/256;

        TL0=-1000%256;

        TL1=0xfd;

        TH1=0xfd;

        SCON=0x50;

        PCON=0x80;

       

    // 开定时器

        TR1=1;

        TR0=1;

        TI=1;

        while(1){}

    }

     

    // 定时器0的中断服务程序,向串口发送姿态数据。

    void intsvr1(void) interrupt 1

    {

     

    // 重新装入定时器0的初值;

        TH0=-10000/256;

        TL0=-10000%256;

    FREQ=FREQ+1;                        // 定时器T0的低四位赋值

    if (FREQ==1000)                    // 1秒判断

        {

    FREQ=0;

    printf("*");                            // 发送字符

        }

    } 

    展开全文
  • RS232通信协议详解

    千次阅读 2016-09-01 16:37:06
    所谓通信协议是指通信双方的一种约定。约定包括对数据格式、同步方式、传送速度、传送步骤、检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。因此,也叫做通信控制规程,或称传输控制规程,它...

    http://blog.csdn.net/mrdingjie/article/details/8126062


    通信协议

    所谓通信协议是指通信双方的一种约定。约定包括对数据格式、同步方式、传送速度、传送步骤、检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。因此,也叫做通信控制规程,或称传输控制规程,它属于ISO'S OSI七层参考模型中的数据链路层。目前,采用的通信协议有两类:异步协议和同步协议。同步协议又有面向字符和面向比特以及面向字节计数三种。其中,面向字节计数的同步协议主要用于DEC公司的网络体系结构中。

    一、物理接口标准

    1.串行通信接口的基本任务
    (1)实现数据格式化:因为来自CPU的是普通的并行数据,所以,接口电路应具有实现不同串行通信方式下的数据格式化的任务。在异步通信方式下,接口自动生成起止式的帧数据格式。在面向字符的同步方式下,接口要在待传送的数据块前加上同步字符。
    (2)进行串-并转换:串行传送,数据是一位一位串行传送的,而计算机处理数据是并行数据。所以当数据由计算机送至数据发送器时,首先把串行数据转换为并行数才能送入计算机处理。因此串并转换是串行接口电路的重要任务。
    (3)控制数据传输速率:串行通信接口电路应具有对数据传输速率——波特率进行选择和控制的能力。
    (4)进行错误检测:在发送时接口电路对传送的字符数据自动生成奇偶校验位或其他校验码。在接收时,接口电路检查字符的奇偶校验或其他校验码,确定是否发生传送错误。
    (5)进行TTL 与EIA电平转换:CPU 和终端均采用TTL电平及正逻辑,它们与EIA采用的电平及负逻辑不兼容,需在接口电路中进行转换。
    (6)提供EIA-RS-232C 接口标准所要求的信号线:远距离通信采用MODEM 时,需要9根信号线;近距离零MODEM 方式,只需要3 根信号线。这些信号线由接口电路提供,以便与MODEM 或终端进行联络与控制。
    2、串行通信接口电路的组成
    为了完成上述串行接口的任务,串行通信接口电路一般由可编程的串行接口芯片、波特率发生器、EIA 与TTL 电平转换器以及地址译码电路组成。其中,串行接口芯片,随着大规模继承电路技术的发展,通用的同步(USRT)和异步(UART)接口芯片种类越来越多,如下表所示。它们的基本功能是类似的,都能实现上面提出的串行通信接口基本任务的大部分工作,且都是可编程的。才用这些芯片作为串行通信接口电路的核心芯片,会使电路结构比较简单。
    3.有关串行通信的物理标准
    为使计算机、电话以及其他通信设备互相沟通,现在,已经对串行通信建立了几个一致的概念和标准,这些概念和标准属于三个方面:传输率,电特性,信号名称和接口标准。
    1、传输率:所谓传输率就是指每秒传输多少位,传输率也常叫波特率。国际上规定了一个标准波特率系列,标准波特率也是最常用的波特率,标准波特率系列为110、300、600、1200、4800、9600 和19200。大多数CRT 终端都能够按110 到9600范围中的任何一种波特率工作。打印机由于机械速度比较慢而使传输波特率受到限制,所以,一般的串行打印机工作在110 波特率,点针式打印机由于其内部有较大的行缓冲区,所以可以按高达2400波特的速度接收打印信息。大多数接口的接收波特率和发送波特率可以分别设置,而且,可以通过编程来指定。
    2、RS-232-C标准:RS-232-C 标准对两个方面作了规定,即信号电平标准和控制信号线的定义。RS-232-C 采用负逻辑规定逻辑电平,信号电平与通常的TTL电平也不兼容,RS-232-C 将-5V~-15V 规定为“1”,+5V~+15V规定为“0”。图1是TTL 标准和RS-232-C标准之间的电平转换。
     
     
    二、软件协议
    1.OSI协议和TCP/IP协议
     
    (1)OSI 协议
    OSI 七层参考模型不是通讯标准,它只给出一个不会由于技术发展而必须修改的稳定模型,使有关标准和协议能在模型定义的范围内开发和相互配合。一般的通讯协议只符合OSI 七层模型的某几层,如: EIA-RS-232-C:实现了物理层。IBM 的SDLC(同步数据链路控制规程):数据链路层。ANSI 的ADCCP(先进数据通讯规程):数据链路层IBM 的BSC(二进制同步通讯协议):数据链路层。应用层的电子邮件协议SMTP只负责寄信、POP3 只负责收信。
    (2)TCP/IP协议
    实现了五层协议。
    (1)物理层:对应OSI 的物理层。
    (2)网络接口层:类似于OSI的数据链路层。
    (3)Internet 层:OSI 模型在Internet 网使用前提出,未考虑网间连接。
    (4)传输层:对应OSI 的传输层。
    (5)应用层:对应OSI 的表示层和应用层。
    2.串行通信协议
    串行通信协议分同步协议和异步协议。
    (1)异步通信协议的实例——起止式异步协议
     
    特点与格式:
    起止式异步协议的特点是一个字符一个字符传输,并且传送一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。其格式如图3 所示。每一个字符的前面都有一位起始位(低电平,逻辑值0),字符本身有5~7 位数据位组成,接着字符后面是一位校验位(也可以没有校验位),最后是一位,或意味半,或二位停止位,停止位后面是不定长度的空闲位。停止位和空闲位都规定为高电平(逻辑值),这样就保证起始位开始处一定有一个下跳沿。
    从图中可以看出,这种格式是靠起始位和停止位来实现字符的界定或同步的,故称为起始式协议。传送时,数据的低位在前,高位在后,图4 表示了传送一个字符E 的ASCAII码的波形1010001。当把它的最低有效位写到右边时,就是E 的ASCII码1000101=45H。
    起/止位的作用:起始位实际上是作为联络信号附加进来的,当它变为低电平时,告诉收方传送开始。它的到来,表示下面接着是数据位来了,要准备接收。而停止位标志一个字符的结束,它的出现,表示一个字符传送完毕。这样就为通信双方提供了何时开始收发,何时结束的标志。传送开始前,发收双方把所采用的起止式格式(包括字符的数据位长度,停止位位数,有无校验位以及是奇校验还是偶校验等)和数据传输速率作统一规定。传送开始后,接收设备不断地检测传输线,看是否有起始位到来。当收到一系列的“1”(停止位或空闲位)之后,检测到一个下跳沿,说明起始位出现,起始位经确认后,就开始接收所规定的数据位和奇偶校验位以及停止位。经过处理将停止位去掉,把数据位拼装成一个并行字节,并且经校验后,无奇偶错才算正确的接收一个字符。一个字符接收完毕,接收设备有继续测试传输线,监视“0”电平的到来和下一个字符的开始,直到全部数据传送完毕。
    由上述工作过程可看到,异步通信是按字符传输的,每传输一个字符,就用起始位来通知收方,以此来重新核对收发双方同步。若接收设备和发送设备两者的时钟频率略有偏差,这也不会因偏差的累积而导致错位,加之字符之间的空闲位也为这种偏差提供一种缓冲,所以异步串行通信的可靠性高。但由于要在每个字符的前后加上起始位和停止位这样一些附加位,使得传输效率变低了,只有约80%。因此,起止协议一般用在数据速率较慢的场合(小于19.2kbit/s)。在高速传送时,一般要采用同步协议。
     
    (2)面向字符的同步协议
    特点与格式:这种协议的典型代表是IBM公司的二进制同步通信协议(BSC)。它的特点是一次传送由若干个字符组成的数据块,而不是只传送一个字符,并规定了10 个字符作为这个数据块的开头与结束标志以及整个传输过程的控制信息,它们也叫做通信控制字。由于被传送的数据块是由字符组成,故被称作面向字符的协议。特定字符(控制字符)的定义:由上面的格式可以看出,数据块的前后都加了几个特定字符。SYN是同步字符(synchronous Character),每一帧开始处都有SYN,加一个SYN的称单同步,加两个SYN的称双同步设置同步字符是起联络作用,传送数据时,接收端不断检测,一旦出现同步字符,就知道是一帧开始了。接着的SOH 是序始字符(Start Of Header),它表示标题的开始。标题中包括院地址、目的地址和路由指示等信息。STX是文始字符(StartOf Text),它标志着传送的正文(数据块)开始。数据块就是被传送的正文内容,由多个
    字符组成。数据块后面是组终字符ETB(End Of Transmission Block)或文终字符ETX(EndOf Text),其中ETB用在正文很长、需要分成若干个分数据块、分别在不同帧中发送的场合,这时在每个分数据块后面用文终字符ETX。一帧的最后是校验码,它对从SOH 开始到ETX(或ETB)字段进行校验,校验方式可以是纵横奇偶校验或CRC。另外,在面向字符协议中还采用了一些其他通信控制字,它们的名称如下表所示:
     
     
    数据透明的实现:面向字符的同步协议,不象异步起止协议那样,需要在每个字符前后附加起始和停止位,因此,传输效率提高了。同时,由于采用了一些传输控制字,故增强了通信控制能力和校验功能。但也存在一些问题,例如,如何区别数据字符代码和特定字符代码的问题,因为在数据块中完全有可能出现与特定字符代码相同的数据字符,这就会发生误解。比如正文有个与文终字符ETX 的代码相同的数据字符,接收端就不会把它当作为普通数据处理,而误认为是正文结束,因而产生差错。因此,协议应具有将特定字符作为普通数据处理的能力,这种能力叫做“数据透明”。为此,协议中设置了转移字符DLE(Data LinkEscape)。当把一个特定字符看成数据时,在它前面要加一个DLE,这样接收器收到一个DLE就可预知下一个字符是数据字符,而不会把它当作控制字符来处理了。DLE 本身也是特定字符,当它出现在数据块中时,也要在它前面加上另一个DLE。这种方法叫字符填充。字符填充实现起来相当麻烦,且依赖于字符的编码。正是由于以上的缺点,故又产生了新的面向比特的同步协议。

    (3)面向比特的同步协议
    特点与格式:面向比特的协议中最具有代表性的是IBM的同步数据链路控制规程SDLC(Synchronous Data Link Control),国际标准化组织ISO(International StandardOrganization)的高级数据链路控制规程HDLC(High Level Data link Control),美国国家标准协会(Americal National Standard Institute)的先进数据通信规程ADCCP(AdvancedData Communication Control Procedure)。这些协议的特点是所传输的一帧数据可以是任意位,而且它是靠约定的位组合模式,而不是靠特定字符来标志帧的开始和结束,故称“面向比特”的协议。这中协议的一般帧格式如图5所示:
    帧信息的分段:由图5 可见,SDLC/HDLC的一帧信息包括以下几个场(Filed),所有场都是从有效位开始传送。
    (1)SDLC/HDLC 标志字符:SDLC/HDLC协议规定,所有信息传输必须以一个标志字符开始,且以同一个字符结束。这个标志字符是 01111110,称标志场(F)。从开始标志到结束标志之间构成一个完整的信息单位,称为一帧(Frame)。所有的信息是以帧的形传输的,而标志字符提供了每一帧的边界。接收端可以通过搜索“01111110”来探知帧的开头和结束,以此建立帧同步。
    (2)地址场和控制场:在标志场之后,可以有一个地址场A(Address)和一个控制场C(Control)。地址场用来规定与之通信的次站的地址。控制场可规定若干个命令。SDLC规定A 场和C场的宽度为8 位或16 位。接收方必须检查每个地址字节的第一位,如果为“0”,则后面跟着另一个地址字节;若为“1”,则该字节就是最后一个地址字节。同理,如果控制场第一个字节的第一位为为“0”,则还有第二个控制场字节,否则就只有一个字节。
    (3)信息场:跟在控制场之后的是信息场I(Information)。I 场包含有要传送的数据,并不是每一帧都必须有信息场。即数据场可以为0,当它为0 时,则这一帧主要是控制命令。
    (4)帧校验信息:紧跟在信息场之后的是两字节的争校验,帧校验场称为FC(FrameCheck)场或称为帧校验序列FCS(Frame check Squence)。SDLC/HDLC 均采用16 位循环冗余校验码CRC(Cyclic Redundancy Code)。除了标志场和自动插入的“0”以外,所有的信息都参加CRC计算。
    实际应用时的两个技术问题:
    (1)“0”位插入/删除:如上所述,SDLC/HDLC协议规定以01111110为标志字节,但在信息场中也完全有可能有同一种模式的字符,为了把它与标志区分开来,所以采取了“0”位插入和删除技术。具体作法是发送端在发送所有信息(除标志字节外)时,只要遇到连续5 个“1”,就自动插入一个“0”,当接收端在接收数据时(除标志字节)如果连续收到5个“1”,就自动将其后的一个“0”删除是,以恢复信息的原有形式。这种“0”位的插入和删除过程是由硬件自动完成的。
    (2)SDLC/HDLC异常结束:若在发送过程中出现错误,则SDLC/HDLC协议常用异常结束(Abort)字符,或称为失效序列使本帧作废。在HDLC规程中,7 个连续的“1”被作为失效字符,而在SDLC 中失效字符是8 个连续的“1”。当然在试销序列中不使用“0”位插入/删除技术。LC/HDLC 协议规定,在一帧之内不允许出现数据间隔。在两帧之间,发送器可以连续输出标志字符序列,也可以输出连续的高电平,它被称为空闲(Idle)信号。

    展开全文
  • FPGA实现串行接口 RS232

    千次阅读 2010-12-31 18:54:00
    串行接口(RS-232)串行接口是连接FPGA和PC机的一种简单方式。这个项目向大家展示了如果使用FPGA来创建RS-232收发器。整个项目包括5个部分 RS232是怎样工作的 如何产生需要的波特率 发送模块 接收模块 应用实例RS...

     

    串行接口(RS-232)
    串行接口是连接FPGA和PC机的一种简单方式。这个项目向大家展示了如果使用FPGA来创建RS-232收发器。
     
    整个项目包括5个部分

    1.  RS232是怎样工作的
    2.  如何产生需要的波特率
    3.  发送模块
    4.  接收模块
    5.  应用实例

    RS-232接口是怎样工作的
    作为标准设备,大多数的计算机都有1到2个RS-232串口。

    特性
    RS-232有下列特性:

    •  使用9针的"DB-9"插头(旧式计算机使用25针的"DB-25"插头).
    •  允许全双工的双向通讯(也就是说计算机可以在接收数据的同时发送数据).
    •  最大可支持的传输速率为10KBytes/s.

    DB-9插头
    你可能已经在你的计算机背后见到过这种插头
     
    它一共有9个引脚,但是最重要的3个引脚是:

    •  引脚2: RxD (接收数据).
    •  引脚3: TxD (发送数据).
    •  引脚5: GND (地).

    仅使用3跟电缆,你就可以发送和接收数据.

    串行通讯
    数据以每次一位的方式传输;每条线用来传输一个方向的数据。由于计算机通常至少需要若干位数据,因此数据在发送之前先“串行化”。通常是以8位数据为1组的。 。先发送最低有效位,最后发送最高有效位。

    异步通讯
    RS-232使用异步通讯协议。也就是说数据的传输没有时钟信号。接收端必须有某种方式,使之与接收数据同步。
    对于RS-232来说,是这样处理的:

    1.  串行线缆的两端事先约定好串行传输的参数(传输速度、传输格式等)
    2.  当没有数据传输的时候,发送端向数据线上发送"1"
    3.  每传输一个字节之前,发送端先发送一个"0"来表示传输已经开始。这样接收端便可以知道有数据到来了。
    4.  开始传输后,数据以约定的速度和格式传输,所以接收端可以与之同步
    5.  每次传输完成一个字节之后,都在其后发送一个停止位("1")

    让我们来看看0x55是如何传输的:
     
    0x55的二进制表示为:01010101。
    但是由于先发送的是最低有效位,所以发送序列是这样的: 1-0-1-0-1-0-1-0.
    下面是另外一个例子 :
     
    传输的数据为0xC4,你能看出来吗?
    从图中很难看出来所传输的数据,这也说明了事先知道传输的速率对于接收端有多么重要。

    数据传输可以多快?
    数据的传输速度是用波特来描述的,亦即每秒钟传输的数据位,例如1000波特表示每秒钟传输100比特的数据, 或者说每个数据位持续1毫秒。
    波特率不是随意的,必须服从一定的标准,如果希望设计123456波特的RS-232接口,对不起,你很不幸运,这是不行的。常用的串行传输速率值包括以下几种:

    •  1200 波特.
    •  9600 波特.
    •  38400 波特.
    •  115200 波特 (通常情况下是你可以使用的最高速度).

    在115200 波特传输速度下, 每位数据持续 (1/115200) = 8.7μs. 如果传输8位数据,共持续 8 x 8.7μs = 69μs。但是每个字节的传输又要求额外的“开始位”和“停止位”,所以实际上需要花费10 x 8.7μs = 87μs的时间。最大的有效数据传输率只能达到 11.5KBytes每秒。
    在115200 波特传输速度下,一些使用了不好的芯片的计算机要求一个长的停止位(1.5或2位数据的长度),这使得最大传输速度降到大约10.5KBytes每秒

    物理层
    电缆上的信号使用正负电压的机制:

    •  "1" 用 -10V 的电压表示(或者在 -5V 与 -15V之间的电压).
    •  "0" 用 +10V 的电压表示(或者在 5V 与 15V之间的电压).

    所以没有数据传输的电缆上的电压应该为-10V或-5到-10之间的某个电压。

     

     

     

    波特率发生器

    这里我们使用串行连接的最大速度115200波特,其他较慢的波特也很容易由此产生。

    FPGA通常运行在远高于115200Hz的时钟频率上(对于今天的标准的来说RS-232真是太慢了),这就意味着我们需要用一个较高的时钟来分频产生尽量接近于115200Hz的时钟信号。
    从1.8432MHz的时钟产生
    通常RS-232芯片使用1.8432MHz的时钟,以为这个时钟很容易产生标准的波特率,所以我们假设已经拥有了一个这样的时钟源。

    只需要将 1.8432MHz 16分频便可得到 115200Hz的时钟,多方便啊!

    reg [3:0] BaudDivCnt;
    always @(posedge clk) BaudDivCnt <= BaudDivCnt + 1;
    wire BaudTick = (BaudDivCnt==15);

    所以 "BaudTick" 每16个时钟周期需要置位一次,从而从1.8432MHz的时钟得到115200Hz的时钟。

    从任意频率产生
    早期的发生器假设使用1.8432MHz的时钟。但如果我们使用2MHz的时钟怎么办呢?要从2MHz的时钟得到 115200Hz,需要将时钟 "17.361111111..." 分频,并不是一个整数。我的解决办法是有时候17分频,有时候18分频,使得整体的分频比保持在 "17.361111111"。这是很容易做到的。

    下面是实现这个想法的C语言代码:
    while(1) // 死循环
    {
    acc += 115200;
    if(acc >=2000000) printf("*"); else printf(" ");
    acc %= 2000000;
    }

    这段代码会精确的以平均每 "17.361111111..." 个时钟间隔打印出一个"*"。

    为了从FPGA得到同样的效果,考虑到串行接口可以容忍一定的波特率误差,所以即使我们使用17.3或者17.4这样的分频比也是没有关系的。

    FPGA波特率发生器
    我们希望2000000是2的整数幂,但很可惜,它不是。所以我们改变分频比,"2000000/115200" 约等于 "1024/59" = 17.356. 这跟我们要求的分频比很接近,并且使得在FPGA上实现起来相当有效。

    //10 位的累加器 ([9:0]), 1位进位输出 ([10])
    reg [10:0] acc; //一共11位!
    always @(posedge clk)
    acc <= acc[9:0] + 59; //我们使用上一次结果的低10位,但是保留11位结果
    wire BaudTick = acc[10]; //第11位作为进位输出

    使用 2MHz 时钟, "BaudTick" 为 115234 波特, 跟理想的115200波特存在 0.03% 的误差。

    参数化的FPGA波特率发生器
    前面的设计我们使用的是10位的累加器,如果时钟频率提高的话,需要更多的位数。

    下面是一个使用 25MHz 时钟和 16 位累加器的设计,该设计是参数化的,所以很容易根据具体情况修改。

    parameter ClkFrequency = 25000000; // 25MHz
    parameter Baud = 115200;
    parameter BaudGeneratorAccWidth = 16;
    parameter BaudGeneratorInc = (Baud<<BaudGeneratorAccWidth)/ClkFrequency;
    reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc;
    always @(posedge clk)
    BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;
    wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];

    上面的设计中存在一个错误: "BaudGeneratorInc"的计算是错误的, 因为 Verilog 使用 32 位的默认结果, 但实际计算过程中的某些数据超过了32位,所以改变一种计算方法。

    parameter BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4);

    这行程序也使得结果成为整数,从而避免截断。

    这就是整个的设计方法了。
    现在我们已经得到了足够精确的波特率,可以继续设计串行接收和发送模块了。 

     

     

     

    RS-232发送模块
    下面是我们所想要实现的:

    它应该能像这样工作:

    •  发送器接收8位的数据,并将其串行输出。("TxD_start"置位后开始传输).
    •  当有数传输的时候,使"busy"信号有效,此时“TxD_start”信号被忽略.

    RS-232模块的参数是固定的: 8位数据, 2个停止位, 无奇偶校验.

    数据串行化
    假设我们已经有了一个115200波特的"BaudTick"信号.

    我们需要产生开始位、8位数据以及停止位。
    用状态机来实现看起来比较合适。

    reg [3:0] state;
    always @(posedge clk)
    case(state)
    4'b0000: if(TxD_start) state <= 4'b0100;
    4'b0100: if(BaudTick) state <= 4'b1000; // 开始位
    4'b1000: if(BaudTick) state <= 4'b1001; // bit 0
    4'b1001: if(BaudTick) state <= 4'b1010; // bit 1
    4'b1010: if(BaudTick) state <= 4'b1011; // bit 2
    4'b1011: if(BaudTick) state <= 4'b1100; // bit 3
    4'b1100: if(BaudTick) state <= 4'b1101; // bit 4
    4'b1101: if(BaudTick) state <= 4'b1110; // bit 5
    4'b1110: if(BaudTick) state <= 4'b1111; // bit 6
    4'b1111: if(BaudTick) state <= 4'b0001; // bit 7
    4'b0001: if(BaudTick) state <= 4'b0010; // 停止位1
    4'b0010: if(BaudTick) state <= 4'b0000; // 停止位2
    default: if(BaudTick) state <= 4'b0000;
    endcase

    注意看这个状态机是怎样实现当"TxD_start"有效就开始,但只在"BaudTick"有效的时候才转换状态的。.

    现在,我们只需要产生"TxD"输出即可.
    reg muxbit;
    always @(state[2:0])
    case(state[2:0])
    0: muxbit <= TxD_data[0];
    1: muxbit <= TxD_data[1];
    2: muxbit <= TxD_data[2];
    3: muxbit <= TxD_data[3];
    4: muxbit <= TxD_data[4];
    5: muxbit <= TxD_data[5];
    6: muxbit <= TxD_data[6];
    7: muxbit <= TxD_data[7];
    endcase

    //将开始位、数据以及停止位结合起来
    assign TxD = (state<4) | (state[3] & muxbit);

     

     

     


    RS232接收模块
    下面是我们想要实现的模块:

    我们的设计目的是这样的:
         1.当RxD线上有数据时,接收模块负责识别RxD线上的数据
         2.当收到一个字节的数据时,锁存接收到的数据到"data"总线,并使"data_ready"有效一个周期。
    注意:只有当"data_ready"有效时,"data"总线的数据才有效,其他的时间里不要使用"data"总线上的数据,因为新的数据可能已经改变了其中的部分数据。

    过采样
    异步接收机必须通过一定的机制与接收到的输入信号同步(接收端没有办法得到发送断的时钟)。这里采用如下办法。
         1.为了确定新数据的到来,即检测开始位,我们使用几倍于波特率的采样时钟对接收到的信号进行采样。
         2.一旦检测到"开始位",再将采样时钟频率降为已知的发送端的波特率。
    典型的过采样时钟频率为接收到的信号的波特率的16倍,这里我们使用8倍的采样时钟。当波特率为115200时,采样时钟为921600Hz。

    假设我们已经有了一个8倍于波特率的时钟信号 "Baud8Tick",其频率为 921600Hz。

    具体设计
    首先,接受到的"RxD"信号与我们的时钟没有任何关系,所以采用两个D触发器对其进行过采样,并且使之我我们的时钟同步。
    reg [1:0] RxD_sync;
    always @(posedge clk) if(Baud8Tick) RxD_sync <= {RxD_sync[0], RxD};

    首先我们对接收到的数据进行滤波,这样可以防止毛刺信号被误认为是开始信号。
    reg [1:0] RxD_cnt;
    reg RxD_bit;
    always @(posedge clk)
    if(Baud8Tick)
    begin
      if(RxD_sync[1] && RxD_cnt!=2'b11) RxD_cnt <= RxD_cnt + 1;
      else
      if(~RxD_sync[1] && RxD_cnt!=2'b00) RxD_cnt <= RxD_cnt - 1;
      if(RxD_cnt==2'b00) RxD_bit <= 0;
      else
      if(RxD_cnt==2'b11) RxD_bit <= 1;
    end

    一旦检测到"开始位",使用如下的状态机可以检测出接收到每一位数据。
    reg [3:0] state;
    always @(posedge clk)
    if(Baud8Tick)
    case(state)
      4'b0000: if(~RxD_bit) state <= 4'b1000; // start bit found?
      4'b1000: if(next_bit) state <= 4'b1001; // bit 0
      4'b1001: if(next_bit) state <= 4'b1010; // bit 1
      4'b1010: if(next_bit) state <= 4'b1011; // bit 2
      4'b1011: if(next_bit) state <= 4'b1100; // bit 3
      4'b1100: if(next_bit) state <= 4'b1101; // bit 4
      4'b1101: if(next_bit) state <= 4'b1110; // bit 5
      4'b1110: if(next_bit) state <= 4'b1111; // bit 6
      4'b1111: if(next_bit) state <= 4'b0001; // bit 7
      4'b0001: if(next_bit) state <= 4'b0000; // stop bit
      default: state <= 4'b0000;
    endcase

    注意,我们使用了"next_bit" 来遍历所有数据位。
    reg [2:0] bit_spacing;
    always @(posedge clk)
    if(state==0)
      bit_spacing <= 0;
    else
    if(Baud8Tick)
      bit_spacing <= bit_spacing + 1;
    wire next_bit = (bit_spacing==7);

    最后我们使用一个移位寄存器来存储接受到的数据。
    reg [7:0] RxD_data;
    always @(posedge clk) if(Baud8Tick && next_bit && state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]}; 

     

     

     

    怎样使用发送和接收模块
    这个设计似的我们可以通过计算机的串行口来控制FPGA的几个引脚。

    具体来说,该设计完成以下功能。

       1. 将FPGA的8个引脚作为输出(称为“通用输出”)。 FPGA收到任何数据时都会更新这8个GPout 的值。
       2. 将FPGA的8个引脚作为输入(称为“通用输入”)。FPGA收到仁厚数据后,都会将GPin上的数值通过串行口发送出去。

    通用输出可以用来通过计算机远程控制任何东西,例如FPGA板上的LED,甚至可以再添加一个继电器来控制咖啡机。
    module serialfun(clk, RxD, TxD, GPout, GPin);
    input clk;

    input RxD;
    output TxD;

    output [7:0] GPout;
    input [7:0] GPin;

    ///
    wire RxD_data_ready;
    wire [7:0] RxD_data;
    async_receiver deserializer(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));

    reg [7:0] GPout;
    always @(posedge clk) if(RxD_data_ready) GPout <= RxD_data;

    ///
    async_transmitter serializer(.clk(clk), .TxD(TxD), .TxD_start(RxD_data_ready), .TxD_data(GPin));

    endmodule

    记得包含异步发送和接收模块的设计文件,并更新里面的时钟频率。

     

    展开全文
  • RS232串口通信详解

    千次阅读 2019-07-27 03:20:47
    RS232串口通信详解 RS232串口通信详解:串口是计算机上一种非常通用的通信协议 9芯 信号方向来自 缩写 描述 1 调制解调器 CD 载波检测 2 调制解调器 RXD 接收数据 ...
  • RS232C串行通信波形
  • 串行通信中,线路空闲或者数据传输结束,线路总是高(RS232协议中由于采用反向电平表示,故是低电平)。一个数据的开始总是一个低电平(RS232线路是高电平),结束的总是一个高电平(Rs232是低电平)。数据总是从...
  • RS232串口通信原理

    千次阅读 2017-10-19 21:27:10
    串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有R
  • RS-232串口通信的verilog实现 RS-232是一种串行数据通信的接口标准,广泛用于计算机串行接口外设连接。 ...实际上,只需要三个管脚就可以实现RS-232串行通信了 pin2 :RxD (reciever data) pin...
  • rs232串口通信原理

    2011-12-09 23:27:52
    rs232串口通信原理 串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB...
  • 单片机实验(十二)RS232串口通信

    千次阅读 2020-02-18 18:28:57
    80S52:串口通信模块 功能:和PC机通信说骚话 模块介绍 串口通信主要四个要点 SBUF寄存 SBUF主要用来储存从PC接收的信息和准备向PC发送的信息,大小为8位 波特率匹配 要与PC通信必须遵守规则,也就是必须有相同的...
  • 串行通信在通讯领域被广泛应用,标准的RS232接口已成为计算机、外设、交换机和许多通讯设备的标准接口。虽然近年来随着USB口的日趋流行,RS232接口串口作为一种传统的串口通信口有被取代的趋势。然而由于它具有较高...
  • 串口通信是一种广泛使用且实用的通信方式,介绍 RS232 串行通信的联结方式,研究利用 C 语言编程实 现 RS232 串行通信的过程.结合实际应用,在约定双方串行通信协议的基础上,运用 C 语言开发的串行通信软 件,实现...
  • delphi 与Rs232 串行通讯控制.rar

    热门讨论 2020-07-26 23:33:31
    delphi 与Rs232 串行通讯控制配套关盘内容
  • 单片机与RS232串口通信C51程序

    千次阅读 2012-11-14 09:17:20
    摘自:...   #include "iom16v.h" //请将# 替换成英文格式的# #include #define baud 9600 //波特率 #define fosc 8000000 //晶振8MHZ  .../************************* 初始化
  • 首先、串口传输数据只要有接收数据针脚和发送...两个不同串口(不论是同一台计算机的两个串口或分别是不同计算机的串口)上面表格是对微机标准串行口而言的、还有许多非标准设备、如接收GPS数据或电子罗盘数据、只要...
  • 基于 ATM89C51的串口通信,LCD1602显示接收到的字符,文件内含有c程序,proteus仿真和hex文件
  • 1.从接线上,RS232是三线制,分别是GRS485是两线制; 2.从传输距离上,RS232只能传输15米,RS485最远可以传输1200米; 3.从速率上,RS232是全双工传输,RS485是半双工传输; 4.从协议层上,RS232只支持点对点通讯(1:...
  • 串口通信是电子工程师面对的最基本的问题,但是往往大家对UART,RS232, COM口这三者的关系理解的不是很透彻,百度他们的区别,网上各种网友自己本身一知半解,更不敢看做出的解答。于是下决心一定要搞清楚他们的关系...
  • main.c配置: /* *说明: *PA0:KEY1;PA1:KEY2; *PA2:LED1;PA3:LED2; *PA9:USART1_TX;PA10:USART1_RX */ #include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_...#
1 2 3 4 5 ... 20
收藏数 5,216
精华内容 2,086
关键字:

rs232串行通信