11.串口接收原理与思路
1.原理
-
基本原理:采样。
-
技巧是:一位数据采多次,统计得到该电平出现的次数,次数多的就是该电平值。
-
起始位检测:通过边沿检测电路。
-
串口接收模块整体框图
2.思路
-
对边沿电平进行检测
-
波特率的设置,我们这里要把它分割成16份
-
对(bps_cnt)16位操作 总共10位数据 那么要计数到160
-
接收16个格子中的中间的数据(r_date,sto_date,sta_date )
-
基本的分频器(div_cnt)来得到bps_clk = ( div_cnt == Bps_DR /2) 和 使能端口(RX_EN)
-
接收数据
-
处理rx_done
3.代码
`timescale 1ns / 1ps
module uart_byte_tx(
sys_clk , sys_rst , baud_set ,date_rx , date , rx_done );
input sys_clk ;
input sys_rst ;
input [2:0] baud_set ;
input date_rx ;
output reg [7:0] date ;
output reg rx_done ;
// 1. 滤波
// reg date_rx_sync_1 ;
// reg date_rx_sync_2 ;
// wire date_rx_sync ;
// always@(posedge sys_clk or negedge sys_rst )
// if(!sys_rst)
// begin
// date_rx_sync_1 <= 0 ;
// date_rx_sync_2 <= 0;
// end
// else
// begin
// date_rx_sync_1 <= date_rx ;
// date_rx_sync_2 <= date_rx_sync_1 ;
// end
// assign date_rx_sync = date_rx_sync_2 ;
// 2.波特率设置
reg [8:0] bps_DR ;
always@(*) begin
case(baud_set) // 一份数据分成了16份
1 : bps_DR <= 325 ; // 1_000_000_000 / 9600 /20 /16
2 : bps_DR <= 163 ; // 1_000_000_000 / 19200 /20/16
3 : bps_DR <= 81 ; // 1_000_000_000 / 38400 /20 /16
4 : bps_DR <= 54 ; // 1_000_000_000 / 57600 /20 /16
5 : bps_DR <= 27 ; // 1_000_000_000 / 115200 /20/16
default bps_DR <= 325 ;
endcase
end
// 3.边沿检测
reg [1:0] check_date_rx;
wire negedge_date_rx; //下降沿检测
//wire posedge_date_rx;
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
check_date_rx <= 2'b00 ;
else
begin
//check_date_rx[0] <= date_rx;
//check_date_rx[1] <= check_date_rx[0] ;
check_date_rx <= { check_date_rx[0] , date_rx };
end
assign negedge_date_rx = ( check_date_rx == 2'b10 );
//assign posedge_date_rx = ( check_date_rx == 2'b01 );
// 4. 检测到有效下降沿 产生 有效的使能信号 RX_EN
reg RX_EN ;
reg [2:0 ] sta_date ;
reg [2:0] sto_date ;
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
RX_EN <= 0 ;
else if (negedge_date_rx)
RX_EN <= 1;
else if ((rx_done) || ( sta_date[2] == 1)) //当数据发送完成 或者 起始位不满足低电平
RX_EN <= 0 ;
else
RX_EN <= RX_EN ;
// 5. bps_DR 分频
reg [8:0] div_cnt ;
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
div_cnt <= 0 ;
else if (RX_EN) begin
if( (bps_DR - 1) <= div_cnt)
div_cnt <= 0 ;
else
div_cnt <= div_cnt + 1'b1 ;
end
else
div_cnt <= 0 ;
// 6 . 对波特率进行计数
wire bps_clk ;
reg [7:0 ] bps_cnt ;
assign bps_clk = (div_cnt == (bps_DR - 1) /2 ) ;
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
bps_cnt <= 0 ;
else if (RX_EN) begin
if(bps_clk) begin
//每来一个bps_clk 进行加一
if ( 8'd159 <= bps_cnt)
bps_cnt<= 0 ;
else
bps_cnt <= bps_cnt + 1'd1 ;
end
else
bps_cnt <= bps_cnt ;
end
else
bps_cnt <= 0 ;
// 7.数据的接收
reg [2:0] r_date [7:0] ;
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst) begin
sta_date<= 0 ;
r_date[0] <= 0 ;
r_date[1] <= 0 ;
r_date[2] <= 0 ;
r_date[3] <= 0 ;
r_date[4] <= 0 ;
r_date[5] <= 0 ;
r_date[6] <= 0 ;
r_date[7] <= 0 ;
sto_date<= 0 ; end
else if (bps_clk) begin
case(bps_cnt)
0 : begin
sta_date <= 0 ;
r_date[0] <= 0 ;
r_date[1] <= 0 ;
r_date[2] <= 0 ;
r_date[3] <= 0 ;
r_date[4] <= 0 ;
r_date[5] <= 0 ;
r_date[6] <= 0 ;
r_date[7] <= 0 ;
sto_date<= 0 ; end
5,6,7,8,9,10,11: sta_date <= sta_date + date_rx;
21,22,23,24,25,26,27 : r_date[0]<= r_date[0]+date_rx;
37,38,39,40,41,42,43 : r_date[1]<= r_date[1]+date_rx;
53,54,55,56,57,58,59: r_date[2]<= r_date[2]+date_rx;
69,70,71,72,73,74,75: r_date[3]<= r_date[3]+date_rx;
85,86,87,88,89,90,91: r_date[4]<= r_date[4]+date_rx;
101,102,103,104,105,106,107 : r_date[5]<= r_date[5]+date_rx;
117,118,119,120,121,122,123: r_date[6]<= r_date[6]+date_rx;
133,134,135,136,137,138,139: r_date[7]<= r_date[7]+date_rx;
149,150,151,152,153,154,155: sto_date <= sto_date +date_rx;
endcase
end
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
date <= 0 ;
else if ((159 <= bps_cnt) && (bps_clk))begin
date[0]<=r_date[0][2] ;
date[1]<=r_date[1][2] ;
date[2]<=r_date[2][2] ;
date[3]<=r_date[3][2] ;
date[4]<=r_date[4][2] ;
date[5]<=r_date[5][2] ;
date[6]<=r_date[6][2] ;
date[7]<=r_date[7][2] ; end
//8.rx_done
always@(posedge sys_clk or negedge sys_rst )
if (!sys_rst)
rx_done <= 0 ;
else if ((159 <= bps_cnt) && ( bps_clk ) )
rx_done <= 1 ;
else
rx_done <= 0 ;
endmodule
4.激励文件代码
`timescale 1ns / 1ps
module uart_byte_tx_tb( );
reg sys_clk ;
reg sys_rst ;
reg [2:0] baud_set ;
reg date_rx ;
wire [7:0] date ;
wire rx_done ;
uart_byte_tx uart_byte_tx(
.sys_clk (sys_clk ) ,
.sys_rst (sys_rst) ,
.baud_set (baud_set) ,
.date_rx (date_rx) ,
.date (date ) ,
.rx_done (rx_done)
);
initial sys_clk = 1 ;
always#10 sys_clk = !sys_clk ;
initial
begin
sys_rst = 0 ;
date_rx = 1 ;
baud_set = 5 ;
#201;
sys_rst = 1 ;
#200;
uart_tx_byte(8'b1001_1010);
#90000
uart_tx_byte(8'b1000_1000);
#90000
uart_tx_byte(8'b1001_1011);
#90000
$stop;
end
task uart_tx_byte;
input [7:0] rx_date;
begin
date_rx = 1;
#20;
date_rx = 0;
#8680;
date_rx = rx_date[0] ;
#8680;
date_rx = rx_date[1] ;
#8680;
date_rx = rx_date[2] ;
#8680;
date_rx = rx_date[3] ;
#8680;
date_rx = rx_date[4] ;
#8680;
date_rx = rx_date[5] ;
#8680;
date_rx = rx_date[6] ;
#8680;
date_rx = rx_date[7] ;
#8680;
date_rx = 1 ;
#8680; end
endtask
endmodule
5.仿真结果