实现uart其实早就写了,不过不太完善,对于一个完美主义者来说,必须解决掉它。
1.什么是UART?
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。是异步通信协议。
2.什么是RS232?
RS232是物理层的电气接口要求。是一种接口标准。uart可以使用rs232物理层来通信。总的来说,对于一项通信任务,通信协议可以使用UART协议,而UART协议可以通过COM端口来实现硬件连线,此协议下的传输方式可以选用RS232或者RS485等。
开发板上的是:
UART实现方式:状态机或者线性序列机。
3.什么叫线性序列机?
当知晓信号在每个时刻的改变情况,那么就可以用计数器去拟合信号变化,比如在cnt=5的时候信号变1了,cnt=8的时候信号变0;当然这是可以自定义的。
简单的测试逻辑(回环测试):
以下通过线性序列机实现:
首先看看uart协议的数据格式:信号线上空闲的时候为高电平,当出现下跳到低电平的时候表示数据的起始位,接着的是低位在前高位在后的数据流,尾部可加奇偶校验位,最后加停止位,停止位长度可以定义。
编码实现:
波特率产生,波特率选择。波特率模块塞tx以及rx模块中了。rx中的采样时钟bps要快16倍。
什么叫波特率?
9600bps/s:表示1s信号可以传输9600bit的数据。
波特率与FPGA时钟关系:
总计数等于系统频率除以波特率。比如50m/9600=5208;
rtl图:
回环测试综合资源使用情况以及糟糕条件下的Fmax:
通过串口助手测试:
测试ok。
代码:
//************************************************ // Filename : uart_tx.v // Author : kingstacker // Company : School // Email : [email protected] // Device : Altera cyclone4 ep4ce6f17c8 // Description : //************************************************ module uart_tx ( /*i*/ input wire clk , input wire rst_n , input wire send_en , input wire [2:0] bps_set , input wire [7:0] data_i , /*o*/ output wire tx , output wire tx_done ); reg send_en_reg0; reg send_en_reg1; reg [7:0] data_i_reg; reg bps_clk; reg bps_en; reg [12:0] bps; reg [12:0] bps_cnt; reg [3:0] cnt; reg tx_done_reg; reg tx_reg; //bps select; always @(posedge clk or negedge rst_n) begin if (~rst_n) begin bps <= 13‘d5207; //324 end //if else begin case (bps_set) 3‘d0: bps <= 13‘d5207; 3‘d1: bps <= 13‘d2603; 3‘d2: bps <= 13‘d1301 ; 3‘d3: bps <= 13‘d867 ; 3‘d4: bps <= 13‘d433 ; default: bps <= 13‘d5207; endcase //case end //else end //always always @(posedge clk or negedge rst_n) begin //bps_cnt; if (~rst_n) begin bps_cnt <= 0; end //if else begin if (bps_en == 1‘b1) begin bps_cnt <= (bps_cnt == bps) ? 13‘d0 : bps_cnt + 1‘b1; end else begin bps_cnt <= 0; end end //else end //always always @(posedge clk or negedge rst_n) begin //bps_clk; if (~rst_n) begin bps_clk <= 0; end //if else begin if (bps_cnt == 13‘d1) begin bps_clk <= 1‘b1; end else begin bps_clk <= 1‘b0; end end //else end //always always @(posedge clk or negedge rst_n) begin //send_en syn; if (~rst_n) begin send_en_reg0 <= 0; send_en_reg1 <= 0; end //if else begin send_en_reg0 <= send_en; send_en_reg1 <= send_en_reg0; end //else end //always always @(posedge clk or negedge rst_n) begin //data refresh; if (~rst_n) begin data_i_reg <= 0; end //if else begin data_i_reg <= (send_en_reg1) ? data_i : data_i_reg; end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin bps_en <= 1‘b0; end //if else begin if (send_en_reg1 == 1‘b1) begin bps_en <= 1‘b1; end else begin bps_en <= (cnt == 4‘d10) ? 1‘b0 : bps_en; end end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin cnt <= 0; end //if else begin if (cnt == 4‘d10) begin cnt <= 0; end else begin cnt <= (bps_clk == 1‘b1) ? cnt + 1‘b1 : cnt; end end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin tx_done_reg <= 1‘b0; tx_reg <= 1‘b1; end //if else begin case (cnt) 0 : begin tx_done_reg <= 1‘b0;tx_reg <= 1‘b1; end 1 : begin tx_reg <= 1‘b0; end 2 : begin tx_reg <= data_i_reg[0]; end 3 : begin tx_reg <= data_i_reg[1]; end 4 : begin tx_reg <= data_i_reg[2]; end 5 : begin tx_reg <= data_i_reg[3]; end 6 : begin tx_reg <= data_i_reg[4]; end 7 : begin tx_reg <= data_i_reg[5]; end 8 : begin tx_reg <= data_i_reg[6]; end 9 : begin tx_reg <= data_i_reg[7]; end 10: begin tx_done_reg <= 1‘b1;tx_reg <= 1‘b1; end default: begin tx_done_reg <= 1‘b0;tx_reg <= 1‘b1; end endcase //case end //else end //always assign tx_done = tx_done_reg; assign tx = tx_reg; endmodule
//************************************************ // Filename : uart_rx.v // Author : kingstacker // Company : School // Email : [email protected] // Device : Altera cyclone4 ep4ce6f17c8 // Description : uart rx; //************************************************ module uart_rx ( /*i*/ input wire clk , input wire rst_n , input wire [2:0] bps_set , input wire rx , /*o*/ output wire [7:0] data_o , output wire rx_done ); reg rx_reg0; reg rx_reg1; reg rx_temp0; reg rx_temp1; reg bps_clk; reg bps_en; wire rx_neg; reg [8:0] bps; reg [8:0] bps_cnt; reg [7:0] cnt; reg rx_done_reg; reg [7:0] data_o_reg; reg [7:0] data_o_reg1; always @(posedge clk or negedge rst_n) begin //syn rx; if (~rst_n) begin rx_reg0 <= 0; rx_reg1 <= 0; end //if else begin rx_reg0 <= rx; rx_reg1 <= rx_reg0; end //else end //always always @(posedge clk or negedge rst_n) begin //neg; if (~rst_n) begin rx_temp0 <= 0; rx_temp1 <= 0; end //if else begin rx_temp0 <= rx_reg1; rx_temp1 <= rx_temp0; end //else end //always assign rx_neg = (~rx_temp0)&&rx_temp1; //bps select; always @(posedge clk or negedge rst_n) begin if (~rst_n) begin bps <= 9‘d324; //324 end //if else begin case (bps_set) 3‘d0: bps <= 9‘d324; 3‘d1: bps <= 9‘d162; 3‘d2: bps <= 9‘d80 ; 3‘d3: bps <= 9‘d53 ; 3‘d4: bps <= 9‘d26 ; default: bps <= 9‘d324; endcase //case end //else end //always always @(posedge clk or negedge rst_n) begin //bps_cnt; if (~rst_n) begin bps_cnt <= 0; end //if else begin if (bps_en == 1‘b1) begin bps_cnt <= (bps_cnt == bps) ? 9‘d0 : bps_cnt + 1‘b1; end else begin bps_cnt <= 0; end end //else end //always always @(posedge clk or negedge rst_n) begin //bps_clk; if (~rst_n) begin bps_clk <= 0; end //if else begin if (bps_cnt == 9‘d1) begin bps_clk <= 1‘b1; end else begin bps_clk <= 1‘b0; end end //else end //always always @(posedge clk or negedge rst_n) begin //cnt; if (~rst_n) begin cnt <= 0; end //if else begin if (bps_en == 1‘b1) begin cnt <= (bps_clk == 1‘b1) ? cnt + 1‘b1 : cnt; end else begin cnt <= 0; end end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin bps_en <= 0; end //if else begin if (rx_neg == 1‘b1) begin bps_en <= 1‘b1; end else begin bps_en <= (cnt == 8‘d159 || (cnt == 8‘d7 && (rx_reg1))) ? 1‘b0 : bps_en; end end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin rx_done_reg <= 1‘b0; data_o_reg <= 0; end //if else begin case (cnt) 0 : begin rx_done_reg <= 1‘b0; end 23 : begin data_o_reg[0] <= rx_reg1; end 39 : begin data_o_reg[1] <= rx_reg1; end 55 : begin data_o_reg[2] <= rx_reg1; end 71 : begin data_o_reg[3] <= rx_reg1; end 87 : begin data_o_reg[4] <= rx_reg1; end 103: begin data_o_reg[5] <= rx_reg1; end 119: begin data_o_reg[6] <= rx_reg1; end 135: begin data_o_reg[7] <= rx_reg1; end 159: begin rx_done_reg <= 1‘b1; end default: ; endcase //case end //else end //always always @(posedge clk or negedge rst_n) begin if (~rst_n) begin data_o_reg1 <= 0; end //if else begin data_o_reg1 <= (cnt == 8‘d159) ? data_o_reg : data_o_reg1; end //else end //always assign rx_done = rx_done_reg; assign data_o = data_o_reg1; endmodule
top.v就不贴了,
工程完整源代码可在码云中查看和下载:https://gitee.com/kingstacker/uart
以上。
时间: 2024-11-07 00:54:02