• 【黑金原创教程】【FPGA那些事儿驱动篇I 】实验十二:串口模块① — 发送


    实验十二:串口模块① — 发送

    串口固然是典型的实验,想必许多同学已经作烂,不过笔者还要循例介绍一下。我们知道串口有发送与接收之分,实验十二的实验目的就是实现串口发送,然而不同的是 ... 笔者会用另一种思路去实现串口发送。

    clip_image002

    图12.1 PS/2发送时序与串口发送时序。

    如图12.1所示,串口发送时序相较PS/2发送时序,串口发送时序就像断了翅膀的小鸟般,没有时钟信号控制整个传输协议。除此之外,串口发送时序与PS/2发送时序近似的地方也非常惊人 ... 默认下,一帧PS/2数据有11位,对此一帧串口数据也有11位,其中位分配如表12.1所示:

    表12.1 一帧串口数据的位分配。

    位分配

    位定义

    [0]

    起始位

    [8:1]

    数据位

    [9]

    校验位

    [10]

    停止位

    如表12.1所示,[0]为拉低的起始位,[8:1]为任意填充的数据位,[9]为任意填充的校验位,[10]为拉高的停止位。

    clip_image004

    图12.2 FPGA发送一帧串口数据(无视波特率)。

    假设我们无视波特率,并且利用FPGA发送一帧串口数据的话 ... 如图12.2所示,一帧有11位的串口数据,一共使用了11个上升沿发送出去,为此Verilog则可以这样表示,结果如代码12.1所示:

          reg [10:0]D1;
         always @(posedge CLOCK)
             case(i)
                0,1,2,3,4,5,6,7,8,9,10:      
                begin TXD <= D1[i]; i <= i + 1'b1; end
                ......
             endcase

    代码12.1

    如代码12.1所示,寄存器D为11位宽的寄存器,并且驱动TXD输出口,期间步骤0~11公按照i的位寻址,将D1的内容逐个发送出去。

    虽然串口传输协议极为类似PS/2传输协议,但是串口传输协议也有区别的地方。其一串口传输协议有波特率的概念,而且串口协议有各种各样的波特率,常用的波特率有9600 bps或者115200 bps,波特率最低为 110 bps,最高为 256000 bps(目前暂定)。所谓波特率就是一秒内,串口可以发送多少位数据,此外波特率也是一位数据的周期,或者说是一位数据的保持时间,就拿115200 bps为例:

    1/115200 = 8.68E-6

    115200波特率的一位数据周期为 8.68us,如果用50Mhz 的时钟频率去量化的话:

    ( 1/115200 ) / (1/50E+6) = 8.68E-6 / 20E-9

    = 434

    clip_image006

    图12.3 FPGA发送一帧串口数据(考虑波特率)。

    如果图12.3考虑115200的波特率,结果如图12.3所示,每一位数据都保持434个时钟

    ,为此Verilog可以这样表示,如代码12.2所示:

          reg [10:0]D1;
          reg [8:0]C1;
         always @(posedge CLOCK)
             case(i)
                0,1,2,3,4,5,6,7,8,9,10:    
                 if( C1 == 9’d434 -1 ) begin C1 <= 9’d0; i <= i + 1’b1; end  
                else begin TXD <= D1[i]; C1 <= C1 + 1'b1; end
                ......
             endcase

    代码12.1

    如代码12.1所示,步骤0~10不再保持一个时钟,换之每个步骤都保持434个时钟,因此每位TXD的发送数据也保持 8.68us。

    除此此外,串口传输协议不仅可以自定义波特率,串口传输协议也可以自定义一帧数据的位宽,自定义内容如表12.2所示:

    表12.2 自定义一帧数据。

    自定义数据位

    自定义内容

    数据位

    5~9

    校验位

    有/无

    停止位

    1~2

    如表12.2所示,可以自定义的数据其中便包含数据位,默认下为1字节,自定义内容则是5~9位,校验位也可以设置为有或者无(默认下是有),停止位也可以增至2位(默认下是1位)。不管怎么样,表12.2是比较官方的自定义内容 ... 只要读者欢喜,任何畸形的自定义内容也有可能实现。

    理解完毕以后,我们便可以开始建模了。

    clip_image008

    图12.4 实验十二的建模图。

    图12.4是实验十二的建模图,不过内容较为寒酸 ... 组合模块 tx_demo 内容包括一段核心操作,还有一只TX功能模块。核心操作负责TX功能模块的调用,亦即控制沟通信号还有Data的输入。TX功能模块被使能以后,便将iData经由TXD输出端发送出去

    ,完后便反馈完成信号以示一次性的操作已经完毕。

    tx_funcmod.v

    clip_image010

    图12.5 TX功能模块的建模图。

    如图12.5所示,该模块的左方有问答信号,还有8位的iData,至于右方则是 TXD 顶层信号。此外,一帧数据的波特率为 115200 bps。

    1.    module tx_funcmod
    2.    (
    3.         input CLOCK, RESET,
    4.         output TXD,
    5.         input iCall,
    6.         output oDone,
    7.         input [7:0]iData
    8.    );
    9.         parameter B115K2 = 9'd434; // formula : ( 1/115200 )/( 1/50E+6 )     

    以上内容为相关的出入端声明,第9行则是波特率为115200的常量声明。

    11.         reg [3:0]i;
    12.         reg [8:0]C1;
    13.         reg [10:0]D1;
    14.         reg rTXD;
    15.         reg isDone;
    16.         
    17.         always @( posedge CLOCK or negedge RESET )
    18.             if( !RESET )
    19.                  begin
    20.                         i <= 4'd0;
    21.                         C1 <= 9'd0;
    22.                         D1 <= 11'd0;
    23.                         rTXD <= 1'b1; 
    24.                         isDone <= 1'b0;
    25.                  end

    以上内容为相关的寄存器声明以及复位操作。

    26.              else if( iCall )
    27.                  case( i )
    28.                    
    29.                         0:
    30.                         begin D1 <= { 2'b11 , iData , 1'b0 }; i <= i + 1'b1; end
    31.                         
    32.                         1,2,3,4,5,6,7,8,9,10,11:      
    33.                         if( C1 == B115K2 -1 ) begin C1 <= 8'd0; i <= i + 1'b1; end
    34.                         else begin rTXD <= D1[i - 1]; C1 <= C1 + 1'b1; end
    35.    
    36.                         12:
    37.                         begin isDone <= 1'b1; i <= i + 1'b1; end
    38.                         
    39.                         13:
    40.                         begin isDone <= 1'b0; i <= 4'd0; end
    41.                    
    42.                    endcase
    43.                        

    以上内容为部分核心操作。第26行的if( iCall ) 表示该模块不使能就不工作。步骤0用来准备发送数据,其中 2’b11 是停止位与校验位(随便填),1’b0则是起始位。步骤1~11用来发送一帧数据。步骤12~13用来反馈完成信号并返回步骤。

    44.        assign TXD = rTXD;
    45.        assign oDone = isDone;           
    46.    
    47.    endmodule

    以上内容为驱动输出的声明。

    tx_demo.v

    连线部署直接看代码比较具体一点。

    1.    module tx_demo
    2.    (
    3.         input CLOCK, RESET,
    4.         output TXD
    5.    );
    6.        wire DoneU1;

    以上内容是相关的出入端声明。

    8.        tx_funcmod U1
    9.         (
    10.              .CLOCK( CLOCK ),
    11.              .RESET( RESET ),
    12.              .TXD( TXD ),
    13.              .iCall( isTX ),
    14.              .oDone( DoneU1 ),
    15.             .iData( D1 )
    16.         );

    以上内容是TX功能模块的实例化,其中isCall由isTX驱动,iData由D驱动。

    18.         reg [3:0]i;
    19.         reg [7:0]D1;
    20.         reg isTX;
    21.         
    22.         always @ ( posedge CLOCK or negedge RESET )
    23.             if( !RESET )
    24.                  begin
    25.                         i <= 4'd0;
    26.                         D1 <= 8'd0;
    27.                         isTX <= 1'b0;
    28.                    end

    以上内容是相关的寄存器声明,第23~28行则是这些寄存器的复位操作。

    29.              else
    30.                  case( i )
    31.                    
    32.                        0:
    33.                         if( DoneU1 ) begin isTX <= 1'b0; i <= i + 1'b1; end
    34.                         else begin isTX <= 1'b1; D1 <= 8'hA1; end
    35.                         
    36.                         1:
    37.                         if( DoneU1 ) begin isTX <= 1'b0; i <= i + 1'b1; end
    38.                         else begin isTX <= 1'b1; D1 <= 8'hA2; end
    39.                         
    40.                         2:
    41.                         if( DoneU1 ) begin isTX <= 1'b0; i <= i + 1'b1; end
    42.                         else begin isTX <= 1'b1; D1 <= 8'hA3; end
    43.                         
    44.                         3: // Stop
    45.                         i <= i;
    46.                    
    47.                    endcase
    48.    
    49.    endmodule

    以上内容是核心操作的内容,步骤0发送数据 8’hA1,步骤1发送数据8’hA2,步骤2发送数据 8’hA3。

    编译完毕便下载程序,并且将串口线连接至电脑与开发板。打开串口调试助手,波特率设为115200,数据位为8,校验位随便,停止位为1位 ... 事后,显示方式设置为HEX(十六进制)。当程序下载完毕以后,串口调试助手便会出现 A1,A2与A3。

    细节一: 完整的个体模块

    实验十二的TX功能模块已经是完整的个体,可以直接拿来调用。

  • 相关阅读:
    ADB高级应用
    struts2 结合extjs实现的一个登录实例
    css3中关于伪类的使用
    漫谈并发编程(三):共享受限资源
    awk依照多个分隔符进行切割
    3星|《财经天下周刊》2017年21期:海外购几乎是亚马逊中国的最后一根救命稻草
    3星|《迷失的盛宴:中国保险产业1978-2014》:序言比正文精彩
    3星|《超级运营术》:互联网社区运营老手经验谈
    3星|《百年流水线》:流水线与工业、社会、艺术的交互史
    5星|戴蒙德《为什么有的国家富裕,有的国家贫穷》:为什么有的国家能发展出好制度
  • 原文地址:https://www.cnblogs.com/alinx/p/3985960.html
Copyright © 2020-2023  润新知