xilinx FPGA 串口设计笔记

xilinx FPGA  串口设计笔记
在设计中,需要用 FPGA 读取 GPS 内部的信息,GPS 的通信方式为串口,所以在 FPGA
中移植了串口程序。
本次移植的程序源代码是特权的串口程序,本以为移植应该很快就能完成, 但其中还是
出了一写小问题,耽误了不少的时间,下面将问题进行一个总结!
以下是串口的时序:
在设计中,耽误时间最长的问题就是数据老是出错,为了找出问题的所在,用示波器观察了
一下串口发送的数据!
串口发送的软件如图所示:
通过定时发送 hex 数据:0x55,如图:
其中绿色的为电脑发送的串口数据波形,紫色为波特率发生器产生的读数据的触发脉冲,
也就是说在上升沿的时候读取串口信号的数据,从图可以看出,在每个数据的中间段, FPGA
对信号进行了读取,也就是说 FPGA 的波特率设置是没有问题的。
为了进一步的验证,又发了一次 0xaa,进行了一次对比。
通过定时发送 hex 数据:0xaa,如图:
通过上面的测试可知,程序设计的波特率以及读写数据的时序是没有问题的,但是在读数据
的时候依然出现错误。
在此过程中,发了两个数据进行验证。
通过定时发送 hex 数据:0xff,0xff 如图:
在通过发送两个数据后发现,串口发送的一个数据的位数为 10 位,
1bit 下降沿的起始位+8bit 的数据位+1bit 的停止位。
也就是说串口发送的数据长度不是固定的,在没有校验位的情况下,其长度为 10bit,
而特权的程序的,他的串口设置的读取长度为 12bit,这样也就造成了数据的错位,最终导
致数据的整体出错!!
在对程序进行了修改过发现,程序运行正常。
module wi125_time(
input      clk,            // 48MHz 主时钟
input      rst_n,          //低电平复位信号
input      wi125_uart_rx,      // RS232 接收数据信号
output    wi125_data_ok,
output[7:0] wi125_rx_data,
output      ww
);
//----------------------------------串口波特率设置---------------------------------//
//功能:将串口的波特率设置为 38400bps
//----------------------------------------------------------reg[12:0] cnt;                      //分频计数
reg clk_bps;                      //波特率时钟寄存器
reg bps_start;
always @ (posedge clk or negedge rst_n)
if(!rst_n) cnt <= 13'd0;
else if((cnt == 1250) || !bps_start) 
cnt <= 13'd0;                  //波特率计数清零
else 
cnt <= cnt+1'b1;                //波特率时钟计数启动
always @ (posedge clk or negedge rst_n)
if(!rst_n) clk_bps <= 1'b0;
else if(cnt == 625) 
clk_bps <= 1'b1;                //  clk_bps_r 高电平为接收
数据位的中间采样点,同时也作为发送数据的数据改变点
else 
clk_bps <= 1'b0;
assign ww=clk_bps;
//----------------------------------串口波特率设置---------------------------------//
//功能:将串口的波特率设置为 38400bps
//----------------------------------------------------------reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;  //接收数据寄存器,滤波用
wire neg_rs232_rx;                 //表示数据线接收到下降沿
reg rx_int1,rx_int2;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) 
begin
rs232_rx0 <= 1'b0;
rs232_rx1 <= 1'b0;
rs232_rx2 <= 1'b0;
rs232_rx3 <= 1'b0;
rx_int1    <= 1'b0;
rx_int2    <= 1'b0; 
end
else 
begin
rs232_rx0 <= wi125_uart_rx;
rs232_rx1 <= rs232_rx0;
rs232_rx2 <= rs232_rx1;
rs232_rx3 <= rs232_rx2;
rx_int1    <= rx_int;
rx_int2    <= rx_int1;
end
end
//下面的下降沿检测可以滤掉<20ns-40ns 的毛刺(包括高脉冲和低脉冲毛刺),
//这里就是用资源换稳定(前提是我们对时间要求不是那么苛刻,因为输入信号打
了好几拍)
//(当然我们的有效低脉冲信号肯定是远远大于 40ns 的)
assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;  // 接收到下降沿
后 neg_rs232_rx 置高一个时钟周期
assign wi125_data_ok = rx_int2&~rx_int1;
//----------------------------------------------------------------reg[3:0] num;                      //移位次数
reg rx_int;                        // 接收数据中断信号,
接收到数据期间始终为高电平
always @ (posedge clk or negedge rst_n)
if(!rst_n) 
begin
bps_start <= 1'bz;
rx_int <= 1'b0;
end
else if(neg_rs232_rx)                //接收到串口接收线 rs232_rx 的
下降沿标志信号
begin   
bps_start <= 1'b1;            //启动串口准备数据接收
rx_int <= 1'b1;              //接收数据中断信号使能
end
else if(num==4'd10)                  //接收完有用数据信息
begin     
bps_start <= 1'b0;            //数据接收完毕,释放波特率启
动信号
rx_int      <= 1'b0;                //接收数据中断信号关闭
end
//---------------------------------------------------------------- 
reg[7:0] rx_data_r;                  //串口接收数据寄存器,保存直
至下一个数据来到
//----------------------------------------------------------------reg[7:0] rx_temp_data;                //当前接收数据寄存器
always @ (posedge clk or negedge rst_n)
if(!rst_n) 
begin
rx_temp_data    <= 8'd0;
num          <= 4'd0;
rx_data_r      <= 8'd0;
end
else if(rx_int) 
begin                          //接收数据处理
if(clk_bps) 
begin                        // 读取并保 存数
据,接收数据为一个起始位,8bit 数据,1 或 2 个结束位
num <= num+1'b1;
case (num)
4'd1: rx_temp_data[0] <= wi125_uart_rx;  //锁存第 0bit
4'd2: rx_temp_data[1] <= wi125_uart_rx;  //锁存第 1bit
4'd3: rx_temp_data[2] <= wi125_uart_rx;  //锁存第 2bit
4'd4: rx_temp_data[3] <= wi125_uart_rx;  //锁存第 3bit
4'd5: rx_temp_data[4] <= wi125_uart_rx;  //锁存第 4bit
4'd6: rx_temp_data[5] <= wi125_uart_rx;  //锁存第 5bit
4'd7: rx_temp_data[6] <= wi125_uart_rx;  //锁存第 6bit
4'd8: rx_temp_data[7] <= wi125_uart_rx;  //锁存第 7bit
default: ;
endcase
end
else if(num == 4'd10)
begin    //我们的标准接收模式下只有 1+8+1(2)=10bit 的有效数据
num <= 4'd0;        //接收到 STOP 位后结束,num 清零
rx_data_r <= rx_temp_data;  //把数据锁存到数据寄存器 rx_data 中
end 
end
assign wi125_rx_data = rx_data_r; 
endmodule

你可能感兴趣的:(xilinx FPGA 串口设计笔记)