补充一些串口里用到的数值的相关知识点
接收端串口时序图:
程序设计:
`timescale 1ns / 1ps
/串口接收端 串行转并行
module uart_rx(
input sys_clk ,
input rst_n ,
input rx_data , //输入串行数据
output reg[7:0] uart_data , // 输出并行数据
output reg rx_done //数据传输完成结束信号
);
parameter SYSCLK = 50_000_000 ;
parameter Baud = 115200 ;
parameter COUNT = SYSCLK/Baud ;//434 传输1比特所需要的时钟周期
parameter MID = COUNT/2 ;
///产生开始信号(检测下降沿-----二级寄存)
reg rx_reg1 ;
reg rx_reg2 ;
wire start_flag ; 开始信号
reg rx_flag ;
reg [3:0] cnt_bit ;///0~9
reg [9:0] cnt ;///434
reg [7:0] data_reg ;
always@(posedge sys_clk)
if(!rst_n)begin
rx_reg1 <= 1 ; //处于空闲位 数据线上无数据
rx_reg2 <= 1 ; //处于空闲位 数据线上无数据
end
else
begin
rx_reg1 <= rx_data ;
rx_reg2 <= rx_reg1 ;
end
assign start_flag = ~rx_reg1 & rx_reg2 ;
//rx_flag
always@(posedge sys_clk )
if(!rst_n)
rx_flag <= 0 ;
else if (start_flag)
rx_flag <= 1 ;
else if ( cnt_bit == 9 && cnt == MID -1 )
rx_flag <= 0 ;
else
rx_flag <= rx_flag ;
cnt 434
always@(posedge sys_clk )
if(!rst_n)
cnt <= 0;
else if ( rx_flag == 1 )begin
if ( cnt == COUNT -1) ///一定要减一,如果不减一,实际会计到435次,反算回去波特率就不是115200了
cnt <= 0;
else
cnt <= cnt +1 ;
end
else
cnt <= 0 ;
/计数器
always@(posedge sys_clk )
if(!rst_n)
cnt_bit <= 0 ;
else if ( rx_flag )begin
if ( cnt == COUNT -1)begin
if(cnt_bit == 9)
cnt_bit <= 0 ;
else
cnt_bit <= cnt_bit +1 ;
end
else
cnt_bit <= cnt_bit ;
end
else
cnt_bit <= 0 ;
[7:0]uart_data
/*
cnt_bit = 0 起始位
cnt_bit = 1-8 数据位
cnt_bit = 9 停止位
但是 [7:0]uart_data 没有uart[8]
所以
if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
uart_data[cnt_bit -1] <= rx_data ;
*/
// always@(posedge sys_clk )
// if(!rst_n)
// uart_data <= 0 ;
// else if ( rx_flag )begin
// if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
// uart_data[cnt_bit -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
// else
// uart_data <= uart_data ;
// end
// else
// uart_data <= 0 ;
因为这里要让uart_data只在rx_done的时候有值,所以定义一个中间寄存器data_reg
always@(posedge sys_clk )
if(!rst_n)
data_reg <= 0 ;
else if ( rx_flag )begin
if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
data_reg[cnt_bit -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
else
data_reg <= data_reg ;
end
else
data_reg <= 0 ;
// 其他赋值方法1
// always@(posedge sys_clk )
// if(!rst_n)
// uart_data <= 0;
// else if (cnt == MID -1)begin
// case(cnt_bit)
// 0: uart_data <= 0 ;
// 1: uart_data [0] <= rx_data ;
// 2: uart_data [1] <= rx_data ;
// 3: uart_data [2] <= rx_data ;
// 4: uart_data [3] <= rx_data ;
// 5: uart_data [4] <= rx_data ;
// 6: uart_data [5] <= rx_data ;
// 7: uart_data [6] <= rx_data ;
// 8: uart_data [7] <= rx_data ;
// 9: uart_data <= uart_data ; ///停止位的时候数据传完,保持
// endcase
// end
// else
// uart_data <= uart_data ;
// 其他赋值方法2
// always@(posedge sys_clk )
// if(!rst_n)
// uart_data <= 0 ;
// else if (cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9)
// uart_data <= {rx_data,uart_data[7:1]} ;
// else
// uart_data <= uart_data ;
给uart_data赋值
always@(posedge sys_clk )
if(!rst_n)
uart_data <= 0 ;
else if (rx_flag)begin
if (cnt_bit == 9 && cnt == MID/4 -1)
uart_data <= data_reg ;
else
uart_data <= uart_data ;
end
else
uart_data <= uart_data ; 可以保持到下一个数据到来
uart_data <= 0 ; 只保持在rx_done处于高电平的时候
/rx_done
always@(posedge sys_clk )
if(!rst_n)
rx_done <= 0 ;
else if (rx_flag)begin
if ( cnt_bit == 9 && cnt == MID/2 -1)
rx_done <= 1 ;
else
rx_done <= 0 ;
end
else
rx_done <= 0 ;
endmodule
仿真程序
`timescale 1ns / 1ps
module test_bench( );
reg sys_clk ;
reg rst_n ;
reg rx_data ; //输入串行数据
wire[7:0] uart_data ; // 输出并行数据
wire rx_done ;//数据传输完成结束信号
parameter SYSCLK = 50_000_000 ;
parameter Baud = 115200 ;
parameter COUNT = SYSCLK/Baud ;//434 传输1比特所需要的时钟周期
parameter MID = COUNT/2 ;
initial
begin
sys_clk = 0 ;
rst_n = 0 ;
#10
rst_n = 1 ;
end
always #1 sys_clk = ~sys_clk ; //2ns
initial
begin
uart_out (8'h34);
uart_out (8'hef);
uart_out (8'h98);
uart_out (8'h70);
uart_out (8'h14);
end
//任务函数
task uart_out ;
input [7:0] DATA ;
begin
rx_data = 1 ;///空闲位初始
#20
rx_data = 0 ;///起始位
///传输1bit的计时次数*1周期时间=总时间
#(COUNT*2) rx_data = DATA[0] ;///数据位第一位
#(COUNT*2) rx_data = DATA[1] ;///数据位第二位
#(COUNT*2) rx_data = DATA[2] ;
#(COUNT*2) rx_data = DATA[3] ;
#(COUNT*2) rx_data = DATA[4] ;
#(COUNT*2) rx_data = DATA[5] ;
#(COUNT*2) rx_data = DATA[6] ;
#(COUNT*2) rx_data = DATA[7] ;
#(COUNT*2) rx_data = 1 ;
#(COUNT*2) ;//停止位也需要时间
end
endtask
uart_rx uart_rx1(
. sys_clk (sys_clk ) ,
. rst_n (rst_n ) ,
. rx_data (rx_data ) , //输入串行数据
. uart_data (uart_data) , // 输出并行数据
. rx_done (rx_done ) //数据传输完成结束信号
);
endmodule
仿真波形