基于Verilog的串口实验报告一、前言随着计系统和网络的快速发展,通信发挥的作用越来越重要。在电路设计和制作上越来越多的采用数字化指令,在一个系统内对外和内部通信越来越多。串行通信作为一种主要的通信方式,由于所用的传输线少,因此特别适合于远距离传送,应用非常广泛。FPGA(现场可编程门阵列)在数字电路的设计中已经被广泛使用。这种设计方式可以增强系统的可靠性和设计的灵活性。二、实验内容本实验使用Verilog编写rs232串口通信程序,利用波形仿真工具进行前仿真,下载到开发板,利用串口调试助手进行验证。本串口实现的功能是可以设置八种波特率,实现多字节的收发。实验芯片选择xilinx的spartan6系列,编译软件使用xilinx专用的ise14.1,仿真工具使用ise自带工具isim。三、实验过程(1)、分模块编写代码,本次设计共有四个模块,分别是串口接收波特率产生模块,串口接收模块,串口发送波特率产生模块,串口发送模块。以下是各模块之间的联系图:由图所示,顶层各端口功能如下Key_in按键选择波特率端口Clk时钟输入端口Rst_n复位端口Rs232_rx数据接收端口Rs232_tx数据发出端口顶层文件主要用于连接以下各个模块接收数据波特率产生模块端口功能如下Key_in按键选择波特率端口Bps_start启动波特率发生模块Clk时钟端口Rst_n复位端口Sample_clk波特率时钟输出端口本模块的作用主要用于产生所需的波特率,共有八种选择,本模块的内部又有以下几个部分:1、波特率选择部分:这一部分主要通过按键输入控制波特率,由case语句完成2、波特率时钟计数部分:这一部分主要是通过计数器对输入时钟进行分频来达到所需的波特率。3、波特率时钟产生部分:这一部分用来产生连接下一模块的波特率时钟。串口接收模块Clk时钟端口Rst_n复位端口Rs232_rx数据输入端口Sample_clk波特率时钟输入端口Rx_data数据存储寄存器Bps_start启动波特率发生模块端口Rx_int发送模块使能端口本模块的作用主要是根据波特率时钟产生模块所产生的波特率,进行数据的接收,包含如下几个部分1、检测数据开始位:这一部分主要依据数据帧的起始位为0这一设置,通过检测下降沿来检测数据的开始位,当检测到下降沿后,发出一系列开始接收数据的信号。2、数据接收部分:这一部分主要通过波特率来采样数据,每一个数据采样九次,选取其中的三次经过加和来判断本位是0还是1。3、数据存储部分:这一部分主要把接收到的数据存储到设定的寄存器中,以便发送。串口发送波特率产生模块Key_in按键选择波特率端口Bps_start启动波特率发生模块(由串口发送模块产生)Clk时钟端口Rst_n复位端口Sample_clk波特率时钟输出端口本模块的作用主要用于产生所需的波特率,共有八种选择,本模块的内部又有以下几个部分:1、波特率选择部分:这一部分主要通过按键输入控制波特率,由case语句完成2、波特率时钟计数部分:这一部分主要是通过计数器对输入时钟进行分频来达到所需的波特率。3、波特率时钟产生部分:这一部分用来产生连接下一模块的波特率时钟。串口发送模块Clk时钟端口Rst_n复位端口Rs232_tx数据输出端口Clk_bps波特率时钟输入端口Rx_data数据存储寄存器Bps_start启动波特率发生模块端口Rx_int发送模块使能端口(由串口接收模块产生)这一模块分为以下几个部分:1,、检测发送使能信号部分:这一部分通过检测下降沿来识别发送使能信号,并产生一系列的发送开始信号。2、发送帧部分:这一部分主要将之前存储在寄存器中的数据逐位发送出去,并加入开始位0,与结束位1,构成一帧十位数据。通过对各个模块的了解,分别编写各个模块的代码(2)、修改程序,编写仿真程序。由于本次实验代码量较小,仿真时采用ise自带的波形仿真工具即可完成仿真,仿真图如下波形为任意两帧数据的接收与发送,可以看出连续两帧数据接收与发送并没有发生错误。(3)、将程序下载到芯片,结合串口助手进行验证。四、实验代码顶层代码:moduleuart_top(clk,rst_n,rs232_rx,rs232_tx,key_in);inputclk;//时钟信号50Minputrst_n;//复位信号,低有效inputrs232_rx;//数据输入信号input[2:0]key_in;outputrs232_tx;//数据输出信号//wire[2:0]key_in;wiresample_clk1;wirebps_start1,bps_start2;//wireclk_bps1,clk_bps2;wire[7:0]rx_data;//接收数据存储器,用来存储接收到的数据,直到下一个数据接收wirerx_int;//接收数据中断信号,接收过程中一直为高,/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////子模块端口申明///////////////////////////////////speed_select_rxspeed_rx(//数据接收波特率选择模块.clk(clk),.rst_n(rst_n),.bps_start(bps_start1),.sample_clk(sample_clk1),//这一个时钟是九分之一波特率时钟.key_in(key_in)//用来选择波特率);uart_rxuart_rx(//数据接收模块.clk(clk),.rst_n(rst_n),.bps_start(bps_start1),//这一个信号用来控制波特率发生器的开启,当检测到输入数据中的下降沿后,开始波特率计数.sample_clk(sample_clk1),.rs232_rx(rs232_rx),//数据输入端口.rx_data(rx_data),//数据输入后存储寄存器.rx_int(rx_int)//这一信号用来表示数据接收完成,接受过程是高,接收完成后变为低,发送模块用此信号来判断是否可以发送);speed_select_txspeed_tx(//数据发送波特率控制模块.clk(clk),.rst_n(rst_n),.bps_start(bps_start2),//.clk_bps(clk_bps2),//发送数据波特率生成端口.key_in(key_in));uart_txuart_tx(.clk(clk),.rst_n(rst_n),.bps_start(bps_start2),//当检测到int下降沿以后开始启动.clk_bps(clk_bps2),.rs232_tx(rs232_tx),//接收数据存储寄存器.rx_data(rx_data),.rx_int(rx_int)//这个是波特率开始发送的标志,由串口接收模块产生);endmodule接收模块波特率发生器:modulespeed_select_rx(clk,rst_n,bps_start,key_in,sample_clk);//波特率设定inputclk;//50M时钟inputrst_n;//复位信号inputbps_start;input[2:0]key_in;//接收到信号以后,波特率时钟信号置位,当接收到uart_rx传来的信号以后,模块开始运行//outputclk_bps;//接收数据中间采样点,outputsample_clk;//`defineBPS_PARA5207;//9600波特率分频计数值//`defineBPS_PARA_22603;//计数一半时采样regsample_clk;reg[13:0]cnt;//分频计数器regclk_bps_r;//波特率时钟寄存器reg[13:0]cntt;parametersystem_clk=50_000_000;/*输入时钟频率设定,默认50M*/localparambps9600=system_clk/9600/9-1;localparambps19200=system_clk/19200/9-1;localparambps38400=system_clk/38400/9-1;localparambps57600=system_clk/57600/9-1;localparambps115200=system_clk/115200/9-1;localparambps230400=system_clk/230400/9-1;localparambps460800=system_clk/460800/9-1;localparambps921600=system_clk/921600/9-1;/**************选择波特率部分程序*************************/always@(posedgeclkornegedgerst_n)if(!rst_n)begincntt=bps9600;/*复位时波特率默认为9600bps*/endelsebegincase(key_in)/*根据波特率控制信号选择不同的波特率计数器计数最大值*/3'd0:cntt=bps9600;3'd1:cntt=bps19200;3'd2:cntt=bps38400;3'd3:cntt=bps57600;3'd4:cntt=bps115200;3'd5:cntt=bps230400;3'd6:cntt=bps460800;3'd7:cntt=bps921600;default:cntt=bps9600;endcaseend/***********波特率时钟计数器工作***************************/always@(posedgeclkornegedgerst_n)beginif(!rst_n)cnt=13'd0;elseif((cnt==cntt)||!bps_start)//判断计数是否达到1个脉宽cnt=13'd0;elsecnt=cnt+1'b1;//波特率时钟启动end/****************产生波特率时钟************************************/always@(posedgeclkornegedgerst_n)beginif(!rst_n)sample_clk=0;elseif(cnt==1)sample_clk=1;elsesample_clk=0;endendmodule接收模块:moduleuart_rx(clk,rst_n,bps_start,sample_clk,rs232_rx,rx_data,rx_int);inputclk;//时钟inputrst_n;//复位inputrs232_rx;//接收数据信号inputsample_clk;//九倍波特率采样点outputbps_start;//接收信号时,波特率时钟信号置位output[7:0]rx_data;//接收数据寄存器outputrx_int;//接收数据中断信号,接收过程中为高regrs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;//接收数据寄存器reg[7:0]rx_data;reg[1:0]Data_Tmp[7:0];regrx_int;wireneg_rs232_rx;//表示数据线接收到下沿/*****************检测下降沿******************************/always@(posedgeclkornegedgerst_n)beginif(!rst_n)beginrs232_rx0=1'b0;rs232_rx1=1'b0;rs232_rx2=1'b0;rs232_rx3=1'b0;endelsebeginrs232_rx0=rs2