新建工程的操作在之前的点灯文章里面 这次只要是重写v文件和io分配即可 v文件参考黑金的,只要改动uart_test文件中的 parameter CLK_FRE = 100;//Mhz 就好,改多少,看自己板子上面的频率。 顶层模块,uart_test.v
module uart_test ( input sys_clk, //system clock 50Mhz on board,100MHZ input rst_n, //reset ,low active input uart_rx, //fpga receive data output uart_tx //fpga send data ); parameter CLK_FRE = 100;//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; reg[7:0] tx_str; reg tx_data_valid; wire tx_data_ready; reg[7:0] tx_cnt; wire[7:0] rx_data; wire rx_data_valid; wire rx_data_ready; reg[31:0] wait_cnt; reg[3:0] state; 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; 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 ) ); endmoduleuart_rx.v,这边的parameter CLK_FRE 最好也改,不过没改也没事,大约是被顶层文件覆盖了
`timescale 1ns / 1ps 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 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 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) 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 endmoduleuart_tx.v。这边的parameter CLK_FRE 最好也改,不过没改也没事,大约是被顶层文件覆盖了
`timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2020/10/04 09:10:26 // Design Name: // Module Name: uart_tx // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module uart_tx #( 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 input[7:0] tx_data, //data to send input tx_data_valid, //data to be sent is valid output reg tx_data_ready, //send ready output tx_pin //serial data output ); //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_SEND_BYTE = 3;//data bits localparam S_STOP = 4;//stop bit reg[2:0] state; reg[2:0] next_state; reg[15:0] cycle_cnt; //baud counter reg[2:0] bit_cnt;//bit counter reg[7:0] tx_data_latch; //latch data to send reg tx_reg; //serial data output assign tx_pin = tx_reg; 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(tx_data_valid == 1'b1) next_state <= S_START; else next_state <= S_IDLE; S_START: if(cycle_cnt == CYCLE - 1) next_state <= S_SEND_BYTE; else next_state <= S_START; S_SEND_BYTE: if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) next_state <= S_STOP; else next_state <= S_SEND_BYTE; S_STOP: if(cycle_cnt == CYCLE - 1) next_state <= S_IDLE; else next_state <= S_STOP; default: next_state <= S_IDLE; endcase end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin tx_data_ready <= 1'b0; end else if(state == S_IDLE) if(tx_data_valid == 1'b1) tx_data_ready <= 1'b0; else tx_data_ready <= 1'b1; else if(state == S_STOP && cycle_cnt == CYCLE - 1) tx_data_ready <= 1'b1; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin tx_data_latch <= 8'd0; end else if(state == S_IDLE && tx_data_valid == 1'b1) tx_data_latch <= tx_data; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin bit_cnt <= 3'd0; end else if(state == S_SEND_BYTE) if(cycle_cnt == CYCLE - 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_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) tx_reg <= 1'b1; else case(state) S_IDLE,S_STOP: tx_reg <= 1'b1; S_START: tx_reg <= 1'b0; S_SEND_BYTE: tx_reg <= tx_data_latch[bit_cnt]; default: tx_reg <= 1'b1; endcase end endmodule时钟和复位管脚:
串口引脚: IO分配如下:
记得是选3.3v的,而且要勾上fix,不然生成比特流会报错,具体原因未知
下载比特流的时候会出现这个,其实没有影响。查了一下,大约是usb口复用为jtag的缘故 官网讨论 用串口助手看,效果正常(波特率是115200)