常态下,fpga 侧实现1s一次的的数据发送。在空闲的时候, fpga侧实现串口的数据的接收,然后再通过串口将数据返回给上位机
说明:以下的代码是我照着黑金的修改后,形成的自己的代码,要看原来的代码可以参考黑金的资料。
`timescale 1ns / 1ps
/*
模块功能简介
接收来自rx_pin 的 uart 数据v
将接收到的数据完成后,将我们的数据的rx_data_valid 置位有效
# 然后将收到的数据 通过rx_data 发送出去
*/
module uart_rx
#(
parameter clk_fre = 50,
parameter baud_rate = 115200
)
(
input clk,
input rst_n,
input rx_pin,
input rx_data_ready,
output reg rx_data_valid,
output reg [7:0] rx_data
);
//calculates the clock cycle for baud rate
localparam cycle = clk_fre * 1000000/baud_rate;
parameter rx_idle=3'b000;
parameter rx_start=3'b001;
parameter rx_rcv_byte=3'b010;
parameter rx_stop=3'b011;
parameter rx_data_state =3'b100;
reg [2:0]rx_state=0;
reg [2:0]next_stae;
reg rx_d0;
reg rx_d1;
wire rx_negedge;
reg [7:0] rx_bits=0;
reg [15:0] cycle_cnt=0;
reg [2:0] bit_cnt=0;
assign rx_negedge = rx_d1 && ~rx_d0;
// This part is for detecting the start of the translation f
always @(posedge clk or negedge rst_n)
begin
if (rst_n ==1'b0)
begin
rx_d0 <=0;
rx_d1 <=0;
end
else
begin
rx_d0 <= rx_pin;
rx_d1 <= rx_d0;
end
end
always@(posedge clk or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
rx_state <= rx_idle;
rx_data_valid <= 1'b0;
end
else
begin
case(rx_state)
rx_idle:
begin
if(rx_negedge == 1'b1)
rx_state <= rx_start;
else
rx_state <= rx_idle;
end
rx_start:
begin
if(cycle_cnt == cycle -1)
begin
rx_state <= rx_rcv_byte;
cycle_cnt <= 16'd0;
end
else
begin
rx_state <= rx_start;
cycle_cnt <= cycle_cnt + 16'd1;
end
end
rx_rcv_byte:
begin
if(cycle_cnt == cycle - 1)
//分成两种情况,达到8个bit/没到8个字节
begin
if(bit_cnt == 3'd7)
begin
rx_state <= rx_stop;
bit_cnt <= 3'd0;
cycle_cnt <= 16'd0;
end
else
begin
bit_cnt <= bit_cnt + 3'd1;
cycle_cnt <= 16'd0;
end
end
else if (cycle_cnt == cycle/2 -1)
begin
rx_bits[bit_cnt] <= rx_pin;
cycle_cnt <= cycle_cnt + 16'd1;
end
else
cycle_cnt <= cycle_cnt + 16'd1;
end
rx_stop:
begin
if(cycle_cnt == cycle/2 -1)
begin
rx_state <= rx_data_state;
rx_data <= rx_bits;//latch received data
cycle_cnt <= 16'd0;
rx_data_valid <=1'b1;
end
else
begin
rx_state <= rx_stop;
rx_data_valid <=1'b0;
cycle_cnt <= cycle_cnt + 16'd1;
end
end
rx_data_state:
begin
if(rx_data_ready) // 低电平时候,就一直处在则个等待数据接收的状态
begin
rx_state <= rx_idle;
rx_data_valid <=1'b0;
end
else
begin
rx_data_valid <=1'b1;
rx_state <= rx_data_state;
end
end
default:
rx_state <= rx_idle;
endcase
end
end
endmodule
//
// //
// //
// Author: meisq //
// [email protected] //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: http://www.alinx.cn/ //
// BBS: http://www.heijin.org/ //
// //
//
// //
// Copyright (c) 2017,ALINX(shanghai) Technology Co.,Ltd //
// All rights reserved //
// //
// This source file may be used and distributed without restriction provided //
// that this copyright statement is not removed from the file and that any //
// derivative work contains the original copyright notice and the associated //
// disclaimer. //
// //
//
//================================================================================
// Revision History:
// Date By Revision Change Description
//--------------------------------------------------------------------------------
//2017/8/1 1.0 Original
//*******************************************************************************/
//module uart_rx
//#(
// parameter CLK_FRE = 50, //clock frequency(Mhz)
// parameter BAUD_RATE = 115200 //serial baud rate
//)
//(
// input clk, //clock input
// input rst_n, //asynchronous reset input, low active
// output reg[7:0] rx_data, //received serial data
// output reg rx_data_valid, //received serial data is valid
// input rx_data_ready, //data receiver module ready
// input rx_pin //serial data input
//);
calculates the clock cycle for baud rate
//localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
state machine code
//localparam S_IDLE = 1;
//localparam S_START = 2; //start bit
//localparam S_REC_BYTE = 3; //data bits
//localparam S_STOP = 4; //stop bit
//localparam S_DATA = 5;
//reg[2:0] state;
//reg[2:0] next_state;
//reg rx_d0; //delay 1 clock for rx_pin
//reg rx_d1; //delay 1 clock for rx_d0
//wire rx_negedge; //negedge of rx_pin
//reg[7:0] rx_bits; //temporary storage of received data
//reg[15:0] cycle_cnt; //baud counter
//reg[2:0] bit_cnt; //bit counter
//assign rx_negedge = rx_d1 && ~rx_d0;
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// begin
// rx_d0 <= 1'b0;
// rx_d1 <= 1'b0;
// end
// else
// begin
// rx_d0 <= rx_pin;
// rx_d1 <= rx_d0;
// end
//end
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// state <= S_IDLE;
// else
// state <= next_state;
//end
外部状态切换
//always@(*)
//begin
// case(state)
// S_IDLE:
// if(rx_negedge)
// next_state <= S_START;
// else
// next_state <= S_IDLE;
// S_START:
// if(cycle_cnt == CYCLE - 1)//one data cycle
// next_state <= S_REC_BYTE;
// else
// next_state <= S_START;
// S_REC_BYTE:
// if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //receive 8bit data
// next_state <= S_STOP;
// else
// next_state <= S_REC_BYTE;
// S_STOP:
// if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
// next_state <= S_DATA;
// else
// next_state <= S_STOP;
// S_DATA:
// if(rx_data_ready) //data receive complete
// next_state <= S_IDLE;
// else
// next_state <= S_DATA;
// default:
// next_state <= S_IDLE;
// endcase
//end
切换到接收数据是否有效
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// rx_data_valid <= 1'b0;
// else if(state == S_STOP && next_state != state)
// rx_data_valid <= 1'b1;
// else if(state == S_DATA && rx_data_ready)
// rx_data_valid <= 1'b0;
//end
当前状态是stop, 并且此时想要切换到下一个状态,此时,stop, stop 表示停止位。
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// rx_data <= 8'd0;
// else if(state == S_STOP && next_state != state)
// rx_data <= rx_bits;//latch received data
//end
当前状态处在数据的接收一个bit 的过程中。
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// begin
// bit_cnt <= 3'd0;
// end
// else if(state == S_REC_BYTE)
// if(cycle_cnt == CYCLE - 1) // 跟随波特率进行,如果cycle cnt 到达一个周期,这个时候,我们实际上就已经接收了一个bit,此时,我们把接收到bit 个数加1
// bit_cnt <= bit_cnt + 3'd1;
// else
// bit_cnt <= bit_cnt;
// else
// bit_cnt <= 3'd0;
//end
波特率计算模块, 这个
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// cycle_cnt <= 16'd0;
// else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
// cycle_cnt <= 16'd0;
// else
// cycle_cnt <= cycle_cnt + 16'd1;
//end
receive serial data bit data
//always@(posedge clk or negedge rst_n)
//begin
// if(rst_n == 1'b0)
// rx_bits <= 8'd0;
// else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
// rx_bits[bit_cnt] <= rx_pin;
// else
// rx_bits <= rx_bits;
//end
//endmodule
module uart_tx
#(
parameter clk_fre = 50,
parameter baud_rate = 115200
)
(
input clk,
input rst_n,
input [7:0]tx_data,
input tx_data_valid,
output tx_pin,
output reg tx_data_ready
);
//calculates the clock cycle for baud rate
localparam cycle = clk_fre * 1000000/baud_rate;
parameter s_idle=3'b000;
parameter s_start=3'b001;
parameter s_send_byte=3'b010;
parameter s_stop=3'b011;
reg [2:0]state=0;
reg [2:0]next_state;
reg [15:0] cycle_cnt=0;
reg [2:0] bit_cnt=0;
reg [7:0] tx_data_latch;
reg tx_reg=1;
assign tx_pin = tx_reg;
always@(posedge clk or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
state <= s_idle;
end
else
begin
case(state)
s_idle:
begin
if(tx_data_valid == 1'b1)
begin
state <= s_start;
tx_data_latch <= tx_data;
tx_data_ready <= 1'b0;
end
else
begin
tx_reg <= 1'b1;
state <=s_idle;
tx_data_ready <= 1'b1;
end
end
s_start:
begin
if(cycle_cnt == cycle -1)
begin
state <= s_send_byte;
cycle_cnt <= 16'd0;
end
else
begin
cycle_cnt <= cycle_cnt + 16'd1;
tx_reg <= 1'b0;
state <= s_start;
end
end
s_send_byte:
begin
if(cycle_cnt == cycle - 1)
//分成两种情况,达到8个bit/没到8个字节
begin
if(bit_cnt == 3'd7)
begin
state <= s_stop;
bit_cnt <= 3'd0;
cycle_cnt <= 16'd0;
end
else
begin
bit_cnt <= bit_cnt + 3'd1;
cycle_cnt <= 16'd0;
end
end
else
begin
cycle_cnt <= cycle_cnt + 16'd1;
tx_reg = tx_data_latch[bit_cnt];
end
end
s_stop:
begin
if(cycle_cnt == cycle -1)
begin
tx_data_ready <= 1'b1;
state <= s_idle;
cycle_cnt <= 16'd0;
end
else
begin
tx_reg <= 1'b1;
cycle_cnt <= cycle_cnt + 16'd1;
end
end
default:
state <= s_idle;
endcase
end
end
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/07/31 12:20:32
// Design Name:
// Module Name: uart_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_top
(
input sys_clk_p, //system clock positive
input sys_clk_n, //system clock negative
input rst_n, //reset ,low active
input uart_rx, //fpga receive data
output uart_tx //fpga send data
);
parameter clk_fre = 200; //Mhz
localparam IDLE = 0;
localparam SEND = 1; //send HELLO ALINX\r\n
localparam WAIT = 2; //wait 1 second and send uart received data
reg[7:0] tx_data; //sending data
reg[7:0] tx_str;
reg tx_data_valid; //sending data valid
wire tx_data_ready; //singal for sending data
reg[7:0] tx_cnt=0;
wire[7:0] rx_data; //receiving data
wire rx_data_valid; // receiving data valid
wire rx_data_ready; // singal for receiving data
reg[31:0] wait_cnt=0;
reg[3:0] state=0;
wire sys_clk; //single end clock
/*************************************************************************
generate single end clock
**************************************************************************/
IBUFDS sys_clk_ibufgds
(
.O (sys_clk ),
.I (sys_clk_p ),
.IB (sys_clk_n )
);
assign rx_data_ready = 1'b1;//always can receive data,
//if HELLO ALINX\r\n is being sent, the received data is discarded
/*************************************************************************
1 second sends a packet HELLO ALINX\r\n , FPGA has been receiving state
****************************************************************************/
always@(posedge sys_clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
wait_cnt <= 32'd0;
tx_data <= 8'd0;
state <= IDLE;
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
end
else
case(state)
IDLE:
state <= SEND;
SEND:
begin
wait_cnt <= 32'd0;
tx_data <= tx_str;
if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1 && tx_cnt < 8'd12)//Send 12 bytes data
begin
tx_cnt <= tx_cnt + 8'd1; //Send data counter
end
else if(tx_data_valid && tx_data_ready)//last byte sent is complete
begin
tx_cnt <= 8'd0;
tx_data_valid <= 1'b0;
state <= WAIT;
end
else if(~tx_data_valid)
begin
tx_data_valid <= 1'b1;
end
end
WAIT:
begin
wait_cnt <= wait_cnt + 32'd1;
// 等待1s 数据的时候
if(rx_data_valid == 1'b1) // 如果接收到数据
begin
tx_data_valid <= 1'b1; //使得发送数据使能,
tx_data <= rx_data; // send uart received data
end
else if(tx_data_valid && tx_data_ready)
begin
tx_data_valid <= 1'b0;
end
else if(wait_cnt >= clk_fre * 1000000) // wait for 1 second
state <= SEND;
end
default:
state <= IDLE;
endcase
end
/*************************************************************************
combinational logic Send "HELLO ALINX\r\n"
****************************************************************************/
always@(*)
begin
case(tx_cnt)
8'd0 : tx_str <= "H";
8'd1 : tx_str <= "E";
8'd2 : tx_str <= "L";
8'd3 : tx_str <= "L";
8'd4 : tx_str <= "O";
8'd5 : tx_str <= " ";
8'd6 : tx_str <= "A";
8'd7 : tx_str <= "L";
8'd8 : tx_str <= "I";
8'd9 : tx_str <= "N";
8'd10: tx_str <= "X";
8'd11: tx_str <= "\r";
8'd12: tx_str <= "\n";
default:tx_str <= 8'd0;
endcase
end
/***************************************************************************
calling uart_tx module and uart_rx module
****************************************************************************/
uart_rx#
(
.clk_fre(clk_fre),
.baud_rate(115200)
) uart_rx_inst
(
.clk (sys_clk ),
.rst_n (rst_n ),
.rx_data (rx_data ),
.rx_data_valid (rx_data_valid ),
.rx_data_ready (rx_data_ready ),
.rx_pin (uart_rx )
);
uart_tx#
(
.clk_fre(clk_fre),
.baud_rate(115200)
) uart_tx_inst
(
.clk (sys_clk ),
.rst_n (rst_n ),
.tx_data (tx_data ),
.tx_data_valid (tx_data_valid ),
.tx_data_ready (tx_data_ready ),
.tx_pin (uart_tx )
);
endmodule
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/08/01 10:50:48
// Design Name:
// Module Name: vtl_uart_rx_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module vtl_uart_rx_test;
wire sys_clk_n;
reg sys_clk_p;
reg rst_n;
reg uart_rx;
wire uart_tx;
uart_top uart_test(
.sys_clk_p(sys_clk_p),
.sys_clk_n(sys_clk_n),
.rst_n(rst_n),
.uart_rx(uart_rx),
.uart_tx(uart_tx)
);
parameter bps_115200 = 86800;
parameter send_data = 8'b1010_0011;
integer i=0;
initial begin
sys_clk_p =0;
#100;
rst_n = 0;
#100;
rst_n =1;
#100;
uart_rx = 1'b1;
#10000;
uart_rx = 1'b0;
for(i =0;i<8;i=i+1)
#bps_115200 uart_rx = send_data[i];
#bps_115200 uart_rx = 1'b0;
#bps_115200 uart_rx = 1'b1;;
#2000000;
end
always #25 sys_clk_p <=~sys_clk_p; //此时的频率是200M
assign sys_clk_n = ~sys_clk_p;
endmodule
相对全面的了解了FPGA中的串口的协议,以及fpga基本状态机的编写的过程,能否相对更加有经验的调试自己所编写的fpga 的程序。