【协议时序】-UART-RS232串口通信-接收模块
一、设计文件
第一种写法:未使用状态机(参考开源骚客程序-SDRAM第一季)
`define SIM module uart_rx ( // system signals input sclk , input s_rst_n , // uart interface input rs232_rx , // output signals output reg [7:0]rx_data ,// 8位的寄存器,对串口接收到的数据进行:串转并,使用位拼接 output reg po_flag // 拉高:接收模块完成数据接收,告诉其他模块可以来使用我接收到的数据了 ); //-------------------------------------------------------- // difine parameter and internal signals //-------------------------------------------------------- `ifndef SIM localparam BAUD_END = 5207 ; `else localparam BAUD_END = 56 ; `endif localparam BAUD_M = BAUD_END/2 - 1 ; localparam BIT_END = 8 ; reg rx_r1 ; reg rx_r2 ; reg rx_r3 ;// 打3拍、捕获rx下降沿——单bit信号跨时钟域处理 reg rx_flag ;// 拉高:FPGA正在接收数据;以rx_r3波形为准 reg [12:0] baud_cnt ;// 波特率计数器,表示串口发送一个bit所占用的系统时钟数,5208需要13位 reg bit_flag ;// 波特率计数器记到中间值后立刻拉高(中间采样) reg [3:0] bit_cnt ;// 计数传了8位数据 wire rx_neg ;// 定义rx的下降沿 //-------------------------------------------------------- // Main code //-------------------------------------------------------- // 检测rx下降沿 assign rx_neg = ~ rx_r2 & rx_r3 ; // ??:为什么不直接检测rx_r3的下降沿 // 打3拍处理 always@(posedge sclk)begin rx_r1 <= rs232_rx ; rx_r2 <= rx_r1 ; rx_r3 <= rx_r2 ; end // 数据接收开始、结束的标志信号 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) rx_flag <= 1'b0 ; else if(rx_neg == 1'b1) rx_flag <= 1'b1 ; else if(bit_cnt == 1'b0 && baud_cnt == BAUD_END) rx_flag <= 1'b0 ; end // 波特率计数器记到中间值拉高 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) bit_flag <= 1'b0 ; else if(baud_cnt == BAUD_M) bit_flag <= 1'b1 ; else bit_flag <= 1'b0 ; end // 波特率计数器 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) baud_cnt <= 1'b0 ; else if(baud_cnt == BAUD_END) baud_cnt <= 1'b0 ; else if(bit_flag == 1'b1) baud_cnt <= baud_cnt + 1'b1 ; else baud_cnt <= 1'b0 ; end // 计数传到第几位数据 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) bit_cnt <= 1'b0 ; else if(bit_cnt == BIT_END && bit_flag == 1'b1) bit_cnt <= 1'b0 ; else bit_cnt <= bit_cnt + 1'b1 ; end // 输入数据 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) rx_data <= 1'b0 ; else if(bit_cnt >=1'b1 && bit_flag == 1'b1) rx_data <= {rx_r2,rx_data[7:1]} ;//??:为啥是rx_r2和输入数据按位拼接 end // 数据传输完成标志位 always@(posedge sclk or negedge s_rst_n)begin if(s_rst_n == 1'b0) po_flag <= 1'b0 ; else if(bit_cnt == BIT_END && bit_flag == 1'b1) // po_flag <= 1'b1 ; else po_flag <= 1'b0 ; end endmodule
第二种写法:使用三段式状态机(参考黑金程序)
//================================================================================ // Revision History: // Date By Revision Change Description //-------------------------------------------------------------------------------- //2017/8/1 1.0 Original //*******************************************************************************/ module uart_rx #( parameter CLK_FRE = 50, //clock frequency(Mhz) parameter BAUD_RATE = 115200 //serial baud rate ??????为什么是串行波特率 ) ( input clk, //clock input input rst_n, //asynchronous reset input, low active output reg[7:0] rx_data, //received serial data output reg rx_data_valid, //received serial data is valid input rx_data_ready, //data receiver module ready input rx_pin //serial data input ); //calculates the clock cycle for baud rate localparam CYCLE = CLK_FRE * 1000000 / BAUD_RATE; //state machine code localparam S_IDLE = 1; localparam S_START = 2; //start bit localparam S_REC_BYTE = 3; //data bits localparam S_STOP = 4; //stop bit localparam S_DATA = 5; reg[2:0] state; reg[2:0] next_state; reg rx_d0; //delay 1 clock for rx_pin reg rx_d1; //delay 1 clock for rx_d0 wire rx_negedge; //negedge of rx_pin reg[7:0] rx_bits; //temporary storage of received data reg[15:0] cycle_cnt; //baud counter reg[2:0] bit_cnt; //bit counter assign rx_negedge = rx_d1 && ~rx_d0; always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin rx_d0 <= 1'b0; rx_d1 <= 1'b0; end else begin rx_d0 <= rx_pin; rx_d1 <= rx_d0; end end always@(posedge clk or negedge rst_n)//第一段:同步时序,描述状态转移 begin if(rst_n == 1'b0) state <= S_IDLE; else state <= next_state; end always@(*) //(*)第二段:组合逻辑判断状态转移条件、描述状态转移规律 begin case(state) S_IDLE: if(rx_negedge) next_state <= S_START; else next_state <= S_IDLE; S_START: if(cycle_cnt == CYCLE - 1)//one data cycle next_state <= S_REC_BYTE; else next_state <= S_START; S_REC_BYTE: if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //receive 8bit data next_state <= S_STOP; else next_state <= S_REC_BYTE; S_STOP: if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver next_state <= S_DATA; else next_state <= S_STOP; S_DATA: if(rx_data_ready) //data receive complete next_state <= S_IDLE; else next_state <= S_DATA; default: next_state <= S_IDLE; endcase end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_data_valid <= 1'b0; else if(state == S_STOP && next_state != state) rx_data_valid <= 1'b1; else if(state == S_DATA && rx_data_ready) rx_data_valid <= 1'b0; end always@(posedge clk or negedge rst_n)//第三段:同步时序,描述每个状态的输出 begin if(rst_n == 1'b0) rx_data <= 8'd0; else if(state == S_STOP && next_state != state) rx_data <= rx_bits;//latch received data end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) begin bit_cnt <= 3'd0; end else if(state == S_REC_BYTE) if(cycle_cnt == CYCLE - 1) bit_cnt <= bit_cnt + 3'd1; else bit_cnt <= bit_cnt; else bit_cnt <= 3'd0; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) cycle_cnt <= 16'd0; else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state) cycle_cnt <= 16'd0; else cycle_cnt <= cycle_cnt + 16'd1; end //receive serial data bit data always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rx_bits <= 8'd0; else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1) rx_bits[bit_cnt] <= rx_pin; else rx_bits <= rx_bits; end endmodule
二、测试文件
`timescale 1ns/1ns module tb_uart_rx; reg sclk ; reg s_rst_n ; reg rs232_rx ; wire po_flag ; wire [7:0] rx_data ; reg [7:0] mem_a[3:0] ; //存储器,位宽8bit,深度4bit initial begin sclk = 1'b1 ; s_rst_n = 1'b0 ; rs232_rx = 1'b1 ; #100 ; s_rst_n = 1'b1 ; #100 ; tx_byte() ; end always # 10 sclk = ~ sclk ; // 读入数据 initial $readmemh ("./tx_data.txt", mem_a) ; //将tx_data.txt文件汇总的输入传入定义好的mem_a存储器中,存放:55、12、34、aa // 发送数据 task tx_byte(); integer i; for(i=0;i<4; i=i+1)begin tx_bit(mem_a[i]); // 任务中调用另一个任务 end endtask task tx_bit( // 任务名 input [7:0] data // 声明输入端口 ); integer i ; for(i=0 ; i<10 ; i=i+1)begin case(i) 0: rs232_rx <= 1'b0 ; 1: rs232_rx <= data[0] ; 2: rs232_rx <= data[1] ; 3: rs232_rx <= data[2] ; 4: rs232_rx <= data[3] ; 5: rs232_rx <= data[4] ; 6: rs232_rx <= data[5] ; 7: rs232_rx <= data[6] ; 8: rs232_rx <= data[7] ; 9: rs232_rx <= 1'b1 ; endcase # 11200; end endtask uart_rx a1 ( .sclk(sclk) , .s_rst_n(s_rst_n) , .rs232_rx(rs232_rx) , .rx_data(rx_data) ,// 8位的寄存器,对串口接收到的数据进行:串转并,使用位拼接 .po_flag(po_flag) // 拉高:接收模块完成数据接收,告诉其他模块可以来使用我接收到的数据了 ); endmodule
三、波形图
波形图还有一点问题
四、RTL图

浙公网安备 33010602011771号