Verilog-UART串口通信协议
@
一、通信特点
uart :异步、串行、全双工
一般描述某种通信的特点为:同步/异步 , 串行/并行 , 半双工/全双工
同步:要求一个芯片控制另一芯片的时序,一般,两者之间至少采用一个总线连接以控制时钟(“时钟线”), 其中主机主动控制时钟线(通过时钟线输出),从机被动接受时钟线(通过时钟线输入)。
异步:双方不会通过总线连接时钟,异步通信要求双方使用独立的时钟生成装置(波特率发生器),生成相 同的通信速度。
串行:在每个数据方向上仅有一根数据线。每次仅传输一位数据。
并行:在每个数据方向上有多根数据线。每次可以传输数据的多个位(一般是8/16位)
半双工:数据线仅有一组,同一时刻,只有一方控制数据线的发送,另一方接收数据(即双方不能同时发送 数据)
全双工:数据线有两组或以上,同一时刻,通信双方都可以给对方发送数据。
二、uart协议介绍
uart:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),是一种通用串行数据总线,用于异步通信。uart能实现双向通信,在嵌入式设计中,它常用于主机与辅助设备通信。uart包括RS232、RS449、RS432、RS422和RS485等接口标准规范和总线标准规范,既uart是异步串行通信口的的总称。而RS232、RS449、RS432、RS422和RS485等是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,实际上属于通信网络中的物理层(最底层)的概念,与通信协议没有直接关系。(内容来源于《搭建你的数字积木-数字电路与逻辑设计》)
参数的意义如下:
- 波特率:是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数(每秒传输多少个比特位(bit))。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信两端设备都要设为相同的波特率。 具体波特率如下图所示。
波特率计算: 特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟,
信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信特率生成,就是用一个定时器来定时,产生频率与对应波特率时钟频率相同的时钟信号。例如,我们使用波特率为115200bps,则我们需要产生一个频率为115200Hz的时钟
信号。那么如何产生这样一个115200Hz的时钟信号呢?这里,我们首先将115200Hz时钟信
波特率:
波特率 | 波特率周期 | 波特率分频计数值 |
---|---|---|
9600 | 104167ns | 104164 / sys_clk_period |
19200 | 52083ns | 52083 / sys_clk_period |
38400 | 26041ns | 26041 / sys_clk_period |
57600 | 17361ns | 17361 / sys_clk_period |
115200 | 8680ns | 8680 / sys_clk_period |
说明:sys_clk_period 为系统时钟周期 |
- 起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。
- 数据位:定义单个UART数据传输在开始到停止期间发送的数据位数。可以选择的值有5,6,7,8(默认)这四个值。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。
- 校验位:用来验证数据的正确性。奇偶校验一般不使用,如果使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。数据位加上奇偶校验后会被相应的置1或0(一般是最高位或最低位),数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。以传输“A”(01000001)为例。
a. 当为奇数校验:”A”字符的8个bit位中有两个1,那么奇偶校验位为1才能满足1的个数为奇数(奇校验)。
b. 当为偶数校验:”A”字符的8个bit位中有两个1,那么奇偶校验位为0才能满足1的个数为偶数(偶校验)。 此位还可以去除,即不需要奇偶校验位。
c. 如果用户选择数据长度为8位,则因为没有多余的比特可被用来作为奇偶校验位,因此就叫做“无奇偶校验(Non) - 停止位:它是一帧数据的结束标志。可以是1bit(默认)、1.5bit、2bit的空闲电平。
- 空闲位:没有数据传输时线路上的电平状态。为逻辑1。
- 传输方向:即数据是从高位(MSB)开始传输还是从低位(LSB)开始传输。比如传输“A”如果是MSB那么就是01000001,如果是LSB那么就是10000010。
- uart传输数据的顺序:刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样完整的一帧数据就传输完了。
- 帧间隔:即传送数据的帧与帧之间的间隔大小,可以以位为计量也可以用时间(知道波特率那么位数和时间可以换算)。比如传送”A”完后,这为一帧数据,再传”B”,那么A与B之间的间隔即为帧间隔。
三、RS232接口标准的Verilog代码实现
使用工具:ISE Design Suite 14.7
FPGA开发板: Basys2
波特率:9600 bit/s
实现的功能:
指令一:PC端发送I like FPGA,开发板回应 I like FPGA, too. 在PC端显示。
指令二:PC端发送I like Verilog,开发板回应 I like Verilog, too. 在PC端显示。
RTL视图如下:
顶层设计代码
module top_uart_tx_rx(
input clk,
input rst_n,
input rs232_rx,
output rs232_tx
);
//uart_rx
wire [7:0] rx_data;
wire rx_done;
//uart_tx
wire tx_finish;
wire send_en;
wire [7:0] data_tx;
//rx_datadeal
wire tx_en1;
wire tx_en2;
//tx_datadeal
uart_rx uart_rx(
.clk (clk) ,
.rst_n (rst_n) ,
.rs232_rx(rs232_rx) ,
.rx_data (rx_data) ,
.rx_done (rx_done)
);
uart_tx uart_tx(
.clk (clk),
.rst_n (rst_n),
.send_en (send_en),
.data_tx (data_tx),
.rs232_tx (rs232_tx),
.tx_finish (tx_finish)
);
tx_datadeal tx_datadeal(
.clk (clk ),
.rst_n (rst_n ),
.tx_en1 (tx_en1),
.tx_en2 (tx_en2),
.tx_finish (tx_finish),
.send_en (send_en),
.data_tx (data_tx)
);
rx_datadeal rx_datadeal(
.clk (clk) ,
.rst_n (rst_n) ,
.rx_data (rx_data),
.rx_done (rx_done),
.tx_en1 (tx_en1),
.tx_en2 (tx_en2)
);
endmodule
接收数据处理代码
module rx_datadeal(
input clk ,
input rst_n ,
input [7:0] rx_data ,
input rx_done ,
output reg tx_en1 ,
output reg tx_en2
);
reg [3:0] data_cnt;
reg [3:0] flag1;
reg [3:0] flag2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data_cnt <= 4'd0;
else if(flag1 == 4'd11 || flag2 == 4'd14 )
data_cnt <= 4'd0;
else if(rx_done)
data_cnt <= data_cnt + 1'b1;
end
//给tx的使能信号
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
tx_en1 <= 1'b0;
tx_en2 <= 1'b0;
end
else if(flag1 == 4'd11)
tx_en1 <= 1'b1;
else if(flag2 == 4'd14)
tx_en2 <= 1'b1;
else
begin
tx_en1 <= 1'b0;
tx_en2 <= 1'b0;
end
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
flag1 <= 4'd0;
flag2 <= 4'd0;
end
else if(flag1 == 4'd11)
flag1 <= 4'd0;
else if(flag2 == 4'd14)
flag2 <= 4'd0;
else
begin
case(data_cnt)
4'd0 : begin
if(rx_data == "I")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd1 : begin
if(rx_data == " ")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd2 : begin
if(rx_data == "L")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd3 : begin
if(rx_data == "i")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd4 : begin
if(rx_data == "k")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd5 : begin
if(rx_data == "e")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd6 : begin
if(rx_data == " ")
begin
flag1 <= flag1 + 1'b1;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd7 : begin
if(rx_data == "F")
begin
flag1 <= flag1 + 1'b1;
flag2 <= 4'd0;
end
else if(rx_data == "V")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd8 : begin
if(rx_data == "P")
begin
flag1 <= flag1 + 1'b1;
flag2 <= 4'd0;
end
else if(rx_data == "e")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd9 : begin
if(rx_data == "G")
begin
flag1 <= flag1 + 1'b1;
flag2 <= 4'd0;
end
else if(rx_data == "r")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd10 : begin
if(rx_data == "A")
begin
flag1 <= flag1 + 1'b1;
flag2 <= 4'd0;
end
else if(rx_data == "i")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd11 : begin
if(rx_data == "l")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd12 : begin
if(rx_data == "o")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
4'd13 : begin
if(rx_data == "g")
begin
flag1 <= 4'd0;
flag2 <= flag2 + 1'b1;
end
else
begin
flag1 <= flag1;
flag2 <= flag2;
end
end
default : begin
flag1 <= 4'd0;
flag2 <= 4'd0;
end
endcase
end
end
endmodule
接收代码
module uart_rx(clk,rst_n,rs232_rx,rx_data,rx_done);
input clk;
input rst_n;
input rs232_rx;
output reg [7:0] rx_data;
output reg rx_done;
reg [1:0]s_rs232_rx;//消除亚稳态
reg [1:0]tmp_rs232_rx;//数据寄存器
wire nedge;
reg [15:0]div_cnt;//分频计数器
reg bps_clk;
reg uart_state;
reg [7:0]bps_cnt;
reg [2:0]start_bit;
reg [2:0]stop_bit;
reg [2:0]rx_data_t [7:0];
// 地址宽度
always@(posedge clk or negedge rst_n)
if(!rst_n)
s_rs232_rx <= 0;
else begin
s_rs232_rx[0] <= rs232_rx;
s_rs232_rx[1] <= s_rs232_rx[0];
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
tmp_rs232_rx <= 0;
else begin
tmp_rs232_rx[0] <= s_rs232_rx[1];
tmp_rs232_rx[1] <= tmp_rs232_rx[0];
end
assign nedge = tmp_rs232_rx[1] & ~tmp_rs232_rx[0];
always@(posedge clk or negedge rst_n)
if(!rst_n)
div_cnt <= 16'd0;
else if(uart_state == 1) begin
if(div_cnt == 325)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1;
end
else
div_cnt <= 0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'b1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
uart_state <= 1'b0;
else if(nedge)
uart_state <= 1'b1;
else if(rx_done || (bps_cnt == 8'd12 && start_bit > 2))
uart_state <= 1'b0;
else
uart_state <= uart_state;
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_cnt <= 0;
else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && start_bit > 2))
bps_cnt <= 0;
else if(bps_clk == 1)
bps_cnt <= bps_cnt + 1;
else
bps_cnt <= bps_cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
rx_done <= 1'b0;
end
else if(bps_cnt == 8'd159) begin
rx_done <= 1'b1;
end
else begin
rx_done <= 1'b0;
end
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
start_bit <= 3'd0;
rx_data_t[0] <= 3'd0;
rx_data_t[1] <= 3'd0;
rx_data_t[2] <= 3'd0;
rx_data_t[3] <= 3'd0;
rx_data_t[4] <= 3'd0;
rx_data_t[5] <= 3'd0;
rx_data_t[6] <= 3'd0;
rx_data_t[7] <= 3'd0;
stop_bit <= 3'd0;
end
else if(bps_clk == 1) begin
case(bps_cnt)
0:begin
start_bit <= 3'd0;
rx_data_t[0] <= 3'd0;
rx_data_t[1] <= 3'd0;
rx_data_t[2] <= 3'd0;
rx_data_t[3] <= 3'd0;
rx_data_t[4] <= 3'd0;
rx_data_t[5] <= 3'd0;
rx_data_t[6] <= 3'd0;
rx_data_t[7] <= 3'd0;
stop_bit <= 3'd0;
end
5,6,7,8,9,10: start_bit <= start_bit + s_rs232_rx[1];
21,22,23,24,25,26: rx_data_t[0] <= rx_data_t[0] + s_rs232_rx[1];
37,38,39,40,41,42: rx_data_t[1] <= rx_data_t[1] + s_rs232_rx[1];
53,54,55,56,57,58: rx_data_t[2] <= rx_data_t[2] + s_rs232_rx[1];
69,70,71,72,73,74: rx_data_t[3] <= rx_data_t[3] + s_rs232_rx[1];
85,86,87,88,89,90: rx_data_t[4] <= rx_data_t[4] + s_rs232_rx[1];
101,102,103,104,105,106: rx_data_t[5] <= rx_data_t[5] + s_rs232_rx[1];
117,119,120,121,122,123: rx_data_t[6] <= rx_data_t[6] + s_rs232_rx[1];
133,135,136,137,138,139: rx_data_t[7] <= rx_data_t[7] + s_rs232_rx[1];
149,151,152,153,154,155: stop_bit <= stop_bit + s_rs232_rx[1];
endcase
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
rx_data <= 8'd0;
else if(bps_cnt == 159) begin
rx_data[0] <= rx_data_t[0][2];
rx_data[1] <= rx_data_t[1][2];
rx_data[2] <= rx_data_t[2][2];
rx_data[3] <= rx_data_t[3][2];
rx_data[4] <= rx_data_t[4][2];
rx_data[5] <= rx_data_t[5][2];
rx_data[6] <= rx_data_t[6][2];
rx_data[7] <= rx_data_t[7][2];
end
endmodule
发送数据处理代码
module tx_datadeal(
input clk,
input rst_n,
input tx_finish,
input tx_en1,
input tx_en2,
output reg send_en,
output reg [7:0] data_tx
);
//define
reg [4:0] data_cnt;
reg tx_state1;
reg tx_state2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
tx_state1 <= 1'b0;
tx_state2 <= 1'b0;
end
else if(tx_en1)
tx_state1 <= 1'b1;
else if(tx_en2)
tx_state2 <= 1'b1;
else if(data_cnt == 5'd15)
tx_state1 <= 1'b0;
else if(data_cnt == 5'd18)
tx_state2 <= 1'b0;
else
begin
tx_state1 <= tx_state1;
tx_state2 <= tx_state2;
end
end
//data_cnt
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data_cnt <= 5'd0;
else if(tx_state1 == 1'b1 && data_cnt == 5'd15)
data_cnt <= 5'd0;
else if(tx_state2 == 1'b1 && data_cnt == 5'd18)
data_cnt <= 5'd0;
else if(tx_finish)
data_cnt <= data_cnt + 1'b1;
else
data_cnt <= data_cnt;
end
//send_en
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
send_en <= 1'b0;
else if(tx_en1 || tx_en2)
send_en <= 1'b1;
else if(tx_finish)
begin
if(tx_state1)
begin
if(data_cnt < 5'd14)
send_en <= 1'b1;
else
send_en <= 1'b0;
end
else if(tx_state2)
begin
if(data_cnt < 5'd17)
send_en <= 1'b1;
else
send_en <= 1'b0;
end
end
else
send_en <= 1'b0;
end
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data_tx <= 8'd0;
else if(tx_state1)
begin
case(data_cnt)
5'd0 : data_tx <= "I";
5'd1 : data_tx <= " ";
5'd2 : data_tx <= "L";
5'd3 : data_tx <= "i";
5'd4 : data_tx <= "k";
5'd5 : data_tx <= "e";
5'd6 : data_tx <= " ";
5'd7 : data_tx <= "F";
5'd8 : data_tx <= "P";
5'd9 : data_tx <= "G";
5'd10 : data_tx <= "A";
5'd11 : data_tx <= ",";
5'd12 : data_tx <= "t";
5'd13 : data_tx <= "o";
5'd14 : data_tx <= "o";
default : data_tx <= 8'd0;
endcase
end
else if(tx_state2)
begin
case(data_cnt)
5'd0 : data_tx <= "I";
5'd1 : data_tx <= " ";
5'd2 : data_tx <= "L";
5'd3 : data_tx <= "i";
5'd4 : data_tx <= "k";
5'd5 : data_tx <= "e";
5'd6 : data_tx <= " ";
5'd7 : data_tx <= "V";
5'd8 : data_tx <= "e";
5'd9 : data_tx <= "r";
5'd10 : data_tx <= "i";
5'd11 : data_tx <= "l";
5'd12 : data_tx <= "o";
5'd13 : data_tx <= "g";
5'd14 : data_tx <= ",";
5'd15 : data_tx <= "t";
5'd16 : data_tx <= "o";
5'd17 : data_tx <= "o";
default : data_tx <= 8'd0;
endcase
end
else
data_tx <= 8'd0;
end
endmodule
发送代码
module uart_tx(clk,rst_n,tx_finish,send_en,rs232_tx,uart_state,data_tx);
input clk ;
input rst_n ;
input send_en ;//发送使能信号
input [ 7:0] data_tx ;//发送字节
output reg rs232_tx ;
output reg tx_finish ;
output reg uart_state ;
reg bps_clk ;//波特率时钟
reg [ 15:0] div_cnt ;//分频计数器
reg [ 15:0] bps_DR = 5207 ;//分频计数最大值
reg [ 3:0] bps_cnt ;//波特率计数时钟
reg [ 7:0] r_data_tx ;
localparam START_BYTE = 1'b0 ;
localparam STOP_BYTE = 1'b1 ;
//控制信号
always@(posedge clk or negedge rst_n)
if(!rst_n)
uart_state <= 1'b0;
else if(send_en)
uart_state <= 1'b1;
else if(bps_cnt == 4'd11)
uart_state <= 1'b0;
else
uart_state <= uart_state;
//寄存器存储发送信息
always@(posedge clk or negedge rst_n)
if(!rst_n)
r_data_tx <= 1'b0;
else if(uart_state)
r_data_tx <= data_tx;
else
r_data_tx <= r_data_tx;
//counter
always@(posedge clk or negedge rst_n)
if(!rst_n)
div_cnt <= 16'd0;
else if(uart_state)
begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
//产生bps_clk
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'd1;
else
bps_clk <= 1'b0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
bps_cnt <= 4'd0;
else if(bps_cnt == 4'd11)
bps_cnt <= 4'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
//产生发送完成信号
always@(posedge clk or negedge rst_n)
if(!rst_n)
tx_finish <= 1'b0;
else if(bps_cnt == 4'd11)
tx_finish <= 1'b1;
else
tx_finish <= 1'b0;
//发送模块
always@(posedge clk or negedge rst_n)
if(!rst_n)
rs232_tx <= 1'b1;
else
begin
case(bps_cnt)
0:rs232_tx <= 1'b1;
1:rs232_tx <= START_BYTE; //0
2:rs232_tx <= r_data_tx[0];
3:rs232_tx <= r_data_tx[1];
4:rs232_tx <= r_data_tx[2];
5:rs232_tx <= r_data_tx[3];
6:rs232_tx <= r_data_tx[4];
7:rs232_tx <= r_data_tx[5];
8:rs232_tx <= r_data_tx[6];
9:rs232_tx <= r_data_tx[7];
10:rs232_tx <= STOP_BYTE; //1
default:rs232_tx <= 1'b1;
endcase
end
endmodule
TESTBENCH
module tb_uart_tx_rx;
// Inputs
reg clk;
reg rst_n;
reg rs232_rx;
// Outputs
wire rs232_tx;
// Instantiate the Unit Under Test (UUT)
top_uart_tx_rx uut (
.clk(clk),
.rst_n(rst_n),
.rs232_rx(rs232_rx),
.rs232_tx(rs232_tx)
);
parameter period=20,
RST_ING=1'b0,
BPS_9600=32'd104_167;
initial begin
// Initialize Inputs
clk = 0;
forever
#(period/2)clk=~clk;
end
reg [4:0] cnt;
reg [7:0] data_tx;
initial begin
rst_n = RST_ING;
#5000;
rst_n = ~RST_ING;
rs232_rx = 1'b1;
//I Like FPGA
#1000_000;
data_tx = "I";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "L";
tx_task(data_tx);
#1000_000;
data_tx = "i";
tx_task(data_tx);
#1000_000;
data_tx = "k";
tx_task(data_tx);
#1000_000;
data_tx = "e";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "F";
tx_task(data_tx);
#1000_000;
data_tx = "P";
tx_task(data_tx);
#1000_000;
data_tx = "G";
tx_task(data_tx);
#1000_000;
data_tx = "A";
tx_task(data_tx);
//I Like Verilog
#100_000_000;
data_tx = "I";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "L";
tx_task(data_tx);
#1000_000;
data_tx = "i";
tx_task(data_tx);
#1000_000;
data_tx = "k";
tx_task(data_tx);
#1000_000;
data_tx = "e";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "V";
tx_task(data_tx);
#1000_000;
data_tx = "e";
tx_task(data_tx);
#1000_000;
data_tx = "r";
tx_task(data_tx);
#1000_000;
data_tx = "i";
tx_task(data_tx);
#1000_000;
data_tx = "l";
tx_task(data_tx);
#1000_000;
data_tx = "o";
tx_task(data_tx);
#1000_000;
data_tx = "g";
tx_task(data_tx);
//I Like FPGA
#100_000_000;
data_tx = "I";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "L";
tx_task(data_tx);
#1000_000;
data_tx = "i";
tx_task(data_tx);
#1000_000;
data_tx = "k";
tx_task(data_tx);
#1000_000;
data_tx = "e";
tx_task(data_tx);
#1000_000;
data_tx = " ";
tx_task(data_tx);
#1000_000;
data_tx = "F";
tx_task(data_tx);
#1000_000;
data_tx = "P";
tx_task(data_tx);
#1000_000;
data_tx = "G";
tx_task(data_tx);
#1000_000;
data_tx = "A";
tx_task(data_tx);
end
task tx_task;
input [7:0] rs232_tx;
integer i;
begin
rs232_rx = 0;
#BPS_9600;
for(i = 0;i < 8;i = i+1) begin
rs232_rx = data_tx[i];
#BPS_9600;
end
rs232_rx = 1;
#BPS_9600;
end
endtask
endmodule
仿真图如下:
本篇博文为记录学习所用,如有错误,请各位指正批评,如有转载请注明出处。
分类:
总线协议
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)