使用FPGA做串口收发实验

yummy 阅读:1150 2022-05-02 12:59:11 评论:0

一、实验目的

使用全双工串口通过时钟分频,产生串口波特率时钟,然后通过起始、结束比特位控制一个字节数据的收发。

二、Vivado工程新建

image.png

三、串口时序简介

通信原理:通过一根总线发送到接收端

image.png

通信过程:空闲,信号初始为高,然后开始拉低一定时间,产生起始信号,然后依次送出地位到高位的BIT数据。

image.png

波特率:波特率决定了通信的快慢。比如115200波特率,表示每秒钟产生115200个bit的速率进行传输。

四、代码讲解

顶层模块

//////////////////////////////////////////////////////////////////////////////////

// Company: 

// Engineer: yu meng ya 

// 

// Create Date: 2022/05/02 13:52:28

// Design Name: 串口收发实验

// Module Name: uart_eco

// Project Name:fpga_uart_eco 

// Target Devices: 

// Tool Versions: 

// Description: 

// 

// Dependencies: 

// 

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

// 

//////////////////////////////////////////////////////////////////////////////////

module uart_eco(

input wire rst,

input wire clk,

input wire rxd,

output wire txd

);

wire [7:0]uart_data_wire_tx;

wire rx_flag;


    wire [19:0]ila_probe0;

    

    assign ila_probe0[0]=rxd;

    assign ila_probe0[1]=txd;   

    assign ila_probe0[2]=rx_flag;   

    assign ila_probe0[10:3]=uart_data_wire_tx[7:0];   

    assign ila_probe0[19:11]='b0;          


    ila_0 ila_0_inst

    (

    .clk(clk),

    .probe0(ila_probe0)

    );



usart_rxusart_rx_inst(

.clock(clk),

.rxd(rxd),

.rst_n(rst),

.rx_data_byte(uart_data_wire_tx),

.rx_valid_wire(rx_flag)

  );

 usart_tx   usart_tx_inst(

.clock(clk),

.txd(txd),

.rst_n(rst),

.tx_data_byte(uart_data_wire_tx),

.tx_triger_flag(rx_flag)

);

endmodule

串口接收模块代码,代码包含模块输入时钟,接收信号线,复位信号,以及接收到的字节数据,以及接收有效标志。当接收完一个字节,接收字节数据就有效。并且,接受有效信号会拉高至少一个时钟周期。

首先,串口平时空闲,rx信号一直为高。当有数据来临时,信号拉低,持续一个波特率的周期为低,这个比特是起始位。我们的一个字节接收rx_start_flag标志在这个时候就置为1,表示正在接收这个字节了。然后,这个标志位1的时候,我们bit接收计数器就开始计数,从0计数到一个波特率周期最大值,然后清零,再次计数。计数到最大值的一半,即为采样时刻,这个时候我们就把rx值读过来,放到一个8bit移位寄存器。接收8bit数据需要9次计数周期,为什么是9次呢?因为起始位也算一个bit。起始bit不会把数据读来放到接收移位寄存器,所以数据开始接收存储到移位寄存器是从第二位开始的。

//////////////////////////////////////////////////////////////////////////////////

// Company: 

// Engineer: yu meng ya 

// 

// Create Date: 2022/05/02 14:08:25

// Design Name: 串口接收模块

// Module Name: uart_rx

// Project Name: fpga_uart_ec

// Target Devices: 

// Tool Versions: 

// Description: 

// 

// Dependencies: 

// 

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

// 

//////////////////////////////////////////////////////////////////////////////////

module uart_rx(

input wire clock,

input wire rxd,

input wire rst_n,

output wire [7:0]rx_data_byte,

output wire rx_valid_wire

);

parameter CLOCK_FRQ=50_000_000;

parameter BADRATE =115_200;

parameter UART_COUTER_MAX=CLOCK_FRQ/BADRATE;

parameter UART_BIT =8;


reg [7:0]rx_data_byte_reg;

reg rx_start_flag;

reg [19:0]rx_counter;

reg [19:0]baud_counter;

reg baud_rat_clk;


reg rxd_reg1;

reg rxd_reg2;

reg rxd_reg3;

wire rxd_negedge;

reg [7:0]rx_bit_cnt;

reg [7:0]rx_data;

reg rx_valid_flag_pre1;

reg rx_valid_flag_pre2;

wire rx_valid_flag;



assign rx_valid_wire=rx_valid_flag_pre2;


assign rx_valid_flag=(rx_bit_cnt==9)?1:0;

assign rxd_negedge=~rxd_reg2&rxd_reg3;


assign rx_data_byte=rx_data_byte_reg;

assign clk_badrate=baud_rat_clk;

always @(posedge clock)

begin

rxd_reg1<=rxd;

rxd_reg2<=rxd_reg1;

rxd_reg3<=rxd_reg2;

end


always @(posedge clock or negedge rst_n)

begin

if(rst_n==0)

begin

baud_counter<=0;

baud_rat_clk=0;

end

else begin

rx_valid_flag_pre2<=rx_valid_flag_pre1;

rx_valid_flag_pre1=rx_valid_flag;

baud_counter<=baud_counter+1;

if(baud_counter==UART_COUTER_MAX)

begin

baud_counter<=0;

baud_rat_clk<=~baud_rat_clk;

end

end

end



always @(posedge clock or negedge rst_n)

begin

if(rst_n==0)rx_counter<=0;

else begin

if(rx_start_flag==1)

begin

rx_counter<=rx_counter+1;

if(rx_counter==UART_COUTER_MAX)rx_counter<=0;

end

end

end


always @(posedge clock or negedge rst_n)

begin

if(rst_n==0)rx_bit_cnt<=0;

else 

begin

if(rx_counter==UART_COUTER_MAX)

begin

rx_bit_cnt<=rx_bit_cnt+1;

end

if(rx_bit_cnt==UART_BIT+1)rx_bit_cnt<=0;

if(rx_bit_cnt==UART_BIT+1)rx_data_byte_reg<=rx_data;

end

end



always @(posedge clock  or negedge rst_n)

begin

if(rst_n==0)

begin

rx_data<=0;

end

else begin

if(rx_counter==UART_COUTER_MAX/2)

begin

if((rx_bit_cnt>=1)&&(rx_bit_cnt<UART_BIT+1))

begin

rx_data<={rxd,rx_data[7:1]};

end

end

end

end


always @(posedge clock  or negedge rst_n)

begin

if(rst_n==0)

begin

rx_start_flag<=0;

end

else 

begin

if(rxd_negedge==1)rx_start_flag<=1;

else if(rx_bit_cnt==UART_BIT+1)rx_start_flag<=0;

end

end


endmodule

发送部分代码

发送代码比接收简单。就是需要发送的数据,当发送触发为1,则触发发送。波特率计数器开始计数,先产生一个bit起始拉低信号,然后依次将8bit数据移位发送出去,最后回到空闲状态。

module usart_tx(

input wire clock,

output wire txd,

input wire rst_n,

input wire [7:0]tx_data_byte,

input wire tx_triger_flag

);

parameter CLOCK_FRQ=50_000_000;

parameter BADRATE =115_200;

parameter UART_COUTER_MAX=CLOCK_FRQ/BADRATE;

parameter UART_BIT =8;



reg [7:0]tx_bit_cnt_reg;

reg [19:0]tx_counter;

reg [19:0]baud_counter;


reg txd_reg;

reg tx_start_flag;

assign txd=txd_reg;


always @(posedge clock)


begin

  if(tx_start_flag==1)

    begin     

case (tx_bit_cnt_reg)

0:txd_reg<=0;

1:txd_reg<=tx_data_byte[0];

2:txd_reg<=tx_data_byte[1];

3:txd_reg<=tx_data_byte[2]; 

4:txd_reg<=tx_data_byte[3]; 

5:txd_reg<=tx_data_byte[4];  

6:txd_reg<=tx_data_byte[5];  

7:txd_reg<=tx_data_byte[6];  

8:txd_reg<=tx_data_byte[7];  

9:txd_reg<=1; 

default:txd_reg<=1;  

     endcase 

  end

 else txd_reg<=1;

end


always @(posedge tx_triger_flag or posedge clock)

begin

if(tx_triger_flag==1)tx_start_flag<=1;

else begin

if(tx_bit_cnt_reg==UART_BIT+1)tx_start_flag<=0;

end

end


always @(posedge clock or negedge rst_n)

begin

if(rst_n==0)

begin

tx_counter<=0;

end

else begin

if(tx_start_flag==1)begin

if(tx_counter<UART_COUTER_MAX)tx_counter<=tx_counter+1;

else begin

tx_counter<=0;

end

end

end

end


always @(posedge clock or negedge rst_n)

begin

if(rst_n==0)

begin

tx_bit_cnt_reg<=0;

end

else begin

if(tx_counter==UART_COUTER_MAX)

begin

if(tx_bit_cnt_reg<UART_BIT+1)tx_bit_cnt_reg<=tx_bit_cnt_reg+1;

end   

else begin    

if(tx_bit_cnt_reg==UART_BIT+1)tx_bit_cnt_reg<=0;

end 

end

end


endmodule




本文 zblog模板 原创,转载保留链接!网址:http://www.xn--zqqs03dbu6a.cn/?id=47

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。