uart通信方式因其简单易于实现和成本低的特点,是工业现场经常用到的一种通信方式,大部分的数字仪表,模块和设备都能支持。常见的Rs232,Rs485,Rs422皆与uart格式相同;不同的是Uart一般是TTL电平的,RS232指的是RS232电平的串口,Rs485指的是Rs485电平(或电气特性)的。

本文实现的是通信参数固定的一种简单情况,参数可变模块后面再整理下。话不多说,直接上代码。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
// 9600, N, 8, 1 module uart_st # ( parameter BAUD_RATE = 115200 ) ( input clk50m, input rst, input [7:0] data, input enable, output reg tx, output reg busy // 指示外部调用模块,在忙的时候,不接收新的数据 ); localparam BAUD_CNT = (BAUD_RATE == 9600) ? 5208 - 1 : (BAUD_RATE == 115200) ? 434 - 1 : 434 - 1 ; // 缓存外部数据data reg [7:0] data_r; always @ (posedge clk50m or posedge rst) if(rst) data_r <= 0; else if (enable && busy == 0) data_r <= data; else data_r <= data_r; // 用状态机来完成发送 reg [12:0] cnt; reg [3:0] num; // 定义状态空间 localparam FSM_IDLE = 0; localparam FSM_START = 1; localparam FSM_DATA = 2; localparam FSM_PARITY = 3; localparam FSM_STOP = 4; // 定义状态变量 reg [2:0] cstate; // 完成状态机,每一个状态里,状态转移和判断,根据状态输出 always @ (posedge clk50m or posedge rst) if(rst) begin cstate <= FSM_IDLE; busy <= 0; tx <= 1; cnt <= 0; num <= 0; end else case (cstate) FSM_IDLE:// 空闲状态 begin tx <= 1; // 空闲发送 1 if(enable) // 需要发送数据 begin cstate <= FSM_START; busy <= 1; cnt <= 0; end else cstate <= FSM_IDLE; end FSM_START: begin tx <= 0; // 发送起始位 if(cnt == BAUD_CNT) begin cnt <= 0; cstate <= FSM_DATA; end else begin cnt <= cnt + 1; cstate <= FSM_START; end end FSM_DATA: begin tx <= data_r[num]; // 并串转换 if(cnt == BAUD_CNT && num == 8 - 1 ) begin cstate <= FSM_STOP; cnt <= 0; num <= 0; end else if(cnt == BAUD_CNT && num < 8 - 1 ) begin num <= num + 1; cnt <= 0; end else begin cnt <= cnt + 1; cstate <= FSM_DATA; num <= num; end end FSM_PARITY: begin cstate <= FSM_STOP; end FSM_STOP: begin tx <= 1; if(cnt == BAUD_CNT ) begin cnt <= 0; cstate <= FSM_IDLE; busy <= 0; end else begin cnt <= cnt + 1; cstate <= FSM_STOP; end end default: begin cstate <= FSM_IDLE; busy <= 0; tx <= 1; cnt <= 0; num <= 0; end endcase endmodule |
仿真程序:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
module tb(); reg clk = 0; always #10 clk = ~clk; wire busy; reg [7:0] data; reg tx_en = 0; reg rst = 0; initial begin data = 0; tx_en = 0; rst = 1; #20; rst = 0; #10; @(posedge clk); repeat(10) begin while(busy) @(posedge clk); data = data + 1; tx_en = 1; @(posedge clk); tx_en = 0; @(posedge clk); end #200; $stop; end wire tx; uart_st uart_st_inst ( .clk50m (clk), .rst (rst), .data (data), .enable (tx_en), .tx (tx), .busy (busy) // 指示外部调用模块,在忙的时候,不接收新的数据 ); endmodule |
仿真波形:

