实现功能,FPGA里实现从PC串口接收数据,接着把接收到的数据发回去。
波特率可选9600bps,可调1bit起始位,8bit数据,1bit停止位,无校验位。
参考《VHDL硬件描述语言与和数字逻辑电路设计》模块介绍如下一、串口数据接收模块:特别注意一个数据位占4个clk_bps_4时钟周期。
串口数据接收控制当数据接收端rxd出现起始位低电平,启动接收控制计数器rx_cnt,置位为8’b0111_00(28),即rx_cnt[5:2]== 4’b0111(7),rx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, rx_cnt加1(每一个数据位加4)串口接收数据移位控制(关键采样点的选取)每当rx_cnt[1:0] == 2'b01,为了保证在rxd一位数据靠近中间位置采样;每4个clk_bps_4, rx_cnt[5:2]加1当rx_cnt[5:2] == 8,9,10….15,完成8位的数据采样,串并变换置位标志位rxdF数据接收标志rxd出现起始位低电平, rxdF置1,表示数据接收开始;当rx_cnt计数到8’b1111_11(63),数据接收完成,rxdF置0置位标志位rdFULL;//接收锁存器满标志空闲时rdFULL置0,当数据接收完成,数据锁存到do_latch,同时rdFULL置1,向上层模块表示数据以准备OK,可以来读取;rd置0,表示上层模块开始读取数据,rdFULL置0,表示数据已读走二、串口数据发送模块:数据发送依赖于wr(低电平有效)空闲时wr置1,数据发送时wr产生低电平脉冲,wr上升沿将数据锁存到din_latch;串口数据发送控制:wr由0跳变为1后,启动发送控制计数器tx_cnt,置位为8’b0111_00(28),即tx_cnt[5:2]== 4’b0111(7), tx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, tx_cnt加1(每一个数据位加4)串口发送数据移位控制每4个clk_bps_4, tx_cnt[5:2]加1当tx_cnt[5:2] ==7,8,9,10….15,完成一位起始位,8位的数据位发送,随后txd置1(停止位),完成并串转换置位标志位txdF,tdEMPTY //发送完成标志当写数据到发送寄存器din_latch时,txdF,tdEMPTY置0;当tx_cnt计数到8’b1111_11(63),数据发送完成,txdF,tdEMPTY置1;三、串口数据自收发控制模块当rdFULL == 1&& tdEMPTY == 1(rdFULL == 1表示数据准备OK,tdEMPTY == 1表示上次发送已完成) ,rd,wr产生低脉冲,rd置0,数据读取到DATA,wr置0使能发送数据控制,低脉冲将DATA锁存到din_latch四、波特率发生模块:针对9600bps,生成4倍于波特率38.4KHz的时钟信号,用于采样代码如下:串口数据自收发控制模块module UART(clk, rst_n, rxd, txd, LED1 );input clk; //时钟周期50MHzinput rst_n; //低电平复位input rxd; //串口引脚输入<--接收<--PCoutput txd; //串口引脚输出-->发送-->PCoutput reg LED1;//lED测试用/****************************************/wire tdEMPTY;//发送寄存器空标志reg wr;//发送使能信号reg [7:0]DATA;wire clk_bps_4;//4倍于波特率时钟信号reg[1:0] wr_cnt;//wr低电平计数reg rd;//读接收锁存器信号wire[7:0] do_latch;//接收数据锁存wire rdFULL;//接收锁存器满标志reg[1:0] rd_cnt;//rd低电平计数/*当rdFULL == 1&& tdEMPTY == 1(rdFULL == 1表示接收锁锁存器数据准备OK,tdEMPTY == 1表示上次发送已完成),rd,wr产生低脉冲,rd置0,do_latch数据读取到DATA,wr置0用于使能发送数据控制,低脉冲将DATA锁存到din_latch*/always@(posedge clk_bps_4 or negedge rst_n)beginif(!rst_n)beginrd <= 1;wr <= 1;wr_cnt <= 0;rd_cnt <= 0;endelsebeginif(rdFULL == 1)beginrd <= 0;wr <= 0;wr_cnt <= 0;rd_cnt <= 0;DATA <= do_latch;endif(rd == 0)//产生rd低电平2个clk_bps_4周期beginrd_cnt <= rd_cnt + 1;if(rd_cnt == 3)rd <= 1;endif(wr == 0)//产生wr低电平2个clk_bps_4周期beginwr_cnt <= wr_cnt + 3;if(wr_cnt == 1)wr <= 1;endendend/*发送*/Uart_TX tx( .rst_n(rst_n),.clk_bps_4(clk_bps_4),.wr(wr),.tdEMPTY(tdEMPTY),.DATA(DATA),.txd(txd));//output to tx_m/*接收*/Uart_RX rx( .rst_n(rst_n),.clk_bps_4(clk_bps_4),.rd(rd),.rdFULL(rdFULL),.do_latch(do_latch),.rxd(rxd));/*针对9600bps,生成38.4KHz的时钟信号,用于接收数据采样与数据发送*/Baudrate baud(.clk(clk),.rst_n(rst_n),.clk_bps_4(clk_bps_4));Endmodule串口数据接收模块:module Uart_RX(rst_n, clk_bps_4, rd, rdFULL, do_latch, rxd);input rst_n; //低电平复位input clk_bps_4; //4倍于波特率时钟信号即一个数据位占4个时钟周期input rd;//接收使能,低电平有效output reg[7:0] do_latch;//接收数据锁存output reg rdFULL;//接收锁存器满标志input rxd;//串口引脚输入reg[7:0] data_r = 8'bx; //接收数据寄存器reg[5:0] rx_cnt;reg rxdF;//数据接收标志,RX模块内部信号/*当数据接收端rxd出现起始位低电平,启动接收控制计数器rx_cnt,置位为8’b0111_00(28),即rx_cnt[5:2]== 4’b0111(7),rx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, rx_cnt加1(每一个数据位加4)*/always@(posedge clk_bps_4 or negedge rst_n)beginif(!rst_n)begin rx_cnt <= 0; endelse if(rx_cnt <= 27 && rxd == 0)begin rx_cnt <= 28; endelse if(rx_cnt <= 27 && rxd == 1)//串口无数据时,rx_cnt保持0begin rx_cnt <= 0; endelsebegin rx_cnt <= rx_cnt + 1;endend/*空闲时rdFULL置0,当数据接收完成,数据锁存到do_latch,同时rdFULL置1,向上层模块表示数据以准备OK,可以来读取;rd置0,表示上层模块开始读取数据,rdFULL置0,表示数据已读走*/always@(posedge clk_bps_4 or negedge rst_n)//置位标志位rdFULLbeginif(!rst_n)begin rdFULL <= 0; endelse if(rd == 0)begin rdFULL <= 0; endelse if(rxdF == 1 && rx_cnt == 63)begindo_latch <= data_r;//数据锁存rdFULL <= 1;//锁存器数据准备OKendend/*rxd出现起始位低电平, rxdF置1,表示数据接收开始;当rx_cnt计数到8’b1111_11(63),数据接收完成,rxdF置0*/always@(posedge clk_bps_4 or negedge rst_n)//置位标志位rxdFbeginif(!rst_n)begin rxdF <= 0; endelse if(rxd == 0)//拉低表示有数据来begin rxdF <= 1;endelse if(rxdF == 1 && rx_cnt == 63)begin rxdF <= 0;endend/*每当rx_cnt[1:0] == 2'b01,为了保证在rxd一位数据靠近中间位置采样;每4个clk_bps_4, rx_cnt[5:2]加1当rx_cnt[5:2] == 8,9,10…15,完成8位的数据采样,串并变换*/always@(posedge clk_bps_4)//数据接收beginif( rx_cnt[1:0] == 2'b01 )case(rx_cnt[5:2])//4'd7:rxd==0;起始位4'd8:data_r[0] <= rxd;// 低第1位4'd9:data_r[1] <= rxd;// 第2位4'd10:data_r[2] <= rxd;// 第3位4'd11:data_r[3] <= rxd;// 第4位4'd12:data_r[4] <= rxd;// 第5位4'd13:data_r[5] <= rxd;// 第6位4'd14:data_r[6] <= rxd;// 第7位4'd15:data_r[7] <= rxd;//高第8位endcaseendendmodule串口数据发送模块:module Uart_TX(rst_n, clk_bps_4,wr,tdEMPTY, DATA, txd);input rst_n; //低电平复位input clk_bps_4; //4倍于波特率时钟信号input [7:0]DATA;input wr;//发送使能信号output reg tdEMPTY;//发送寄存器空标志对外输出output txd;//串口引脚输出reg txdF;//发送完成标志模块内部信号reg txd_r; //发送寄存器reg[7:0] din_latch;//发送数据锁存reg[5:0] tx_cnt;//发送计数器/*空闲时wr置1,数据发送时wr产生低电平脉冲,wr上升沿将数据锁存到din_latch;*/ always@(posedge wr)begin//din_latch <= 8'hAB;din_latch <= DATA;end/*wr由0跳变为1后,启动发送控制计数器tx_cnt,置位为8’b0111_00(28),即tx_cnt[5:2]== 4’b0111(7), tx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, tx_cnt加1(每一个数据位加4)*/always@(posedge clk_bps_4 or negedge rst_n)beginif(!rst_n)begin tx_cnt <= 0; endelse if(tx_cnt <= 27)beginif(tdEMPTY == 0 && wr == 1)begin tx_cnt <= 28;endelse begin tx_cnt <= 0; endendelsebegin tx_cnt <= tx_cnt + 1;endend/*当写数据到发送寄存器din_latch时,txdF,tdEMPTY置0;当tx_cnt计数到8’b1111_11(63),数据发送完成,txdF,tdEMPTY置1;*/always@(posedge clk_bps_4 or negedge rst_n)beginif(!rst_n)begintxdF <= 1;tdEMPTY <= 1;endelse if(wr == 0)begintxdF <= 0;tdEMPTY <= 0;endelse if(txdF == 0 && tx_cnt == 63)begintxdF <= 1;tdEMPTY <= 1;endend/*每4个clk_bps_4, tx_cnt[5:2]加1当tx_cnt[5:2] ==7,8,9,10…15,完成一位起始位,8位的数据位发送,随后txd置1(停止位),完成并串转换*/always@(posedge clk_bps_4 or negedge rst_n)if(!rst_n)begintxd_r <= 1;endelsebegincase(tx_cnt[5:2])4'd7:txd_r <= 1'b0; //起始位04'd8:txd_r <= din_latch[0]; //低第1位4'd9:txd_r <= din_latch[1]; // 第2位4'd10:txd_r <= din_latch[2];// 第3位4'd11:txd_r <= din_latch[3];// 第4位4'd12:txd_r <= din_latch[4];// 第5位4'd13:txd_r <= din_latch[5];// 第6位4'd14:txd_r <= din_latch[6];// 第7位4'd15:txd_r <= din_latch[7];//高第8位default:txd_r <= 1;endcaseendassign txd = txd_r;endmodule波特率发生模块:/*针对9600bps,生成4倍于波特率38.4KHz的时钟信号,用于采样*/ module Baudrate(clk, rst_n,clk_bps_4);input clk; //时钟周期50MHzinput rst_n; //低电平复位output clk_bps_4; //38.4KHz时钟信号9600*4reg clk_bps_4;reg [12:0] bps_cnt; //波特率产生时计数parameter N=1302;//分频系数9600bpsalways@(posedge clk or negedge rst_n)beginif(!rst_n) begin clk_bps_4 <= 0; bps_cnt <= 0;endelsebeginif(bps_cnt == N/2 - 1)begin clk_bps_4 <= ~clk_bps_4; bps_cnt <= 0;endelsebegin bps_cnt <= bps_cnt + 1;endendendendmoduleModelsim仿真波形图:rxd端输入数据01010101,txd发送01010101连接PC 串口助手。