【小眼睛科技紫光盘古50K开发板试用体验】串口回环实验 - FPGA开发者技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

[文章]

【小眼睛科技紫光盘古50K开发板试用体验】串口回环实验

  串口通信是将并行数据转换为串行数据进行传输,常见的电平信号有TTL、RS-232、RS-485。盘古50K使用的是CP2102芯片,可以直接通过USB接口与PC进行串口通信。
image.png
对于我们常用的CH340芯片,CP2102在学习时使用的较少。因此第一步是对其驱动进行安装。
CP210x USB to UART Bridge VCP Drivers - Silicon Labs (silabs.com)
驱动直接在官网下载即可,之后直接点开进行安装。
之后便是串口通信的verilog代码。分为发送和接收两个部分。
(1)发送模块
`

module uart_tx
(
    input   wire        sys_clk,
    input   wire        sys_rst_n,
    input   wire [7:0]  tx_data,
    input   wire        tx_flag,

    output  reg         tx
);
parameter BAUD_CNT_MAX = 16'd5028;
reg         work_en;
reg  [15:0] baud_cnt;
reg         bit_flag;
reg  [3:0]  bit_cnt;
//work_en
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        work_en <= 1'b0;
    else if(tx_flag == 1'b1)
        work_en <= 1'b1;
    else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        work_en <= 1'b0;

//baud_cnt
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        baud_cnt <= 16'b0;
    else if((work_en == 1'b1) && (baud_cnt<= BAUD_CNT_MAX - 1'b1))
        baud_cnt <= baud_cnt + 1'b1;
    else 
        baud_cnt <= 16'b0;

//bit_flag
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bit_flag <= 1'b0;
    else if(baud_cnt == 1'b1)
        bit_flag <= 1'b1;
    else 
        bit_flag <= 1'b0;

//bit_cnt
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bit_cnt <= 4'b0;
    else if((bit_flag == 1'b1) && (bit_cnt <= 4'd8))
        bit_cnt <= bit_cnt + 1'b1;
    else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        bit_cnt <= 4'b0;

//tx
always @(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        tx <= 1'b1;
    else if((bit_flag == 1'b1) && (bit_cnt == 4'd0))
        tx <= 1'b0;
    else if((bit_flag == 1'b1) && (bit_cnt >= 4'd1) && (bit_cnt <= 4'd8))
        tx <= tx_data[bit_cnt - 1];
    else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        tx <= 1'b1;

endmodule

(2)接收模块
`

module uart_rx
(
    input   wire        sys_clk,
    input   wire        sys_rst_n,
    input   wire        rx,
    output  reg  [7:0]  rx_data,
    output  reg         rx_flag
);

parameter BAUD_CNT_MAX = 16'd5028;

reg         reg1;            //时钟同步
reg         reg2;            //消除亚稳态
reg         reg3;            //消除亚稳态
reg         start_flag;      //串口数据开始
reg         work_en;         //数据处理使能
reg [15:0]  baud_cnt;        //波特率计数
reg         bit_flag;        //波特率计数字节标志
reg [3:0]   bit_cnt;         //字节计数
reg [7:0]   rx_data_temp;    //数据中转 
reg         rx_flag_temp;    //接收标志中转
//reg1
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        reg1 <= 1'b1;
    else 
        reg1 <= rx;
//reg2
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        reg2 <= 1'b1;
    else 
        reg2 <= reg1;
//reg3
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        reg3 <= 1'b1;
    else 
        reg3 <= reg2;
//start_flag
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        start_flag <= 1'b0;
    else if((reg2 == 1'b0) && (reg3 == 1'b1))
        start_flag <= 1'b1;
    else 
        start_flag <= 1'b0;
//work_en
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        work_en <= 1'b0;
    else if((reg3 == 1'b0) && (start_flag == 1'b1))
        work_en <= 1'b1;
    else if((bit_cnt == 4'd9) && (bit_flag == 1'b1))
        work_en <= 1'b0;

//baud_cnt
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        baud_cnt <= 16'b0;
    else if((work_en == 1'b1) && (baud_cnt <= BAUD_CNT_MAX - 1'b1))
        baud_cnt <= baud_cnt + 1'b1;
    else 
        baud_cnt <= 16'b0;

//bit_flag
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        bit_flag <= 1'b0;
    else if(baud_cnt == (BAUD_CNT_MAX >> 1))
        bit_flag <= 1'b1;
    else 
        bit_flag <= 1'b0;

//bit_cnt
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        bit_cnt <= 4'b0;
    else if(bit_flag == 1'b1)
        bit_cnt <= bit_cnt + 1'b1;
    else if(bit_cnt >= 4'd10)
        bit_cnt <= 4'b0;

//rx_data_temp
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        rx_data_temp <= 8'b0;
    else if((bit_flag == 1'b1) && (bit_cnt >= 4'd1) && (bit_cnt <= 4'd8))
        rx_data_temp <= {reg3,rx_data_temp[7:1]};

//rx_flag_temp
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        rx_flag_temp <= 1'b0;
    else if((bit_cnt == 4'd9) && (bit_flag == 1'b1))
        rx_flag_temp <= 1'b1;
    else 
        rx_flag_temp <= 1'b0;

//rx_data
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        rx_data <= 8'b0;
    else if(rx_flag_temp == 1'b1)
        rx_data <= rx_data_temp;

//rx_flag
always @(posedge sys_clk or negedge sys_rst_n) 
    if(!sys_rst_n)
        rx_flag <= 1'b0;
    else if(rx_flag_temp == 1'b1)
        rx_flag <= 1'b1;
    else 
        rx_flag <= 1'b0; 


endmodule

(3)顶层模块
串口回环实验就是将串口所接收到的数据再发送出去,因此顶层模块就是将接收模块和发送模块串联起来。
`

module rs232
(
    input   wire        sys_clk,
    input   wire        sys_rst_n,
    input   wire        rx,
    output  wire        tx
);

wire [7:0]      rx_data;
wire            rx_flag;          

uart_rx uart_rx_inst
(
    .sys_clk    (sys_clk    ),
    .sys_rst_n  (sys_rst_n  ),
    .rx         (rx         ),
    .rx_data    (rx_data    ),
    .rx_flag    (rx_flag    )
);
    
uart_tx uart_tx_inst
(
    .sys_clk    (sys_clk    ),
    .sys_rst_n  (sys_rst_n  ),
    .tx_data    (rx_data    ),
    .tx_flag    (rx_flag    ),
    .tx         (tx         )
);

endmodule

查看RTL视图
image.png
和预期结构相吻合,再通过仿真验证。
先编写仿真文件
`

`timescale 1ns/1ns

module tb_rs232();
    
reg         sys_clk;
reg         sys_rst_n;
reg         rx;

wire        tx;

initial begin
    sys_clk <= 1'b0;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
end

always #10 sys_clk <= ~sys_clk;

initial begin
    #200
    rx_task(8'd0);
    rx_task(8'd1);
    rx_task(8'd2);
    rx_task(8'd3);
    rx_task(8'd4);
    rx_task(8'd5);
    rx_task(8'd6);
    rx_task(8'd7);
    rx_task(8'd8);
    rx_task(8'd9);
end

task rx_task
(
    input [7:0]     rx_data
);
    integer i;
    for(i=0;i<10;i=i+1)
        begin
            case (i)
                0: rx <= 1'b0;
                1: rx <= rx_data[0];
                2: rx <= rx_data[1];
                3: rx <= rx_data[2];
                4: rx <= rx_data[3];
                5: rx <= rx_data[4];
                6: rx <= rx_data[5];
                7: rx <= rx_data[6];
                8: rx <= rx_data[7];
                9: rx <= 1'b1;
            endcase
            #(5028*20);
        end

endtask

rs232 rs232_inst
(
    .sys_clk    (sys_clk    ),
    .sys_rst_n  (sys_rst_n  ),
    .rx         (rx         ),
    .tx         (tx         )
);

endmodule

使用ModelSim进行仿真,得到仿真波形
image.png
通过下载验证,观察现象
image.png
发送数据与接收数据一致,符合实验要求

更多回帖

×
发帖