赞
踩
(完整代码在文末,包括仿真文件与设计文件,通过仿真与板级验证)本文利用verilog语言实现uart串口异步通信,FPGA接收串口发来的数据,并将接收到的数据通过tx端发送到PC端,在PC端串口打印显示数据
开发板:SF-AT7
软件平台:Vivado 2016.2
FPGA实时检测uart_rx信号是否有数据,若接收到数据,你把接收到的数据通过uart_tx发送给PC端。
我们知道串口数据传输在设置的波特率下进行,因此需要有专门的波特率产生单元,且发送与接收分别对应一个波特率产生单元,将波特率设置包装成一个模块,分别在发送与接收端例化该模块即可,这是两个独立的硬件资源,属于逻辑复制,而并非资源共享。
整个程序具体实现过程就是有一个顶层模块,在顶层模块中例化波特率设置模块、串口发送与接收处理模块。
speed_setting u2_speed_rx( .clk(clk_25m), //波特率选择模块 .rst_n(sys_rst_n), .bps_start(bps_start1), .clk_bps(clk_bps1) ); //UART接收数据处理 my_uart_rx_q u3_my_uart_rx( .clk(clk_25m), //接收数据模块 .rst_n(sys_rst_n), .uart_rx(uart_rx), .rx_data(rx_data), .rx_int(rx_int), .clk_bps(clk_bps1), .bps_start(bps_start1) ); //------------------------------------- //UART发送信号波特率设置 speed_setting u4_speed_tx( .clk(clk_25m), //波特率选择模块 .rst_n(sys_rst_n), .bps_start(bps_start2), .clk_bps(clk_bps2) ); //UART发送数据处理 my_uart_tx_q u5_my_uart_tx( .clk(clk_25m), //发送数据模块 .rst_n(sys_rst_n), .rx_data(rx_data), .rx_int(rx_int), .uart_tx(uart_tx), .clk_bps(clk_bps2), .bps_start(bps_start2) );
module speed_setting( input clk, input rst_n, input bps_start, output clk_bps ); `define BPS_9600 `define CLK_PERIORD 40 //定义时钟周期为40ns(25MHz) `define BPS_SET 9600 //定义通信波特率为9600bps(将需要的波特率省去两个零后定义即可) `define BPS_PARA (1_000_000_000/`CLK_PERIORD/`BPS_SET)//10_000_000/`CLK_PERIORD/96; //波特率为9600时的分频计数值 `define BPS_PARA_2 (`BPS_PARA/2)//BPS_PARA/2; //波特率为9600时的分频计数值的一半,用于数据采样 reg[12:0] cnt; //分频计数 reg clk_bps_r; //波特率时钟寄存器 //---------------------------------------------------------- reg[2:0] uart_ctrl; // uart波特率选择寄存器 //计数器计数 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 13'd0 ; else if(bps_start)begin if(cnt < BPS_PARA) cnt <= cnt + 13'd1 ; else cnt <= 13'd0 ; end else cnt <= 13'd0 ; end //采样信号标志位 always@(posedge clk or negedge rst_n)begin if(!rst_n) clk_bps_r <= 1'b0 ; else if(cnt == BPS_PARA_2) clk_bps_r <= 1'b1 ; else clk_bps_r <= 1'b0 ; end assign clk_bps = clk_bps_r ; endmodule
该模块实现对UART接收信号uart_rx进行解码,并实现串并转换,并将数据保存在【rx_data[7:0]】中。具体程序内部实现框图如下:
module my_uart_rx( clk,rst_n, uart_rx,rx_data,rx_int, clk_bps,bps_start ); input clk; // 25MHz主时钟 input rst_n; //低电平复位信号 input uart_rx; // RS232接收数据信号 input clk_bps; // clk_bps的高电平为接收或者发送数据位的中间采样点 output bps_start; //接收到数据后,波特率时钟启动信号置位 output[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 output rx_int; //接收数据中断信号,接收到数据期间始终为高电平 //---------------------------------------------------------------- reg uart_rx0,uart_rx1,uart_rx2,uart_rx3; //接收数据寄存器,滤波用 wire neg_uart_rx; //表示数据线接收到下降沿 always @ (posedge clk or negedge rst_n) if(!rst_n) begin uart_rx0 <= 1'b0; uart_rx1 <= 1'b0; uart_rx2 <= 1'b0; uart_rx3 <= 1'b0; end else begin uart_rx0 <= uart_rx; uart_rx1 <= uart_rx0; uart_rx2 <= uart_rx1; uart_rx3 <= uart_rx2; end assign neg_uart_rx = uart_rx3 & uart_rx2 & ~uart_rx1 & ~uart_rx0;
波特率控制模块
该模块因为信号下降沿的到来,使得【bps_start】信号置为1,启动波特率设置模块。
计数采样模块
由于数据从低位到高位串行传输,所以要先用一个寄存器暂存数据,且第一位是标识位,不应该将其存储在寄存器中,采用【num】从0开始计数,计数到1时在每个波特率高电平有效的一个周期内从低位到高位保存数据。
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] <= uart_rx; //锁存第0bit 4'd2: rx_temp_data[1] <= uart_rx; //锁存第1bit 4'd3: rx_temp_data[2] <= uart_rx; //锁存第2bit 4'd4: rx_temp_data[3] <= uart_rx; //锁存第3bit 4'd5: rx_temp_data[4] <= uart_rx; //锁存第4bit 4'd6: rx_temp_data[5] <= uart_rx; //锁存第5bit 4'd7: rx_temp_data[6] <= uart_rx; //锁存第6bit 4'd8: rx_temp_data[7] <= uart_rx; //锁存第7bit default: ; endcase end else if(num == 4'd9) begin //我们的标准接收模式下只有1+8+1(2)=11bit的有效数据 num <= 4'd0; //接收到STOP位后结束,num清零 rx_data_r <= rx_temp_data; //把数据锁存到数据寄存器rx_data中 end end assign rx_data = rx_data_r;
uart接收端接收数据完成后,通过【uart_tx】端将接收到的数据【rx_data】f发送出去。程序流程框图如下:
注意:因为要完全按照帧格式发送数据,所以要先发送一个波特率周期的低电平,在从低到高传输数据位。
reg uart_tx_r ; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin num <= 4'd0 ; uart_tx_r <= 1'b1; end else if(tx_en)begin if(clk_bps)begin num <= num + 4'd1 ; case(num) 4'd0 : uart_tx_r <= 1'b0 ; 4'd1 : uart_tx_r <= tx_data[0] ; 4'd2 : uart_tx_r <= tx_data[1] ; 4'd3 : uart_tx_r <= tx_data[2] ; 4'd4 : uart_tx_r <= tx_data[3] ; 4'd5 : uart_tx_r <= tx_data[4] ; 4'd6 : uart_tx_r <= tx_data[5] ; 4'd7 : uart_tx_r <= tx_data[6] ; 4'd8 : uart_tx_r <= tx_data[7] ; 4'd9 : uart_tx_r <= 1'b1 ; default: uart_tx_r <= 1'b1; endcase end else if(num == 4'd10)begin num <= 4'd0 ; end end end assign uart_tx = uart_tx_r;
https://pan.baidu.com/s/1dnoyo84pEtMlk5fSQdaqSA 提取码:p4q1
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。