与恶魔做交易的网站,深圳龙岗建网站公司,农产品电子商务网站建设,做网站购买模板目录 简介接口与引脚通信协议亚稳态RS232接收模块模块框图时序波形RTL 代码易错点Testbench 代码仿真 RS232发送模块模块框图时序波形RTL 代码Testbench 代码仿真 简介
UART#xff1a;Universal Asynchronous Receiver/Transmitter#xff0c;异步串行通信接口。发送数据时… 目录 简介接口与引脚通信协议亚稳态RS232接收模块模块框图时序波形RTL 代码易错点Testbench 代码仿真 RS232发送模块模块框图时序波形RTL 代码Testbench 代码仿真 简介
UARTUniversal Asynchronous Receiver/Transmitter异步串行通信接口。发送数据时并行转串行接收数据时串行转并行。RS232UART包括多种接口标准规范和总线标准规范RS232为其一还有RS499、RS423、RS422、RS485等。
接口与引脚 重点关注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、格雷码、握手。
RS232接收模块
模块框图 输入输出描述
时钟50MHz每10ns翻转一次复位高电平异步复位RX接收的串口数据DATA处理后的数据并行输出FLAG置高时代表已处理好一帧数据只维持一个时钟周期
时序波形
示意时序图以9600波特率为例。 时序图分析
RX_REG RX_REG1是将 RX 同步到时钟信号上。RX_REG2、3打两拍避免亚稳态。 START_FLAG 标志数据接收的开始、WORK_EN 标志数据接收的状态 START_FLAG这里使用的是组合方式赋值通过 RX_REG2、3 检测 RX_REG 的下降沿。由于 RX_REG 的数据位中也有可能存在下降沿所以 START_FLAG 置高的前提条件还应有 WORK_EN 为 0 。WORK_ENWORK_EN 通过判断 START_FLAG 的状态而置高通过判断 BIT_CNT、BIT_FLAG 的状态而置低其余时刻保持不变。 BAUD_CNT、BIT_FLAG BAUD_CNTBAUD_CNT 只在 WORK_EN 为高时计数BIT_FLAG在每比特数据传输时的中间时刻拉高 RX_DATA 由于是低位数据先发所以 RX_REG 的数据存在 RX_DATA 的高位每次更新时 RX_DATA 右移实现数据的串行转并行。RX_DATA 的值在 BAUD_CNT 为 1-8 并且 BIT_FLAG 为高时采集 RX_REG。
RTL 代码
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_reg1always(posedge clk or posedge rst) beginif(rst 1b1)rx_reg1 1b1;elserx_reg1 rx;end// 赋值rx_reg2always(posedge clk or posedge rst) beginif(rst 1b1)rx_reg2 1b1;elserx_reg2 rx_reg1;end// 赋值rx_reg3always(posedge clk or posedge rst) beginif(rst 1b1)rx_reg3 1b1;elserx_reg3 rx_reg2;end// 赋值start_flagassign start_flag ((rx_reg2 1b0) (rx_reg3 1b1));// 赋值work_enalways(posedge clk or posedge rst) beginif(rst 1b1)work_en 1b0;else if(start_flag 1b1)work_en 1b1;else if((bit_flag 1b1) (bit_cnt 4d8))work_en 1b0;elsework_en work_en;end// 赋值baud_cntalways(posedge clk or posedge rst) beginif(rst 1b1)baud_cnt 17b0;else if((baud_cnt BAUD_CNT_MAX - 1) || (work_en 1b0))baud_cnt 17b0;elsebaud_cnt baud_cnt 1b1;end // 赋值bit_flagalways(posedge clk or posedge rst) beginif(rst 1b1)bit_flag 1b0;else if(baud_cnt BAUD_CNT_MAX / 2 - 1)bit_flag 1b1;elsebit_flag 1b0;end // 赋值bit_cntalways(posedge clk or posedge rst) beginif(rst 1b1)bit_cnt 4b0;else if((bit_flag 1b1) (bit_cnt 4d8))bit_cnt 4b0;else if(bit_flag 1b1)bit_cnt bit_cnt 1b1;elsebit_cnt bit_cnt;end// 赋值rx_dataalways(posedge clk or posedge rst) beginif(rst 1b1)rx_data 8b0;else if((bit_cnt 4d1) (bit_cnt 4d8) (bit_flag 1b1))rx_data {rx_reg3,rx_data[7:1]};elserx_data rx_data;end// 赋值data_flagalways(posedge clk or posedge rst) beginif(rst 1b1)data_flag 1b0;else if((bit_flag 1b1) (bit_cnt 4d8))data_flag 1b1;elsedata_flag 1b0;end// 赋值dataalways(posedge clk or posedge rst) beginif(rst 1b1)data 8d0;else if(data_flag 1b1)data rx_data;elsedata data;end// 赋值flagalways(posedge clk or posedge rst) beginif(rst 1b1)flag 1b0;elseflag data_flag;end
endmodule易错点
如果数据是多位的赋值时需要注意其位宽大小。如果一个多位宽的数据赋值为“1’b0”这将只赋值给这个数据的最低位其他位将保留原值与本意相悖。
Testbench 代码
timescale 1ns / 1ps
module tb_RS232_RX();reg clk;reg rst;reg rx;wire [7:0] data;wire flag;// 初始化clk和rstinitial beginclk 1b0;rst 1b1;#60;rst 1b0;end always #10 clk ~clk;// 初始化rxinitial beginrx 1b1;#100;rx_bit(8b1001_0001);rx_bit(8b0101_0010);rx_bit(8b1110_0101);rx_bit(8b0110_1000);rx_bit(8b0110_1011);rx_bit(8b0011_0110);rx_bit(8b0001_1110);end// rx_bit函数生成串行数据task rx_bit(input [7:0] rx_data);integer i;for(i 0; i 10; i i 1) begincase(i)0: rx 1b0;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 1b1;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仿真 RS232发送模块
模块框图 输入输出描述
时钟50MHz每10ns翻转一次复位高电平异步复位DATA待发送的并行数据FLAG数据标志位TX输出处理后的串行数据
时序波形
示意时序图以9600波特率为例。 时序图分析
WORK_ENWORK_EN 通过判断 START_FLAG 的状态而置高通过判断 BIT_CNT、BIT_FLAG 的状态而置低其余时刻保持不变。BAUD_CNT、BIT_FLAG BAUD_CNTBAUD_CNT 只在 WORK_EN 为高时计数BIT_FLAG在 BAUD_CNT 计数为1时刻拉高
RTL 代码
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_enalways(posedge clk or posedge rst) beginif(rst 1b1)work_en 1b0;else if(flag 1b1)work_en 1b1;else if((bit_flag 1b1) (bit_cnt 4d10))work_en 1b0;elsework_en work_en;end// 赋值baud_cntalways(posedge clk or posedge rst) beginif(rst 1b1)baud_cnt 17b0;else if((baud_cnt BAUD_CNT_MAX - 1b1) || (work_en 1b0))baud_cnt 17b0;elsebaud_cnt baud_cnt 1b1;end// 赋值bit_flagalways(posedge clk or posedge rst) beginif(rst 1b1)bit_flag 1b0;else if(baud_cnt 17b1)bit_flag 1b1;elsebit_flag 1b0;end// 赋值bit_cntalways(posedge clk or posedge rst) beginif(rst 1b1)bit_cnt 4b0;else if((bit_flag 1b1) (bit_cnt 4d10))bit_cnt 4b0;else if(bit_flag 1b1)bit_cnt bit_cnt 1b1;elsebit_cnt bit_cnt;end// 赋值txalways(posedge clk or posedge rst) beginif(rst 1b1)tx 1b1;else begincase(bit_cnt)4d1: tx 1b0;4d2: tx data[0];4d3: tx data[1];4d4: tx data[2];4d5: tx data[3];4d6: tx data[4];4d7: tx data[5];4d8: tx data[6];4d9: tx data[7];4d10: tx 1b1;default: tx 1b1;endcaseendend
endmoduleTestbench 代码
timescale 1ns / 1ps
module tb_RS232_TX();reg clk; reg rst; reg [7:0] data;reg flag;wire tx; // 初始化clk和rstinitial beginclk 1b0;rst 1b1;#60;rst 1b0;end always #10 clk ~clk;// 初始化data和flaginitial begindata 8d0;flag 1d0;#200;// 数据1data 8b0010_1011;flag 1d1;#20;flag 1d0;#(5208*12*20);// 数据2data 8b0111_0101;flag 1d1;#20;flag 1d0;#(5208*12*20);// 数据3data 8b1010_0001;flag 1d1;#20;flag 1d0;#(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仿真