1 //基本原理:采样
2 //技巧是:一位数据采多次,统计得到高电平的出现的次数
3 //次数多的就是该位的电平值。采样7次,0、1、2、3低电平,4、5、6、7位高电平。
4 //把一位数据分为16段,舍弃前五段和后四段,取中间7段来进行采样。
5 //起始位检测:通过边沿检测电路。
6 //设置波特率为9600
7 //1000000000/9600/16/20=325
8 //设置波特率115200
9 //1000000000/115200/16/20=27
10 //源代码
11 //verilog无法实现542.5ns的定时,只能实现540ns,故而tx_done会提前到来。
12 //不过没有关系,可以提前接收,但是不能滞后接收,
13 //如果出现,就会出现丢数据的现象。
14 module uart_rx_p(
15 clk,
16 reset_n,
17 baud_set,
18 uart_rx,
19 data,
20 rx_done
21 );
22 input clk;
23 input reset_n;
24 input [2:0] baud_set;
25 input uart_rx;
26 output reg [7:0] data;
27 output reg rx_done;
28
29 //先写一个两位寄存器来保存,边沿检测的两个时刻。
30 //同时定义两个寄存器的状态
31 reg [1:0] uart_rx_r;
32 always@(posedge clk or negedge reset_n)
33 if(!reset_n)
34 uart_rx_r<=2'b00;
35 else begin
36 uart_rx_r[0]<=uart_rx;
37 uart_rx_r[1]<=uart_rx_r[0];
38 end
39
40 //利用寄存器的时刻,来形成下降沿。
41 //这个下降沿是用来形成(数据的起始位(从高电平变为低电平))
42 //再利用这个下降沿来控制形成发送的rx_en(发送使能信号)
43 //使得计数器在整个计数范围内都可以计数,而不是短暂得一个下降沿
44 //reg[1]存储的是前一拍的采样结果,reg[0]是后一拍的采样结果,因为reg[0]连接的是uart_rx。
45 wire nedge_uart_rx ;
46 assign nedge_uart_rx=((uart_rx_r[1]==1) && (uart_rx_r[0]==0));
47 assign negde_uart_rx=(uart_rx_r==2'b10);
48
49 //书写一个上升沿,以致对比和学习
50 // wire pedge_uart_rx;
51 // assign pedge_uart_rx=(uart_rx_r==2'b01);
52
53 //开始书写采样分频
54 reg [8:0]bps_DR;
55 always@(*)begin
56 case(baud_set)
57 0:bps_DR=1000000000/9600/16/20-1;
58 1:bps_DR=1000000000/19200/16/20-1;
59 2:bps_DR=1000000000/38400/16/20-1;
60 3:bps_DR=1000000000/57600/16/20-1;
61 4:bps_DR=1000000000/115200/16/20-1;
62 default:bps_DR=1000000000/9600/16/20-1;
63 endcase
64 end
65 //书写采样的16
66 wire bps_clk_16x;
67 assign bps_clk_16x=(div_cnt==bps_DR/2);
68
69 //书写发送是能信号rx_en;
70 reg rx_en;
71 always@(posedge clk or negedge reset_n)
72 if(!reset_n)
73 rx_en<=0;
74 else if(nedge_uart_rx)//为什么sta_bit>=4;
75 rx_en<=1;
76 else if(rx_done || sta_bit>=4)
77 rx_en<=0;
78 //书写基本计数单元
79 reg[8:0]div_cnt;
80 always@(posedge clk or negedge reset_n)
81 if(!reset_n)
82 div_cnt<=0;
83 else if(rx_en)begin
84 if(div_cnt==bps_DR)
85 div_cnt<=0;
86 else
87 div_cnt<=div_cnt+1'b1;
88 end
89 else
90 div_cnt<=0;
91
92 //开始书写160位的接受数据的计数器
93 reg [7:0] bps_cnt;
94 always@(posedge clk or negedge reset_n)
95 if(!reset_n)
96 bps_cnt<=0;
97 else if(rx_en)begin
98 if(bps_clk_16x)begin
99 if(bps_cnt==160)
100 bps_cnt<=0;
101 else
102 bps_cnt<=bps_cnt+1'b1;
103 end
104 else
105 bps_cnt<=bps_cnt;
106 end
107 else
108 bps_cnt<=0;
109
110 //开始书写接收160位的数据和采样
111 reg [2:0] sta_bit;//存放加法的结果,来判断采样结果为1还是0;
112 reg [2:0] sto_bit;
113 reg [2:0] r_data [7:0];
114 always@(posedge clk or negedge reset_n)
115 if(!reset_n)begin
116 sta_bit<=0;
117 sto_bit<=0;
118 r_data[0]<=0;
119 r_data[1]<=0;
120 r_data[2]<=0;
121 r_data[3]<=0;
122 r_data[4]<=0;
123 r_data[5]<=0;
124 r_data[6]<=0;
125 r_data[7]<=0;
126 end
127 else if(bps_clk_16x)begin
128 case(bps_cnt)
129 0:begin//初始化各个数据,一便可以接收多位数据。
130 sta_bit<=0;
131 sto_bit<=0;
132 r_data[0]<=0;
133 r_data[1]<=0;
134 r_data[2]<=0;
135 r_data[3]<=0;
136 r_data[4]<=0;
137 r_data[5]<=0;
138 r_data[6]<=0;
139 r_data[7]<=0;
140 end
141 5,6,7,8,9,10,11:sta_bit<=sta_bit+uart_rx;
142 21,22,23,24,25,26,27:r_data[0]<=r_data[0]+uart_rx;
143 37,38,39,40,41,42,43:r_data[1]<=r_data[1]+uart_rx;//为什么加上uart_rx而不是r_data[0],因为每隔16个脉冲uart_rx会变化
144 53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
145 69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
146 85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
147 101,102,103,104,105,106,107:r_data[5] <= r_data[5] + uart_rx;
148 117,118,119,120,121,122,123:r_data[6] <= r_data[6] + uart_rx;
149 133,134,135,136,137,138,139:r_data[7] <= r_data[7] + uart_rx;
150 149,150,151,152,153,154,155:sto_bit<=sto_bit + uart_rx;//没有判断结果是1还是0啊
151 default:;
152 endcase
153 end
154
155 //开始书写判断每16位采样的结果是什么(是0还是1)
156 always@(posedge clk or negedge reset_n)
157 if(!reset_n)
158 data<=0;
159 //为什么不判断sta_bit和sto_bit;(没有寄存器存储sta_bit和sto_bit)
160 //因为在设置rx_en的时候,已经判断了开始的位置。
161 else if((bps_clk_16x)&&(bps_cnt==160))begin
162 data[0]<=(r_data[0]>=4)?1:0;
163 data[1]<=(r_data[1]>=4)?1:0;
164 data[2]<=(r_data[2]>=4)?1:0;
165 data[3]<=(r_data[3]>=4)?1:0;
166 data[4]<=(r_data[4]>=4)?1:0;
167 data[5]<=(r_data[5]>=4)?1:0;
168 data[6]<=(r_data[6]>=4)?1:0;
169 data[7]<=(r_data[7]>=4)?1:0;
170 end
171 // else if((bps_clk_16x)&&(bps_cnt==160))begin
172
173 // data[0]<=r_data[0][2];
174 // data[1]<=r_data[1][2];
175 // data[2]<=r_data[2][2];
176 // data[3]<=r_data[3][2];
177 // data[4]<=r_data[4][2];
178 // data[5]<=r_data[5][2];
179 // data[6]<=r_data[6][2];
180 // data[7]<=r_data[7][2];
181 // end
182
183 //书写rx_done
184 always@(posedge clk or negedge reset_n)
185 if(!reset_n)
186 rx_done<=0;
187 else if((bps_cnt==160)&&(div_cnt==bps_DR/2))
188 rx_done<=1;
189 else
190 rx_done<=0;
191 endmodule
192
193 //仿真代码
194 //仿真代码中有一个新的语法task,endtask
195 `timescale 1ns / 1ps
196 module uart_rx_p_tb();
197 reg clk;
198 reg reset_n;
199 wire [2:0] baud_set;
200 reg uart_rx;
201 wire [7:0] data;
202 wire rx_done;
203 assign baud_set=4;
204 uart_rx_p uart_rx_p_inst0(
205 clk,
206 reset_n,
207 baud_set,
208 uart_rx,
209 data,
210 rx_done
211 );
212
213 initial clk=1;
214 always #10 clk=!clk;
215
216 initial begin
217 reset_n=0;
218 uart_rx=1;
219 #201;
220 reset_n=1;
221 #200;
222 uart_tx_byte(8'ha5);
223 #90000;
224 uart_tx_byte(8'h5a);
225 #90000;
226 uart_tx_byte(8'h86);
227 #90000;
228 $stop;
229 end
230
231 //开始书写新的语法
232 task uart_tx_byte;
233 input [7:0] tx_data;
234 begin
235 uart_rx=1;
236 #20;
237 uart_rx=0;
238 #8680;//每隔8680发送一位数据,1000000000/115200/20;
239 uart_rx=tx_data[0];
240 #8680;
241 uart_rx = tx_data[1];
242 #8680;
243 uart_rx = tx_data[2];
244 #8680;
245 uart_rx = tx_data[3];
246 #8680;
247 uart_rx = tx_data[4];
248 #8680;
249 uart_rx = tx_data[5];
250 #8680;
251 uart_rx = tx_data[6];
252 #8680;
253 uart_rx = tx_data[7];
254 #8680;
255 uart_rx=1;
256 #8680;
257
258 end
259 endtask
260 endmodule