FPGA模拟串口自收发-Verilog

实现功能,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; //时钟周期50MHz input rst_n; //低电平复位

input rxd; //串口引脚输入<--接收<--PC output txd; //串口引脚输出-->发送-->PC output reg LED1;//lED测试用

/****************************************/ wire tdEMPTY;//发送寄存器空标志 regwr;//发送使能信号 reg [7:0]DATA;

wire clk_bps_4;//4倍于波特率时钟信号 reg[1:0] wr_cnt;//wr低电平计数

regrd;//读接收锁存器信号

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) begin if(!rst_n) begin rd<= 1; wr<= 1; wr_cnt<= 0; rd_cnt<= 0; end else begin if(rdFULL == 1) begin rd<= 0; wr<= 0; wr_cnt<= 0; rd_cnt<= 0; DATA <= do_latch; end

if(rd == 0)//产生rd低电平 2个clk_bps_4周期 begin rd_cnt<= rd_cnt + 1; if(rd_cnt == 3) rd<= 1; end if(wr == 0)//产生wr低电平 2个clk_bps_4周期 begin wr_cnt<= wr_cnt + 3; if(wr_cnt == 1) wr<= 1; end end end

/*发送*/

Uart_TXtx( .rst_n(rst_n), .clk_bps_4(clk_bps_4), .wr(wr), .tdEMPTY(tdEMPTY), .DATA(DATA), .txd(txd) );//output to tx_m /*接收*/

Uart_RXrx( .rst_n(rst_n), .clk_bps_4(clk_bps_4), .rd(rd), .rdFULL(rdFULL), .do_latch(do_latch), .rxd(rxd) );

/*针对9600bps,生成38.4KHz的时钟信号,用于接收数据采样与数据发送*/ Baudratebaud(.clk(clk), .rst_n(rst_n), .clk_bps_4(clk_bps_4)); Endmodule

串口数据接收模块:

moduleUart_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 regrdFULL;//接收锁存器满标志 input rxd;//串口引脚输入

reg[7:0] data_r = 8'bx; //接收数据寄存器 reg[5:0] rx_cnt;

regrxdF;//数据接收标志,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) begin if(!rst_n) begin rx_cnt <= 0; end

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4