FPGA 串口通讯
module Baud # ( parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率,12000000/9600 ) ( input clk, //系统时钟 input rst_n, //系统复位,低有效 input bps_en, //接收或发送时钟使能 output reg bps_clk //接收或发送时钟输出 ); reg [12:0] cnt; //计数器计数满足波特率时钟要求 always @ (posedge clk or negedge rst_n) begin if(!rst_n) cnt <= 1'b0; else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数 cnt <= 1'b0; //当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期 else cnt <= cnt + 1'b1; end //产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收 always @ (posedge clk or negedge rst_n) begin if(!rst_n) bps_clk <= 1'b0; else if(cnt == (BPS_PARA>>1)) //右移一位等于除以2,终值BPS_PARA为数据更替点,中值数据稳定,做采样点 bps_clk <= 1'b1; else bps_clk <= 1'b0; end endmodule
module Uart_Tx ( input clk, //系统时钟 12MHz input rst_n, //系统复位,低有效 output reg bps_en, //发送时钟使能 input bps_clk, //发送时钟输入 input tx_data_valid, //发送数据有效脉冲 input [7:0] tx_data_in, //要发送的数据 output reg uart_tx //UART发送输出 ); reg [3:0] num; reg [9:0] tx_data_r; //融合了起始位和停止位的数据 //驱动发送数据操作 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin bps_en <= 1'b0; tx_data_r <= 10'd0; end else if(tx_data_valid && (!bps_en))begin bps_en <= 1'b1; //当检测到接收时钟使能信号的下降沿,表明接收完成,需要发送数据,使能发送时钟使能信号 tx_data_r <= {1'b1,tx_data_in,1'b0}; end else if(num==4'd10) begin bps_en <= 1'b0; //一次UART发送需要10个时钟信号,然后结束 end end //当处于工作状态中时,按照发送时钟的节拍发送数据 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin num <= 1'b0; uart_tx <= 1'b1; end else if(bps_en) begin if(bps_clk) begin num <= num + 1'b1; uart_tx <= tx_data_r[num]; end else if(num>=4'd10) num <= 4'd0; end end endmodule
module Uart_Rx ( input clk, //系统时钟 12MHz input rst_n, //系统复位,低有效 output reg bps_en, //接收时钟使能 input bps_clk, //接收时钟输入 input uart_rx, //UART接收输入 output reg rx_data_valid, //接收数据有效脉冲 output reg [7:0] rx_data_out //接收到的数据 ); reg uart_rx0,uart_rx1,uart_rx2; //多级延时锁存去除亚稳态 always @ (posedge clk) begin uart_rx0 <= uart_rx; uart_rx1 <= uart_rx0; uart_rx2 <= uart_rx1; end //检测UART接收输入信号的下降沿 wire neg_uart_rx = uart_rx2 & ~uart_rx1; reg [3:0] num; //接收时钟使能信号的控制 always @ (posedge clk or negedge rst_n) begin if(!rst_n) bps_en <= 1'b0; else if(neg_uart_rx && (!bps_en)) //当空闲状态(bps_en为低电平)时检测到UART接收信号下降沿,进入工作状态(bps_en为高电平),控制时钟模块产生接收时钟 bps_en <= 1'b1; else if(num==4'd9) //当完成一次UART接收操作后,退出工作状态,恢复空闲状态 bps_en <= 1'b0; end reg [7:0] rx_data; //当处于工作状态中时,按照接收时钟的节拍获取数据 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin num <= 4'd0; rx_data <= 8'd0; end else if(bps_en) begin if(bps_clk) begin num <= num + 1'b1; if(num<=4'd8) rx_data[num-1] <= uart_rx1; //先接受低位再接收高位,8位有效数据 end else if(num == 4'd9) begin //完成一次UART接收操作后,将获取的数据输出 num <= 4'd0; end end else begin num <= 4'd0; end end //将接收的数据输出,同时控制输出有效信号产生脉冲 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin rx_data_out <= 8'd0; rx_data_valid <= 1'b0; end else if(num == 4'd9) begin rx_data_out <= rx_data; rx_data_valid <= 1'b1; end else begin rx_data_out <= rx_data_out; rx_data_valid <= 1'b0; end end endmodule
module Uart_Bus # ( parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率 ) ( input clk, //系统时钟 12MHz input rst_n, //系统复位,低有效 input uart_rx, //UART接收输入 output rx_data_valid, //接收数据有效脉冲 output [7:0] rx_data_out //接收到的数据 //input tx_data_valid, //发送数据有效脉冲 //input [7:0] tx_data_in, //要发送的数据 //output uart_tx //UART发送输出 ); /////////////////////////////////UART接收功能模块例化//////////////////////////////////// wire bps_en_rx,bps_clk_rx; //UART接收波特率时钟控制模块 例化 Baud # ( .BPS_PARA (BPS_PARA ) ) Baud_rx ( .clk (clk ), //系统时钟 12MHz .rst_n (rst_n ), //系统复位,低有效 .bps_en (bps_en_rx ), //接收时钟使能 .bps_clk (bps_clk_rx ) //接收时钟输出 ); //UART接收数据模块 例化 Uart_Rx Uart_Rx_uut ( .clk (clk ), //系统时钟 12MHz .rst_n (rst_n ), //系统复位,低有效 .bps_en (bps_en_rx ), //接收时钟使能 .bps_clk (bps_clk_rx ), //接收时钟输入 .uart_rx (uart_rx ), //UART接收输入 .rx_data_valid (rx_data_valid ), //接收数据有效脉冲 .rx_data_out (rx_data_out ) //接收到的数据 ); /////////////////////////////////UART发送功能模块例化//////////////////////////////////// /* wire bps_en_tx,bps_clk_tx; //UART发送波特率时钟控制模块 例化 Baud # ( .BPS_PARA (BPS_PARA ) ) Baud_tx ( .clk (clk ), //系统时钟 12MHz .rst_n (rst_n ), //系统复位,低有效 .bps_en (bps_en_tx ), //发送时钟使能 .bps_clk (bps_clk_tx ) //发送时钟输出 ); //UART发送数据模块 例化 Uart_Tx Uart_Tx_uut ( .clk (clk ), //系统时钟 12MHz .rst_n (rst_n ), //系统复位,低有效 .bps_en (bps_en_tx ), //发送时钟使能 .bps_clk (bps_clk_tx ), //发送时钟输入 .tx_data_valid (tx_data_valid ), //发送数据有效脉冲 .tx_data_in (tx_data_in ), //要发送的数据 .uart_tx (uart_tx ) //UART发送输出 ); */ endmodule