【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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
接下来的工作就和之前一样,直接仿真运行,查看波形即可,