赞
踩
重点关注RXD、TXD即可。
帧结构:包含8bit有效数据和起始位、停止位。空闲状态是高电平,起始位低电平,停止位高电平。低位数据先发,后发高位。
假设我要传输字符“1”,对应的ASCII码值是0x31,即“0011 0001” ,低位先发,那么我的这帧数据波形为 0 1000 1100 1
波特率:假设波特率为9600Bps,传输一个码元(一个码元在这里代表一个二进制数,就是1bit数据)需要1/9600秒。假设系统时钟50MHz(周期为20ns),那么传输1bit数据所需的时间为 (1/9600)/(20*e-9) = 5208.33 ≈ 5208 个时钟周期。
产生原因:
触发器采集输入信号时需要一定的建立时间和保持时间,如果在这一期间输入信号发生变化,那么触发器将无法稳定输出,导致输出信号在高低电平间快速振荡,即进入亚稳态。
不良影响:
如果处于亚稳态的信号直接接入组合逻辑电路,会导致亚稳态在整个系统中传递,从而影响整个电路的运行,导致不稳定。
解决方案:
单比特信号可以采用“打两拍”,多比特信号可以采用异步FIFO、格雷码、握手。
输入输出描述:
示意时序图,以9600波特率为例。
时序图分析:
module RS232_RX #( parameter UART_BPS = 'd9600, parameter CLK_FREQ = 'd50_000_000 ) ( input wire clk, input wire rst, input wire rx, output reg [7:0] data, output reg flag ); parameter BAUD_CNT_MAX = CLK_FREQ / UART_BPS; reg rx_reg1; reg rx_reg2; reg rx_reg3; wire start_flag; reg work_en; reg [16:0] baud_cnt; reg bit_flag; reg [3:0] bit_cnt; reg [7:0] rx_data; reg data_flag; // 赋值rx_reg1 always@(posedge clk or posedge rst) begin if(rst == 1'b1) rx_reg1 <= 1'b1; else rx_reg1 <= rx; end // 赋值rx_reg2 always@(posedge clk or posedge rst) begin if(rst == 1'b1) rx_reg2 <= 1'b1; else rx_reg2 <= rx_reg1; end // 赋值rx_reg3 always@(posedge clk or posedge rst) begin if(rst == 1'b1) rx_reg3 <= 1'b1; else rx_reg3 <= rx_reg2; end // 赋值start_flag assign start_flag = ((rx_reg2 == 1'b0) && (rx_reg3 == 1'b1)); // 赋值work_en always@(posedge clk or posedge rst) begin if(rst == 1'b1) work_en <= 1'b0; else if(start_flag == 1'b1) work_en <= 1'b1; else if((bit_flag == 1'b1) && (bit_cnt == 4'd8)) work_en <= 1'b0; else work_en <= work_en; end // 赋值baud_cnt always@(posedge clk or posedge rst) begin if(rst == 1'b1) baud_cnt <= 17'b0; else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0)) baud_cnt <= 17'b0; else baud_cnt <= baud_cnt + 1'b1; end // 赋值bit_flag always@(posedge clk or posedge rst) begin if(rst == 1'b1) bit_flag <= 1'b0; else if(baud_cnt == BAUD_CNT_MAX / 2 - 1) bit_flag <= 1'b1; else bit_flag <= 1'b0; end // 赋值bit_cnt always@(posedge clk or posedge rst) begin if(rst == 1'b1) bit_cnt <= 4'b0; else if((bit_flag == 1'b1) && (bit_cnt == 4'd8)) bit_cnt <= 4'b0; else if(bit_flag == 1'b1) bit_cnt <= bit_cnt + 1'b1; else bit_cnt <= bit_cnt; end // 赋值rx_data always@(posedge clk or posedge rst) begin if(rst == 1'b1) rx_data <= 8'b0; else if((bit_cnt >= 4'd1) && (bit_cnt <= 4'd8) && (bit_flag == 1'b1)) rx_data <= {rx_reg3,rx_data[7:1]}; else rx_data <= rx_data; end // 赋值data_flag always@(posedge clk or posedge rst) begin if(rst == 1'b1) data_flag <= 1'b0; else if((bit_flag == 1'b1) && (bit_cnt == 4'd8)) data_flag <= 1'b1; else data_flag <= 1'b0; end // 赋值data always@(posedge clk or posedge rst) begin if(rst == 1'b1) data <= 8'd0; else if(data_flag == 1'b1) data <= rx_data; else data <= data; end // 赋值flag always@(posedge clk or posedge rst) begin if(rst == 1'b1) flag <= 1'b0; else flag <= data_flag; end endmodule
如果数据是多位的,赋值时需要注意其位宽大小。如果一个多位宽的数据赋值为“1’b0”,这将只赋值给这个数据的最低位,其他位将保留原值,与本意相悖。
`timescale 1ns / 1ps module tb_RS232_RX(); reg clk; reg rst; reg rx; wire [7:0] data; wire flag; // 初始化clk和rst initial begin clk <= 1'b0; rst <= 1'b1; #60; rst <= 1'b0; end always #10 clk = ~clk; // 初始化rx initial begin rx <= 1'b1; #100; rx_bit(8'b1001_0001); rx_bit(8'b0101_0010); rx_bit(8'b1110_0101); rx_bit(8'b0110_1000); rx_bit(8'b0110_1011); rx_bit(8'b0011_0110); rx_bit(8'b0001_1110); end // rx_bit函数,生成串行数据 task rx_bit( 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 #(5208*20); end endtask // 实例化模块 RS232_RX #( .UART_BPS(9600), .CLK_FREQ(50_000_000) )tb_RS232_RX ( .clk (clk ), .rst (rst ), .rx (rx ), .data (data ), .flag (flag ) ); endmodule
输入输出描述:
示意时序图,以9600波特率为例。
时序图分析:
module RS232_TX #( parameter UART_BPS = 'd9600, parameter CLK_FREQ = 'd50_000_000 ) ( input wire clk, input wire rst, input wire [7:0] data, input wire flag, output reg tx ); parameter BAUD_CNT_MAX = CLK_FREQ / UART_BPS; reg work_en; reg [16:0] baud_cnt; reg bit_flag; reg [3:0] bit_cnt; // 赋值work_en always@(posedge clk or posedge rst) begin if(rst == 1'b1) work_en <= 1'b0; else if(flag == 1'b1) work_en <= 1'b1; else if((bit_flag == 1'b1) && (bit_cnt == 4'd10)) work_en <= 1'b0; else work_en <= work_en; end // 赋值baud_cnt always@(posedge clk or posedge rst) begin if(rst == 1'b1) baud_cnt <= 17'b0; else if((baud_cnt == BAUD_CNT_MAX - 1'b1) || (work_en == 1'b0)) baud_cnt <= 17'b0; else baud_cnt <= baud_cnt + 1'b1; end // 赋值bit_flag always@(posedge clk or posedge rst) begin if(rst == 1'b1) bit_flag <= 1'b0; else if(baud_cnt == 17'b1) bit_flag <= 1'b1; else bit_flag <= 1'b0; end // 赋值bit_cnt always@(posedge clk or posedge rst) begin if(rst == 1'b1) bit_cnt <= 4'b0; else if((bit_flag == 1'b1) && (bit_cnt == 4'd10)) bit_cnt <= 4'b0; else if(bit_flag == 1'b1) bit_cnt <= bit_cnt + 1'b1; else bit_cnt <= bit_cnt; end // 赋值tx always@(posedge clk or posedge rst) begin if(rst == 1'b1) tx <= 1'b1; else begin case(bit_cnt) 4'd1: tx <= 1'b0; 4'd2: tx <= data[0]; 4'd3: tx <= data[1]; 4'd4: tx <= data[2]; 4'd5: tx <= data[3]; 4'd6: tx <= data[4]; 4'd7: tx <= data[5]; 4'd8: tx <= data[6]; 4'd9: tx <= data[7]; 4'd10: tx <= 1'b1; default: tx <= 1'b1; endcase end end endmodule
`timescale 1ns / 1ps module tb_RS232_TX(); reg clk; reg rst; reg [7:0] data; reg flag; wire tx; // 初始化clk和rst initial begin clk <= 1'b0; rst <= 1'b1; #60; rst <= 1'b0; end always #10 clk = ~clk; // 初始化data和flag initial begin data <= 8'd0; flag <= 1'd0; #200; // 数据1 data <= 8'b0010_1011; flag <= 1'd1; #20; flag <= 1'd0; #(5208*12*20); // 数据2 data <= 8'b0111_0101; flag <= 1'd1; #20; flag <= 1'd0; #(5208*12*20); // 数据3 data <= 8'b1010_0001; flag <= 1'd1; #20; flag <= 1'd0; #(5208*12*20); end // 实例化模块 RS232_TX #( .UART_BPS(9600), .CLK_FREQ(50_000_000) )tb_RS232_TX ( .clk (clk), .rst (rst), .data (data), .flag (flag), .tx (tx) ); endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。