精华内容
下载资源
问答
  • 异步通信的特点及信息帧格式:以起止式异步协议为例,下图显示的是起止式一帧数据的格式:图1起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以"起始位"开始,以"停止...

    串行通信可以分为两种类型:同步通信、异步通信.

    1. 异步通信的特点及信息帧格式:

    以起止式异步协议为例,下图显示的是起止式一帧数据的格式:

    图1

    起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以"起始位"开始,以"停止位"结束,字符之间没有固定的时间间隔要求.每一个字符的前面都有一位起始位(低电平,逻辑值),字符本身由5-7位数据位组成,接着字符后面是一位校验位(也可以没有校验位),最后是一位或一位半或二位停止位,停止位后面是不定长的空闲位.停止位和空闲位都规定为高电平(逻辑值1),这样就保证起始位开始处一定有一个下跳沿.

    从图中可看出,这种格式是靠起始位和停止位来实现字符的界定或同步的,故称为起止式协议.

    异步通信可以采用正逻辑或负逻辑,正负逻辑的表示如下表所示:

    逻辑0

    逻辑1

    正逻辑

    低电平

    高电平

    负逻辑

    高电平

    低电平

    异步通信的信息格式如下边的表所示:

    起始位

    逻辑0

    1位

    数据位

    逻辑0或1

    5位、6位、7位、8位

    校验位

    逻辑0或1

    1位或无

    停止位

    逻辑1

    1位,1.5位或2位

    空闲位

    逻辑1

    任意数量

    注:表中位数的本质含义是信号出现的时间,故可有分数位,如1.5.

    例:传送8位数据45H(0100,0101B),奇校验,1个停止位,则信号线上的波形象图2所示那样:异步通信的速率:若9600bps,每字符8位,1起始,1停止,无奇偶,则实际每字符传送10位,则960字符/秒.

    图2

    2. 异步通信的接收过程

    接收端以"接收时钟"和"波特率因子"决定一位的时间长度.下面以波特率因子等于16(接收时钟每16个时钟周期,使接收移位寄存器移位一次),正逻辑为例说明,如图3所示.

    图3

    开始通信时,信号线为空闲(逻辑1),当检测到由1到0的跳变时,开始对"接收时钟"计数.

    当计到8个时钟时,对输入信号进行检测,若仍为低电平,则确认这是"起始位"B,而不是干扰信号.

    接收端检测到起始位后,隔16个接收时钟,对输入信号检测一次,把对应的值作为D0位数据.若为逻辑1, 作为数据位1;若为逻辑0,作为数据位0.

    再隔16个接收时钟,对输入信号检测一次,把对应的值作为D1位数据.….,直到全部数据位都输入.

    检测校验位P(如果有的话).

    接收到规定的数据位个数和校验位后,通信接口电路希望收到停止位S(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置"帧错误"标志.若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中送数据输入寄存器.若校验错,在状态寄存器中置奇偶错标志.

    本幀信息全部接收完,把线路上出现的高电平作为空闲位.

    当信号再次变为低时,开始进入下一幀的检测.

    3. 异步通信的发送过程

    发送端以"发送时钟"和"波特率因子"决定一位的时间长度.

    当初始化后,或者没有信息需要发送时,发送端输出逻辑1,即空闲位,空闲位可以有任意数量.

    当需要发送时,发送端首先输出逻辑0,作为起始位.

    接着,发送端首先发送D0位,直到各数据位发送完.

    如果需要的话,发送端输出校验位.

    最后,发送端输出停止位(逻辑1).

    如果没有信息需要发送时,发送端输出逻辑1,即空闲位,空闲位可以有任意数量.如果还有信息需要发送,转入第(2)步.

    对于以上发送、接收过程应注意以下几点:

    接收端总是在每个字符的头部(即起始位)进行一次重新定位,因此发送端可以在字符之间插入不等长的空闲位,不影响接收端的接收.

    发送端的发送时钟和接收端的接收时钟,其频率允许有一定差异,当频率差异在一定范围内,不会引起接收端检测错位,能够正确接收.并且这种频率差异不会因多个字符的连续接收而造成误差累计(因为每个字符的开始(起始位处)接收方均重新定位).只有当发送时钟和接收时钟频率差异太大,引起接收端采样错位,才造成接收错误.

    起始位,校验位,停止位,空闲位的信号,由"发送移位寄存器"自动插入.在接收方,"接收移位寄存器"接收到一帧完整信息(起始,数据,校验,停止)后,仅把数据的各位送至"数据输入寄存器",即CPU从"数据输入寄存器"中读得的信息,只是有效数字,不包含起始位,校验位,停止位信息.

    展开全文
  • 本篇文章介绍,串口协议数据帧格式串行通信的工作方式、电平标准、编码方式及Verilog实现串口发送一个字节数据和接收一个字节数据。对于MCU串口的发送接收,可能就是1行代码就能实现串口的发送和接收:STM32的串口...

    d34803a8700324ff9536d54a803e89c1.png

    详解串行通信协议及其FPGA实现

    前言

    好久没更新博客了,这篇文章写写停停,用了近一周的时间,终于写完了。本篇文章介绍,串口协议数据帧格式、串行通信的工作方式、电平标准、编码方式及Verilog实现串口发送一个字节数据和接收一个字节数据。

    对于MCU串口的发送接收,可能就是1行代码就能实现串口的发送和接收:

    STM32的串口接收和发送

    //STM32发送1个字节
    USART_SendData(USART1, 'A'); 
    while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
    
    //STM32接收1个字节:
    uint8_t Res;
    while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    Res = USART_ReceiveData(USART1);
    

    51单片机的发送和接收

    //51单片机发送1个字节
    SBUF = 'A;
    while(!TI);
    TI=0;
    
    
    //51单片机接收1个字节:
    char Res;
    if(RI)
    {
       Res = SBUF;
       RI = 0;
    }
    

    更方便一点的,通过重写C库fput函数和fgetc函数,还可以实现printf直接重定向到串口,用来输出一些调试信息再方便不过了。

    STM32实现输入输出重定向到串口发送接收

    //可重定向printf函数
    int fputc(int ch, FILE *f)
    {
            USART_SendData(DEBUG_USARTx, (uint8_t) ch);
            while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);     
            return (ch);
    }
    //可重定向scanf函数
    int fgetc(FILE *f)
    {
            while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
            return (int)USART_ReceiveData(DEBUG_USARTx);
    }
    

    而MCU上的串口是半导体厂商预先设计好的,几乎是MCU的标配,高度集成,使用起来十分方便,但是串口的引脚基本上是固定的,不可以更改。对于硬件橡皮泥——FPGA来说,需要使用HDL从底层串口数据帧来实现,可以直接在任意一个引脚实现串口功能。为了用Verilog HDL实现标准的串口通讯协议,我们有必要先来详细了解一下串口通讯协议。

    串口数据帧格式

    波特率

    波特率,即比特率(Baud rate),即通信双方“沟通的语言”,通信双方要设置为一样的波特率才可以正常通信。表示每秒发送的二进制位数,即传输1位的时间是:1/波特率 秒,如,波特率9600bps,即每秒传输9600bit,那么每一位的时间为:1/9600 s = 104.1666us,常用的波特率有:4800/9600/115200/12800等等,也可以根据需要自定义波特率大小,如1M或者3M,但是有的PC或者USB-TTL模块不支持太高速度的波特率,常用的USB-TTL芯片有:CH340,CP2102,PL2103,FT232等,其中FT232HL芯片最大支持12M的波特率,当然价格也比其他芯片高一些。

    起始位和停止位

    数据帧从起始位开始,到停止位结束。起始信号用逻辑0表示,而停止位是用逻辑1表示,一般有0.5位、1位、1.5位或2位停止位,常用的一般是1位停止位,只要通信双方约定一致即可。

    数据位

    起始位之后,紧跟着的是数据位,低位(LSB)在前,高位(MSB)在后,一般有5位、6位、7位和8位数据位,常用的是8位数据位,因为一个字节正好是8位。

    校验位

    校验位一般用来判断接收的数据位有无错误,校验方法有:奇校验(odd)、偶校验(even)、0校验(space)、1校验(mark)及无校验(noparity)。奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个8位长的有效数据为:01101001,此时共有4个“1”,为达到奇数个"1"的效果,校验位为“1”,让“1”的个数变成5个(奇数)。偶校验刚好相反,要求有效数据和校验位的“1”数量为偶数,则此时为达到偶校验效果,校验位为“0”。而0校验,即校验位总是为“0”,1校验校验位总是为“1”。奇偶校验逻辑相反,01校验逻辑相反。一般是奇偶校验或者是无校验位。

    奇偶校验的Verilog实现

    在Verilog中奇偶校验的计算非常简单,根据奇偶校验的原理,偶校验为数据位各位异或,奇校验是偶校验取反,通过使用单目运算符的缩减功能,可以非常简单的计算奇偶校验位:

    input [7:0] data_in,       //需要发送的8位数据
    
    wire even_bit;  //偶校验位 = 各位异或
    wire odd_bit;   //奇校验位 = ~偶校验位
    
    assign even_bit = ^data_in; //一元约简运算符,等效于data_in[0] ^ data_in[1] ^ .....
    assign odd_bit = ~even_bit;
    
    wire POLARITY_BIT = even_bit;  //偶校验
    

    关于波特率允许的误差

    经过我的实际测试,波特率是有一定的容错范围的,例如,STM32配置成115200波特率,每10ms发送一个30字节的字符串,串口芯片用的CH340,上位机波特率设置成113000-121000也可以接收,无乱码,差不多正负2000的波特率,这容错范围也太大了,当然如果发送频率太快,数据量太大,误码率肯定会大大增加,所以还是建议通信双方使用同样的波特率以减少误差。

    串口数据的实际波形

    使用串口上位机连接USB-TTL模块,发送一个字节数据:1位停止位+8位数据位+1位奇校验位+1位停止位,使用示波器的单次触发功能,可以在USB-TTL模块的TX引脚测得串口协议数据的实际波形,你知道这发送的是什么字符吗?

    一个字符的实际波形

    e18e5cbca23983f7c4b77d715a286f6a.png

    两个字符的实际波形

    acec0c291da324c34553e731ad0d2545.png

    单工、半双工、全双工、异步和同步的区别

    在介绍串口的电平标准之前,先来了解一下串行通信的工作方式,即单工、半双工、全双工,异步和同步的区别。

    单工

    单工,即数据传输只在一个方向上传输,只能你给我发送或者我给你发送,方向是固定的,不能实现双向通信,如:室外天线电视、调频广播等。

    半双工

    半双工比单工先进一点,传输方向可以切换,允许数据在两个方向上传输,但是某个时刻,只允许数据在一个方向上传输,可以基本双向通信,如:对讲机,IIC通信。

    f46aad03d2da6c9f0ebed098099a028e.png

    全双工

    比半双工更先进的是全双工,允许数据同时在两个方向传输。发送和接收完全独立,在发送的同时可以接收信号,或者在接收的同时可以发送。它要求发送和接收设备都要有独立的发送和接收能力,如:电话通信,SPI通信,串口通信。

    同步和异步的区别

    串行通信可以分为两种类型,一种叫同步通信,另一种叫异步通信。

    717c0a6b54b7d236e1387bd038cff2f1.png

    简单的说,就是同步通信需要时钟信号,而异步通信不需要时钟信号。

    • 同步:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。
    • 异步:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

    SPI和IIC为同步通信,UART为异步通信,而USART为同步&异步通信。

    • USART:通用同步和异步收发器
    • UART:通用异步收发器

    即USART支持同步和异步收发,而UART只支持异步收发。

    如STM32的串口工作在同步模式时,即智能卡模式时,就需要连接同步时钟引脚。

    a924b944e725a46ac4e9af908b5883b5.png

    常用的串行通信协议/电平标准

    TTL电平

    即普通MCU芯片输出的串口电平,如各MCU输出的串口信号就是TTL电平。低电平为0-GND,高电平为1-VCC,标准的数字电路逻辑。特点是速度快,延迟低,但是功耗大。基本上用于板内两个芯片之间短距离通信。

    RS232

    RS232是工业上常用的串口标准,无论是PLC的232接口,还是工控机上的串口,输出的串口电平都是232电平标准,232标准采用负逻辑电平,即-15~-3v为逻辑1,+3~+15为逻辑0,这里的电平是指RX和TX相对于GND的电压,可见无论在电压范围还是电压极性上都和TTL不同,显然这两种电平不能直接连接,需要使用MAX232类似的电平转换芯片,对两种电平进行互相转换,全双工,传输距离一般控制在20m以内,原因是RS-232属单端信号传送,存在共地噪声和不能抑制共模干扰等问题。

    d08ad17ece6d5713b20809966bbf8f3f.png

    RS485

    在要求通信距离为几十米到上千米时,广泛采用RS-485 串行总线标准。RS-485采用平衡发送和差分接收,因此具有抑制共模干扰的能力。加上总线收发器具有高灵敏度,能检测低至200mV的电压,故传输信号能在千米以外得到恢复。 RS-485采用半双工工作方式,任何时候只能有一点处于发送状态,因此,发送电路须由使能信号加以控制。RS-485用于多点互连时非常方便,可以省掉许多信号线。应用RS-485 可以联网构成分布式系统,其允许最多并联32台驱动器和32台接收器。

    RS422

    RS-422和RS-485电路原理基本相同,都是以差分方式发送和接受,不需要数字地线。RS-422通过两对双绞线可以全双工工作收发互不影响,而RS485只能半双工工作,发收不能同时进行,但它只需要一对双绞线。RS422和RS485在19kpbs下能传输1200米。RS-422的电气性能与RS-485完全一样。主要的区别在于:RS-422有4根信号线:两根发送(Y、Z)、两根接收(A、B)。由于RS-422的收与发是分开的所以可以同时收和发(全双工)。

    串行通信的编码方式

    RZ编码

    RZ编码也成为归零码,归零码的特性就是在一个周期内,用二进制传输数据位,在数据位脉冲结束后,需要维持一段时间的低电平。如图:

    ab6d4aaa451690e9a2bea366754d9361.png

    上图表示的是单极性归零码,即低电平表示0,正电平表示1。对于双极性归零码来说,则是高电平表示1,负电平表示0。如下图所示:

    bc872497f057f32f8735701524114dbd.png

    NRZ编码

    NRZ编码也成为不归零编码,也是我们最常见的一种编码,即正电平表示1,低电平表示0。它与RZ码的区别就是它不用归零,也就是说,一个周期可以全部用来传输数据,这样传输的带宽就可以完全利用。

    eb13e9688755e7ed2204cb8fe4297d66.png

    NRZI编码

    NRZI编码的全称为反向不归零编码,这种编码方式集成了前两种编码的优点,即既能传输时钟信号,又能尽量不损失系统带宽。对于USB2.0通信的编码方式就是NRZI编码。其实NRZI编码方式非常的简单,即信号电平翻转表示0,信号电平不变表示1。例如想要表示00100010(B),则信号波形如下图所示:

    8c9fd39c66606fb416953b8a144dfa9a.png

    例如有一段数据为:1111 1111 (B)要发送,则整个传输线上的电平状态是这样的:

    2aeb41b383425415e4f9d25009fd465f.png

    Manchester编码

    曼彻斯特编码,又称数字双向码、分相码或相位编码(PE),是一种常用的的二元码线路编码方式。常用在以太网通信,列车总线控制,工业总线等领域。在曼彻斯特编码中,每一位的中间有一跳变,位中间的跳变既作时钟信号,又作数据信号;从高到低跳变表示“0”,从低到高跳变表示“1”。其中非常值得注意的是,在每一位的"中间"必有一跳变,根据此规则,可以得出曼彻斯特编码波形图的画法。例如:传输二进制信息0,若将0看作一位,我们以0为中心,在两边用虚线界定这一位的范围,然后在这一位的中间画出一个电平由高到低的跳变。后面的每一位以此类推即可画出整个波形图。举个图例吧,若要表示数据1001 1010(B),则信号波形图如下图所示:

    66a53cfe1a3ddf097990163c7842d625.png

    曼彻斯特编码方式也如前面所说,虽然传输了时钟信号,但也损失了一部分的带宽,主要表现在相邻相同数据上。但对于高速数据来说,这种编码方式无疑是这几种编码方式中最优的,相比NRZI编码,曼彻斯特编码不存在长时间信号状态不变导致的时钟信号丢失的情况,所以在这种编码方式在以太网通信中是十分常用的。

    串行和并行哪个速度快?

    串口,即串行通信接口,与之对应的是并行接口。在实际时钟频率比较低的情况下,并口因为可以同时传输若干比特,速率确实比串口快。但是,随着技术的发展,时钟频率越来越高,当时钟频率提高到一定的程度时,并行接口因为有多条并行且紧密的导线,导线之间的相互干扰越来越严重。而串口因为导线少,线间干扰容易控制,况且加上差分信号的加持,抗干扰性能大大提升,因此可以通过不断提高时钟频率来提高传输速率,这就是为什么现在高速传输都采用串行方式的原因。例如常见的USB、SATA、PCIe、以太网等。

    如果有人问关于串行传输与并行传输谁更好的问题,你也许会脱口而出:串行通信好!但是,串行传输之所以走红,是由于将单端信号传输转变为差分信号传输,并提升了控制器工作频率的原因,而“在相同频率下并行通信速度更高”这个基本道理是永远不会错的,通过增加位宽来提高数据传输率的并行策略仍将发挥重要作用。当然,前提是有更好的措施来解决并行传输过程中的种种问题。

    标准串口协议的Verilog实现

    基于Verilog实现标准串口协议发送8位数据:起始位 + 8位数据位 + 校验位 + 停止位 = 11位,每1位的时间是16个时钟周期,所以输入时钟应该为:波特率*16,带Busy忙信号输出。实现方法比较简单,数据帧的拼接、计数器计时钟周期,每16个时钟周期输出一位数据即可。

    串口发送1个字节实现

    /*
    串口协议发送:起始位 + 8位数据位 + 校验位 + 停止位 = 11位 * 16 = 176个时钟周期
    clk频率 = 波特率 * 16
    */
    
    module uart_tx_8bit(
    
    //input
    input clk,                //UART时钟=16*波特率
    input rst_n,
    input [7:0] data_in,       //需要发送的数据
    input trig,                //上升沿发送数据
    
    //output
    output busy,                 //高电平忙:数据正在发送中
    output reg tx                //发送数据信号
    
    );
    
    reg[7:0] cnt;             //计数器
    reg trig_buf;
    reg trig_posedge_flag;
    // reg trig_negedge_flag;
    reg send;
    
    reg [10:0] data_in_buf;     //trig上升沿读取输入的字节,拼接数据帧
    
    wire odd_bit;   //奇校验位 = ~偶校验位
    wire even_bit;  //偶校验位 = 各位异或
    wire POLARITY_BIT = even_bit;  //偶校验
    // wire POLARITY_BIT = odd_bit;   //奇校验
    
    assign even_bit = ^data_in; //一元约简,= data_in[0] ^ data_in[1] ^ .....
    assign odd_bit = ~even_bit;
    assign busy = send;     //输出的忙信号
    
    //起始位+8位数据位+校验位+停止位 = 11位 * 16 = 176个时钟周期
    parameter CNT_MAX = 176;
    
    always @(posedge clk)
    begin
        if(!rst_n)
        begin
            trig_buf <= 0;
            trig_posedge_flag <= 0;
            // trig_negedge_flag <= 0;
        end
        else 
        begin
            trig_buf <= trig;
            trig_posedge_flag <= (~trig_buf) & trig; //在trig信号上升沿时产生1个时钟周期的高电平
            // trig_negedge_flag <= trig_buf & (~trig); //在trig信号下降沿时产生1个时钟周期的高电平    
        end
    end
    
    always @(posedge clk)
    begin
        if(!rst_n)
            send <= 0;
        else if (trig_posedge_flag &  (~busy))  //当发送命令有效且线路为空闲时,启动新的数据发送进程
            send <= 1;
        else if(cnt == CNT_MAX)      //一帧资料发送结束
            send <= 0;
    end
    
    always @ (posedge clk)
    begin
        if(!rst_n)
            data_in_buf <= 11'b0;
        else if(trig_posedge_flag & (~busy))    //只读取一次数据,一帧数据发送过程中,改变输入无效
            data_in_buf <= {1'b1, POLARITY_BIT, data_in[7:0], 1'b0};   //数据帧拼接
    end
    
    always @ (posedge clk)
    begin
        if(!rst_n)
            cnt <= 0;
        else if(!send || cnt >= CNT_MAX)
            cnt <= 0;
        else if(send)
            cnt <= cnt + 1;
    end
    
    always @(posedge clk)
    begin
        if(!rst_n)
            tx <= 1;
        else if(send)  
        begin
            case(cnt)                 //1位占用16个时钟周期
                0: tx <= data_in_buf[0];           //低位在前,高位在后
                16: tx <= data_in_buf[1];    //bit0,占用第16~31个时钟
                32: tx <= data_in_buf[2];    //bit1,占用第47~32个时钟
                48: tx <= data_in_buf[3];    //bit2,占用第63~48个时钟
                64: tx <= data_in_buf[4];    //bit3,占用第79~64个时钟
                80: tx <= data_in_buf[5];    //bit4,占用第95~80个时钟
                96: tx <= data_in_buf[6];    //bit5,占用第111~96个时钟
                112: tx <= data_in_buf[7];   //bit6,占用第127~112个时钟
                128: tx <= data_in_buf[8];   //bit7,占用第143~128个时钟
                144: tx <= data_in_buf[9];   //发送奇偶校验位,占用第159~144个时钟
                160: tx <= data_in_buf[10];  //发送停止位,占用第160~167个时钟            
                CNT_MAX: tx <= 1;            //无空闲位
                default:;
            endcase
        end
        else if(!send) 
            tx <= 1;
    end
    
    endmodule
    

    仿真波形

    b0485161b539740e068331d580c7d6a1.png

    串口接收1个字节实现

    串口接收部分的实现,涉及到串口数据的采样,对于MCU来说,不同单片机集成外设的处理方式有所不同,具体采样原理可以参考内核的Reference Manual。以传统51内核为例,按照所设置的波特率,每个位时间被分为16个时间片。UART接收器会在第7、8、9三个时间片进行采样,按照三取二的逻辑获得该位时间内的采样结果。其它一些类型的单片机则可能会更加严苛,例如有些工业单片机会五取三甚至七取五(设置成抗干扰模式时)。

    本程序中采用的中间值采样,即取16个时钟周期中的中间位作为当前的采样值。

    //Verilog实现串口协议接收,带错误指示,校验错误和停止位错误
    
    /*
    16个时钟周期接收1位,中间采样
    */
    module my_uart_rx(
    
    input clk,             //采样时钟
    input rst_n,
    input rx,              //UART数据输入
    output reg [7:0] dataout,        //接收数据输出
    output reg rx_ok,          //接收数据有效,高说明接收到一个字节
    output reg err_check,      //数据出错指示
    output reg err_frame     //帧出错指示
    
    );
    
    reg [7:0] cnt;
    reg [10:0] dataout_buf;
    
    reg rx_buf;
    reg rx_negedge_flag;
    reg receive;
    
    wire busy;
    wire odd_bit;   //奇校验位 = ~偶校验位
    wire even_bit;  //偶校验位 = 各位异或
    wire POLARITY_BIT;   //本地计算的奇偶校验
    // wire polarity_ok;
    // assign polarity_ok = (POLARITY_BIT == dataout_buf[9]) ? 1 : 0; //校验正确=1,否则=0
    
    assign busy = rx_ok;
    assign even_bit = ^dataout;     //一元约简,= data_in[0] ^ data_in[1] ^ .....
    assign odd_bit = ~even_bit;
    assign POLARITY_BIT = even_bit;  //偶校验
    // assign POLARITY_BIT = odd_bit;  //奇校验
    
    parameter CNT_MAX = 176;
    
    //rx信号下降沿标志位
    always @(posedge clk)   
    begin
        if(!rst_n)
        begin
            rx_buf <= 0;
            rx_negedge_flag <= 0;
        end
        else
        begin
            rx_buf <= rx;
            rx_negedge_flag <= rx_buf & (~rx);
        end
    end
    //在接收期间,保持高电平
    always @(posedge clk)
    begin
        if(!rst_n)
            receive <= 0;
        else if (rx_negedge_flag && (~busy))  //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程
            receive <= 1;      //开始接收数据
        else if(cnt == CNT_MAX)  //接收数据完成
            receive <= 0;
    end
    //起始位+8位数据位+校验位+停止位 = 11位 * 16 = 176个时钟周期
    always @ (posedge clk)
    begin
        if(!rst_n)
            cnt <= 0;
        else if(!receive || cnt >= CNT_MAX)
            cnt <= 0;
        else if(receive)
            cnt <= cnt + 1;
    end
    //校验错误:奇偶校验不一致
    always @ (posedge clk)
    begin
        if(!rst_n)
            err_check <= 0;
        else if(cnt == 152)
        begin
            // if(POLARITY_BIT == rx)
            if(POLARITY_BIT != dataout_buf[9])      //奇偶校验正确
                err_check <= 1;         //锁存
            // else
                // err_check <= 1;       
        end
    end
    //帧错误:停止位不为1
    always @ (posedge clk)
    begin
        if(!rst_n)
            err_frame <= 0;
        else if(cnt == CNT_MAX)
        begin
            if(dataout_buf[10] != 1)        //停止位
                err_frame <= 1;
            // else
                // err_frame <= 1;      //如果没有接收到停止位,表示帧出错
        end
    end
    
    always @ (posedge clk)
    begin
        if(!rst_n)
            dataout <= 11'h00;
        else if(receive)
        begin
            // if(rx_ok)
            if(cnt >= 137)
                dataout <= dataout_buf[8:1];        //数据位:8-1位
            // else if(!rx_ok)
                // dataout <= 0;
        end
    end
    
    always @ (posedge clk)
    begin
        if(!rst_n)
            rx_ok <= 0;
        else if(receive)
        begin
            if(cnt >= 137)   //137-169
                rx_ok <= 1;
            else 
                rx_ok <= 0;
        end
        else 
            rx_ok <= 0;
    end
    
    
    //起始位+8位数据+奇偶校验位+停止位 = 11 * 16 = 176位
    
    always @(posedge clk)
    begin
        if(!rst_n)
            dataout_buf <= 8'h00;
        else if(receive)
        begin
            case (cnt)      //中间采样
                8'd8: dataout_buf[0] <= rx;         //起始位=0
                8'd24: dataout_buf[1] <= rx;        //LSB低位在前
                8'd40: dataout_buf[2] <= rx;
                8'd56: dataout_buf[3] <= rx;
                8'd72: dataout_buf[4] <= rx;
                8'd88: dataout_buf[5] <= rx;
                8'd104: dataout_buf[6] <= rx;
                8'd120: dataout_buf[7] <= rx;
                8'd136: dataout_buf[8] <= rx;       //MSB高位在后
                8'd152: dataout_buf[9] <= rx;       //奇偶校验位
                8'd168: dataout_buf[10] <= rx;      //停止位=1
                default:;
            endcase
        end
    end
    
    endmodule
    

    322639f8886e0bf7da8cd598d5f91d6a.png

    代码工程下载

    • Github工程地址:https://github.com/whik/UART_Demo_Verilog
    • Gitee工程地址:https://gitee.com/whik/UART_Demo_Verilog

    工程包含:

    • my_uart_rx:串口接收1个字节示例程序
    • uart_tx_8bit:串口发送1个字节示例程序
    • uart_tx_demo:串口每隔500ms循环发送0-9字符

    参考资料:

    • 百度百科_TTL电平
    • 一文读懂RS-232与RS-422及RS-485三者之间的特性与区别
    • 工作中经常遇到的232、485、TTL信号

    推荐阅读:

    • 玄铁910是个啥?是芯片吗?
    • Qt平台下使用QJson解析和构建JSON字符串
    • 国产处理器的逆袭机会——RISC-V
    • 真正的RISC-V开发板——VEGA织女星开发板开箱评测
    • 【2019北京国际消费电子博览会】参观总结
    • Qt实现软件自动更新的一种简单方法

    我的博客:www.wangchaochao.top

    或微信扫码关注我的公众号:mcu149

    d6d16d1f7e3394afc5819f5e450a383b.png
    展开全文
  • 串行异步通信-UART

    千次阅读 2012-09-17 11:05:26
    异步通信的特点及信息帧格式:   以起止式异步协议为例,下图显示的是起止式一帧数据的格式: 起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时...

    串行通信可以分为两种类型:同步通信、异步通信。

      1.异步通信的特点及信息帧格式: 
       以起止式异步协议为例,下图显示的是起止式一帧数据的格式:

    起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求。每一个字符的前面都有一位起始位(低电平,逻辑值),字符本身由5-7位数据位组成,接着字符后面是一位校验位(也可以没有校验位),最后是一位或一位半或二位停止位,停止位后面是不定长的空闲位。停止位和空闲位都规定为高电平(逻辑值1),这样就保证起始位开始处一定有一个下跳沿。
       从图中可看出,这种格式是靠起始位和停止位来实现字符的界定或同步的,故称为起止式协议。 
       异步通信可以采用正逻辑或负逻辑,正负逻辑的表示如下表所示:

      逻辑0 逻辑1
    正逻辑 低电平 高电平
    负逻辑 高电平 低电平


    异步通信的信息格式如下边的表所示:

    起始位 逻辑0 1位
    数据位 逻辑0或1 5,6,7,8位
    校研位 逻辑0或1 1位或无
    停止位 逻辑1 1位,1.5位或2位
    空闲位 逻辑1 任意数量


    注:表中位数的本质含义是信号出现的时间,故可有分数位,如1.5。 
       例:传送8位数据45H(0100,0101B),奇校验,1个停止位,则信号线上的波形象图2所示那样:异步通信的速率:若9600bps,每字符8位,1起始,1停止,无奇偶,则实际每字符传送10位,则960字符/秒。 


    图2

    2.异步通信的接收过程

      接收端以“接收时钟”和“波特率因子”决定一位的时间长度。下面以波特率因子等于16(接收时钟每16个时钟周期,使接收移位寄存器移位一次)、正逻辑为例说明,如图3所示。

     



    图3

        (1)开始通信时,信号线为空闲(逻辑1),当检测到由1到0的跳变时,开始对“接收时钟”计数。 

      (2)当计到8个时钟时,对输入信号进行检测,若仍为低电平,则确认这是“起始位”B,而不是干扰信号。

      (3)接收端检测到起始位后,隔16个接收时钟,对输入信号检测一次,把对应的值作为D0位数据。若为逻辑1, 作为数据位1;若为逻辑0,作为数据位0。

      (4)再隔16个接收时钟,对输入信号检测一次,把对应的值作为D1位数据。….,直到全部数据位都输入。

      (5)检测校验位P(如果有的话)。

      (6)接收到规定的数据位个数和校验位后,通信接口电路希望收到停止位S(逻辑1),若此时未收到逻辑1,说明出现了错误,在状态寄存器中置“帧错误”标志。若没有错误,对全部数据位进行奇偶校验,无校验错时,把数据位从移位寄存器中送数据输入寄存器。若校验错,在状态寄存器中置奇偶错标志。

      (7)本幀信息全部接收完,把线路上出现的高电平作为空闲位。

      (8)当信号再次变为低时,开始进入下一幀的检测。

      3、异步通信的发送过程

      发送端以“发送时钟”和“波特率因子”决定一位的时间长度。

      (1)当初始化后,或者没有信息需要发送时,发送端输出逻辑1,即空闲位,空闲位可以有任意数量。

      (2)当需要发送时,发送端首先输出逻辑0,作为起始位。

      (3)接着,发送端首先发送D0位,直到各数据位发送完。

      (4)如果需要的话,发送端输出校验位。

      (5)最后,发送端输出停止位(逻辑1)。

      (6)如果没有信息需要发送时,发送端输出逻辑1,即空闲位,空闲位可以有任意数量。如果还有信息需要发送,转入第(2)步。

      对于以上发送、接收过程应注意以下几点:

      (1)接收端总是在每个字符的头部(即起始位)进行一次重新定位,因此发送端可以在字符之间插入不等长的空闲位,不影响接收端的接收。

      (2)发送端的发送时钟和接收端的接收时钟,其频率允许有一定差异,当频率差异在一定范围内,不会引起接收端检测错位,能够正确接收。并且这种频率差异不会因多个字符的连续接收而造成误差累计(因为每个字符的开始(起始位处)接收方均重新定位)。只有当发送时钟和接收时钟频率差异太大,引起接收端采样错位,才造成接收错误。

      (3)起始位、校验位、停止位、空闲位的信号,由“发送移位寄存器”自动插入。在接收方,“接收移位寄存器”接收到一帧完整信息(起始、数据、校验、停止)后,仅把数据的各位送至“数据输入寄存器”,即CPU从“数据输入寄存器”中读得的信息,只是有效数字,不包含起始位、校验位、停止位信息。

    展开全文
  • 串行口是单片机与外界进行信息交换的工具。■ 8051单片机的通信方式...其每帧的格式如下:在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(能省略),最后是停止位1。...
    fbf36f0b03915feb12c6b3c2fdb06b07.png

    串行口是单片机与外界进行信息交换的工具。

    ■ 8051单片机的通信方式有两种:

    并行通信:数据的各位同时发送或接收。

    串行通信:数据一位一位次序发送或接收。

    参看下图:

    67804a4b14a715524f6ed02b16d8ca16.png

    串行通信的方式包括异步通信和同步通信。

    异步通信

    它用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:

    在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(能省略),最后是停止位1。用这种格式表示字符,则字符能一个接一个地传送。

    在异步通信中,CPU与外设之间必须有两项规定,即字符格式和波特率。字符格式的规定是双方能够在对同一种0和1的串理解成同一种意义。原则上字符格式能由通信的双方自由制定,但从通用、方便的角度出发,一般还是使用一些标准为好,如采用ASCII标准。

    波特率即数据传送的速率,其定义是每秒钟传送的二进制数的位数。例如,数据传送的速率是120字符/s,而每个字符如上述规定包含10数位,则传送波特率为1200波特。

    同步通信

    在同步通信中,每个字符要用起始位和停止位作为字符开始和结束的标志,占用了时间;所以在数据块传递时,为了提高速度,常去掉这些标志,采用同步传送。由于数据块传递开始要用同步字符来指示,同时要求由时钟来实现发送端与接收端之间的同步,故硬件较复杂。

    通信方向

    在串行通信中,把通信接口只能发送或接收的单向传送办法叫单工传送;而把数据在甲乙两机之间的双向传递,称之为双工传送。在双工传送方式中又分为半双工传送和全双工传送。半双工传送是两机之间不能同时进行发送和接收,任一时该,只能发或者只能收信息。

    8051单片机的串行接口结构

    8051单片机串行接口是一个可编程的全双工串行通信接口。它可用作异步通信方式(UART),与串行传送信息的外部设备相连接,或用于通过标准异步通信协议进行全双工的8051多机系统也能通过同步方式,使用TTL或CMOS移位寄存器来扩充I/O口。

    8051单片机通过管脚RXD(P3.0,串行数据接收端)和管脚TXD(P3.1,串行数据发送端)与外界通信。SBUF是串行口缓冲寄存器,包括发送寄存器和接收寄存器。它们有相同名字和地址空间,但不会出现冲突,因为它们两个一个只能被CPU读出数据,一个只能被CPU写入数据。

    ▲串行口的控制与状态寄存器

    串行口控制寄存器SCON

    它用于定义串行口的工作方式及实施接收和发送控制。字节地址为98H,其各位定义如下表:

    e138beb13e6e46abb15952b7558023e3.png

    SM0、SM1:串行口工作方式选择位,其定义如下:

    aefdc71b29d93ada430a9389c12b4ce2.png

    (注:其中fosc为晶体震荡器频率)

    SM2:多机通信控制位。在方式0时,SM2一定要等于0。在方式1中,当(SM2)=1则只有接收到有效停止位时,RI才置1。在方式2或方式3当(SM2)=1且接收到的第九位数据RB8=0时,RI才置1。

    REN:接收允许控制位。由软件置位以允许接收,又由软件清0来禁止接收。

    TB8: 是要发送数据的第9位。在方式2或方式3中,要发送的第9位数据,根据需要由软件置1或清0。例如,可约定作为奇偶校验位,或在多机通信中作为区别地址帧或数据帧的标志位。

    RB8:接收到的数据的第9位。在方式0中不使用RB8。在方式1中,若(SM2)=0,RB8为接收到的停止位。在方式2或方式3中,RB8为接收到的第9位数据。

    TI:发送中断标志。在方式0中,第8位发送结束时,由硬件置位。在其它方式的发送停止位前,由硬件置位。TI置位既表示一帧信息发送结束,同时也是申请中断,可根据需要,用软件查询的办法获得数据已发送完毕的信息,或用中断的方式来发送下一个数据。TI必须用软件清0。

    RI:接收中断标志位。在方式0,当接收完第8位数据后,由硬件置位。在其它方式中,在接收到停止位的中间时刻由硬件置位(例外情况见于SM2的说明)。RI置位表示一帧数据接收完毕,可用查询的办法获知或者用中断的办法获知。RI也必须用软件清0。

    ▲特殊功能寄存器PCON

    PCON是为了在CHMOS的80C51单片机上实现电源控制而附加的。其中最高位是SMOD。

    串行口的工作方式

    8051单片机的全双工串行口可编程为4种工作方式,现分述如下:

    方式0 移位寄存器输入/输出方式。

    可外接移位寄存器以扩展I/O口,也能外接同步输入/输出设备。8位串行数据者是从RXD输入或输出,TXD用来输出同步脉冲。

    输出 串行数据从RXD管脚输出,TXD管脚输出移位脉冲。CPU将数据写入发送寄存器时,立即启动发送,将8位数据以fos/12的固定波特率从RXD输出,低位在前,高位在后。发送完一帧数据后,发送中断标志TI由硬件置位。

    输入 当串行口以方式0接收时,先置位允许接收控制位REN。此时,RXD为串行数据输入端,TXD仍为同步脉冲移位输出端。当(RI)=0和(REN)=1同时满足时,开始接收。当接收到第8位数据时,将数据移入接收寄存器,并由硬件置位RI。

    下面两图分别是方式0扩展输出和输入的接线图。

    1a64fbe23359832e48ce072e297a5fd0.png

    方式1 波特率可变的10位异步通信接口方式

    发送或接收一帧信息,包括1个起始位0,8个数据位和1个停止位1。

    输出 当CPU执行一条指令将数据写入发送缓冲SBUF时,就启动发送。串行数据从TXD管脚输出,发送完一帧数据后,就由硬件置位TI。

    输入 在(REN)=1时,串行口采样RXD管脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。只有当(RI)=0且停止位为1或者(SM2)=0时,停止位才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;不然信息丢失。所以在方式1接收时,应先用软件清零RI和SM2标志。

    方式2 固定波特率的11位UART方式。

    它比方式1增加了一位可程控为1或0的第9位数据。

    输出: 发送的串行数据由TXD端输出一帧信息为11位,附加的第9位来自SCON寄存器的TB8位,用软件置位或复位。它可作为多机通信中地址/数据信息的标志位,也能作为数据的奇偶校验位。当CPU执行一条数据写入SUBF的指令时,就启动发送器发送。发送一帧信息后,置位中断标志TI。

    输入: 在(REN)=1时,串行口采样RXD管脚,当采样到1至0的跳变时,确认是开始位0,就开始接收一帧数据。在接收到附加的第9位数据后,当(RI)=0或者(SM2)=0时,第9位数据才进入RB8,8位数据才能进入接收寄存器,并由硬件置位中断标志RI;不然信息丢失。且不置位RI。再过一位时间后,不管上述条件时否满足,接收电路即行复位,并重新检测RXD上从1到0的跳变。

    方式3 波特率可变的11位UART方式。

    除波特率外,其余与方式2相同。

    关于波特率选择

    如前所述,在串行通信中,收发双方的数据传送率(波特率)要有一定的约定。在8051串行口的四种工作方式中,方式0和2的波特率是固定的,而方式1和3的波特率是可变的,由定时器T1的溢出率控制。

    ▲ 方式0

    方式0的波特率固定为主振频率的1/12。

    ▲ 方式2

    方式2的波特率由PCON中的选择位SMOD来决定,可由下式表示:

    波特率=2的SMOD次方除以64再乘一个fosc,也就是当SMOD=1时,波特率为1/32fosc,当SMOD=0时,波特率为1/64fosc

    ▲ 方式1和方式3

    定时器T1作为波特率发生器,其公式如下:

    43d9b8cb86aca0f8975e86937bb9cc69.png

    式中T1计数率取决于它工作在定时器状态还是计数器状态。当工作于定时器状态时,T1计数率为fosc/12;当工作于计数器状态时,T1计数率为外部输入频率,此频率应小于fosc/24。产生溢出所需周期与定时器T1的工作方式、T1的预置值有关。

    定时器T1工作于方式0:溢出所需周期数=8192-x;

    定时器T1工作于方式1:溢出所需周期数=65536-x;

    定时器T1工作于方式2:溢出所需周期数=256-x。

    因为方式2为自动重装入初值的8位定时器/计数器模式,所以用它来做波特率发生器最恰当。

    当时钟频率选用11.0592MHZ时,取易获得标准的波特率,所以很多单片机系统选用这个看起来“怪”的晶体震荡器就是这个道理。

    下表列出了定时器T1工作于方式2常用波特率及初值。

    以上所有信息仅作为学习交流使用,不作为任何学习和商业标准。若您对文中任何信息有异议,欢迎随时提出,谢谢!

    关于云创硬见

    云创硬见是国内最具特色的电子工程师社区,融合了行业资讯、社群互动、培训学习、活动交流、设计与制造分包等服务,以开放式硬件创新技术交流和培训服务为核心,连接了超过30万工程师和产业链上下游企业,聚焦电子行业的科技创新,聚合最值得关注的产业链资源, 致力于为百万工程师和创新创业型企业打造一站式公共设计与制造服务平台。

    展开全文
  • 主要内容:串行口的结构、串行口的4 种工作方式、多机...传送的数据是以一帧一帧格式进行的。串行通信(英语:Serial communication)是指在计算机总线或其他数据通道上,每次传输一个位元数据,并连续进行以上单...
  • 异步同步通信数据帧格式

    千次阅读 2020-07-10 13:52:52
    1. 异步通信的特点及信息帧格式: 以起止式异步协议为例,下图显示的是起止式一帧数据的格式: 图1 起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以"起始位"开始,以...
  •  异步通信数据的第一位是开始位,在通信线上没有数据传送时处于逻辑“1”状态。当发送设备要发送一个字符数据时,首先发出一个逻辑“0”信号,这个逻辑低电平就是起始位。起始位通过通信线传向接收设备,当接收...
  • 目录 第一章、简介 第二章、并行通信 第三章、串行通信 ...3.2.2、典型异步通信结构 3.2.3、异步通信其他的结构 3.2.4、CRC校验 3.2.5、异步通信特点 第四章、串口异步通信的工程应用 参考: h...
  • 根据异步串行通信协议来说,空闲状态是高电平,开始位是以低电平开始的,如下图所示 在这里我们选取数据格式位1个起始位,8个数据位,0校验位,1停止位(1+8+0+1) 在串口的接收模块中,由于数据的定义格式...
  • 参看下图:串行通信的方式:异步通信:它用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位...
  • 文章框架 ...为了让大家在直到你是在给我传数据而不是外面的噪音或者是胡说八道,所以串行数据的各位要组装帧(看正文中的帧格式)。乍一看,这种方式跟并行比肯定慢的一腿。但实际上,多亏了它的稳...
  • 异步通信的特点及信息帧格式:      以起止式异步协议为例,下图显示的是起止式一帧数据的格式:         图1     起止式异步通信的特点是:一个字符一个字符地传输...
  • 1. 异步串行通信 异步串行通信是以字符为单位的间歇传输形式传送时按字符进行包装为此在数据位之外要增添起始位奇偶校验位和停止位构成一个通信帧下图为异步通信帧格式 ; 几点说明 在串行通信中信息的两种状态分别...
  • 异步通信方式

    千次阅读 2010-03-16 14:51:00
    1.异步通信的特点及信息帧格式: 以起止式异步协议为例,下图显示的是起止式一帧数据的格式: http://hi.csdn.net/space-3213884-do-album-picid-497605.html图1 起止式异步通信的特点是:一个字符一个字符地...
  • 并行通信:是指数据的各位同时进行传送的通信方式。串行通信:是指数据一位一位顺序传送的通信方式。串行通信的两种基本形式:同步通信和异步通信...异步通信所传输的数据帧格式是由1个起始位、1~9个数据位、1~2个停
  • 串口通讯—异步通信方式

    千次阅读 2013-03-14 12:33:26
    1.异步通信的特点及信息帧格式: 以起止式异步协议为例,下图显示的是起止式一帧数据的格式: 图1 起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输...
  • UART串行通信

    千次阅读 2017-06-24 11:36:18
    什么是串行通信? 将数据字节分成一位一位的形式在一条传输线上逐位地发送。 优点:成本低,控制复杂。 ...什么是异步通信?...异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。...异步通信
  • 1. 异步通信的特点及信息帧格式: 以起止式异步协议为例,下图显示的是起止式一帧数据的格式: 图1 起止式异步通信的特点是:一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以"起始位...
  • 串行通信接口

    2014-11-06 16:11:00
     串口通讯—异步通信方式 以起止式异步协议为例,下图显示的是起止式一数据的格式:  串口通讯—同步通信方式 【没有时钟线,应属于通常意义的异步串行通信】 面向字符的...
  • 串行通信方式

    千次阅读 2018-11-17 16:37:56
    同步和异步即是使用同一时钟还是各自时钟,即便使用不同的时钟信号,也尽可能的保持的一致。 同步通信: 面向字符的格式:  此时,传送的数据和控制信息都必须由规定的字符集(如ASCII码)中的字符所组成。图...
  • 文章目录一、基本概念1:异步串行通信2:同步串行通信3:波特率及时钟频率4:串行通信的校验5:数据通信的传输方式二、通用同步异步收发器(USART)1:I/O口说明2:时钟管理3:中断源3:USART帧格式 一、基本概念 ...
  • 主要内容:串行口的结构、串行口的4 种工作方式、多机...传送的数据是以一帧一帧格式进行的。串行通信(英语:Serial communication)是指在计算机总线或其他数据通道上,每次传输一个位元数据,并连续进行以上单...
  • 停止位1bit,串口通信分两种一种是同步通信,一种是异步通信,像ps\2键盘就是同步,一般的单片机下载都是异步通信,起始位表示过了这个位就是数据位了,接着8位数据,然后校验,然后停止位,停止位表示这一桢数据...

空空如也

空空如也

1 2 3 4 5 6
收藏数 112
精华内容 44
关键字:

串行异步通信帧格式