基于verilog的串口通信实验指导和源程序

合集下载

Verilog_串口通信_1113

Verilog_串口通信_1113

踏雪无痕的博客串口通信是目前比较重要的一种通信方式,主要是用于计算机和外部的通信。

首先简单的介绍一下串口通信的原理:串口用于ASCII码字符的传输。

通信使用3根线完成:(1)地线(GND),(2)发送(TXD),(3)接收(RXD)。

由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。

其它线用于握手,但是不是必须的。

串口通信最重要的参数是波特率、数据位、停止位和奇偶校验位。

对于两个进行通信的端口,这些参数必须匹配:a,波特率:这是一个衡量通信速度的参数。

它表示每秒钟传送的bit的个数。

例如300波特表示每秒钟发送300个bit。

当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。

这意味着串口通信在数据线上的采样率为4800Hz。

通常电话线的波特率为14400,28800和36600。

波特率可以远远大于这些值,但是波特率和距离成反比。

高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB 设备的通信。

b,数据位:这是衡量通信中实际数据位的参数。

当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。

如何设置取决于你想传送的信息。

比如,标准的ASCII码是0~127(7位)。

扩展的ASCII 码是0~255(8位)。

如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。

每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。

由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

c,停止位:用于表示单个包的最后一位。

典型的值为1,1.5和2位。

由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。

因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。

适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

基于VerilogHDL语言的串口设计说明

基于VerilogHDL语言的串口设计说明

基于Verilog HDL语言的串口设计串口Verilog HDL代码://串口module trans(clk,rst,en,TxD_data,Wsec,RxD,TxD,TxD_busy,rcven,RxD_data);//时钟50MHzinput clk,rst,en; //en时发送数据使能input [7:0]TxD_data; //发送数据输入input [2:0]Wsec; //波特率调节0-2400;1-4800;2-9600;3-14400;4-19200;5-38400;6-115200;7-128000input RxD; //接收数据输入端output TxD,TxD_busy,rcven;//发送,发送忙,接收结束标志输出output [7:0]RxD_data;//接收数据输出wire Baud1,Baud8;reg [7:0]addwire;//RAM地址连线reg [7:0]data;wire[7:0]AD_t;//读取RAM数据的地址用于发送wire[7:0]AD_r;//接收的数据存储在RAM中的地址wire [7:0]datawire;//数据连线//发送例化trans_t tt1(.clk_t(clk),.rst_t(rst),.en_t(en),.BTI_t(Baud1),.recen(recen),.TxD_data_t(datawire),.TxD_t(TxD),.addro_t(AD_t),.TxD_busy_t(TxD_busy));//波特生成例化BaudG tt2(.clk_b(clk),.rst_b(rst),.BTO_b(Baud1),.BTO_R(Baud8),.Wsec_b(Wsec));//接收例化trans_r tt3(.clk_r(clk),.rst_r(rst),.BTI_r(Baud8),.RxD_r(RxD),.RxD_data_r(RxD_data),.wren_r(wren_r),.addro_r(AD_r),.RxD_end(RxD_end));//LPM_RAM例化RAM0tt4(.address(addwire),.clock(~clk),.data(data),.wren(wren_r),.q(datawire));always (posedge clk or negedge rst)if(~rst)addwire <= 8'b00000000;else if(RxD_end)beginaddwire <=AD_r ;data<=RxD_data;endelse addwire<=AD_t;endmodule//发送模块moduletrans_t(clk_t,rst_t,en_t,BTI_t,TxD_data_t,TxD_t,recen,TxD_busy_t,addro_t,recen );input clk_t,rst_t,en_t,BTI_t;input [7:0]TxD_data_t;output TxD_t;output TxD_busy_t;output recen;output [7:0]addro_t;reg TxD_t;reg [7:0]TxD_dataReg;//寄存器reg [7:0]addro_t;//reg [3:0]state;reg recen;wire TxD_busy_t;assign BaudTick = BTI_t;//波特输出// 发送启动wire TxD_ready = (state==0); // TxD_ready = 1assign TxD_busy_t = ~TxD_ready;// 加载发送数据always (posedge clk_t or negedge rst_t)if(~rst_t)TxD_dataReg <= 8'b00000000;else if(TxD_ready && en_t)TxD_dataReg <= TxD_data_t;// 状态机发送always (posedge clk_t or negedge rst_t)if(~rst_t)beginstate <= 4'b0000; // 复位时发送1TxD_t <= 1'b1;endelsecase(state)4'b0000: if(en_t ) beginstate <= 4'b0100; // 检测发送开始end4'b0100: if(BaudTick && en_t) beginstate <= 4'b1000; // 发送起始位0end4'b1000: if(BaudTick && en_t) beginstate <= 4'b1001; // bit 0if(en_t) TxD_t <= TxD_dataReg[0];else TxD_t <= 1'b0;end4'b1001: if(BaudTick && en_t) beginstate <= 4'b1010; // bit 1if(en_t) TxD_t <= TxD_dataReg[1];else TxD_t <= 1'b0;end4'b1010: if(BaudTick && en_t) beginstate <= 4'b1011; // bit 2if(en_t) TxD_t <= TxD_dataReg[2];else TxD_t <= 1'b0;end4'b1011: if(BaudTick && en_t) beginstate <= 4'b1100; // bit 3if(en_t) TxD_t <= TxD_dataReg[3];else TxD_t <= 1'b0;end4'b1100: if(BaudTick && en_t) beginstate <= 4'b1101; // bit 4if(en_t) TxD_t <= TxD_dataReg[4];else TxD_t <= 1'b0;end4'b1101: if(BaudTick && en_t) beginstate <= 4'b1110; // bit 5if(en_t) TxD_t <= TxD_dataReg[5];else TxD_t <= 1'b0;end4'b1110: if(BaudTick && en_t) beginstate <= 4'b1111; // bit 6if(en_t) TxD_t <= TxD_dataReg[6];else TxD_t <= 1'b0;end4'b1111: if(BaudTick && en_t) beginstate <= 4'b0010; // bit 7if(en_t) TxD_t <= TxD_dataReg[7];else TxD_t <= 1'b0;end4'b0010: if(BaudTick && en_t) beginstate <= 4'b0011; // stop1end4'b0011: if(BaudTick) beginstate <= 4'b0000; // stop2TxD_t <= 1'b1;enddefault: if(BaudTick) beginstate <= 4'b0000;TxD_t <= 1'b1;endendcasealways (posedge clk_t or negedge rst_t)if(~rst_t)begin recen<=0;endelse if(~TxD_ready)recen<=1;else recen<=0;//地址计数器ddressalways (posedge clk_t or negedge rst_t)if(~rst_t)addro_t <= 8'b00000000;else if(TxD_ready && en_t)addro_t <=addro_t +1;endmodule//波特生成模块module BaudG(clk_b,rst_b,BTO_b,BTO_R,Wsec_b);input clk_b,rst_b;input [2:0]Wsec_b;output BTO_b,BTO_R;reg FT,FT8;reg [16:0]BGA;reg [16:0]BGA1;wire BTO_b = FT; //发送波特wire BTO_R = FT8;//接收模块波特=发送*16always (posedge clk_b or negedge rst_b )if(~rst_b)begin BGA <= 0;BGA1 <= 0;endelsecase(Wsec_b)0:begin接收波特=2400*16else begin FT8=1'b0; BGA1 <= BGA1+ 1; endif(BGA>62500)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=2400else begin FT=1'b0; BGA <= BGA+ 3; endend1: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end //接收波特=4800*16else begin FT8=1'b0; BGA1 <= BGA1+ 1; endif(BGA>62500)begin FT=1'b1; FT8=1'b1; BGA1<=0;BGA<=0; end // 发送波特=4800else begin FT=1'b0; BGA <= BGA+ 6; endend2: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end // 接收波特=9600*16else begin FT8=1'b0; BGA1<= BGA1+ 2; endif(BGA>15625)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=9600else begin FT=1'b0; BGA <= BGA+ 3; endend3: begin if(BGA1>217)begin FT8=1'b1; BGA1<=0; end // 接收波特=14400*16else begin FT8=1'b0; BGA1 <= BGA1+ 1;endif(BGA>17361)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=14400else begin FT=1'b0; BGA <= BGA+ 5; endend4: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end // 接收波特=19200*16else begin FT8=1'b0; BGA1 <= BGA1+ 4;endif(BGA>15625)begin FT=1'b1; FT8=1'b1; BGA1<=0;BGA<=0; end // 发送波特=19200else begin FT=1'b0; BGA <= BGA+ 6;endend5: begin if(BGA1>244)begin FT8=1'b1; BGA1<=0; end // 接收波特=38400*16else begin FT8=1'b0; BGA1 <= BGA1+ 3;endBGA<=0; end // 发送波特=38400else begin FT=1'b0; BGA <= BGA+ 12;endend6: begin if(BGA1>217)begin FT8=1'b1; BGA1<=0; end // 接收波特=115200*16else begin FT8=1'b0; BGA1 <= BGA1+ 8;endif(BGA>434) begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=115200else begin FT=1'b0; BGA <= BGA+ 1;endend7: begin if(BGA1>122)begin FT8=1'b1; BGA1<=0; end // 接收波特=128000*16else begin FT8=1'b0; BGA1 <= BGA1+ 5;endif(BGA>3125) begin FT=1'b1; BGA<=0;FT8=1'b1; BGA1<=0; end // 发送波特=128000else begin FT=1'b0; BGA <= BGA+ 8;endenddefault:begin BGA<=0;FT=1'b0;endendcaseendmodule//接收模块module trans_r(clk_r,rst_r,BTI_r,RxD_r,RxD_data_r,wren_r,addro_r,RxD_end);input clk_r,rst_r,RxD_r,BTI_r;output [7:0]RxD_data_r;output wren_r,RxD_end;output [7:0]addro_r;reg [3:0]bit_spacing;//两Bit间隔16reg RxD_end; //接收数据有效标志reg RxD_delay; //中间参量reg RxD_en; //接收使能reg [7:0]RxD_data_r; //接收数据输出reg [7:0]RxD_cach; //接收数据缓存reg [3:0]state;reg [7:0]addro_r; //地址reg wren_r;assign Baud8Tick = BTI_r;//接收波特always (posedge clk_r or negedge rst_r)if(~rst_r)bit_spacing<=0;elsecase(state)0: bit_spacing<=0;default:if(Baud8Tick)bit_spacing<=bit_spacing+1;endcasewire next_bit=(bit_spacing==5);//两bit间隔16波特always (posedge clk_r)if(Baud8Tick)beginRxD_delay<=RxD_r;RxD_en<=(Baud8Tick & RxD_delay & (~RxD_r));//检测接收信号是否有下降沿end//状态机接收always(posedge clk_r or negedge rst_r)if(~rst_r)state <= 4'b0000;else if(Baud8Tick)case(state)4'b0000: if(RxD_en) state <= 4'b0001; // 有下降沿开始接收4'b0001: if(next_bit) state <= 4'b1000; // bit 04'b1000: if(next_bit) state <= 4'b1001; // bit 14'b1001: if(next_bit) state <= 4'b1010; // bit 24'b1010: if(next_bit) state <= 4'b1011; // bit 34'b1011: if(next_bit) state <= 4'b1100; // bit 44'b1100: if(next_bit) state <= 4'b1101; // bit 54'b1101: if(next_bit) state <= 4'b1110; // bit 64'b1110: if(next_bit) state <= 4'b1111; // bit 74'b1111: if(next_bit) state <= 4'b0010; // 停止位4'b0010: if(next_bit) state <= 4'b0000;default: state <= 4'b0000;endcase// 移位寄存器接收always (posedge clk_r or negedge rst_r)if(~rst_r)RxD_cach <= 8'b00000000;else if(Baud8Tick && next_bit && state[3])RxD_cach <= {RxD_r, RxD_cach[7:1]};//停止位与接收结束标志位有效时将数据输出always (posedge clk_r or negedge rst_r)if(~rst_r)RxD_data_r <= 8'b00000000;else if(RxD_end && RxD_r)RxD_data_r <= RxD_cach;// 产生接收结束标志位always (posedge clk_r or negedge rst_r)if(~rst_r)begin RxD_end<=0;endelsebegin RxD_end<=(Baud8Tick && next_bit && state==4'b0010 && RxD_r);endalways (posedge clk_r or negedge rst_r)if(~rst_r)begin wren_r<=0;endelse if(RxD_end)wren_r<=1;else wren_r<=0;//地址计数器ddressalways (posedge clk_r or negedge rst_r)if(~rst_r)addro_r <= 8'b11111111;else if(RxD_end)addro_r <=addro_r +1;endmodule为了测试收发是否正常,写的Test Bench`timescale 1ns/1nsmodule trsb;reg clk,rst,en;reg [7:0]TxD_data;reg [2:0]Wsec;wire TxD,TxD_busy,rcven;wire [7:0]RxD_data;trans trsb(.clk(clk),.rst(rst),.en(en),.TxD(TxD),.Wsec(Wsec),.TxD_busy(TxD_busy),.TxD_data(TxD_data),.rcven(rcven),.RxD_data(RxD_data),.RxD(TxD));initial beginen = 0;TxD_data = 0;rst = 1;#1 Wsec=2;#54 rst=0;#70 rst=1;#10 TxD_data = 8'b11011001;#10 en = 1'b1;#1250000 en = 1'b1;endinitial begin#3790000 TxD_data = 8'b01011010; #10 en = 1'b1;#2750000 en = 1'b0;#1290000 TxD_data = 8'b101001010; #10 en = 1'b1;#2750000 en = 1'b0;endinitial beginclk = 1;while (1)#10 clk = ~clk;endendmoduleFPGA实现串行接口RS232(1)2008-12-17 11:38串行接口(RS-232)串行接口是连接FPGA和PC机的一种简单方式。

基于FPGA Verilog RS232串口回环测试例程,附源程序仿真源码及测试图片

基于FPGA Verilog RS232串口回环测试例程,附源程序仿真源码及测试图片

FPGA Verilog RS232串口回环测试基于FPGA Verilog RS232串口回环测试例程,支持多byte数据传输,附源程序仿真源码及测试图片。

测试基于SSCOM/友善之臂上位机软件测试,测试结果如下图一图二所示。

图一SSCOM图二图三连续发送仿真截图图四连续接收仿真截图后附verilog源程序代码及testbech仿真例程,注释欠。

重点:多byte回环测试要点,上位机串口多位数据连续发送停止位和起始位之间无间隔,回环程序在接收和发送都需要具备在停止位后能立马跳转到下一个起始位的能力。

重点关注cnt_bit的处理方式。

附录1 顶层例化uart_txd uart_txd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.tx_data(rx_data),.baud_set(3'd4),.send_en(rx_done),.send_done(),.send_busy(send_busy),.uart_tx(uart_tx));uart_rxd uart_rxd(.clk_50m(sys_clk_50m),.reset_n(sys_rst_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));附录2 串口发送源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 09:45:23// Design Name:// Module Name: uart_txd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies:// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd(clk_50m,reset_n,tx_data,baud_set,send_en,send_done,send_busy,uart_tx);input clk_50m;input reset_n;input[7:0] tx_data;input[2:0] baud_set;input send_en;output reg send_done;output reg send_busy;output reg uart_tx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg[7:0] tx_data_r;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)tx_data_r <=8'd0;else if(send_en)tx_data_r <= tx_data;elsetx_data_r <= tx_data_r;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_busy <=1'b0;else if(send_en)send_busy <=1'b1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_busy <=1'b0;elsesend_busy <= send_busy;endelsesend_busy <= send_busy;always@(posedge clk_50m or negedge reset_n)if(!reset_n)send_done <=1'b0;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit ==4'd10)send_done <=1'b1;elsesend_done <=1'b0;endelsesend_done <=1'b0;always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt <=13'd0;else if(send_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;/****************************************always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <= 4'd0;else if(send_en) //send_en needs to be 1 clock high pulse cnt_bit <= 4'd1;else if(cnt == baud_rate_cnt_max)beginif(cnt_bit == 4'd10)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 1'b1;endelsecnt_bit <= cnt_bit;******************************************/always@(posedge clk_50m or negedge reset_n)if(!reset_n)cnt_bit <=4'd0;else if(send_busy &&(cnt_bit ==4'd11))cnt_bit <=4'd1;else if(cnt ==1)cnt_bit <= cnt_bit +1'b1;elsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_tx <=1'b1;endelsecase(cnt_bit)4'd0:;4'd1: uart_tx <=1'b0;//start4'd2: uart_tx <= tx_data_r[0];//bit 04'd3: uart_tx <= tx_data_r[1];4'd4: uart_tx <= tx_data_r[2];4'd5: uart_tx <= tx_data_r[3];4'd6: uart_tx <= tx_data_r[4];4'd7: uart_tx <= tx_data_r[5];4'd8: uart_tx <= tx_data_r[6];4'd9: uart_tx <= tx_data_r[7];//bit 84'd10: uart_tx <=1'b1;//stopdefault:;endcaseendmodule附录3 串口发送testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 11:38:04// Design Name:// Module Name: uart_txd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_txd_tb();reg clk_50m;reg reset_n;reg[7:0] tx_data;reg[2:0] baud_set;reg send_en;wire send_done;wire send_busy;wire uart_tx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial begintx_data =8'h55;baud_set =4;reset_n =0;send_en =0;#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);send_en =1;#(CLK_PERIOD );send_en =0;#(CLK_PERIOD *4340);#(CLK_PERIOD *100);$stop;enduart_txd uart_txd(.clk_50m(clk_50m),.reset_n(reset_n),.tx_data(tx_data),.baud_set(baud_set),.send_en(send_en),.send_done(send_done),.send_busy(send_busy),.uart_tx(uart_tx));endmodule附录4 串口接收源程序`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 15:30:30// Design Name:// Module Name: uart_rxd// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd(clk_50m,reset_n,rx_data,baud_set,rx_done,rx_busy,uart_rx);input clk_50m;input reset_n;output reg[7:0] rx_data;input[2:0] baud_set;output reg rx_done;output reg rx_busy;input uart_rx;reg[12:0] cnt;reg[12:0] baud_rate_cnt_max;reg[3:0] cnt_bit;reg uart_rx_r1;reg uart_rx_r2;wire nedge;localparam baud_rate_9600 =13'd5207;localparam baud_rate_19200 =13'd2603;localparam baud_rate_38400 =13'd1301;localparam baud_rate_57600 =13'd867;localparam baud_rate_115200 =13'd433;always@(posedge clk_50m or negedge reset_n)if(!reset_n)baud_rate_cnt_max <= baud_rate_115200;elsecase(baud_set)3'd0:baud_rate_cnt_max = baud_rate_9600;3'd1:baud_rate_cnt_max = baud_rate_19200;3'd2:baud_rate_cnt_max = baud_rate_38400;3'd3:baud_rate_cnt_max = baud_rate_57600;3'd4:baud_rate_cnt_max = baud_rate_115200;default:baud_rate_cnt_max = baud_rate_115200;endcasealways@(posedge clk_50m or negedge reset_n)if(!reset_n)beginuart_rx_r1 <=8'd0;uart_rx_r2 <=8'd0;endelse beginuart_rx_r1 <= uart_rx;uart_rx_r2 <= uart_rx_r1;endassign nedge = uart_rx_r2 &(!uart_rx_r1);always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_busy <=1'b0;else if(nedge)rx_busy <=1'b1;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_busy <=1'b0;elserx_busy <= rx_busy;endelserx_busy <= rx_busy;always@(posedge clk_50m or negedge reset_n) if(!reset_n)rx_done <=1'b0;else if(cnt == baud_rate_cnt_max)begin if(cnt_bit ==4'd10)rx_done <=1'b1;elserx_done <=1'b0;endelserx_done <=1'b0;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt <=13'd0;else if(rx_busy)beginif(cnt == baud_rate_cnt_max)cnt <=13'd0;elsecnt <= cnt +1'b1;endelsecnt <= cnt;always@(posedge clk_50m or negedge reset_n) if(!reset_n)cnt_bit <=4'd1;else if(cnt == baud_rate_cnt_max )begin if(cnt_bit ==4'd10)cnt_bit <=4'd1;elsecnt_bit <= cnt_bit +1'b1;endelsecnt_bit <= cnt_bit;always@(posedge clk_50m or negedge reset_n)if(!reset_n)beginrx_data <=8'd0;endelse if(cnt == baud_rate_cnt_max /2)case(cnt_bit)4'd1:;//start4'd2: rx_data[0]<= uart_rx_r2;//bit 04'd3: rx_data[1]<= uart_rx_r2;4'd4: rx_data[2]<= uart_rx_r2;4'd5: rx_data[3]<= uart_rx_r2;4'd6: rx_data[4]<= uart_rx_r2;4'd7: rx_data[5]<= uart_rx_r2;4'd8: rx_data[6]<= uart_rx_r2;4'd9: rx_data[7]<= uart_rx_r2;//bit 74'd10:;//stopdefault:;endcaseelserx_data <= rx_data;endmodule附录5串口接收testbench`timescale1ns/1ps///////////////////////////////////////////////////////////////////// /////////////// Company:// Engineer://// Create Date: 2020/06/21 19:44:29// Design Name:// Module Name: uart_rxd_tb// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://///////////////////////////////////////////////////////////////////// /////////////module uart_rxd_tb();reg clk_50m;reg reset_n;wire[7:0] rx_data;wire rx_done;wire rx_busy;reg uart_rx;parameter CLK_PERIOD =20;initial clk_50m =0;always#(CLK_PERIOD /2) clk_50m =~clk_50m;initial beginreset_n =0;uart_rx =1;//idle#(CLK_PERIOD *100);reset_n =1;# CLK_PERIOD;uart_rx =0;//start#(CLK_PERIOD *434);uart_rx =1;//bit0#(CLK_PERIOD *434);uart_rx =0;//bit1#(CLK_PERIOD *434);uart_rx =1;//bit2#(CLK_PERIOD *434);uart_rx =0;//bit3#(CLK_PERIOD *434);uart_rx =1;//bit4#(CLK_PERIOD *434);uart_rx =0;//bit5#(CLK_PERIOD *434);uart_rx =1;//bit6#(CLK_PERIOD *434);uart_rx =0;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);uart_rx =0;//start #(CLK_PERIOD *434);uart_rx =0;//bit0#(CLK_PERIOD *434);uart_rx =1;//bit1#(CLK_PERIOD *434);uart_rx =0;//bit2#(CLK_PERIOD *434);uart_rx =1;//bit3#(CLK_PERIOD *434);uart_rx =0;//bit4#(CLK_PERIOD *434);uart_rx =1;//bit5#(CLK_PERIOD *434);uart_rx =0;//bit6#(CLK_PERIOD *434);uart_rx =1;//bit7#(CLK_PERIOD *434);uart_rx =1;//stop#(CLK_PERIOD *434);uart_rx =1;//idle#(CLK_PERIOD *434);#(CLK_PERIOD *434);#(CLK_PERIOD *434);$stop;enduart_rxd uart_rxd(.clk_50m(clk_50m),.reset_n(reset_n),.rx_data(rx_data),.baud_set(3'd4),.rx_done(rx_done),.rx_busy(rx_busy),.uart_rx(uart_rx));endmodule。

基于VHDL的串口程序

基于VHDL的串口程序

在quartus里面没找到SCI的LPM部件,又不想自己从头编写,在网上找到了一个verilog的程序,也找到了和这个实现方法相同的VHDL程序。

都是接收到按键按下时候,启动串口发送,发送welcom但是都是发现一个,并延时重新读取按键,然后再重新启动发送。

数据格式是9600 boud rate、8数据位、1启动位、1停止位,每16个bit周期发送一个byte,接收程序,没有中间多位判断部分,考虑接收的有效性和可靠性,对程序进行了修改,改为每11个bit周期发送一个byte,这样也可以兼容接收2个停止位的接收程序,在接收程序中进行了多相判断。

程序和截图如下:--本模块的功能是验证实现和PC机进行基本的串口通信的功能。

需要在PC机上安装一个串口调试工具来验证程序的功能。

--程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控制器,10个bit是1位起始位,8个数据位,1个结束位。

--串口的波特律由程序中定义的div_par参数决定,更改该参数可以实现相应的波特率。

程序当前设定的div_par 的值--是0x145,对应的波特率是9600。

用一个8倍波特率的时钟将发送或接受每一位bit的周期时间划分为8个时隙以使通--信同步.--程序的基本工作过程是,按动一个按键key1 控制器向PC的串口发送“welcome",--PC机接收后显示验证数据是否正确(串口调试工具设成按ASCII码接受方式).--PC可随时向FPGA发送0-F的十六进制数据,FPGA接受后显示在7段数码管上.library ieee;-- design by jiaolonglanuse myserial isgeneric ( boud_rate:integer := 9600;clk_rate :integer := 50_000_000);port( clk : in std_logic;rstn : in std_logic;rxd : in std_logic; --receive bittxd : out std_logic; --send bit-- txd_buff :in std_logic_vector(7 downto 0); -- buffer write in-- write_data: in std_logic; -- write dataen :out std_logic_vector(7 downto 0);seg_data:out std_logic_vector(7 downto 0);-- rxd_buff :out std_logic_vector(7 downto 0);key_input:in std_logic-- testout: out std_logic-- read_data: in std_logic);end entity myserial;architecture bhv of myserial isSIGNAL div_reg : integer range 0 to 2**16-1;--分频计数器,分频值由波特率决定。

VerilogRS232串口模块实验报告范文

VerilogRS232串口模块实验报告范文

VerilogRS232串口模块实验报告范文1设计概述实验功能:实现RS232的双工通信。

实验环境:1)硬件环境:PC机一台、ml507PFGA开发套件;2)软件环境:开发软件ISE14.5、代码编写软件Notepad++、仿真软件Modelim、调试软件chipcope、串口调试工具。

2设计原理2.1串行接口RS232工作原理串口用来连接FPGA和PC机,RS-232允许全双工通信,即计算机在接收数据的同时可以发送数据。

串口按位(bit)发送和接收字节。

通常以8位数据为1组,先发送最低有效位,最后发送最高有效位。

尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。

通信使用3根线完成:(1)地线,(2)发送,(3)接收。

由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。

其他线用于握手,但不是必须的。

数据的传输没有时钟信号,接收端必须采取某种方式,使之与接收数据同步。

1)串行线缆的两端先约定好串行传输的参数(传输速度、传输格式等);2)当没有数据传输的时候,发送端向数据线上发送"1";3)每传输一个字节之前,发送端先发送一个"0"来表示传输已经开始,这样接收端便可以知道有数据到来了;图1数据帧结构4)开始传输后,数据以约定的速度和格式传输,所以接收端可以与之同步;5)在串口总线上高电平是默认的状态,当一帧数据开始传输必须先拉低电平,这就是起始位,起始位之后是8位数据位,最后是校验位和停止位(可不加校验位)。

传输完成一个字节之后,都在其后发送一个停止位("1")。

(图1)2.2波特率发生器波特率是串口传输的传输速度;在微观上就是一个位的周期。

常用的波特率有9600bp和115200bp。

“9600bp”表示每秒可以传输9600位。

本次实验我所选用的传输速率为9600bp。

由于我们的FPGA通常运行在远高于9600Hz的频率上(100MHz),因此需要分频产生接近9600Hz的时钟信号。

基于Verilog的串口通信程序

基于Verilog的串口通信程序

算作是Verilog 入门的第一个程序吧,在别人的程序修改过来的,还没有做太多的优化,只优化了一部分。

程序分成4个模块第一个模块时钟分频:`timescale 1ns / 1ps////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 21:27:40 14/07/28// Design Name:// Module Name: speed_select// Project Name:// Target Device:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////module speed_select(clk,rst_n,bps_start,clk_bps);input clk; // 50MHz主时钟input rst_n; //低电平复位信号input bps_start; //接收到数据后,波特率时钟启动信号置位output clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点/*parameter bps9600 = 5207, //波特率为9600bpsbps19200 = 2603, //波特率为19200bpsbps38400 = 1301, //波特率为38400bpsbps57600 = 867, //波特率为57600bpsbps115200 = 433; //波特率为115200bpsparameter bps9600_2 = 2603,bps19200_2 = 1301,bps38400_2 = 650,bps57600_2 = 433,bps115200_2 = 216;*///以下波特率分频计数值可参照上面的参数进行更改`define BPS_PARA 5207 //波特率为9600时的分频计数值`define BPS_PARA_2 2603 //波特率为9600时的分频计数值的一半,用于数据采样reg[12:0] cnt; //分频计数reg clk_bps_r; //波特率时钟寄存器//----------------------------------------------------------reg[2:0] uart_ctrl; // uart波特率选择寄存器//----------------------------------------------------------always @ (posedge clk or negedge rst_n)if(!rst_n) cnt <= 13'd0;else if((cnt == `BPS_PARA) || !bps_start) cnt <= 13'd0; //波特率计数清零else cnt <= cnt+1'b1; //波特率时钟计数启动always @ (posedge clk or negedge rst_n)if(!rst_n) clk_bps_r <= 1'b0;else if(cnt == `BPS_PARA_2) clk_bps_r <= 1'b1;// clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点else clk_bps_r <= 1'b0;assign clk_bps = clk_bps_r;endmodule第二个模块:接收模块`timescale 1ns / 1ps////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 21:27:40 14/07/28// Design Name:// Module Name: my_uart_rx// Project Name:// Target Device:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////// module my_uart_rx(clk,rst_n,rs232_rx,rx_data,rx_int,clk_bps,bps_start,led);input clk; // 50MHz主时钟input rst_n; //低电平复位信号input rs232_rx; // RS232接收数据信号input clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点output bps_start; //接收到数据后,波特率时钟启动信号置位output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到output rx_int; //接收数据中断信号,接收到数据期间始终为高电平output led;//----------------------------------------------------------------reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3; //接收数据寄存器,滤波用wire neg_rs232_rx; //表示数据线接收到下降沿always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginrs232_rx0 <= 1'b0;rs232_rx1 <= 1'b0;rs232_rx2 <= 1'b0;rs232_rx3 <= 1'b0;endelse if(!rx_int) beginrs232_rx0 <= rs232_rx;rs232_rx1 <= rs232_rx0;rs232_rx2 <= rs232_rx1;rs232_rx3 <= rs232_rx2;endend//下面的下降沿检测可以滤掉<20ns-40ns的毛刺(包括高脉冲和低脉冲毛刺),//这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打了好几拍)//(当然我们的有效低脉冲信号肯定是远远大于40ns的)assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;//接收到下降沿后neg_rs232_rx置高一个时钟周期//----------------------------------------------------------------reg bps_start_r;reg[3:0] num; //移位次数reg rx_int; //接收数据中断信号,接收到数据期间始终为高电平always @ (posedge clk or negedge rst_n)if(!rst_n) beginbps_start_r <= 1'bz;rx_int <= 1'b0;endelse if(neg_rs232_rx) begin //接收到串口接收线rs232_rx的下降沿标志信号bps_start_r <= 1'b1; //启动串口准备数据接收rx_int <= 1'b1; //接收数据中断信号使能endelse if(num==4'd8) begin //接收完有用数据信息bps_start_r <= 1'b0; //数据接收完毕,释放波特率启动信号rx_int <= 1'b0; //接收数据中断信号关闭endassign bps_start = bps_start_r;//----------------------------------------------------------------reg[7:0] rx_data_r; //串口接收数据寄存器,保存直至下一个数据来到//----------------------------------------------------------------reg[7:0] rx_temp_data; //当前接收数据寄存器always @ (posedge clk or negedge rst_n)if(!rst_n) beginrx_temp_data <= 8'd0;num <= 4'd0;rx_data_r <= 8'd0;endelse if(rx_int) begin //接收数据处理if(clk_bps) begin //读取并保存数据,接收数据为一个起始位,8bit数据,1或2个结束位num <= num+1'b1;case (num)4'd1: rx_temp_data[0] <= rs232_rx; //锁存第0bit4'd2: rx_temp_data[1] <= rs232_rx; //锁存第1bit4'd3: rx_temp_data[2] <= rs232_rx; //锁存第2bit4'd4: rx_temp_data[3] <= rs232_rx; //锁存第3bit4'd5: rx_temp_data[4] <= rs232_rx; //锁存第4bit4'd6: rx_temp_data[5] <= rs232_rx; //锁存第5bit4'd7: rx_temp_data[6] <= rs232_rx; //锁存第6bit4'd8: rx_temp_data[7] <= rs232_rx; //锁存第7bit4'd9: beginnum <= 4'd0; //接收到STOP位后结束,num清零xiarx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中enddefault: ;endcaseend/* else if(num == 4'd9) begin //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据num <= 4'd0; //接收到STOP位后结束,num清零xiarx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中end */endassign rx_data = rx_data_r;assign led= rs232_rx;endmodule第三个模块发送:`timescale 1ns / 1ps////////////////////////////////////////////////////////////////////////////////// Company:// Engineer://// Create Date: 21:27:40 14/07/28// Design Name:// Module Name: my_uart_rx// Project Name:// Target Device:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments://////////////////////////////////////////////////////////////////////////////////module my_uart_tx(clk,rst_n,rx_data,rx_int,rs232_tx,clk_bps,bps_start,led);input clk; // 50MHz主时钟input rst_n; //低电平复位信号input clk_bps; // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点input[7:0] rx_data; //接收数据寄存器input rx_int; //接收数据中断信号,接收到数据期间始终为高电平,在该模块中利用它的下降沿来启动串口发送数据output rs232_tx; // RS232发送数据信号output bps_start; //接收或者要发送数据,波特率时钟启动信号置位output led;//---------------------------------------------------------reg rx_int0,rx_int1,rx_int2; //rx_int信号寄存器,捕捉下降沿滤波用wire neg_rx_int; // rx_int下降沿标志位always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginrx_int0 <= 1'b0;rx_int1 <= 1'b0;rx_int2 <= 1'b0;endelse beginrx_int0 <= rx_int;rx_int1 <= rx_int0;rx_int2 <= rx_int1;endendassign neg_rx_int = rx_int1 & ~rx_int2; //捕捉到下降沿后,neg_rx_int拉高保持一个主时钟周期//---------------------------------------------------------reg[7:0] tx_data; //待发送数据的寄存器//---------------------------------------------------------reg bps_start_r;reg tx_en; //发送数据使能信号,高有效reg[3:0] num;always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginbps_start_r <= 1'bz;tx_en <= 1'b0;tx_data <= 8'd0;endelse if(neg_rx_int) begin //接收数据完毕,准备把接收到的数据发回去bps_start_r <= 1'b1;tx_data <= rx_data; //把接收到的数据存入发送数据寄存器tx_en <= 1'b1; //进入发送数据状态中endelse if(num==4'd9) begin //数据发送完成,复位bps_start_r <= 1'b0;tx_en <= 1'b0;endendassign bps_start = bps_start_r;//---------------------------------------------------------reg rs232_tx_r;always @ (posedge clk or negedge rst_n) beginif(!rst_n) beginnum <= 4'd0;rs232_tx_r <= 1'b1;endelse if(tx_en) beginif(clk_bps) beginnum <= num+1'b1;case (num)4'd0: rs232_tx_r <= 1'b0; //发送起始位4'd1: rs232_tx_r <= tx_data[0]; //发送bit04'd2: rs232_tx_r <= tx_data[1]; //发送bit14'd3: rs232_tx_r <= tx_data[2]; //发送bit24'd4: rs232_tx_r <= tx_data[3]; //发送bit34'd5: rs232_tx_r <= tx_data[4]; //发送bit44'd6: rs232_tx_r <= tx_data[5]; //发送bit54'd7: rs232_tx_r <= tx_data[6]; //发送bit64'd8: rs232_tx_r <= tx_data[7]; //发送bit74'd9: rs232_tx_r <= 1'b1; //发送结束位4'd10: num <= 4'd0;default: rs232_tx_r <= 1'b1;endcaseendendendassign rs232_tx = rs232_tx_r;assign led = rs232_tx_r;endmodule第四个模块底层设计:`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////// // Company:// Engineer://// Create Date:// Design Name:// Module Name: my_uart_top// Project Name:// Target Device:// Tool versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////// module my_uart_top(clk,rst_n,rs232_rx,rs232_tx,ledr,ledt);input clk; // 50MHz主时钟input rst_n; //低电平复位信号input rs232_rx; // RS232接收数据信号output rs232_tx; // RS232发送数据信号output ledr; //接收指示灯output ledt; //发送指示灯wire bps_start1,bps_start2; //接收到数据后,波特率时钟启动信号置位wire clk_bps1,clk_bps2; // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点wire[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到wire rx_int; //接收数据中断信号,接收到数据期间始终为高电平//----------------------------------------------------//下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制//(不是资源共享,和软件中的同一个子程序调用不能混为一谈)////////////////////////////////////////////speed_select speed_rx(.clk(clk), //波特率选择模块.rst_n(rst_n),.bps_start(bps_start1),.clk_bps(clk_bps1));my_uart_rx my_uart_rx(.clk(clk), //接收数据模块.rst_n(rst_n),.rs232_rx(rs232_rx),.rx_data(rx_data),.rx_int(rx_int),.clk_bps(clk_bps1),.bps_start(bps_start1),.led(ledr));///////////////////////////////////////////speed_select speed_tx(.clk(clk), //波特率选择模块.rst_n(rst_n),.bps_start(bps_start2),.clk_bps(clk_bps2));my_uart_tx my_uart_tx(.clk(clk), //发送数据模块.rst_n(rst_n),.rx_data(rx_data),.rx_int(rx_int),.rs232_tx(rs232_tx),.clk_bps(clk_bps2),.bps_start(bps_start2),.led(ledt));endmodule。

RS232设计报告和verilog代码,含testbench,可以直接运行

RS232设计报告和verilog代码,含testbench,可以直接运行

RS232接口数据转发协议实验报告1.设计要求设计RS232接口数据转发协议,将8位并行数据转发为RS232协议的串口数据发送出去。

entity rs232port ( clk: in std_logic; -- 16MHz输入时钟rdy: in std_logic; --数据准备好信号, 1个时钟周期的正脉冲data: in std_logic_vector(7 downto 0); --要发送的并行数据bps: in std_logic_vector(1 downto 0); --波特率设置-- 00:4800bps 01:9600 10:19200 11:38400parity : in std_logic; --奇偶校验控制,0:奇校验 1:偶校验d_out: out std_logic); --串行数据输出end rs232;协议要求:(1)波特率:4800/ 9600/19200/38400可选(2)8位数据位,1位停止位,偶校验可选设计要求:(1)采用VHDL或Verilog语言设计上述电路;(2)写出测试激励文件,并仿真;(3)分析仿真结果,并撰写设计报告.(4)提交完整的纸质设计报告并附源代码.2.接口协议要求一个字符一个字符传输,每传一个字符总是以起始位开始,以停止位结束,字符之间没有固定时间间隔要求。

波特率可在4800、9600、19200、38400中选择。

每一个字符前面都有一位起始位(低电平),字符本身有5-7位数据位,接着是一位校验位,最后是一位停止位。

停止位和空闲位规定必须为高电平3.系统结构分析本设计采用自顶向下的分析方法,结合端口要求和协议要求,将设计分为顶层模块和底层模块。

顶层模块框图如下:底层模块主要又包含两个部分,时钟分频和串行输出。

时钟分频模块结构图如下:串行输出模块结构图如下:顶层模块和底层模块的关系如下:4.实验结果分析在使用verilog HDL实现各模块的过程中,采用自底向上的实现方法,将各个模块逐一实现后进行编译、仿真。

串口通讯设计之Verilog实现

串口通讯设计之Verilog实现

串口通讯设计之V e r i l o g实现FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。

FPGA选用Xilinx公司的Spartan?II系列xc2s50。

此部分为该设计的主体。

如上所述,输入数据的传输速率为700k波特率。

为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。

1 串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要。

串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线。

串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送。

在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定。

约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。

异步起止式的祯信息格式为:每祯信息由四部分组成:a.1位起始位。

b.5~8位数据位。

传送顺序是低位在前,高位在后.依次传送。

c.一位校验位,也可以没有。

d.最后是1位或是2位停止位。

FPGA(Field Pmgrammable Gate Array)现场可编程门阵列在数字电路的设计中已经被广泛使用。

这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性。

本文详细介绍了已在实际项目中应用的基于FPGA的串口通讯设计。

本设计分为硬件电路设计和软件设计两部分,最后用仿真验证了程序设计的正确性。

2 系统的硬件设计本方案的异步串行通信的硬件接口电路图如图1所示,主要由四部分组成:RS-485数据发送模块、FPGA 串口模块、MAX3223和DB9。

串口通讯设计之Verilog实现

串口通讯设计之Verilog实现

串口通讯设计之Verilog 实现FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。

FPGA选用Xilinx公司的Spartan II系列xc2s50。

此部分为该设计的主体。

如上所述,输入数据的传输速率为700k波特率。

为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。

1串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要。

串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线。

串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送。

在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定。

约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做岀统一规定,通信双方必须共同遵守。

异步起止式的祯信息格式为:每祯信息由四部分组成:a. 1位起始位。

b. 5~8位数据位。

传送顺序是低位在前,高位在后.依次传送。

c. 一位校验位,也可以没有。

d. 最后是1位或是2位停止位。

FPGA(Field Pmgrammable Gate Array) 现场可编程门阵列在数字电路的设计中已经被广泛使用。

这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性。

本文详细介绍了已在实际项目中应用的基于FPGA的串口通讯设计。

本设计分为硬件电路设计和软件设计两部分,最后用仿真验证了程序设计的正确性。

2系统的硬件设计本方案的异步串行通信的硬件接口电路图如图1所示,主要由四部分组成:RS-485数据发送模块、FPGA串口模块、MAX3223和DB9。

verilog串口通信程序

verilog串口通信程序

verilog串⼝通信程序FPGA实现RS-232串⼝收发的仿真过程(Quartus+Synplify+ModelSim)(2007-09-11 12:17:37)⽹上关于RS-232的异步收发介绍得很多,最近没事学着摸索⽤ModelSim来做时序仿真,就结合⽹上的参考资料和⾃⼰的琢磨,做了这个东西。

针对我这个⼩程序结合FPGA的开发流程,主要⾛了以下⼏步:1. ⽂本程序输⼊(Verilog HDL)2. 功能仿真(ModelSim,查看逻辑功能是否正确,要写⼀个Test Bench)3. 综合(Synplify Pro,程序综合成⽹表)4. 布局布线(Quartus II,根据我选定的FPGA器件型号,将⽹表布到器件中,并估算出相应的时延)5. 时序仿真(ModelSim,根据时延做进⼀步仿真)这⾥贴出我的程序和各个详细步骤,能和各位正在学习的新⼿们⼀起分享。

0. 原理略⼀、⽂本程序输⼊(Verilog HDL)发送端:module trans(clk,rst,TxD_start,TxD_data,TxD,TxD_busy);input clk,rst,TxD_start;input[7:0] TxD_data; lk(clk),.rst(rst),.TxD_start(TxD_start),.TxD_busy(TxD_busy),.TxD_data(TxD_data),.TxD(TxD));rcv rcv(.clk(clk),.rst(rst),.RxD(TxD), xD_data(RxD_data),.RxD_data_ready(RxD_data_ready));initial beginTxD_start = 0;TxD_data = 0;clk = 0;rst = 1;#54 rst = 0;#70 rst = 1;#40 TxD_start = 1'b1;#10 TxD_data = 8'b;#100 TxD_start = 1'b0;endalways begin#30 clk = ~clk;#10 clk = ~clk;endendmodule⼆、综合三、FPGA与PC串⼝⾃收发通信串⼝通信其实简单实⽤,这⾥我就不多说,只把⾃⼰动⼿写的verilog代码共享下。

Verilog之串口(UART)通信

Verilog之串口(UART)通信

Verilog之串口(UART)通信0:起始位,低电平;1~8:数据位;9:校验位,高电平;10:停止位,高电平。

波特率“9600bps”表示每秒可以传输9600位。

波特率定时计数器由时钟频率除以波特率。

采集1~8位,忽略0、9、10位。

发送“0、8位数据、1、1”串口传输数据,从最低位开始,到最高位结束。

串口发送:module tx_bps_module(CLK, RSTn,Count_Sig,BPS_CLK);input CLK;input RSTn;input Count_Sig;output BPS_CLK;/***************************/reg [12:0]Count_BPS;always @ ( posedge CLK or negedge RSTn )if( !RSTn )Count_BPS <= 13'd0;else if( Count_BPS == 13'd5207 )Count_BPS <= 13'd0;else if( Count_Sig )Count_BPS <= Count_BPS + 1'b1;elseCount_BPS <= 13'd0;/********************************/assign BPS_CLK = ( Count_BPS == 13'd2604 ) ? 1'b1 : 1'b0; /*********************************/endmodulemodule tx_control_module(CLK, RSTn,TX_En_Sig, TX_Data, BPS_CLK,TX_Done_Sig, TX_Pin_Out);input CLK;input RSTn;input TX_En_Sig;input [7:0]TX_Data;input BPS_CLK;output TX_Done_Sig;output TX_Pin_Out;/********************************************************/reg [3:0]i;reg rTX;reg isDone;always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;rTX <= 1'b1;isDone <= 1'b0;endelse if( TX_En_Sig )case ( i )4'd0 :if( BPS_CLK ) begin i <= i + 1'b1; rTX <= 1'b0; end4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7, 4'd8 :if( BPS_CLK ) begin i <= i + 1'b1; rTX <= TX_Data[ i - 1 ]; end4'd9 :if( BPS_CLK ) begin i <= i + 1'b1; rTX <= 1'b1; end4'd10 :if( BPS_CLK ) begin i <= i + 1'b1; rTX <= 1'b1; end4'd11 :if( BPS_CLK ) begin i <= i + 1'b1; isDone <= 1'b1; end4'd12 :begin i <= 4'd0; isDone <= 1'b0; endendcase/********************************************************/assign TX_Pin_Out = rTX;assign TX_Done_Sig = isDone;/*********************************************************/ endmodulemodule tx_module(CLK, RSTn,TX_Data, TX_En_Sig,TX_Done_Sig, TX_Pin_Out);input CLK;input RSTn;input [7:0]TX_Data;input TX_En_Sig;output TX_Done_Sig;output TX_Pin_Out;/********************************/wire BPS_CLK;tx_bps_module U1(.CLK( CLK ),.RSTn( RSTn ),.Count_Sig( TX_En_Sig ), // input - from U2 .BPS_CLK( BPS_CLK ) // output - to U2 );/*********************************/tx_control_module U2(.CLK( CLK ),.RSTn( RSTn ),.TX_En_Sig( TX_En_Sig ), // input - from top.TX_Data( TX_Data ), // input - from top.BPS_CLK( BPS_CLK ), // input - from U2.TX_Done_Sig( TX_Done_Sig ), // output - to top .TX_Pin_Out( TX_Pin_Out ) // output - to top );/***********************************/endmodule串口接受module detect_module(CLK, RSTn,RX_Pin_In,H2L_Sig);input CLK;input RSTn;input RX_Pin_In;output H2L_Sig;/******************************/reg H2L_F1;reg H2L_F2;always @ ( posedge CLK or negedge RSTn )if( !RSTn )beginH2L_F1 <= 1'b1;H2L_F2 <= 1'b1;endelsebeginH2L_F1 <= RX_Pin_In;H2L_F2 <= H2L_F1;end/***************************************/ assign H2L_Sig = H2L_F2 & !H2L_F1;/***************************************/ endmodulemodule rx_control_module(CLK, RSTn,H2L_Sig, RX_Pin_In, BPS_CLK, RX_En_Sig,Count_Sig, RX_Data, RX_Done_Sig);input CLK;input RSTn;input H2L_Sig;input RX_En_Sig;input RX_Pin_In;input BPS_CLK;output Count_Sig;output [7:0]RX_Data;output RX_Done_Sig;/********************************************************/reg [3:0]i;reg [7:0]rData;reg isCount;reg isDone;always @ ( posedge CLK or negedge RSTn )if( !RSTn )begini <= 4'd0;rData <= 8'd0;isCount <= 1'b0;isDone <= 1'b0;endelse if( RX_En_Sig )case ( i )4'd0 :if( H2L_Sig ) begin i <= i + 1'b1; isCount <= 1'b1; end /*进入第0位,同时驱动bps_module开始计数。

串口通信Verilog源程序

串口通信Verilog源程序

串口通信Verilog源程序测试过,很好用。

//----------------------------------------------------- // Design Name : uart// File Name :// Function : Simple UART// Coder : Deepak Kumar Tala//----------------------------------------------------- module uart (reset ,txclk ,ld_tx_data ,tx_data ,tx_enable ,tx_out ,tx_empty ,rxclk ,uld_rx_data ,rx_data ,rx_enable ,rx_in ,rx_empty);// Port declarationsinput reset ; input txclk ; input ld_tx_data ; input [7:0] tx_data ; input tx_enable ; output tx_out ; output tx_empty ; input rxclk ; input uld_rx_data ; output [7:0] rx_data ; input rx_enable ; input rx_in ; output rx_empty ; // Internal Variablesreg [7:0] tx_reg ;reg tx_empty ;reg tx_over_run ;reg [3:0] tx_cnt ;reg tx_out ;reg [7:0] rx_reg ;reg [7:0] rx_data ;reg [3:0] rx_sample_cnt ;reg [3:0] rx_cnt ;reg rx_frame_err ;reg rx_over_run ;reg rx_empty ;reg rx_d1 ;reg rx_d2 ;reg rx_busy ;// UART RX Logicalways @ (posedge rxclk or posedge reset) if (reset) beginrx_reg <= 0;rx_data <= 0;rx_sample_cnt <= 0;rx_cnt <= 0;rx_frame_err <= 0;rx_over_run <= 0;rx_empty <= 1;rx_d1 <= 1;rx_d2 <= 1;rx_busy <= 0;end else begin// Synchronize the asynch signalrx_d1 <= rx_in;rx_d2 <= rx_d1;// Uload the rx dataif (uld_rx_data) beginrx_data <= rx_reg;rx_empty <= 1;end// Receive data only when rx is enabledif (rx_enable) begin// Check if just received start of frameif (!rx_busy && !rx_d2) beginrx_busy <= 1;rx_sample_cnt <= 1;rx_cnt <= 0;end// Start of frame detected, Proceed with rest of dataif (rx_busy) beginrx_sample_cnt <= rx_sample_cnt + 1;// Logic to sample at middle of dataif (rx_sample_cnt == 7) beginif ((rx_d2 == 1) && (rx_cnt == 0)) beginrx_busy <= 0;end else beginrx_cnt <= rx_cnt + 1;// Start storing the rx dataif (rx_cnt > 0 && rx_cnt < 9) beginrx_reg[rx_cnt - 1] <= rx_d2;endif (rx_cnt == 9) beginrx_busy <= 0;// Check if End of frame receivedcorrectlyif (rx_d2 == 0) beginrx_frame_err <= 1;end else beginrx_empty <= 0;rx_frame_err <= 0;// Check if last rx data was not unloaded,rx_over_run <= (rx_empty) ? 0 : 1;endendendendendendif (!rx_enable) beginrx_busy <= 0;endend// UART TX Logicalways @ (posedge txclk or posedge reset)if (reset) begintx_reg <= 0;tx_empty <= 1;tx_over_run <= 0;tx_out <= 1;tx_cnt <= 0;end else beginif (ld_tx_data) beginif (!tx_empty) begintx_over_run <= 0;end else begintx_reg <= tx_data;tx_empty <= 0;endendif (tx_enable && !tx_empty) begintx_cnt <= tx_cnt + 1;if (tx_cnt == 0) begintx_out <= 0;endif (tx_cnt > 0 && tx_cnt < 9) begin tx_out <= tx_reg[tx_cnt -1];endif (tx_cnt == 9) begintx_out <= 1;tx_cnt <= 0;tx_empty <= 1;endendif (!tx_enable) begintx_cnt <= 0;endendendmodule。

基于VerilogHDL语言的串口设计说明

基于VerilogHDL语言的串口设计说明

基于Verilog HDL语言的串口设计串口Verilog HDL代码://串口moduletrans(clk,rst,en,TxD_data,Wsec,RxD,TxD,TxD_busy,rcven,RxD_data);//时钟50MHzinput clk,rst,en; //en时发送数据使能input [7:0]TxD_data; //发送数据输入input [2:0]Wsec; //波特率调节0-2400;1-4800;2-9600;3-14400;4-19200;5-38400;6-115200;7-128000input RxD; //接收数据输入端output TxD,TxD_busy,rcven;//发送,发送忙,接收结束标志输出output [7:0]RxD_data;//接收数据输出wire Baud1,Baud8;reg [7:0]addwire;//RAM地址连线reg [7:0]data;wire[7:0]AD_t;//读取RAM数据的地址用于发送wire[7:0]AD_r;//接收的数据存储在RAM中的地址wire [7:0]datawire;//数据连线//发送例化trans_ttt1(.clk_t(clk),.rst_t(rst),.en_t(en),.BTI_t(Baud1),.recen(recen),.TxD_data_t(datawire),.TxD_t(TxD),.addro_t(AD_t),.TxD_busy_t(TxD_ busy));//波特生成例化BaudGtt2(.clk_b(clk),.rst_b(rst),.BTO_b(Baud1),.BTO_R(Baud8),.Wsec_b(Wsec) );//接收例化trans_r tt3(.clk_r(clk),.rst_r(rst),.BTI_r(Baud8),.RxD_r(RxD),.RxD_data_r(RxD_data),.wren_r(wren_r),.addro_r(AD_r),.RxD_end(RxD _end));//LPM_RAM例化RAM0tt4(.address(addwire),.clock(~clk),.data(data),.wren(wren_r),.q(dataw ire));always (posedge clk or negedge rst)if(~rst)addwire <= 8'b00000000;else if(RxD_end)beginaddwire <=AD_r ;data<=RxD_data;endelse addwire<=AD_t;endmodule//发送模块moduletrans_t(clk_t,rst_t,en_t,BTI_t,TxD_data_t,TxD_t,recen,TxD_busy_t,addr o_t,recen );input clk_t,rst_t,en_t,BTI_t;input [7:0]TxD_data_t;output TxD_t;output TxD_busy_t;output recen;output [7:0]addro_t;reg TxD_t;reg [7:0]TxD_dataReg;//寄存器reg [7:0]addro_t;//reg [3:0]state;reg recen;wire TxD_busy_t;assign BaudTick = BTI_t;//波特输出// 发送启动wire TxD_ready = (state==0); // TxD_ready = 1assign TxD_busy_t = ~TxD_ready;// 加载发送数据always (posedge clk_t or negedge rst_t)if(~rst_t)TxD_dataReg <= 8'b00000000;else if(TxD_ready && en_t)TxD_dataReg <= TxD_data_t;// 状态机发送always (posedge clk_t or negedge rst_t)if(~rst_t)beginstate <= 4'b0000; // 复位时发送1TxD_t <= 1'b1;endelsecase(state)4'b0000: if(en_t ) beginstate <= 4'b0100; // 检测发送开始end4'b0100: if(BaudTick && en_t) beginstate <= 4'b1000; // 发送起始位0TxD_t <= 1'b0;end4'b1000: if(BaudTick && en_t) beginstate <= 4'b1001; // bit 0if(en_t) TxD_t <= TxD_dataReg[0];else TxD_t <= 1'b0;end4'b1001: if(BaudTick && en_t) beginstate <= 4'b1010; // bit 1if(en_t) TxD_t <= TxD_dataReg[1];else TxD_t <= 1'b0;end4'b1010: if(BaudTick && en_t) beginstate <= 4'b1011; // bit 2if(en_t) TxD_t <= TxD_dataReg[2];else TxD_t <= 1'b0;end4'b1011: if(BaudTick && en_t) beginstate <= 4'b1100; // bit 3if(en_t) TxD_t <= TxD_dataReg[3];else TxD_t <= 1'b0;end4'b1100: if(BaudTick && en_t) beginstate <= 4'b1101; // bit 4if(en_t) TxD_t <= TxD_dataReg[4];else TxD_t <= 1'b0;end4'b1101: if(BaudTick && en_t) beginstate <= 4'b1110; // bit 5if(en_t) TxD_t <= TxD_dataReg[5];else TxD_t <= 1'b0;end4'b1110: if(BaudTick && en_t) beginstate <= 4'b1111; // bit 6if(en_t) TxD_t <= TxD_dataReg[6];else TxD_t <= 1'b0;end4'b1111: if(BaudTick && en_t) beginstate <= 4'b0010; // bit 7if(en_t) TxD_t <= TxD_dataReg[7];else TxD_t <= 1'b0;end4'b0010: if(BaudTick && en_t) beginstate <= 4'b0011; // stop1TxD_t <= 1'b1;end4'b0011: if(BaudTick) beginstate <= 4'b0000; // stop2TxD_t <= 1'b1;enddefault: if(BaudTick) beginstate <= 4'b0000;TxD_t <= 1'b1;endendcasealways (posedge clk_t or negedge rst_t)if(~rst_t)begin recen<=0;endelse if(~TxD_ready)recen<=1;else recen<=0;//地址计数器ddressalways (posedge clk_t or negedge rst_t)if(~rst_t)addro_t <= 8'b00000000;else if(TxD_ready && en_t)addro_t <=addro_t +1;endmodule//波特生成模块module BaudG(clk_b,rst_b,BTO_b,BTO_R,Wsec_b);input clk_b,rst_b;input [2:0]Wsec_b;output BTO_b,BTO_R;reg FT,FT8;reg [16:0]BGA;reg [16:0]BGA1;wire BTO_b = FT; //发送波特wire BTO_R = FT8;//接收模块波特=发送*16always (posedge clk_b or negedge rst_b )if(~rst_b)begin BGA <= 0;BGA1 <= 0;endelsecase(Wsec_b)0:beginif(BGA1>1302)begin FT8=1'b1; BGA1<=0; end // 接收波特=2400*16else begin FT8=1'b0; BGA1 <= BGA1+ 1;endif(BGA>62500)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=2400else begin FT=1'b0; BGA <= BGA+ 3; endend1: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end // 接收波特=4800*16else begin FT8=1'b0; BGA1 <= BGA1+ 1;endif(BGA>62500)begin FT=1'b1; FT8=1'b1; BGA1<=0;BGA<=0; end // 发送波特=4800else begin FT=1'b0; BGA <= BGA+ 6; endend2: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end // 接收波特=9600*16else begin FT8=1'b0; BGA1<= BGA1+ 2; endif(BGA>15625)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=9600else begin FT=1'b0; BGA <= BGA+ 3; endend3: begin if(BGA1>217)begin FT8=1'b1; BGA1<=0; end // 接收波特=14400*16else begin FT8=1'b0; BGA1 <= BGA1+ 1;endif(BGA>17361)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=14400else begin FT=1'b0; BGA <= BGA+ 5; endend4: begin if(BGA1>651)begin FT8=1'b1; BGA1<=0; end //接收波特=19200*16else begin FT8=1'b0; BGA1 <= BGA1+ 4;endif(BGA>15625)begin FT=1'b1; FT8=1'b1; BGA1<=0;BGA<=0; end // 发送波特=19200else begin FT=1'b0; BGA <= BGA+ 6;endend5: begin if(BGA1>244)begin FT8=1'b1; BGA1<=0; end // 接收波特=38400*16else begin FT8=1'b0; BGA1 <= BGA1+ 3;endif(BGA>15625)begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=38400else begin FT=1'b0; BGA <= BGA+ 12;endend6: begin if(BGA1>217)begin FT8=1'b1; BGA1<=0; end // 接收波特=115200*16else begin FT8=1'b0; BGA1 <= BGA1+ 8;endif(BGA>434) begin FT=1'b1;FT8=1'b1; BGA1<=0; BGA<=0; end // 发送波特=115200else begin FT=1'b0; BGA <= BGA+ 1;endend7: begin if(BGA1>122)begin FT8=1'b1; BGA1<=0; end // 接收波特=128000*16else begin FT8=1'b0; BGA1 <= BGA1+ 5;endif(BGA>3125) begin FT=1'b1; BGA<=0;FT8=1'b1; BGA1<=0; end // 发送波特=128000else begin FT=1'b0; BGA <= BGA+ 8;endenddefault:begin BGA<=0;FT=1'b0;endendcaseendmodule//接收模块moduletrans_r(clk_r,rst_r,BTI_r,RxD_r,RxD_data_r,wren_r,addro_r,RxD_end);input clk_r,rst_r,RxD_r,BTI_r;output [7:0]RxD_data_r;output wren_r,RxD_end;output [7:0]addro_r;reg [3:0]bit_spacing;//两Bit间隔16reg RxD_end; //接收数据有效标志reg RxD_delay; //中间参量reg RxD_en; //接收使能reg [7:0]RxD_data_r; //接收数据输出reg [7:0]RxD_cach; //接收数据缓存reg [3:0]state;reg [7:0]addro_r; //地址reg wren_r;assign Baud8Tick = BTI_r;//接收波特always (posedge clk_r or negedge rst_r)if(~rst_r)bit_spacing<=0;elsecase(state)0: bit_spacing<=0;default:if(Baud8Tick)bit_spacing<=bit_spacing+1;endcasewire next_bit=(bit_spacing==5);//两bit间隔16波特always (posedge clk_r)if(Baud8Tick)beginRxD_delay<=RxD_r;RxD_en<=(Baud8Tick & RxD_delay & (~RxD_r));//检测接收信号是否有下降沿end//状态机接收always(posedge clk_r or negedge rst_r)if(~rst_r)state <= 4'b0000;else if(Baud8Tick)case(state)4'b0000: if(RxD_en) state <= 4'b0001; // 有下降沿开始接收4'b0001: if(next_bit) state <= 4'b1000; // bit 04'b1000: if(next_bit) state <= 4'b1001; // bit 14'b1001: if(next_bit) state <= 4'b1010; // bit 24'b1010: if(next_bit) state <= 4'b1011; // bit 34'b1011: if(next_bit) state <= 4'b1100; // bit 44'b1100: if(next_bit) state <= 4'b1101; // bit 54'b1101: if(next_bit) state <= 4'b1110; // bit 64'b1110: if(next_bit) state <= 4'b1111; // bit 74'b1111: if(next_bit) state <= 4'b0010; // 停止位4'b0010: if(next_bit) state <= 4'b0000;default: state <= 4'b0000;endcase// 移位寄存器接收always (posedge clk_r or negedge rst_r)if(~rst_r)RxD_cach <= 8'b00000000;else if(Baud8Tick && next_bit && state[3])RxD_cach <= {RxD_r, RxD_cach[7:1]};//停止位与接收结束标志位有效时将数据输出always (posedge clk_r or negedge rst_r)if(~rst_r)RxD_data_r <= 8'b00000000;else if(RxD_end && RxD_r)RxD_data_r <= RxD_cach;// 产生接收结束标志位always (posedge clk_r or negedge rst_r)if(~rst_r)begin RxD_end<=0;endelsebegin RxD_end<=(Baud8Tick && next_bit && state==4'b0010 && RxD_r);endalways (posedge clk_r or negedge rst_r)if(~rst_r)begin wren_r<=0;endelse if(RxD_end)wren_r<=1;else wren_r<=0;//地址计数器ddressalways (posedge clk_r or negedge rst_r)if(~rst_r)addro_r <= 8'b11111111;else if(RxD_end)addro_r <=addro_r +1;endmodule为了测试收发是否正常,写的Test Bench`timescale 1ns/1nsmodule trsb;reg clk,rst,en;reg [7:0]TxD_data;reg [2:0]Wsec;wire TxD,TxD_busy,rcven;wire [7:0]RxD_data;trans trsb(.clk(clk),.rst(rst),.en(en),.TxD(TxD),.Wsec(Wsec),.TxD_busy(TxD_busy),.TxD_data(TxD_data),.rcven(rcven),.RxD_data(RxD_data),.RxD(TxD));initial beginen = 0;TxD_data = 0;rst = 1;#1 Wsec=2;#54 rst=0;#70 rst=1;#10 TxD_data = 8'b11011001;#10 en = 1'b1;#1250000 en = 1'b1;endinitial begin#3790000 TxD_data = 8'b01011010; #10 en = 1'b1;#2750000 en = 1'b0;#1290000 TxD_data = 8'b101001010; #10 en = 1'b1;#2750000 en = 1'b0;endinitial beginclk = 1;while (1)#10 clk = ~clk;endendmoduleFPGA实现串行接口 RS232(1)2008-12-17 11:38串行接口(RS-232)串行接口是连接FPGA和PC机的一种简单方式。

串口RS232通信程序(Verilog)

串口RS232通信程序(Verilog)

串口RS232通信程序(Verilog)串口有9个管脚,其中只有三个是最重要的,分别是pin 2: RxD (receive data). 接收数据pin 3: TxD (transmit data). 发送数据pin 5: GND (ground). 地串行通信时序我们先来看看字节0x55的发送0x55的二进制代码是01010101,但发送时由低字节开始的,因此发送次序依次为1-0-1-0-1-0-1-0.串行通信电平·"1" is sent using -10V (or between -5V and -15V).·"0" is sent using +10V (or between 5V and 15V).由于计算机RS232的电平与电路板(通常+5V)之间电平的不同所以要用到转换芯片如果PCB板电源+-5V的话用MAX232如果PCB板(FPGA)电源是+-3.3V的话用MAX3232这个图的串口如果采用母头的话,要用交叉公母线,保证是PCB板上这边的RxD连计算机的TxD(3 Pin),PCB板这边的TxD连计算机的RxD(2 Pin).串行通信波特率这里要弄清楚波特率与比特率的差别:比特率是数字信号的传输速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数bit/s(bps)、每秒千比特数(Kbps)或每秒兆比特数(Mbps)来表示(此处K和M分别为1000和1000000,而不是涉及计算机存储器容量时的1024和1048576)。

波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,其单位为波特(Baud)。

波特率与比特率的关系为:比特率=波特率X单个调制状态对应的二进制位数两相调制(单个调制状态对应1个二进制位)的比特率等于波特率;四相调制(单个调制状态对应2个二进制位)的比特率为波特率的两倍;八相调制(单个调制状态对应3个二进制位)的比特率为波特率的三倍;依次类推。

串口通讯设计之Verilog实现

串口通讯设计之Verilog实现

串口通讯设计之V e r i l o g实现Company Document number:WUUT-WUUY-WBBGB-BWYTT-1982GT串口通讯设计之V e r i l o g实现FPGA串口模块是将由RS-485发送过来的数据进行处理,提取出8位有效数据,并按异步串口通讯的格式要求输出到MAX3223的12脚。

FPGA选用Xilinx公司的SpartanII系列xc2s50。

此部分为该设计的主体。

如上所述,输入数据的传输速率为700k波特率。

为了使FPGA能够正确地对输入数据进行采样,提高分辨率能力和抗干扰能力,采样时钟必须选用比波特率更高的时钟,理论上至少是波特率时钟的2倍。

1 串口通信基本特点随着多微机系统的应用和微机网络的发展,通信功能越来越显得重要。

串行通信是在一根传输线上一位一位地传送信息.这根线既作数据线又作联络线。

串行通信作为一种主要的通信方式,由于所用的传输线少,并且可以借助现存的电话网进行信息传送,因此特别适合于远距离传送。

在串行传输中,通信双方都按通信协议进行,所谓通信协议是指通信双方的一种约定。

约定对数据格式、同步方式、传送速度、传送步骤、纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。

异步起止式的祯信息格式为:每祯信息由四部分组成:位起始位。

~8位数据位。

传送顺序是低位在前,高位在后.依次传送。

c.一位校验位,也可以没有。

d.最后是1位或是2位停止位。

FPGA(Field Pmgrammable Gate Array)现场可编程门阵列在数字电路的设计中已经被广泛使用。

这种设计方式可以将以前需要多块集成芯片的电路设计到一块大模块可编程逻辑器件中,大大减少了电路板的尺寸,增强了系统的可靠性和设计的灵活性。

本文详细介绍了已在实际项目中应用的基于FPGA的串口通讯设计。

本设计分为硬件电路设计和软件设计两部分,最后用仿真验证了程序设计的正确性。

2 系统的硬件设计本方案的异步串行通信的硬件接口电路图如图1所示,主要由四部分组成:RS-485数据发送模块、FPGA 串口模块、MAX3223和DB9。

基于verilog的串口通信实验指导和源程序

基于verilog的串口通信实验指导和源程序

自己看了很多材料以后,精心整理的串口通信实验原理和指导,在网上找了很多代码,大部分因为没有很好的注释,看起来很头疼,于是自己写了一份,附带详细的注释,在modelsim仿真器上已经得到验证,现在传上来,仅供参考。

PS1:最后部分给出了一个测试文件,写的非常简单,只是验证了功能,不是很好的测试;PS2:代码部分看上去有点乱,因为在word中代码的层次结构无法清晰显示,如有需要,下载后把代码copy到notepad++这种类似的专用变成工具里面,就很清晰的显示代码和注释了。

第一部分:实验原理串行通信要求的传输线少,可靠性高,传输距离远,被广泛应用于计算机和外设的数据交换。

通常都由通用异步收发器(UART)来实现串口通信的功能。

在实际应用中,往往只需要UART的几个主要功能,专用的接口芯片会造成资源浪费和成本提高。

随着FPGA/CPLD的飞速发展与其在现代电子设计中的广泛应用,FPGA/CPLD功能强大、开发过程投资小、周期短、可反复编程、保密性好等特点也越来越明显。

因此可以充分利用其资源,在芯片上集成UART功能模块,从而简化了电路、缩小了体积、提高了可靠性,而且设计时的灵活性更大,周期更短。

UART简介UART(Universal Asynchronous Receiver Transmitter通用异步收发器)是一种应用广泛的短距离串行传输接口。

常常用于短距离、低速、低成本的通讯中。

8250、8251、NS16450等芯片都是常见的UART器件。

基本的UART通信只需要两条信号线(RXD、TXD)就可以完成数据的相互通信,接收与发送是全双工形式。

TXD是UART发送端,为输出;RXD是UART接收端,为输入。

UART的基本特点是:(1)在信号线上共有两种状态,可分别用逻辑1(高电平)和逻辑0(低电平)来区分。

在发送器空闲时,数据线应该保持在逻辑高电平状态。

(2)起始位(Start Bit):发送器是通过发送起始位而开始一个字符传送,起始位使数据线处于逻辑0状态,提示接受器数据传输即将开始。

EDA基于Verilog串口通信设计汇总

EDA基于Verilog串口通信设计汇总

石家庄经济学院信息工程学院电子信息工程专业
EDA技术课程设计报告
题目:串口通信设计
姓名
学号
班级
指导教师
2014年1 月09 日
课程设计任务书
课程设计报告
图2串口数据传输顶层模块的时序仿真波形图
3)顶层模块的RTL图如图3所示:
图3 串口数据传输顶层模块的RTL图
4)设计分析:
该顶层模块主要是对底层模块的连接和端口的定义,通过定义几个网线型的连接线将底层元件连接起来进行数据传输,用元件利化法将底层模块组合起来实现串口对
图4串口波特率产生模块时序仿真波形图7)设计分析:
课程设计验收。

串口接收端verilog代码分析

串口接收端verilog代码分析

串⼝接收端verilog代码分析串⼝接收端verilog代码分析`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company:// Engineer: chensimin//// Create Date: 2018/05/23 16:14:30// Design Name:// Module Name: uart_rx// Project Name:// Target Devices:// Tool Versions:// Description://// Dependencies://// Revision:// Revision 0.01 - File Created// Additional Comments:////////////////////////////////////////////////////////////////////////////////////module uart_rx(input wire clk,input wire rxd,output reg [7:0]data_i,output wire receive_ack);reg [7:0] data_i = 0;localparam IDLE = 0,RECEIVE = 1,RECEIVE_END = 2;reg [3:0]cur_st = 0;reg [3:0]nxt_st = 0;always @(posedge clk)begincur_st <= nxt_st;endalways @(*)beginnxt_st = cur_st;case(cur_st)IDLE:beginif(!rxd) //当从接收端⼝上进来的数据开始为0时,即启动接收nxt_st = RECEIVE;endRECEIVE:beginif(count == 7)nxt_st = RECEIVE_END;endRECEIVE_END:beginnxt_st = IDLE;enddefault:beginnxt_st = IDLE;endendcaseendreg [4:0]count = 0;always @(posedge clk)beginif(cur_st == RECEIVE)count <= count + 1;else if(cur_st == IDLE || cur_st == RECEIVE_END)count <= 0;end//当前状态为接收状态时,rxd 信号线上的数据存储在data_i的最⾼位//同时data_i 的数据总体右移⼀位always @(posedge clk)beginif(cur_st == RECEIVE)begindata_i[6:0] <= data_i[7:1];data_i[7] <= rxd; // rxd 传过来什么数据, data_i上⽴马显⽰什么数据,因为是从端⼝采集到的数据endendassign receive_ack = (cur_st == RECEIVE_END) ? 1: 0;endmodule/*add_force {/uart_rx/clk} -radix hex {1 0ns} {0 50000ps} -repeat_every 100000psadd_force {/uart_rx/rxd} -radix hex {1 0ns} {0 300ns} {1 400ns} {0 500ns} {1 600ns} {0 700ns} {1 800ns} {0 900ns} {1 1000ns} */仿真结果:注意: 分析寄存器的更新⼀定要结合时钟沿,然后寄存器在时钟沿前后的变化状态。

X458Verilog参考例程-实战训练7 FPGA与PC串口自收发通信

X458Verilog参考例程-实战训练7 FPGA与PC串口自收发通信

实战训练7 FPGA与PC串口自收发通信
串口通信其实简单实用,这里我就不多说(如果有朋友还对串口通信的协议不是很了解,建议到google输入“串口通信协议”补补)。

我们的实验要实现的功能如题,就是FPGA里实现从PC接收数据,然后把接收到的数据发回去。

使用的是串口UART协议进行收发数据。

上位机用的是串口调试助手。

在FPGA设计中,FPGA端发送数据的波特率是可选的,有以下几种:9600bp s,19200bps,38400bps,57600bps,115200bps等,这部分在模块speed_select 里,可以根据需要进行设置。

发送的数据帧格式为:1bit起始位(从高电平到低电平保持一个bit周期),8bit数据,1bit停止位,无校验位。

以下的代码有比较详细的注释,经过下载验证!此外可参考同目录下的myuartverilog里的工程,打开编译后下载到开发板即可观看实验效果。

具体的实现过程有待大家慢慢消化verilog代码。

(下载本工程代码后,打开串口调试助手,设置好波特率和FPGA中的一致,无校验位,8个数据位,1个停止位,然后在发送的字符/数据后的空白栏内输入2位16进制数据,点击手动发送即可看到上方的数据接收区内返回了刚才发送过来的数据)。

注:在FPGA核心板上做此实验时,请注意不要直接将FPGA管脚接到高于5V电平的信号线上,如需跟电脑连接,请中间加上电平转换芯片。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

自己看了很多材料以后,精心整理的串口通信实验原理和指导,在网上找了很多代码,大部分因为没有很好的注释,看起来很头疼,于是自己写了一份,附带详细的注释,在modelsim仿真器上已经得到验证,现在传上来,仅供参考。

PS1:最后部分给出了一个测试文件,写的非常简单,只是验证了功能,不是很好的测试;PS2:代码部分看上去有点乱,因为在word中代码的层次结构无法清晰显示,如有需要,下载后把代码copy到notepad++这种类似的专用变成工具里面,就很清晰的显示代码和注释了。

第一部分:实验原理串行通信要求的传输线少,可靠性高,传输距离远,被广泛应用于计算机和外设的数据交换。

通常都由通用异步收发器(UART)来实现串口通信的功能。

在实际应用中,往往只需要UART的几个主要功能,专用的接口芯片会造成资源浪费和成本提高。

随着FPGA/CPLD的飞速发展与其在现代电子设计中的广泛应用,FPGA/CPLD功能强大、开发过程投资小、周期短、可反复编程、保密性好等特点也越来越明显。

因此可以充分利用其资源,在芯片上集成UART功能模块,从而简化了电路、缩小了体积、提高了可靠性,而且设计时的灵活性更大,周期更短。

UART简介UART(Universal Asynchronous Receiver Transmitter通用异步收发器)是一种应用广泛的短距离串行传输接口。

常常用于短距离、低速、低成本的通讯中。

8250、8251、NS16450等芯片都是常见的UART器件。

基本的UART通信只需要两条信号线(RXD、TXD)就可以完成数据的相互通信,接收与发送是全双工形式。

TXD是UART发送端,为输出;RXD是UART接收端,为输入。

UART的基本特点是:(1)在信号线上共有两种状态,可分别用逻辑1(高电平)和逻辑0(低电平)来区分。

在发送器空闲时,数据线应该保持在逻辑高电平状态。

(2)起始位(Start Bit):发送器是通过发送起始位而开始一个字符传送,起始位使数据线处于逻辑0状态,提示接受器数据传输即将开始。

(3)数据位(Data Bits):起始位之后就是传送数据位。

数据位一般为8位一个字节的数据(也有6位、7位的情况),低位(LSB)在前,高位(MSB)在后。

(4)校验位(parity Bit):可以认为是一个特殊的数据位。

校验位一般用来判断接收的数据位有无错误,一般是奇偶校验。

在使用中,该位常常取消。

(5)停止位:停止位在最后,用以标志一个字符传送的结束,它对应于逻辑1状态。

(6)位时间:即每个位的时间宽度。

起始位、数据位、校验位的位宽度是一致的,停止位有0.5位、1位、1.5位格式,一般为1位。

(7)帧:从起始位开始到停止位结束的时间间隔称之为一帧。

(8)波特率:UART的传送速率,用于说明数据传送的快慢。

在串行通信中,数据是按位进行传送的,因此传送速率用每秒钟传送数据位的数目来表示,称之为波特率。

如波特率9600=9600bps(位/秒)。

UART的数据帧格式为:START D0 D1 D2 D3 D4 D5 D6 D7 P STOP起始位数据位校验位停止位FPGA UART系统组成:如下图所示,FPGA UART由三个子模块组成:波特率发生器;接收模块;发送模块;模块设计:系统由四部部分组成:顶层模块;波特率发生器;UART接收器;UART发送器顶层模块异步收发器的顶层模块由波特率发生器、UART接收器和UART发送器构成。

UART发送器的用途是将准备输出的并行数据按照基本UART帧格式转为TXD信号串行输出。

UART接收器接收RXD串行信号,并将其转化为并行数据。

波特率发生器就是专门产生一个远远高于波特率的本地时钟信号对输入RXD不断采样,使接收器与发送器保持同步。

波特率发生器波特率发生器实际上就是一个分频器。

可以根据给定的系统时钟频率(晶振时钟)和要求的波特率算出波特率分频因子,算出的波特率分频因子作为分频器的分频数。

波特率分频因子可以根据不同的应用需要更改。

波特率发生器模块主要用于产生接收模块和发送模块的时钟频率,其实质就是一个分频器,可以根据给定的系统时钟频率和要求的波特率算出波特率分频因子,作为分频器的分频数。

波特率发生器产生的时钟频率CLK16X不是波特率时钟频率CLK,而是波特率时钟频率CLK的16倍。

UART在发送或接收数据时,使用的时钟信号频率f是波特率(b=9 600 b/s)的16倍,由外部系统时钟进行16分频得到。

UART每16个波特时钟发送或接收一个二进制位,设计中采用的晶振频率c=25 MHz,那么波特率发生器输出的时钟信号周期为:UART接收器由于串行数据帧和接收时钟是异步的,由逻辑1转为逻辑0可以被视为一个数据帧的起始位。

然而,为了避免毛刺影响,能够得到正确的起始位信号,必须要求接收到的起始位在波特率时钟采样的过程中至少有一半都是属于逻辑0才可认定接收到的是起始位。

由于内部采样时钟bclk周期(由波特率发生器产生)是发送或接收波特率时钟频率的16倍,所以起始位需要至少8个连续bclk周期的逻辑0被接收到,才认为起始位接收到,接着数据位和奇偶校验位将每隔16个bclk 周期被采样一次(即每一个波特率时钟被采样一次)。

如果起始位的确是16个bclk周期长,那么接下来的数据将在每个位的中点处被采样。

UART接收器的接收状态机接收状态机一共有5个状态:R_START(等待起始位);R_CENTER(求中点);R_WAIT(等待采样);R_SAMPLE(采样);R_STOP(停止位接收)。

R_START状态当UART接收器复位后,接收状态机将处于这一个状态。

在此状态,状态机一直在等待RXD的电平跳转,从逻辑1变为逻辑0,即起始位,这意味着新的一帧UART数据帧的开始,一旦起始位被确定,状态机将转入R_CENTER状态。

状态图中的RXD_SYNC信号是RXD的同步信号,因为在进行逻辑1或逻辑0判断时,不希望检测的信号是不稳定的,所以不直接检测RXD信号,而是检测经过同步后的RXD_SYNC信号。

R_CENTER状态对于异步串行信号,为了使每一次都检测到正确的位信号,而且在较后的数据位检测时累计误差较小,显然在每位的中点检测是最为理想的。

在本状态,就是由起始位求出每位的中点,通过对bclk的个数进行计数(RCNT16),但计数值不是想当然的“1000”,要考虑经过一个状态,也即经过了一个bclk周期,所希望得到的是在采样时1/2位。

另外,可能在R_START状态检测到的起始位不是真正的起始位,可能是一个偶然出现的干扰尖脉冲(负脉冲)。

这种干扰脉冲的周期是很短的,所以可以认为保持逻辑0超过1/4个位时间的信号一定是起始位。

R_WAIT状态当状态机处于这一状态,等待计满15个bclk,在第16个bclk是进入R_SAMPLE状态进行数据位的采样检测,同时也判断是否采集的数据位长度已达到数据帧的长度(FRAMELEN),如果到来,就说明停止位来临了。

FRAMELEN在设计时是可更改的(使用了Generic),在本设计中默认为8,即对应的UART工作在8位数据位、无校验位格式。

R_SAMPLE状态即数据位采样检测,完成后无条件状态机转入R_WAIT状态,等待下次数据位的到来。

R_STOP状态无论停止位是1还是1.5位,或是2位,状态机在R_STOP不具体检测RXD,只是输出帧接收完毕信号(REC_DONE<=‘1’),停止位后状态机转回到R_START状态,等待下一个帧的起始位。

补充:接收模块的作用是把收到的串行数据转换成并行数据进行输出,并判断收到的数据是否有错。

接收模块的引脚如图4所示,各引脚功能见表2。

接收器进入准备接收数据状态,不断监视串行输入线RXD端,如果出现低电平,立刻启动起始位检测电路进行确认,一旦确认为接收到正确的起始位,则以波特率作为采样时钟,对每个数据位的中间位置采样一次,并把采样到的信息以移位方式送人接收移位寄存器RSR。

接收到一帧数据位后,把串行数据转化成并行数据,并进行奇偶校验、停止位、中止态的检查。

接收完毕后,DAT_READ 置1。

接收模块功能仿真接收模块功能仿真结果如图5所示。

二进制数11101010从引脚RXD 串行输入,接收器先要捕捉起始位,在RDN信号为0条件下,启动接收程序,计数器开始计数,数据从RXD[7..0]串行输入,由接收移位寄存器RSR[7..0]逐位移位接收,并在接收完成时传送给接收缓冲寄存器RBR[7..0],最后接收缓冲寄存器RBR[7..0]将接收的数据传送至DOUT[7..0],由它并行输出,同时输出一个接收数据准备好信号DATA _RE标志数据接收完毕。

UART发送器发送器只要每隔16个bclk周期输出1个数据即可,次序遵循第1位是起始位,第8位是停止位。

在本设计中没有校验位,但只要改变Generic参数FrameLen,也可以加入校验位,停止位是固定的1位格式。

发送状态机的状态图发送状态机一共有5个状态:X_IDLE(空闲);X_START(起始位);X_WAIT(移位等待);X_SHIFT(移位);X_STOP(停止位)。

X_IDLE状态:当UART被复位信号复位后,状态机将立刻进入这一状态。

在这个状态下,UART的发送器一直在等待一个数据帧发送命令XMIT_CMD。

XMIT_CMD_P信号是对XMIT_CMD的处理,XMIT_CMD_P是一个短脉冲信号。

这时由于XMIT_CMD是一个外加信号,在FPGA之外,不可能对XMIT_CMD的脉冲宽度进行限制,如果XMIT_CMD有效在UART发完一个数据帧后仍然有效,那么就会错误地被认为,一个新的数据发送命令又到来了,UART发送器就会再次启动UART帧的发送,显然该帧的发送是错误的。

在此对XMIT_CMD进行了脉冲宽度的限定,XMIT_CMD_P就是一个处理后的信号。

当XMIT_CMD_P=‘1’,状态机转入X_START,准备发送起始位。

X_START状态:在这个状态下,UART发送一个位时间宽度的逻辑0信号至TXD,即起始位。

紧接着状态机转入X_WAIT状态。

XCNT16是bclk的计数器X_WAIT状态同UART接收状态机中的R_WAIT状态类似。

X_SHIFT状态当状态机处于这一状态时,实现待发数据的并串转换。

转换完成立即回到X_WAIT状态。

X_STOP停止位发送状态,当数据帧发送完毕,状态机转入该状态,并发送16个bclk周期的逻辑1信号,即1位停止位。

状态机送完停止位后回到X_IDLE状态,并等待另一个数据帧的发送命令。

补充:发送模块主要实现对并行数据的缓存、并串转换,并把串行数据按照既定数据帧格式进行输出。

相关文档
最新文档