rs串口verilog代码
- 格式:doc
- 大小:37.00 KB
- 文档页数:8
1.全加器Sum=A⊕B⊕CinCount=AB+Cin(A+B)①数据流module adder(a,b,Cin,Sum,Count); input [2:0]a,b;input Cin;output [2:0] Sum;output Count;assign {Count,Sum}=a+b+Cin; endmodule②行为描述always语句module adder(a,b,c,Cin,Sum,Count); input [4:0] a,b;input Cin;output reg [4:0] Sum;output reg Count;reg T1,T2,T3;always@(a or b or Cin)beginSum=a^b^Cin;T1=A&B;T2=Cin&A;T3=Cin&B;Count=T1|T2|T3;endendmodule③结构体module adder (a,b,Cin,Sum,Count);input a,b,Cin;output Sum,Count;Xor a1(s1,a1,b);Xor a2(Sum,s1,Cin);and a3(T1,a,b);or a4(T2,a,b);and a5(T3,Cin,T2);or a6(Count,T1,T3);Endmodule2.数值比较器①判断两值是否相等module compare(a,b,equal);input [7:0] a,b;output equal;assign equal=(a==b)?|0; ②谁大谁输出module compare(a,b,out);input [7:0] a,b;output reg[7:0] out;always@(a or b)beginif (a>b) out<=a;else if (a==b) out<=a;else out<=b;endendmodule③输出参数module compare(a.b.xgy,xsy,xey);input [7:0] x,y;output reg xgy,xsy,xey;always@(x or y)beginif (x==y) xey=1;else xey=0;if (x>y) begin xgy=1;xsy=0;endelse if (x<y) begin xgy=0;xsy=1;end endendmodule3.编码器(4-2 8-3 16-4编码)①case语句8-3编码(优先)module code (in ,out);input [7:0] in;output reg [2:0] out;always@(in)case x(in)begin f=1;8’b1xxxxxxx:out=3’b111;end begin f=1;8’b01xxxxxx:out=3’b110;end begin f=1;8’b001xxxxx:out=3’b101;end begin f=1;8’b0001xxxx:out=3’b100;end begin f=1;8’b00001xxx:out=3’b011;end begin f=1;8’bxx:out=3’b010;endbegin f=1;8’bx:out=3’b001;endbegin f=1;8’b:out=3’b000;end default:begin f=0:out=3’b000;end endcaseendmodule②if-else语句(4-2优先编码)module code(in,out);input[3:0] in;output reg [1:0] out;always@(in)if (in[3]==1):begin f=1;out=2’b11;end else if (in[2]==1):begin f=1;out=2’b10;end else if (in[1]==1):begin f=1;out=2’b01;end else if (in[0]==1):begin f=1;out=2’b00;end else begin f=0;out=2’b00;end endmodule4.多路选择器①行为描述(4选1)module choice(A,B,C,D,ncs addr out);input [7:0]A,B,C,D;input ncs;input [1:0] addr ;output reg[7:0] out;always@(A or B or C or D or ncs or addr) beginif (!ncs)case(addr)2’b00:out=A;2’b01:out=B;2’b10:out=C;2’b11:out=D;endcaseelse out=0;endendmodule5.设计一个4位双向移位寄存器。
串口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的很基础的RS232串口收发代码写代码,记笔记,防忘记,须牢记。
写串口的Verilog代码关键是要搞明白RS232串口的通信协议,它并不像单片机,直接读写SBUF就可实现串口的收发功能,收发整个字节。
而FPGA要一位一位的收发,因此必须了解RS232的数据格式。
起始位:RS232约定一位起始位“0”。
停止位:约定停止位为“1”。
可选一位或两位停止位。
奇偶校验位:可选。
通过串口发送数据时,要严格遵守RS232的数据格式,先发送起始位,然后是数据,最后是停止位(无奇偶校验的情况)。
通过串口接收数据时,若接收端无数据输入,会一直处于高电平,若开始接收数据,会首先收到来自串口的起始位“0”,然后是要接收的数据,最后为停止位(无奇偶校验的情况)。
所以对于接收模块,可如此设计,FPGA一直检测接收端是否有下降沿到来,直到检测到下降沿,才开始接收数据。
波特率设置的重要性不言而喻,毋庸赘述。
此设计为最基础的串口收发代码,控制逻辑简单,适合编写第一次编写串口代码的朋友。
此设计收发的数据格式为1位起始位,1位停止位,无奇偶校验位,8位数据位。
波特率为19200,代码中可随意更改。
具体Verilog代码如下:顶层模块`timescale 1ns / 1ps/////////////////////////////////////////////////////////////////// /////////////// Company : 杭州电子科技大学// Engineer : 晓晓川// Create Date : 2012.08.26// Design Name : serial_test// Module Name : serial_test// Project Name: serial_test// Target Device: CycloneII EP2C5T144C8// Tool versions: Quartus II 11.0// Revision : V1.0// Description : 一个极为简单的串口收发工程,适于串口收发的入门。
verilog 传递参数在Verilog中,模块之间传递参数通常通过模块的端口进行。
Verilog中的模块可以有输入端口(input)、输出端口(output)和双向端口(inout)。
通过这些端口,可以在模块之间传递参数和数据。
首先,你需要在模块的定义中声明端口,并指定它们的方向和数据类型。
例如:verilog.module MyModule(。
input wire clk, // 输入时钟信号。
input wire [7:0] data_in, // 8位输入数据。
output reg [7:0] data_out // 8位输出数据。
);// 模块逻辑。
endmodule.在该例子中,MyModule模块有一个输入时钟信号(clk)、一个8位的输入数据(data_in)和一个8位的输出数据(data_out)。
当你实例化这个模块并连接到其他模块时,你需要将参数传递给端口。
例如:verilog.module MyTopModule(。
input wire clk,。
input wire [7:0] input_data,。
output reg [7:0] output_data.);MyModule inst1(。
.clk(clk), // 将顶层模块的时钟信号连接到子模块的时钟信号。
.data_in(input_data), // 将输入数据连接到子模块的输入数据。
.data_out(output_data) // 将子模块的输出数据连接到顶层模块的输出数据。
);// 其他逻辑。
endmodule.在这个例子中,MyTopModule模块实例化了MyModule模块,并通过连接端口将参数传递给子模块。
当顶层模块的输入发生变化时,这些变化将传递到子模块,并子模块的输出也会传递回顶层模块。
总的来说,在Verilog中传递参数是通过模块的端口进行的,你需要在模块定义和实例化时正确地连接端口,以实现参数的传递和数据交换。
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。
RS 编码RS(255,249) 码的生成多项式为G (x )=∏=-5)(i ia x ,其中a 为本原元,是本原多项式p (x )=12348++++xxxx 的根。
RS 系统编码器可看作是一个多项式除法器,首先用kn x-乘以消息多项式m (x ),,即在信息码后附加(n-k )个“0”, ,将得到的结果kn x -m (x )除以g (x ),得到余式,b (x )=112210...----++++k n k n xb x b x b b 为所求的校验位,从而,可将码字多项式表示为c (x )=kn x -m (x )+b (x )。
RS 译码由于RS 码是一种循环码,令码字多项式为c (x ),错误多项式为e (x ),则接收多项式可表示为r (x )= c (x )+ e (x )。
存在校验矩阵H ,使c*TH=0,!,定义接收矢量的伴随式S= r*TH=(t s s s 221,...,,)。
可得伴随式:)()(jjj a e a r s ==j=1,2,3,…n 可知伴随式完全由噪声E 决定,充分反映了信道干扰的情况。
循环码编码循环码通常采用码多项式描述, 假设(7, 4)循环码的码字为(1001000), 就可用T(x)=1+x3 表示。
特别是用g(x)表示前k- 1 位皆为0 的码组, 称为生成多项式。
由循环码的性质可知, 循环码对生成矩阵可由码对生成多项式g( x) 及其循环移位构成, (7, 4)循环码生成多项式g(x)=1+x+x3(1011)或g(x)=1+x2+x3(1101), 以选1011 为(7, 4)CRC 码的生成多项式, 用矩阵表示如下式2- 1。
根据生成矩阵, 就可利用上面介绍的方法设计编码器了。
还可以利用循环码自身的循环性, 更方便地实现编码器。
(7, 4)循环码为例, 若输入信息码元为u(x)=1+x3, 则: kn x-u (x )=63x x +=x+)1m od(22x x x ++因此, 码多项式为:o (x )=r (x )+kn x -u (x )=x+632x xx++其中r(x)=x+x2 为信息码元置为高位后整除生成多项式的余式, 它正好对应于校验序列。
实现功能,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 计数到rxdflk reserr<scido hichF1 fr冲'豔K/ tt/ L J弃L--XrdbLLLCLK RESETI rrpset|EMPTY8'b1111_11( 63), 数据接收完成,rxdF 置0置位标志位rdFULL; 5,完成一位起始位,8 位的数据位发送,随后txd 置1(停止位),完成并串转换置位标志位txdF ,tdEMPTY st_n(rst_n),.clk_bps_4(clk_bps_4),.wr(wr),.tdEMPTY(tdEMPTY),.DATA(DATA),.txd(txd));st_n(rst_n),.clk_bps_4(clk_bps_4),.rd(rd),.rdFULL(rdFULL),.do_latch(do_latch),.rxd(rxd));/* 针对9600bps ,生成的时钟信号,用于接收数据采样与数据发送*/ 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, 置位为b0111_00(28),8'即rx_cnt[5:2]== 4 'b0111(7),rx_cnt[1:0] == 2'b00(0);一个计数周期开始,伴随clk_bps_4, rx_cnt 加1(每一个数据位加4) */ always@(posedgeclk_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 保持0 begin rx_cnt <= 0;endelsebegin rx_cnt <= rx_cnt + 1;endend/* 空闲时rdFULL 置0,当数据接收完成,数据锁存到do_latch,同时rdFULL置1,向上层模块表示数据以准备0K可以来读取;rd 置0, 表示上层模块开始读取数据,rdFULL 置0,表示数据已读走*/ always@(posedgeclk_bps_4 or negedge rst_n)// 置位标志位rdFULL beginif(!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;// 锁存器数据准备0Kendend/*rxd 出现起始位低电平, rxdF 置1 ,表示数据接收开始;当rx_cnt计数到8' b1111_11(63),数据接收完成,rxdF置0* always@(posedge clk_bps_4 or negedge rst_n)// 置位标志位rxdFendcaseend endmodule串口数据发送模块:module Uart_TX(rst_n, clk_bps_4,wr,tdEMPTY, DATA, txd); input rst_n; // 低电平复位 input clk_bps_4; //4 倍于波特率时钟信号 input [7:0]DATA;beginif(!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, 每 4 个 clk_bps_4, rx_cnt[5:2] 串并变换 */ 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;// 4'd9:data_r[1] <= rxd;// 4'd10:data_r[2] <= rxd;// 4'd11:data_r[3] <= rxd;// 4'd12:data_r[4] <= rxd;// 4'd13:data_r[5] <= rxd;// 4'd14:data_r[6] <= rxd;// 4'd15:data_r[7] <= rxd;//为了保证在 力口 1 当rx_cnt[5:2]数据接收rxd 一位数据靠近中间位置采样 ; ==8,9,10…15,完成8位的数据采样,低第 1 位 第 2 位 第 3 位 第 4 位 第5位 第 6 位 第 7 位 高第 8 位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; endcase endassign txd = txd_r; endmodule波特率发生模块:/* 针对 9600bps ,生成 4 倍于波特率的时钟信号,用于采样 */ module Baudrate(clk, rst_n,clk_bps_4); input clk; // 时钟周期 50MHzinput rst_n; // 低电平复位reg clk_bps_4;always@(posedge clk or negedge rst_n) beginif(!rst_n) begin clk_bps_4 <= 0; bps_cnt <= 0;end elsebeginif(bps_cnt == N/2 - 1)begin clk_bps_4 <= ~clk_bps_4; bps_cnt <= 0;end elsebegin bps_cnt <= bps_cnt + 1;end endend endmoduleoutput clk_bps_4; //时钟信号 9600*4 reg [12:0] bps_cnt; // parameter N=1302;//波特率产生时计数 分频系数 9600bpsModelsim 仿真波形图:rxd 端输入数据 01010101 , txd 发送01010101 'i LUU'JUITJ J..ULU If.'UU- J LLbllJUJ Jlf_ L L_LLUUJllUL.LLUlllniL j.jiirjuJJUJuuLuirjiiiiiiiniLL'UU'.J J ipunnLiii 2 LJ^,ULX5tl hrjuEJumninnrLuiJiJui JirjinmfjujnLWTnimfnr TTTD 】门丁q■■nr '1 tfejarli danaj U.-UmJlfiLLfUlTJUlJ ja —i 暫主诞OfnEMJini'jinjrL'ULrjiLri I 咼岂巫:HS3E 1SS«二.■UITJXJ ifL :ui^.:jioiwwirjinr. i连接PC 串口助手。
11.9.2 RS(204, 188)译码器的设计RS码在通信系统、数字电视和计算机存储系统中应用很广泛。
例如,DVB(数字电视)标准中信道编/解码采用RS(204, 188);ATM网络中使用RS(128, 124)作为前向纠错编码(Forward Error Correcting, FEC)。
本节将以DVB标准中定义的RS(204, 188)译码器为例,详细介绍基于改进的BM迭代算法、pipeline结构的译码的所有技术细节。
考虑到译码器的可扩展性、可维护性,实例中尽可能地使用参数化、模块化的设计。
读者可在实例代码基础上作很小的改动,就能实现不同需要的RS译码器。
1. 应用背景在数字通信、数字电视中,信道编码的使用提高了数据传输的质量。
虽然增加了传输带宽,但信道编码减小了数据传输出现误码的概率,同时也减小了所需要的信噪比(signal-to-noise rate)。
在大多数应用中,将RS码与卷积码级联使用进行纠错。
在自信源至接收的过程中,数字电视信号的编码包括信源编码、信道编码及加密。
信道编码又称做前向纠错编码,其目的是提高信息传送或传输的可靠性,当传输差错在一定范围内,接收机都能将误码纠正过来。
必须指出,信道编码并非指信号经上变频发送出去后,在传输信道中(有线、卫星或地面)进行编码,而是指经过编码后便匹配信道传输和减少差错。
因此,自信源编码后的所有编码包括能量随机化扰码、卷积、交织、Reed-Solomon编码等都可划为信道编码。
典型的数字电视信道编码如图11-73所示。
为信息位,t为能纠正误码的最大的码位,且RS外码编码的特点是纠正与本组有关的误码,尤其对纠正突发性的误码最有效。
通常,n、k、t分别为204、188和8。
如图11-74所示为"EN 300 429"有线数字电视(DVB-C)标准规定的发送端(Cable Head-end)框图,其中包括了数据帧结构(Framing structure)、信道编码及调制。
UART是通用异步收发器的简称,其中有一种电平规范较RS232规范,它用-3~-15V表示正逻辑,3~15V表示负逻辑,通过FPGA芯片实现RS232通信首先要解决的就是FPGA电平和RS232电平之间的矛盾,通常采用MAX3232作为物理层的电平接口,根据MAX3232提供的标准配制方式把物理电路设计好后,接下来的通信就是要实现逻辑的接收和发送……设计最简单的RS232通信逻辑,FPGA实现将接收到的数据会发出去,总共两个数据传输引脚,一收一发。
将此通信模块分为三个部分:接收模块,波特率控制模块,发送模块。
工作原理:此模块接收MAX3232传过来的串行数据,对齐进行判断采样,校验,最后将数据流中的串行数据转换为八位并行数据,将此八位数据储存,或送给发送模块发送出去。
根据RS232通信标准器串行数据分为起始位、数据位、校验位、停止位,空闲时为高电平,起始位通常为低电平,数据位通常为8位,校验位分为奇校验、偶校验等,停止位一位或两位且为高电平。
FPGA接收模块对此数据进行异步接收,首先就要检测其数据传输开始标识,当然就是检测开始位,于是要有下降沿检测电路,检测到下降沿是输出一高脉冲,此电路可以用两个D触发器加上基本门电路实现,脉冲触发开始进入接收状态,输出接收状态标志位,使其为1,此标志位使能波特率控制模块输出采样脉冲,此计数脉冲触发接收模块中的计数器计数,加到相应的位就把当前的串行总线上的值赋给缓冲器,或对其判断,当计数完成11次计数后,已将8位串行数据转成并行数据到缓冲器中,且进行了校验的判断和停止位的判别,这是接收状态结束,接收状态位置0,计数器清零。
对于波特率产生模块用于控制采样数据脉冲的周期,其周期就为串行数据传送一个bit所用的时间,根据此时间和时钟周期设置计数值。
当接收模块完成工作时,接收状态位为0时可以触发发送模块,发送模块检测接收状态的下降沿,由此产生一高脉冲,与发送模块类似,根据波特率控制模块产生的计数脉冲将并行数据转成串行数据,并加上开始位、校验位、停止位。
由此完成整个串行通信模块。
要熟悉:下降沿检测程序设计,并转串设计等。
顶层模块图如下所示:各模块的程序如下://本程序实现rs232通信中的串行数据接收模块module rs232_rx(//inputclk,//50M的时钟输入rst_n,//低电平复位信号输入rx_cnt_pluse,//采样脉冲输入,总共11个采样脉冲,一个时钟宽度的高电平rs232_in_s,//串行数据输入,空闲时为高电平,1bit低电平作为起始位,接着8bit数据位LSB传输模式,接着偶数校验位,接着1bit低电平作为停止位//outputrs232_out_p,//输出8位并行数据rx_flag,//数据接收状态输出,接收状态下为高电平,其余为低电平rx_error_flag//接收校验错误标识位,若检测奇数校验位或者停止位不正确时输出高电平 );parameter WIGTH=8;input clk,rst_n;input rx_cnt_pluse;input rs232_in_s;output [WIGTH-1:0] rs232_out_p;output rx_flag;output rx_error_flag;reg [3:0] cnt=0;reg rx_flag=0;reg [WIGTH-1:0] rs232_out_p;reg rs232_in_s_r1,rs232_in_s_r2,rs232_in_s_r3,rs232_in_s_r4;wire rs232_in_s_start_flag;always@(posedge clk or negedge rst_n)beginif(!rst_n)beginrs232_in_s_r1<=0;rs232_in_s_r2<=0;endelse//串行数据开始传输检测电路,检测其下降沿,有下降沿是输出一个clk宽度的高脉冲beginrs232_in_s_r1<=rs232_in_s;rs232_in_s_r2<=rs232_in_s_r1;rs232_in_s_r3<=rs232_in_s_r2;rs232_in_s_r4<=rs232_in_s_r3;endendassignrs232_in_s_start_flag=rs232_in_s_r4&(~rs232_in_s_r1)&(~rs232_in_s_r2)&(~rs232_in_ s_r3);always@(posedge clk or negedge rst_n)begin//接收状态控制电路,第一个下降沿时标识位置高,当cnt计数到11时置低if(!rst_n)rx_flag<=0; //数据接收状态输出,接收状态下为高电平,其余为低电平else if(rs232_in_s_start_flag)rx_flag<=1;else if(cnt==11)rx_flag<=0;endreg rx_error_flag_r1,rx_error_flag_r2;rx_error_flag//接收校验错误标识位,若检测奇数校验位或者停止位不正确时输出高电平reg [WIGTH-1:0] rs232_out_p_temp=0;always@(posedge clk or negedge rst_n)begin//串转并逻辑if(!rst_n)begincnt<=0;rs232_out_p_temp<=0;rx_error_flag_r1<=0;rx_error_flag_r2<=0;endelse if(rx_flag)//接收有效状态下,开始接收数据beginif(rx_cnt_pluse)//采样脉冲出发cnt累加// rx_cnt_pluse,//采样脉冲输入,总共11个采样脉冲,一个时钟宽度的高电平begincnt<=cnt+1;case(cnt)//将当前串行数据输入线上的数据锁存到寄存器的相应的位1: rs232_out_p_temp[0]<=rs232_in_s;2: rs232_out_p_temp[1]<=rs232_in_s;3: rs232_out_p_temp[2]<=rs232_in_s;4: rs232_out_p_temp[3]<=rs232_in_s;5: rs232_out_p_temp[4]<=rs232_in_s;6: rs232_out_p_temp[5]<=rs232_in_s;7: rs232_out_p_temp[6]<=rs232_in_s;8: rs232_out_p_temp[7]<=rs232_in_s;9:beginif(rs232_in_s!=^rs232_out_p_temp)//偶数校验位,有奇数个1为1,偶数个1为0 rx_error_flag_r1<=1;else//若校验出错,则给出标识1rx_error_flag_r1<=0;end10:beginif(!rs232_in_s)//1bit1作为停止位。
//串行数据输入,空闲时为高电平,1bit低电平作为起始位,接着8bit数据位rx_error_flag_r2<=1;else//若停止位出错,则给出标识2rx_error_flag_r2<=0;enddefault: ;endcaseendelse if(cnt==11)begincnt<=0;//当计数到11时cnt清零,把缓存中的数据输出rs232_out_p<=rs232_out_p_temp;endendend//两标识相或得到错误标识输出assign rx_error_flag=rx_error_flag_r2 | rx_error_flag_r1;endmodule//////////////////////////////////////////////////////////////////////////此程序完成对8位数据通过RS232口发送出去module rs232_tx(//inputclk,//50M的时钟输入rst_n,//异步置位信号输入rs232_in_p,//8位并行数据输入tx_cnt_flag,//并转串同步脉冲输入rx_flag,//发送开始信号,检测其低电平开始发送//outputrs232_out_s,//串行数据输出tx_flag//发送状态标志,高电平表示正在处于发送状态 );parameter WIGTH=8;input clk,rst_n;input [WIGTH-1:0] rs232_in_p;input tx_cnt_flag; //并转串同步脉冲输入input rx_flag; ,//发送开始信号,检测其低电平开始发送output rs232_out_s;output tx_flag; //发送状态标志,高电平表示正在处于发送状态reg rs232_out_s;reg tx_flag;reg rx_flag_r1,rx_flag_r2;wire rx_flag_negedge;always@(posedge clk or negedge rst_n)begin//检测发送开始信号,检测rx_flag信号的下降沿if(!rst_n)beginrx_flag_r1<=0;rx_flag_r2<=0;endelsebeginrx_flag_r1<=rx_flag;rx_flag_r2<=rx_flag_r1;endendassign rx_flag_negedge=(~rx_flag_r1)&rx_flag_r2;reg [3:0] cnt=0;always@(posedge clk or negedge rst_n)beginif(!rst_n)begintx_flag<=0; //发送状态标志,高电平表示正在处于发送状态endelse if(rx_flag_negedge)tx_flag<=1;else if(cnt==12)tx_flag<=0;endalways@(posedge clk or negedge rst_n) beginif(!rst_n)rs232_out_s<=1; //串行数据输出else if(tx_flag)beginif(tx_cnt_flag//并转串同步脉冲输入)begin//并转串逻辑,停止位是0cnt<=cnt+1;case(cnt)0:rs232_out_s<=0;1:rs232_out_s<=rs232_in_p[0];2:rs232_out_s<=rs232_in_p[1];3:rs232_out_s<=rs232_in_p[2];4:rs232_out_s<=rs232_in_p[3];5:rs232_out_s<=rs232_in_p[4];6:rs232_out_s<=rs232_in_p[5];7:rs232_out_s<=rs232_in_p[6];8:rs232_out_s<=rs232_in_p[7];9:rs232_out_s<=^rs232_in_p;10:rs232_out_s<=1;default:rs232_out_s<=1;endcaseendelse if(cnt==12)begincnt<=0;rs232_out_s<=1;endendendendmodule////////////////////////////////////////////////本程序实现对rs232波特率的控制module baudrate_ctr(//inputclk,//50M的时钟输入rx_tx_en,//发送或接收数据有效标识引脚,其为高电平是表示处于发送或接收状态rst_n,baudrate_word,//波特率设置数输入//outputrx_tx_cnt_pluse//此信号给接收模块作为采样基准信号,给发送模块作为发送同步基准信号);input clk,rst_n;input rx_tx_en;input [13:0] baudrate_word;output rx_tx_cnt_pluse;reg rx_tx_cnt_pluse;reg [13:0] cnt=0;reg [13:0] baudrate_word_reg=0;always@(posedge clk or negedge rst_n)begin//波特率设置数锁存逻辑if(!rst_n)baudrate_word_reg<=0;elsebaudrate_word_reg<=baudrate_word;endalways@(posedge clk or negedge rst_n)begin//完成一个bit传输时间的计数if(!rst_n)begincnt<=0;endelseif((cnt==baudrate_word_reg) || !rx_tx_en)cnt<=0;elsecnt<=cnt+1;endalways@(posedge clk or negedge rst_n)begin//当计数到1bit中间是输出一个clk周期宽度的高脉冲作为输出 if(!rst_n)rx_tx_cnt_pluse<=0;elseif(cnt==(baudrate_word_reg>>1))rx_tx_cnt_pluse<=1;elserx_tx_cnt_pluse<=0;endendmodule。