【UART发送与接收(代码详解)/2023年7月19日】

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只是显示作用?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iKUNqa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值