串口数据发送与接收"/>
4、vivado之uart串口数据发送与接收
文章目录
- 实验目标
- 实验原理
- 串口协议
- 状态机设定
- 关于波特率,采用115200的波特率设计
- 实验代码
- rx_uart
- uart_tx
- uart_top
- 实验结果
- 仿真结果
- 仿真代码
- 上电测试
- 总结
实验目标
常态下,fpga 侧实现1s一次的的数据发送。在空闲的时候, fpga侧实现串口的数据的接收,然后再通过串口将数据返回给上位机
实验原理
串口协议
状态机设定
关于波特率,采用115200的波特率设计
实验代码
说明:以下的代码是我照着黑金的修改后,形成的自己的代码,要看原来的代码可以参考黑金的资料。
rx_uart
`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)
beginif (rst_n ==1'b0)beginrx_d0 <=0;rx_d1 <=0;endelse beginrx_d0 <= rx_pin;rx_d1 <= rx_d0; end
endalways@(posedge clk or negedge rst_n)
beginif (rst_n == 1'b0)beginrx_state <= rx_idle;rx_data_valid <= 1'b0;endelse begincase(rx_state)rx_idle:beginif(rx_negedge == 1'b1)rx_state <= rx_start;elserx_state <= rx_idle;endrx_start:beginif(cycle_cnt == cycle -1)beginrx_state <= rx_rcv_byte;cycle_cnt <= 16'd0;endelsebeginrx_state <= rx_start;cycle_cnt <= cycle_cnt + 16'd1;endendrx_rcv_byte:beginif(cycle_cnt == cycle - 1)//分成两种情况,达到8个bit/没到8个字节beginif(bit_cnt == 3'd7)beginrx_state <= rx_stop;bit_cnt <= 3'd0;cycle_cnt <= 16'd0;endelsebeginbit_cnt <= bit_cnt + 3'd1;cycle_cnt <= 16'd0;endendelse if (cycle_cnt == cycle/2 -1)beginrx_bits[bit_cnt] <= rx_pin;cycle_cnt <= cycle_cnt + 16'd1;endelsecycle_cnt <= cycle_cnt + 16'd1;endrx_stop:beginif(cycle_cnt == cycle/2 -1)beginrx_state <= rx_data_state; rx_data <= rx_bits;//latch received datacycle_cnt <= 16'd0; rx_data_valid <=1'b1;endelsebegin rx_state <= rx_stop;rx_data_valid <=1'b0;cycle_cnt <= cycle_cnt + 16'd1;endendrx_data_state:begin if(rx_data_ready) // 低电平时候,就一直处在则个等待数据接收的状态beginrx_state <= rx_idle;rx_data_valid <=1'b0;endelsebegin rx_data_valid <=1'b1;rx_state <= rx_data_state;endenddefault:rx_state <= rx_idle;endcaseend
endendmodule//
// //
// //
// Author: meisq //
// msq@qq //
// ALINX(shanghai) Technology Co.,Ltd //
// heijin //
// WEB: / //
// BBS: / //
// //
//
// //
// 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
uart_tx
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)
beginif (rst_n == 1'b0)beginstate <= s_idle;endelse begincase(state)s_idle:beginif(tx_data_valid == 1'b1)beginstate <= s_start;tx_data_latch <= tx_data;tx_data_ready <= 1'b0;endelsebegintx_reg <= 1'b1;state <=s_idle;tx_data_ready <= 1'b1;endends_start:beginif(cycle_cnt == cycle -1)beginstate <= s_send_byte;cycle_cnt <= 16'd0;endelsebegincycle_cnt <= cycle_cnt + 16'd1;tx_reg <= 1'b0;state <= s_start;endends_send_byte:beginif(cycle_cnt == cycle - 1)//分成两种情况,达到8个bit/没到8个字节beginif(bit_cnt == 3'd7)beginstate <= s_stop;bit_cnt <= 3'd0;cycle_cnt <= 16'd0;endelsebeginbit_cnt <= bit_cnt + 3'd1;cycle_cnt <= 16'd0;endendelsebegincycle_cnt <= cycle_cnt + 16'd1;tx_reg = tx_data_latch[bit_cnt];endends_stop:beginif(cycle_cnt == cycle -1)begintx_data_ready <= 1'b1; state <= s_idle; cycle_cnt <= 16'd0; endelsebegin tx_reg <= 1'b1;cycle_cnt <= cycle_cnt + 16'd1;endenddefault:state <= s_idle;endcaseend
endendmodule
uart_top
`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)
beginif(rst_n == 1'b0)beginwait_cnt <= 32'd0;tx_data <= 8'd0;state <= IDLE;tx_cnt <= 8'd0;tx_data_valid <= 1'b0;endelsecase(state)IDLE:state <= SEND;SEND:beginwait_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 databegintx_cnt <= tx_cnt + 8'd1; //Send data counterendelse if(tx_data_valid && tx_data_ready)//last byte sent is completebegintx_cnt <= 8'd0;tx_data_valid <= 1'b0;state <= WAIT;endelse if(~tx_data_valid)begintx_data_valid <= 1'b1;endendWAIT:beginwait_cnt <= wait_cnt + 32'd1;// 等待1s 数据的时候if(rx_data_valid == 1'b1) // 如果接收到数据begintx_data_valid <= 1'b1; //使得发送数据使能,tx_data <= rx_data; // send uart received dataendelse if(tx_data_valid && tx_data_ready)begintx_data_valid <= 1'b0;endelse if(wait_cnt >= clk_fre * 1000000) // wait for 1 secondstate <= SEND;enddefault:state <= IDLE;endcase
end
/*************************************************************************
combinational logic Send "HELLO ALINX\r\n"
****************************************************************************/
always@(*)
begincase(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 beginsys_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; endalways #25 sys_clk_p <=~sys_clk_p; //此时的频率是200Massign sys_clk_n = ~sys_clk_p;endmodule
上电测试
总结
相对全面的了解了FPGA中的串口的协议,以及fpga基本状态机的编写的过程,能否相对更加有经验的调试自己所编写的fpga 的程序。
更多推荐
4、vivado之uart串口数据发送与接收
发布评论