Zynq开发实践(FPGA之uart发送)

发布于:2025-09-06 ⋅ 阅读:(12) ⋅ 点赞:(0)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        fpga作为独立的模块,本身肯定有很多的优势,当然也有缺点,价格就是缺点。不过fpga很少是独立使用的,它得和其他嵌入式板子通信,或者是直接和pc进行通信。通信的方法很多,有uart、iic和spi,这几种是经常出现的方式。这里面最简单的就是uart,因为它比较简单,发送就是tx,接收就是rx。

1、uart的波特率

        uart的发送频率一般都不快,从4800到115200都可以。当然,也可以发送得更快一点,比如说115200的2倍、4倍等等,这需要看接收方支不支持。

2、发送的格式

        uart空闲状态一般是拉高。一次uart可以发送一个字节,发送的时候有起始位、数据位、校验位、停止位四个部分。校验位大部分不添加,所以就是剩下来的三个部分。其中数据位一般是8位为主,起始位是0,停止位是1。数据位也是从低到高,一个bit、一个bit发送。

3、一般先开发发送功能

        针对各种通信协议,我们一般都是先开发发送功能。发送验证好了,就可以继续验证接收功能。比如,这个时候就可以通过回环发送的形式,验证发送模块是不是ok。这样借助于回环检测,就可以把发送和接收都验证好了。

4、串口发送的实现

        整个串口发送是从计数器开始的,因为发送的频率不同,所以需要确认发送的时候,计数器的大小是多少,

always@(posedge clk or negedge rst)
	if(!rst)
		counter <= 16'h0;
	else if(state != 3'h0) begin
		if(counter != `BAUD_CNT)
			counter <= counter + 1;
		else
			counter <= 16'h0;
	end 

        至于状态机切换,直接根据串口的发送顺序,用传统的三段式方法去编写即可,

// state machine

always@(posedge clk or negedge rst)
	if(!rst)
		state <= 3'h0;
	else
		state <= next_state;
		
// about next_state

always@(*)
	if(!rst)
		next_state = 3'h0;
	else if(state == 3'h0 && out_valid)
		next_state = 3'h1; // first bit
	else if(state == 3'h1 && counter == `BAUD_CNT)
		next_state = 3'h2; // send data
	else if(state == 3'h2 && num == 7 && counter == `BAUD_CNT)
		next_state = 3'h3; // send stop
	else if(state == 3'h3 && counter == `BAUD_CNT)
		next_state = 3'h0;
	else
		next_state = state;

                发送数据的时候由于需要计数处理,所以要对num进行计数,

// num of sending signal

always@(posedge clk or negedge rst)
	if(!rst)
		num <= 3'h0;
	else if(state == 3'h2 && counter == `BAUD_CNT)
		num <= num + 1;

        最后就是依次发送数据,并且及时通知接收端当前可以继续发送其他数据了,

// about sending data

always@(posedge clk or negedge rst)
	if(!rst)
		out_data <= 8'd0;
	else if(state == 3'h0 && out_valid)
		out_data <= data;

// tx signal

always@(*)
	if(!rst)
		tx = 1'b1;
	else if(state == 3'h1)
		tx = 1'b0;
	else if(state == 3'h2)
		tx = out_data[num];
	else
		tx = 1'b1;
		
// about status

always@(posedge clk or negedge rst)
	if(!rst)
		accept_status <= 1'b1;
	else if(state !=3'h0 )
		accept_status <= 1'b0;
	else
		accept_status <= 1'b1;

5、测试和验证

        验证部分,直接使用testbench即可,首先我们先准备一个testbench文件,

`timescale 1ns/1ps
module test();
 
reg rst;
reg clk;
reg out_valid;
reg[7:0] data;
wire tx;
wire accept_status;
 
initial
    begin
        rst = 1;
        clk = 0;
		out_valid = 0;
		data = 48;
        #12 rst = 0;
        #21 rst = 1;
		#30 out_valid = 1;
		#50 out_valid = 0;
        #10000 $finish;
    end
 
initial
begin
    while(1)
    clk = #5 !clk;
end

uart_tx uart_tx(.rst(rst),
    .clk(clk),
    .out_valid(out_valid),
	.data(data),
	.tx(tx),
	.accept_status(accept_status));

initial
begin
    $dumpfile("hello.vcd");
    $dumpvars(0, test);
end
 
endmodule

        接下来的工作就和之前一样,直接仿真运行,查看波形即可,


网站公告

今日签到

点亮在社区的每一天
去签到