串口的简单收发实验

串口接收和发送两个独立模块的代码,接收到的信号连接到发送的模块信号,实现回环。

顶层:

module uart_eco(
    input wire rst,
    (*mark_debug="true"*)input wire clk,
    (*mark_debug="true"*)input wire rxd,
    (*mark_debug="true"*)output wire txd
);

(*mark_debug="true"*)wire [7:0] uart_data_wire_tx;
(*mark_debug="true"*)wire rx_flag;

usart_rx usart_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

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

module usart_tx(
    input wire clock,
    output wire txd,    //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;

//要发送的BIT选择
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

//发送bit计数
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

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

/* 代码包含模块输入时钟,接收信号线,复位信号,以及接收到的字节数据,以及接收有效标志。
当接收完一个字节,接收字节数据就有效,并且,接受有效信
号会拉高至少一个时钟周期 */
module usart_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;   //模块输入时钟 50M
parameter BADRATE = 115_200;    //串口波特率 115200
parameter UART_COUTER_MAX = CLOCK_FRQ / BADRATE;    //接收的比特计数器最大值
parameter UART_BIT = 8;     //串口比特数,我们用8BIT

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

//接收过程的BIT计数
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

//接收到一个比特,接收的字节寄存器每一个比特往前移位,采样点为BIT计数的一半点
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二炮

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值