note
实现功能:发送:vivado利用vio输入,串口软件CH340端口显示数据
接收:串口软件CH340端口发送,vio显示数据
板内、板间或者下位机与上位机之间进行数据的发送与接收,需要双方共同遵循一定的通信协议来保证数据传输的正确性。常见的协议有UART(通用异步收发传输器)、IIC(双向两线总线)、SPI(串行外围总线)、USB2.0/3.0(通用串行总线)以及 Ethernet(以太网)等。
!和~的区别
“!”是逻辑非运算,对 4’b0110 逻辑非运算后是 4’b0000;而“~”是按位取反,对 4’b0110按位取反后是 4’b1001,对于单 bit 数据使用“!”和“~”后的结果是一样的。
发送
code
/*输入8位data_byte转uart_tx输出并转串*/
module uart_send(
input clk,
input rst,
input [2:0]baud_set,
input send_en,
input [7:0]data_byte,
output reg tx_done,
output reg uart_state,
output reg uart_tx
);
/*波特率时钟生成模块*/
//bps_set0/1/2/3/4分别对应于波特率9600/19200/38400/57600/115200_set0/1/2/3/4分别对应于波特率9600/19200/38400/57600/115200
reg [12:0]baud_cnt;//最大计数值5208=0001010001011000,需要13位
always@(posedge clk or posedge rst)
if(rst)
baud_cnt<=5207;//计数值减一
else begin
case(baud_set)
0:baud_cnt<=5207;//一个周期时间1/9600=104167ns 104167/20=5208.35
1:baud_cnt<=2603;//52083
2:baud_cnt<=1301;//26041
3:baud_cnt<=867;//17361
4:baud_cnt<=433;//8680
default:baud_cnt<=5207;//默认情况下为9600bps
endcase
end
reg [12:0]div_cnt;
always@(posedge clk or posedge rst)
if(rst)
div_cnt<=0;
else if(uart_state)begin
if(div_cnt==baud_cnt)
div_cnt<=0;
else
div_cnt<=div_cnt+1;
end
else
div_cnt<=0;
//波特率时钟bps_clk,标记发送数据的每一位,观察起始位、停止位以及数据位
reg bps_clk;//一个数据位11个标记脉冲
always@(posedge clk or posedge rst)
if(rst)
bps_clk<=0;
else if(div_cnt==1)
bps_clk<=1;
else
bps_clk<=0;
/*数据输出模块*/
reg [3:0]bps_cnt;
always@(posedge clk or posedge rst)
if(rst)
bps_cnt<=0;
else if(bps_cnt==11)
bps_cnt<=0;
else if(bps_clk)
bps_cnt<=bps_cnt+1;
else
bps_cnt<=bps_cnt;
//tx_done标记一个数据位传输的结束
always@(posedge clk or posedge rst)
if(rst)
tx_done<=0;
else if(bps_cnt==11)
tx_done<=1;
else
tx_done<=0;
//uart_state正常传输为高,否则为低,可控制div_cnt的计数
always@(posedge clk or posedge rst)
if(rst)
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;
//寄存输入,保证数据稳定
reg [7:0]data_byte_reg;
always@(posedge clk or posedge rst)
if(rst)
data_byte_reg <= 8'd0;
else if(send_en)
data_byte_reg <= data_byte;
else
data_byte_reg <= data_byte_reg;
/*数据传输状态控制模块*/
localparam START_BIT=0;
localparam STOP_BIT=1;
always@(posedge clk or posedge rst)
if(rst)
uart_tx <= 1'b1;
else begin
case(bps_cnt)
0:uart_tx <= 1'b1;
1:uart_tx <= START_BIT;
2:uart_tx <= data_byte_reg[0];
3:uart_tx <= data_byte_reg[1];
4:uart_tx <= data_byte_reg[2];
5:uart_tx <= data_byte_reg[3];
6:uart_tx <= data_byte_reg[4];
7:uart_tx <= data_byte_reg[5];
8:uart_tx <= data_byte_reg[6];
9:uart_tx <= data_byte_reg[7];
10:uart_tx <= STOP_BIT;
default:uart_tx <= 1'b1;
endcase
end
endmodule
tb
`timescale 1ns / 1ps
module uart_send_tb();
reg clk;
reg rst;
reg [2:0]baud_set;
reg send_en;
reg [7:0]data_byte;
wire tx_done;
wire uart_state;
wire uart_tx;
uart_send uart_send0(
clk,
rst,
baud_set,
send_en,
data_byte,
tx_done,
uart_state,
uart_tx);
initial clk = 1;
always #10 clk = ~clk;
initial begin
rst = 1;
data_byte = 8'd0;
send_en = 1'd0;
baud_set =4;
#201;
rst = 0;
#200;
data_byte = 8'haa;//10101010
send_en = 1'd1;
#20;
send_en = 1'd0;
@(posedge tx_done)
#1000;
data_byte = 8'h55;//01010101
send_en = 1'd1;
#20;
send_en = 1'd0;
@(posedge tx_done)
#1000;
$stop;
end
endmodule
接收
code
module self(
clk,
rst_n,
mode,
data,
uart_rx
);
input clk;
input rst_n;
input [2:0]mode;
input uart_rx;
output [7:0]data;
reg [8:0]const;
always@(*)
case(mode)
1:const=5208/16-1;//9600
2:const=2604/16-1;//19200
3:const=1302/16-1;//38400
4:const=868/16-1;//57600
5:const=434/16-1;//115200
default:const=434/16-1;//115200
endcase
reg [8:0]div;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
div<=0;
else if(div==const)
div<=0;
else
div<=1;
end
wire bps_clk;
assign bps_clk=(div==const/2);
reg [7:0]cnt160;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt160<=0;
else if(en)begin//#####
if(bps_clk)begin
if(cnt160==160);
cnt160<=0;
else
cnt160<=cnt160+1;
end
end
else
cnt160<=0;
wire [1:0]r_data2;
wire up;
wire down;
always@(posedge clk)begin
r_data2[0]<=uart_rx;
r_data2[1]<=r_data2[0];
end
assign up=(r_data2==2'b01);
assign down=(r_data2==2'b10);
reg rx_done;
reg en;
always@(posedge clk or negedge rst_n)
if(!rst_n)
en<=0;
else if(down)
en<=1;
else if(rx_done||(sta>=4))//####
en<=0;
always@(posedge clk or negedge rst_n)
if(!rst_n)
rx_done<=0;
else if(cnt160==160)
rx_done<=1;
else
rx_done<=0;
reg [2:0]r_data8[7:0];
reg sta;
reg sto;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
sta<=0;
sto<=0;
r_data8[0]<=0;
r_data8[1]<=0;
r_data8[2]<=0;
r_data8[3]<=0;
r_data8[4]<=0;
r_data8[5]<=0;
r_data8[6]<=0;
r_data8[7]<=0;
end
else case(cnt160)
0:begin
sta<=0;
sto<=0;
r_data8[0]<=0;
r_data8[1]<=0;
r_data8[2]<=0;
r_data8[3]<=0;
r_data8[4]<=0;
r_data8[5]<=0;
r_data8[6]<=0;
r_data8[7]<=0;
end
5,6,7,8,9,10,11:r_data8[0]=r_data2[1]+sta;
21,22,23,24,25,26,27:r_data8[0]=uart_rx+r_data2[1];
37,38,39,40,41,42,43:r_data8[1]=uart_rx+r_data2[1];
53,54,55,56,57,58,59:r_data8[2]=uart_rx+r_data2[1];
69,70,71,72,73,74,75:r_data8[3]=uart_rx+r_data2[1];
85,86,87,88,89,90,91:r_data8[4]=uart_rx+r_data2[1];
101,102,103,104,105,106,107: r_data8[5]=uart_rx+r_data2[1];
117,118,119,120,121,122,123:r_data8[6]=uart_rx+r_data2[1];
133,134,135,136,137,138,139:r_data8[7]=uart_rx+r_data2[1];
149,150,151,152,153,154,155:sto=uart_rx+r_data2[1];
default:;
endcase
reg [7:0]rx;
always@(posedge clk or negedge rst_n)
if(!rst_n)
rx<=0;
else if(en)begin//决定了rx_done的延迟160不159延迟
rx[0]<= r_data8[0]>=4?1:0;
rx[1]<= r_data8[0]>=4?1:0;
rx[2]<= r_data8[0]>=4?1:0;
rx[3]<= r_data8[0]>=4?1:0;
rx[4]<= r_data8[0]>=4?1:0;
rx[5]<= r_data8[0]>=4?1:0;
rx[6]<= r_data8[0]>=4?1:0;
rx[7]<= r_data8[0]>=4?1:0;
end
endmodule
think
判断是2’b10就是下降沿,是说明给的数据第一个下降沿必须是数据起始位?
发送是并转串FPGA发送给土豪金?
接收是串转并FPGA接收到土豪金的数据?
PC只是显示作用?