小梅哥课程学习——串口接收程序的设计与调试

发布时间 2023-03-22 21:11:39作者: 无情的造轮子
  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 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