串口学习
- 设计思路
实验任务:通过电脑端的串口调试助手向FPGA发送数据,FPGA通过串口接收数据并将接受到的数据发送给上位机,实现串口回环功能。
接收模块(RX):通过检测起始位来表示数据传输的开始,在波特率中间时刻去采样总线上的数据,最后将数据进行串并转换。
发送模块(TX):将并行数据转换成串行数据,然后在串行数据帧头加上起始位,帧尾加上停止位,发送给上位机。
-
编写tx模块和rx模块,并进行验证。
-
工程记录/*===============================* filename : uart_tx.v description : 串口发送模块 time : 2024-1-20 author : *================================*/ module uart_tx( input clk ,//时钟 50MHZ input rst_n ,//复位 input [2:0] baud_sel ,//波特率选择 input [7:0] pi_data ,//数据 input pi_flag ,//数据使能 output reg uart_tx //tx数据线 ); //参数定义 parameter SCLK = 50_000_000;//系统时钟 50MHZ //波特率选择 parameter BAUD_9600 = SCLK/9600 , BAUD_19200 = SCLK/19200 , BAUD_38400 = SCLK/38400 , BAUD_57600 = SCLK/57600 , BAUD_115200 = SCLK/115200; //信号定义 reg work_en ;//工作使能 reg [15:0] cnt_baud ;//波特率计数器 reg [15:0] BAUD_NUM ; reg bit_flag ;//bit标志信号 reg [3:0] cnt_bit ;//bit计数器 //work_en always @(posedge clk or negedge rst_n)begin if(!rst_n)begin work_en <= 1'b0; end else if(pi_flag == 1'b1)begin work_en <= 1'b1; end else if((cnt_bit == 4'd9) && (bit_flag == 1'b1))begin work_en <= 1'b0; end end //cnt_baud always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_baud <= 16'd0; end else if((work_en == 1'b0) || (cnt_baud == BAUD_NUM - 1))begin cnt_baud <= 16'd0; end else if(work_en == 1'b1)begin cnt_baud <= cnt_baud + 1'b1; end end //BAUD_NUM always @(*)begin case(baud_sel) 3'd0 : BAUD_NUM = BAUD_9600 ; 3'd1 : BAUD_NUM = BAUD_19200 ; 3'd2 : BAUD_NUM = BAUD_38400 ; 3'd3 : BAUD_NUM = BAUD_57600 ; 3'd4 : BAUD_NUM = BAUD_115200; default : BAUD_NUM = BAUD_115200; endcase end //bit_flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin bit_flag <= 1'b0; end else if(cnt_baud == 16'd1)begin bit_flag <= 1'b1; end else begin bit_flag <= 1'b0; end end //cnt_bit always @(posedge clk or negedge rst_n) begin if(!rst_n)begin cnt_bit <= 4'd0; end else if((cnt_bit == 4'd9)&&(bit_flag == 1'b1))begin cnt_bit <= 4'd0; end else if((work_en == 1'b1)&&(bit_flag == 1'b1))begin cnt_bit <= cnt_bit + 1'b1; end end //输出 uart_tx always @(posedge clk or negedge rst_n)begin if(!rst_n)begin uart_tx <= 1'b1; end else if(bit_flag == 1'b1)begin case(cnt_bit) 0 : uart_tx <= 1'b0;//起始位 1 : uart_tx <= pi_data[0]; 2 : uart_tx <= pi_data[1]; 3 : uart_tx <= pi_data[2]; 4 : uart_tx <= pi_data[3]; 5 : uart_tx <= pi_data[4]; 6 : uart_tx <= pi_data[5]; 7 : uart_tx <= pi_data[6]; 8 : uart_tx <= pi_data[7]; 9 : uart_tx <= 1'b1;//停止位 default : uart_tx <= 1'b1; endcase end end endmodule
/*===============================* filename : uart_rx.v description : 串口接收模块 time : 2024-1-20 author : *================================*/ module uart_rx( input clk ,//时钟 50MHZ input rst_n ,//复位 input uart_rx ,//rx数据线 input [2:0] baud_sel ,//波特率选择 output reg [7:0] po_data ,//接收的数据 output reg po_flag //数据使能 ); //参数定义 parameter SCLK = 50_000_000;//系统时钟 50MHZ //波特率选择 parameter BAUD_9600 = SCLK/9600 , BAUD_19200 = SCLK/19200 , BAUD_38400 = SCLK/38400 , BAUD_57600 = SCLK/57600 , BAUD_115200 = SCLK/115200; //信号定义 reg uart_rx_1 ;//同步、打拍 reg uart_rx_2 ; wire rx_nedge ;//下降沿检测 reg start_flag ;//起始标志 reg work_en ;//工作使能 reg [15:0] cnt_baud ;//波特率计数器 reg [15:0] BAUD_NUM ; reg bit_flag ;//接收数据使能 reg [3:0] cnt_bit ;//bit计数器 reg [7:0] rx_data ;//数据 reg rx_flag ;//数据标志 //同步、打拍 检测下降沿 always @(posedge clk or negedge rst_n)begin if(!rst_n)begin uart_rx_1 <= 1'b1; uart_rx_2 <= 1'b1; end else begin uart_rx_1 <= uart_rx; uart_rx_2 <= uart_rx_1; end end assign rx_nedge = uart_rx_2 && ~uart_rx_1; //start_flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin start_flag <= 1'b0; end else if(rx_nedge && work_en == 1'b0)begin start_flag <= 1'b1; end else begin start_flag <= 1'b0; end end //work_en always @(posedge clk or negedge rst_n)begin if(!rst_n)begin work_en <= 1'b0; end else if(start_flag == 1'b1)begin work_en <= 1'b1; end else if(cnt_bit == 4'd8 && bit_flag == 1'b1)begin work_en <= 1'b0; end else begin work_en <= work_en; end end //cnt_baud always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_baud <= 16'd0; end else if((cnt_baud == BAUD_NUM - 1) || (work_en == 1'b0))begin cnt_baud <= 16'd0; end else if(work_en == 1'b1)begin cnt_baud <= cnt_baud + 1'b1; end end //BAUD_NUM always @(*)begin case(baud_sel) 3'd0 : BAUD_NUM = BAUD_9600 ; 3'd1 : BAUD_NUM = BAUD_19200 ; 3'd2 : BAUD_NUM = BAUD_38400 ; 3'd3 : BAUD_NUM = BAUD_57600 ; 3'd4 : BAUD_NUM = BAUD_115200; default : BAUD_NUM = BAUD_115200; endcase end //bit_flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin bit_flag <= 1'b0; end else if(cnt_baud == (BAUD_NUM >> 1) - 1)begin bit_flag <= 1'b1; end else begin bit_flag <= 1'b0; end end //cnt_bit always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt_bit <= 4'd0; end else if((cnt_bit == 4'd8) && (bit_flag == 1'b1))begin cnt_bit <= 4'd0; end else if(bit_flag == 1'b1)begin cnt_bit <= cnt_bit + 1'b1; end end //rx_data always @(posedge clk or negedge rst_n)begin if(!rst_n)begin rx_data <= 8'b0; end else if((cnt_bit>=4'd1)&&(cnt_bit<=4'd8)&&(bit_flag==1'b1))begin rx_data <= {uart_rx_2,rx_data[7:1]}; end end //rx_flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin rx_flag <= 1'b0; end else if((cnt_bit == 4'd8) && (bit_flag == 1'b1))begin rx_flag <= 1'b1; end else begin rx_flag <= 1'b0; end end //输出 //po_data always @(posedge clk or negedge rst_n)begin if(!rst_n)begin po_data <= 8'b0; end else if(rx_flag == 1'b1)begin po_data <= rx_data; end end //po_flag always @(posedge clk or negedge rst_n)begin if(!rst_n)begin po_flag <= 1'b0; end else begin po_flag <= rx_flag; end end endmodule
下周学习计划
- 学习调用IP核PLL;
- 学习AD采集代码编写;
学习资源
- 开发板
- 找别人的代码来看